2

这个问题是这个主题的延续: 如何正确绑定数千个缓冲区

这个问题与粒子模拟课题有关。假设我需要一个全局结构,其中包括:

  1. 一个 3D 矩阵 (32*32*32) 的 uints(保存散列链表的标头 id)。
  2. 一个计数器,告诉我散列链表中的粒子数量。
  3. 散列的粒子链表。

第一个想法是为第一项使用 3D 纹理,第二项使用原子计数器缓冲区,第三项使用 SSB。

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

这里没有什么神奇的。

现在,为了独立于空间(不绑定到唯一的立方空间),我必须能够将粒子从立方体传递到它周围的其他物体。由于我在 3D 空间中,27 个立方体(正面)作为物理计算的输入变量,还有 27 个立方体(背面)作为输出,因为我可以将一个粒子从一个立方体(正面)写入另一个(背面)覆盖空间的不同部分。

这导致我需要绑定 54 个纹理、54 个 SSB 和 54 个原子计数器。虽然这两个第一个可能不是问题(我的硬件限制都在 90 左右),但 ACB 绑定限制是 8。

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

语境 :

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 分开?

4

1 回答 1

0

即使绑定缓冲区并将计数器放入内部在理论上是可能的,但通过进一步推动“everything-in-it-SSB”的概念,还有一种更简单的方法可以做到这一点。

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

然后在将正确的 SSB 绑定到目标后调用而不是glDispatchCompute()调用。glDispatchComputeIndirect()GL_DISPATCH_INDIRECT_BUFFER

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

于 2014-05-17T04:25:47.370 回答