在glsl中使用实例化时,为什么纹理缓冲区比顶点输入更快?

时间:2016-06-13 19:00:08

标签: c++ performance opengl glsl opengl-4

我正在编写自己的渲染引擎。目前我正在研究地形。 我使用glDrawArraysInstanced渲染地形。地形是由很多"块组成的。每个块都是一个四边形,它也是绘制调用的一个实例。然后在曲面细分着色器中对每个四边形进行细分。对于我的着色器输入,我使用 VBOs 实例化VBO (使用顶点属性除数)和纹理缓冲区。这是我的一个着色器的一个简单示例:

#version 410 core

layout (location = 0) in vec3 perVertexVector; // VBO attribute  
layout (location = 1) in vec3 perInstanceVector; // VBO instanced attribute
uniform samplerBuffer someTextureBuffer; // texture buffer
out vec3 outputVector;

void main()
{
    // some processing of the inputs;
    outputVector = something...whatever...;
} 

一切正常,我没有错误。它呈现在 60-70 FPS 附近。但今天我改变了代码,我不得不将所有实例化的VBO更改为纹理缓冲区。由于某种原因,性能增加了一倍,它运行在 120-160 FPS!(有时甚至更多!)我没有改变任何其他东西,我只是创建了更多的纹理缓冲区并使用它们代替所有实例化属性。

这是我用于创建着色器实例化属性的代码(简化为可读版本):

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribDivisor(0, 1); // this makes the buffer instanced

这是我创建纹理缓冲区的简化代码:

glBindTexture(GL_TEXTURE_BUFFER, textureVBO);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32F, VBO);

我不认为我做错了什么因为一切正常。它只是性能...我会假设属性比纹理快,但我得到了相反的结果,我真的很惊讶纹理缓冲区比属性快两倍以上。

但还有一件事我不明白。

我实际上两次调用地形(glDrawArraysInstanced)的渲染函数。第一次是渲染地形,第二次是使用不同的水反射变换矩阵将其渲染到FBO。当我只渲染一次(没有反射)并且我使用实例属性时,我得到 90 FPS ,这比我之前提到的60 FPS快一点。

但是!当我只渲染一次并使用纹理缓冲区时,差异非常小。它的运行速度与我渲染两次(大约120-150 fps)时一样快!

我想知道它是否使用某种缓存或其他东西,但它对我没有任何意义,因为顶点用两个渲染调用中的每一个的不同矩阵进行变换,因此着色器输出完全不同的结果。 / p>

我真的很感激这个问题的一些解释:

为什么纹理缓冲区比实例属性更快?

修改

以下是我的问题的摘要,以便更好地理解:

我唯一能做的就是在我的glsl代码中更改这些行:

layout (location = 1) in vec3 perInstanceVector; // VBO instanced attribute
outputVector = perInstanceVector;

到此:

uniform samplerBuffer textureBuffer; // texture buffer which has the same data as the previous VBO instanced attribute
outputVector = texelFetch(textureBuffer, gl_InstanceID).xyz

一切都和以前完全一样,但在性能方面却快了两倍。

1 个答案:

答案 0 :(得分:0)

我看到3个可能的原因:

  1. 着色器的占用率可能会不同,因为寄存器的使用方式不同,因此性能会大不相同
  2. 在属性之间,获取的方法不同,调度程序在着色器中的等待处理比输入汇编器中的处理更好。
  3. 第二个驱动程序可能会减少驱动程序开销

您尝试过使用不同数量的原语吗?还是尝试使用计时器?