GLSL - 使用着色器存储缓冲区的一部分作为计数器的正确性

时间:2014-05-16 03:13:53

标签: opengl glsl compute-shader

这个问题是这个主题的延续: How to bind thousands of buffers properly

这个问题与粒子模拟主题有关。 假设我需要一个包含以下内容的全局结构:

  1. uints的3D矩阵(32 * 32 * 32)(保存散列链表的标题ID)。
  2. 一个计数器,告诉我哈希链表中的粒子数量。
  3. 散列链接的粒子列表。
  4. 第一个想法是为第一个项目使用3D纹理,为第二个项目使用原子计数器缓冲区,为第三个项目使用SSB。

    SSB中的每个条目都是一个粒子加上一个uint,该值指向同一体素中下一个粒子的位置。

    这里没什么神奇的。

    现在,为了与空间无关(不限于独特的立方体空间),我必须能够将粒子从立方体传递到围绕它的其他人。因为我在一个3D空间,27个立方体(前面)作为物理计算的输入变量,但也有27个立方体(后面)作为输出,因为我可以将一个粒子从一个立方体(前面)写到另一个(后面)覆盖一个空间的不同部分。

    这使我需要绑定54个纹理,54个SSB和54个原子计数器。虽然这两个第一次可能不是问题(我的硬件限制大约是90),但ACB绑定限制为8。

    假设单个ACB包含每个立方体的粒子数并不容易维护(我没有花很长时间思考,这可能是解决方案,但这不是问题所在。)

    背景:

    SSB可以包含任何内容。因此,解决方案是将三个结构(标题矩阵,计数器和链表)连接在一个SSB中,该SSB将成为我的立方体超级结构。

    我需要在每次传递之前知道SSB中有多少粒子可以进行正确的glDispatchCompute()调用。

    问题:

    绑定SSB只是为了读取包含粒子数量的uint会不好?

    如果不是,那么访问计数的两种方法之一是否比另一种更好?为什么?

    GLuint value;
    
    //1st method
    m_pFunctions->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
    m_pFunctions->glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, OFFSET_TO_VALUE, sizeof(GLuint), &value);
    m_pFunctions->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
    
    //2nd method
    m_pFunctions->glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, m_buffer, OFFSET_TO_VALUE, sizeof(GLuint));
    m_pFunctions->glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint), &value);
    m_pFunctions->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
    

    如果不是,是否有好方法或者我应该将计数器与SSB分开?

1 个答案:

答案 0 :(得分:0)

即使绑定缓冲区并将计数器放入内部理论上是可行的,但通过进一步推动“一切都在SSB”的概念,有一种更简单的方法。

通过在SSB中保留3个连续uint的空间,我们可以将它们的值用作调度参数X,Y和Z.X仍然是粒子的数量,但Y和Z只是硬设置1s。

然后,在将glDispatchCompute()目标绑定到glDispatchComputeIndirect()后,调用GL_DISPATCH_INDIRECT_BUFFER代替coherent

但是,通过使用部分SSB作为伪原子计数器,缓冲区必须以类型限定符coherent为前缀“以强制执行内存访问的一致性”。还应设置memory barriers以实现{{1}}变量之间的可见性。