我可以定义共享数据结构(例如数组):
每个工作组shared float [gl_WorkGroupSize.x]
。工作组内的执行顺序是未定义的,所以在某些时候我可能需要同步所有使用共享数组的线程,例如所有线程必须在计算之前将一些数据写入共享数组。我找到了两种方法来实现这一目标:
OpenGL SuperBible:
barrier();
memoryBarrierShared();
OpenGL 4着色语言手册:
barrier();
我应该在屏障之后调用 memoryBarrierShared 吗?如果我可以使用 memoryBarrierShared 或 memoryBarrier 而不使用屏障,你能给我一些实际的例子吗?
答案 0 :(得分:7)
内存障碍确保了 可见性 ,否则会导致内存不连贯。
这实际上意味着不允许调用您的计算着色器来尝试某种读取和/或写入缓存内存的优化。
写入像Shader存储缓冲区之类的东西是通常不连贯的内存访问的一个例子,没有在一次调用中进行的内存屏障更改只能保证在该调用中可见。除非您告诉GLSL编译器强制执行一致的内存访问以及在何处执行此操作(memoryBarrier* ()
),否则允许其他调用维护自己的内存缓存视图。
这里有一个严重的警告,那就是能见度只是等式的一半。编译着色器时强制一致的内存访问不会解决工作组中线程之间的实际执行顺序问题。要确保工作组中的所有执行都已完成处理着色器中的某个点,您必须使用barrier ()
。
#version 450
layout (local_size_x = 128) in;
shared float foobar [128]; // shared implies coherent
void main (void)
{
foobar [gl_LocalInvocationIndex] = 0.0;
memoryBarrierShared (); // Ensure change to foobar is visible in other invocations
barrier (); // Stall until every thread is finished clearing foobar
// At this point, _every_ index (0-127) of `foobar` will have the value **0.0**.
// Without the barrier, and just the memory barrier, the contents of everything
// but foobar [gl_LocalInvocationIndex] would be undefined at this point.
}
在GLSL之外,GL命令级别(glMemoryBarrier (...)
)也存在障碍。您可以在需要计算着色器完成执行的情况下使用它们,然后才允许GL执行取决于其结果的操作。
在传统的渲染管道中,GL可以隐式地确定哪些命令必须等待其他命令完成(例如 glReadPixels (...)
停顿,直到所有命令完成写入帧缓冲区为止。但是,对于计算着色器和图像加载/存储,隐式同步不再起作用,您必须告诉GL必须完成哪些管道存储器操作并且对下一个命令可见。