GPU 具有非常大工作负载的计算着色器的适当线程尺寸是多少?

GPU What are the proper thread dimensions for a compute shader with a very large work load?


我正在统一处理高度图侵蚀计算着色器,其中地图上的每个点都被单独侵蚀。这适用于小地图,但我正在处理的项目需要 4096x4096 地图。这意味着要模拟 4096^2 = 16777216 个点。使用默认线程尺寸 [64,1,1],这将创建 262144 个线程组,远远超过允许的限制 65535。

我的问题是:
我可以简单地增加线程尺寸吗,我在性能方面需要考虑什么? 是否可以简单地 运行 着色器多次,使用不同的高度图坐标范围?

这是我第一次使用着色器。我在网上看到的教程很快就深入到了 gpu 硬件规格,所以我没有从中学到太多东西。

每个工作组有 64x64 个线程,您可以 Dispatch 64x64 个工作组来执行您需要的操作:请记住,每个工作都会调用 64x64 个线程你派遣的小组,所以你将执行 64x64 work groups x 64x64 threads = 4096 workgroups x 4096 threads

computeShader.Dispatch(computeShader.FindKernel("kernel"), 64, 64, 1);
[numthreads(64, 64, 1)]
void kernel(uint3 id : SV_DispatchThreadID)
{
    // ...
    // 0 <= id.x < 4096
    // 0 <= id.y < 4096
}

至于对性能的影响,一般的回答是“试一试!” : 运行 您的内核具有不同大小的线程和工作组。结果可能因您的计算和硬件而异。

但是,如果您需要绕过 65535 限制,您可以使用 DispatchIndirect。基本上,它与 Dispatch 相同,但参数通过 ComputeBuffer 传递。

ComputeBuffer argsBuffer = new ComputeBuffer(3, sizeof(uint), ComputeBufferType.IndirectArguments);
uint[] args = { 64, 64, 1 }; // work groups
argsBuffer.SetData(args);
computeShader.DispatchIndirect(computeShader.FindKernel("kernel"), argsBuffer);

Ps :在 GPU 上工作需要了解其架构,因为 (1) 您在低级别工作,接近硬件,并且您使用的许多功能实际上是硬件实现的(例如纹理) ; (2) 您想从您的程序中获得最佳性能(例如,充分利用块、扭曲和缓存...);)