多个着色器使用的无人机计数器索引?

时间:2013-06-18 12:26:06

标签: graphics hlsl directx-11 compute-shader

我一直在尝试实现基于计算着色器的粒子系统。

我有一个计算着色器,它使用带有D3D11_BUFFER_UAV_FLAG_COUNTER标志的UAV构建粒子的结构化缓冲区。

当我添加到此缓冲区时,我会检查此粒子是否有任何复杂的行为,我想要过滤掉并在单独的计算着色器中执行。例如,如果粒子想要执行碰撞检测,我将其索引添加到另一个结构化缓冲区,同时使用D3D11_BUFFER_UAV_FLAG_COUNTER标志。

然后我运行第二个计算着色器,它处理所有索引,并对这些粒子应用碰撞检测。

然而,在第二个计算着色器中,我估计大约5%的索引是错误的 - 它们属于其他不支持碰撞检测的粒子。

这是用于构建列表构建的计算着色器代码:

// append to destination buffer
uint dstIndex = g_dstParticles.IncrementCounter();
g_dstParticles[ dstIndex ] = particle;

// add to behaviour lists
if ( params.flags & EMITTER_FLAG_COLLISION )
{
    uint behaviourIndex = g_behaviourCollisionIndices.IncrementCounter();
    g_behaviourCollisionIndices[ behaviourIndex ] = dstIndex;
}

如果我将“添加到行为列表”位拆分为单独的计算着色器,并在构建粒子列表后运行它,那么一切都很完美。但是我认为我不应该这样做 - 这会浪费带宽再次通过所有粒子。

我怀疑IncrementCounter实际上并不能保证将唯一索引返回到UAV中,并且有一些聪明的优化正在进行,这意味着索引仅在其使用的计算着色器内有效。因此,我将其传递给第二个计算着色器的尝试无效。

任何人都能对这里发生的事情给出具体的答案吗?如果我有办法将过滤保留在与我的核心更新相同的计算着色器中?

谢谢!

1 个答案:

答案 0 :(得分:1)

IncrementCounter是一个原子操作,因此(尽管有驱动程序/硬件错误)会为每个调用它的线程返回一个唯一值。

你有没有想过为它使用Append / Consume缓冲区,因为它是为它们设计的?第一个传递只是将复杂的碰撞粒子附加到AppendStructuredBuffer,第二个传递消耗来自相同的缓冲区,而是使用ConsumeStructuredBuffer视图。第二轮计算将需要使用DispatchIndirect,因此您只需要为列表中的数字运行尽可能多的线程组(CPU不会知道)。

通常的建议适用,您是否尝试过D3D11调试层并在参考设备上运行它以确保它不是驱动程序问题?