GLSL memoryBarrierShared()有用吗?

Ant*_*ier 9 opengl glsl compute-shader

我想知道memoryBarrierShared的用处.

实际上,当我查看屏障功能的文档时:我读到:

对于计算着色器中任何给定的屏障静态实例,单个工作组中的所有调用必须在允许任何调用继续超出它之前输入.这确保了在调用相同的屏障静态实例之后,其他调用可以安全地读取在给定静态屏障实例之前由一次调用写入的值.因为调用可能在这些屏障调用之间以未定义的顺序执行,所以在许多情况下,每顶点或每个补丁输出变量或任何共享变量的值将是未定义的.

因此,如果我们可以在使用障碍后安全地读取值,为什么我们会在一些代码中看到

memoryBarrierShared();
barrier();
Run Code Online (Sandbox Code Playgroud)

或者像错误的东西

barrier();
memoryBarrierShared();
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是:如果使用障碍足够,memoryBarrier {Shared,...}的目的是什么?

对于memoryBarrierBuffer/Image我可以理解,如果我们使用多个阶段,但对于共享,我不知道...

Nic*_*las 10

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的规则.好吧,直到他们以某种方式解决这个问题.

话虽如此,ES的措辞更有意义,因为对于一切而言,完全的内存屏障非常昂贵.特别是如果你想要做的就是同步对共享变量的访问.

我建议在barrier通话时使用内存屏障.这样,您的着色器将是正确的,即使在某些实现上可能稍微慢一点.但是,如果您要使用内存屏障以及barrier调用,则必须首先考虑内存屏障.同步执行后执行内存屏障不正确.

  • 如果人们觉得上面的内容令人困惑,这里是我的总结。在当前版本的规范中,OpenGL 4.6 和 GL ES 3.2 之间保持一致,“barrier()”调用可同步控制流(工作组内的调用)和共享内存。仅其他内存访问(例如缓冲区)才需要显式内存屏障。 (2认同)