如何在Metal片段着色器中实现/使用原子计数器?

6
我想在我的Metal应用程序中实现A-Buffer算法以实现无序透明度。该技术的说明提到了使用原子计数器。我从未使用过这些,甚至从未听说过。我刚刚阅读了Metal Shading Language规范中有关原子变量的内容,但我无法弄清楚如何实际实现或使用它们。
有没有人在Metal中有这方面的经验?你能给我指出如何设置和使用简单整数计数器的示例吗?基本上,每个渲染通道我需要能够从片段着色器内部递增一个整数,从零开始。这用于索引A-Buffer。
谢谢!
1个回答

12

你的问题缺乏足够的细节,只能提供一般性的概述。如果您在实现某些东西时不确定如何操作,可以考虑添加一个不完整的着色器函数并提供伪代码。

无论如何,原子计数器是一种 atomic_uint 类型的变量(如果需要符号,则使用 atomic_int)。为了有用,这个变量需要在特定的地址空间中共享。你的例子听起来需要 device 地址空间。因此,您需要一个由缓冲区支持的 device 变量。您可以声明它如下:

fragment FragmentOut my_fragment_func(device atomic_uint &counter [[buffer(0)]], ...)
{
    ...
}

你也可以使用结构体类型作为参数,并让一个结构体字段成为你的atomic_uint变量。

为了以原子方式将原子变量增加1并获取先前的值,你可以这样做:

    uint value = atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed);

原子变量的初始值取自缓冲区在执行绘制或调度命令之前的内容。虽然规范没有明确说明,但是原子类型的大小和位解释似乎与相应的非原子类型匹配。也就是说,您可以将 uint(又称 unsigned intuint32_t)写入缓冲区以初始化 atomic_uint


谢谢,这是一个很好的解释!一般概述正是我所需要的。抱歉我没有提供更多的细节 - 我还没有开始编写着色器,我只是在学习是否理解足够以继续进行。 - bsabiston
5
我非常有兴趣学习关于金属计算核心/着色器的知识,但是我不知道哪里可以找到解释优化/功能等相关内容的书籍或网站。我已经写了很多着色器,但是我对像imageblocks这样的功能一无所知。例如,我该如何实现一个自定义的MPSGaussianBlur,使其每个像素的内核大小都是随机的,并且性能接近于苹果的实现?我知道这将是X、Y两次通行,但这只是第一步。我感觉这些GPU有巨大的潜力,而我们只是挖掘了其中的冰山一角。 - Summon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接