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

Why is texture buffer faster than vertex inputs when using instancing in glsl?

本文关键字:缓冲区 纹理 顶点 输入 为什么 glsl 实例化      更新时间:2023-10-16

我正在编写自己的渲染引擎。目前我在地形上工作。我使用glDrawArraysInstanced渲染地形。地形是由许多"块"组成的。每个chunk都是一个quad,也是draw调用的一个实例。然后在镶嵌着色器中对每个四边形进行镶嵌。对于着色器输入,我使用VBOs实例化VBOs使用顶点属性除数)和纹理缓冲区。这是我的一个着色器的简单示例:

#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帧/秒)!

我想知道它是否使用了某种缓存之类的东西,但这对我来说没有任何意义,因为顶点在两个渲染调用中都使用不同的矩阵进行变换,因此着色器输出完全不同的结果。


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

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


编辑:

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

我唯一要做的就是更改我的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

一切都和以前一样,但就性能而言,速度是原来的两倍。

我看到3个可能的原因:

  1. 着色器可能具有不同的占用率,因为寄存器的使用方式不同,因此性能将大不相同
  2. 在属性之间,获取不是以相同的方式实现的,调度器在Shaders中可以比在输入汇编程序中做得更好的等待处理
  3. 也许第二辆车的头顶司机更少

你尝试过不同数量的原语吗?或者尝试使用计时器?