0

我有一个 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 循环内调用的,着色器实例之间的循环数不同。

4

0 回答 0