我有一个 OpenGL 计算着色器,它生成未定义数量的顶点并将它们存储在着色器存储缓冲区 (SSB) 中。SSB 容量足够大,因此计算着色器永远不会生成超出其容量的顶点数量。我需要生成的值从一开始就填充缓冲区并且没有不连续性(就像push_back
在 C++ 上使用一样vector
)。为此,我使用原子计数器来计算生成一个时将顶点值放置在 SSB 中的位置的索引。这种方法似乎有效,但会使计算着色器运行得更慢。下面是 GLSL 函数的样子:
void createVertex(/*some parameters*/){
uint index = atomicCounterIncrement(numberOfVertices);
Vector vertex;
// some processing that calculates the coordinates of the vertex
vertices[index] = vertex;
}
SSB 定义vertices
在哪里:vec3
struct Vector
{
float x, y, z;
};
layout (std430, binding = 1) buffer vertexBuffer
{
Vector vertices[];
};
AndnumberOfVertices
是一个原子计数器缓冲区,其值在运行着色器之前被初始化为 0。
一旦着色器完成运行,我可以在 CPU 端加载回numberOfVertices
变量,以了解存储在缓冲区中的已创建顶点的数量 range [0; numberOfVertices*3*sizeof(float)]
。在测量着色器运行的时间(使用glBegin/EndQuery(GL_TIME_ELAPSED)
)时,我得到大约50ms。然而,当删除atomicCounterIncrement
线(因此也没有将顶点分配到数组中)时,测量的时间大约是几毫秒。随着我增加工作组的数量,这种差距也会增加。
我认为问题可能是由于使用了原子操作引起的。那么有没有更好的方法在 SSB 中附加值?一旦着色器完成运行,在某种程度上也会给我附加值的总数?
编辑:经过一些重构和测试后,我注意到实际上是缓冲区 ( vertices[index] = vertex;
) 中的值分配减慢了所有速度(删除此行时减少了大约 40 毫秒)。我应该通知该createVertex()
函数是在 for 循环内调用的,着色器实例之间的循环数不同。