glsl compute shader - 同步

Irb*_*bis 3 opengl synchronization glsl

我可以shared float [gl_WorkGroupSize.x] 为每个工作组定义一个共享数据结构(例如一个数组) .工作组内的执行顺序是未定义的,所以在某些时候我可能需要同步所有使用共享数组的线程,例如所有线程必须在计算之前将一些数据写入共享数组.我找到了两种方法来实现这一目标:

OpenGL SuperBible:

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

OpenGL 4着色语言手册:

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

我应该在屏障后调用memoryBarrierShared吗?当我可以在不使用屏障的情况下使用memoryBarrierSharedmemoryBarrier时,你能给我一些实际的例子吗?

And*_*man 7

内存屏障确保了在不连贯的内存访问中的可见性.

这实际上意味着不允许调用您的计算着色器来尝试某种读取和/或写入高速缓存内存的优化.

写入像Shader存储缓冲区之类的东西是通常不连贯的内存访问的一个例子,没有在一次调用中进行的内存屏障更改只能保证在该调用中可见.除非您告诉GLSL编译器强制执行一致的内存访问以及在何处执行此操作,否则允许其他调用维护其自己的内存缓存视图(memoryBarrier* ()).

这里有一个严重的警告,那就是能见度只是等式的一半.编译着色器时强制一致的内存访问不会解决工作组中线程之间的实际执行顺序问题.要确保工作组中的所有执行都已完成处理到着色器中的某个点,您必须使用barrier ().

考虑以下Comptue Shader伪代码:

#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.
}
Run Code Online (Sandbox Code Playgroud)

在GLSL之外,GL命令级别也存在障碍(glMemoryBarrier (...)).您可以在需要计算着色器完成执行的情况下使用它们,然后才允许GL执行取决于其结果的操作.

在传统的渲染管道中,GL可以隐式地确定哪些命令必须等待其他命令完成(例如, glReadPixels (...)在所有命令完成写入帧缓冲之前停止).但是,对于计算着色器和图像加载/存储,隐式同步不再起作用,您必须告诉GL必须完成哪些管道存储器操作并且对下一个命令可见.