我想知道memoryBarrierShared的用处。
的确,当我查看屏障功能的文档时:我读到了:
对于计算着色器中任何给定的屏障静态实例,单个工作组中的所有调用必须在允许任何调用继续超出它之前输入。这确保了在调用相同的屏障静态实例之后,其他调用可以安全地读取在给定静态屏障实例之前由一次调用写入的值。因为调用可能在这些屏障调用之间以未定义的顺序执行,所以在许多情况下,每个顶点或每个补丁输出变量或任何共享变量的值将是未定义的。
因此,如果我们可以在使用障碍后安全地读取值,为什么我们会在某些代码中看到
memoryBarrierShared();
barrier();
或者像
这样的错误barrier();
memoryBarrierShared();
所以,我的问题是:如果使用障碍足够,memoryBarrier {Shared,...}的目的是什么?
对于memoryBarrierBuffer / Image我可以理解我们是否使用多个阶段,但对于共享,我不知道......
答案 0 :(得分:8)
GLSL 4.60澄清了这一点:
为了实现对共享变量的读取和写入的排序,必须使用
barrier()
和memoryBarrier()
函数来使用控制流和内存屏障的组合(请参阅“着色器调用控制函数”) “)。
最好将桌面GLSL视为总是这样说。即使以下是GLSL 4.50中的陈述方式。
GLSL 4.50非常明确地表明不需要明确的内存屏障。计算着色器中的barrier
包含所有内存障碍。
然而,GLSL ES 3.20同样清楚地表明barrier
不包含任何类型的内存障碍:
对于计算着色器,屏障仅影响控制流,并且本身不会同步内存访问。特别是,它不能确保在调用同一静态
barrier()
实例后,其他调用可以安全地读取在barrier()
的给定静态实例之前由一次调用写入的值。要实现这一点,需要同时使用两者barrier()
和记忆障碍。
值得注意的是,离线glslang编译器总是使用GLSL ES措辞。因此,如果您要生成SPIR-V以提供给Vulkan,则必须遵循ES的规则。好吧,until they get that fixed, one way or another。
话虽如此,ES的措辞更有意义,因为所有的完整内存屏障非常昂贵。特别是如果你想要做的就是同步访问共享变量。
我建议在barrier
调用旁边使用内存屏障。这样,您的着色器将是正确的,即使在某些实现上可能稍微慢一点。但是,如果您要使用内存屏障以及barrier
调用,那么内存屏障必须首先。同步执行后执行内存屏障不正确。