glsl 计算着色器 - 同步
glsl compute shader - synchronization
我可以定义一个共享数据结构(例如数组):
shared float [gl_WorkGroupSize.x]
每个工作组。工作组内的执行顺序未定义,因此在某些时候我可能需要同步所有使用共享数组的线程,例如所有线程都必须在计算之前将一些数据写入共享数组。我找到了两种实现此目的的方法:
OpenGL 超级圣经:
barrier();
memoryBarrierShared();
OpenGL 4 着色语言手册:
barrier();
我应该在 barrier 之后调用 memoryBarrierShared 吗?当我可以使用 memoryBarrierShared 或 memoryBarrier 而不使用 barrier 时,你能给我一些实际的例子吗?
内存屏障确保 可见性 在其他不连贯的内存访问中。
这真正的意思是不允许调用您的计算着色器尝试进行某种优化,即读取 and/or 写入缓存内存。
写入着色器存储缓冲区之类的东西是通常不连贯的内存访问的一个例子,没有内存屏障,在一次调用中所做的更改只能保证在该调用中可见。允许其他调用维护它们自己的内存缓存视图,除非您告诉 GLSL 编译器强制执行一致的内存访问以及在何处执行此操作 (memoryBarrier* ()
)。
这里有一个严重的警告,那就是能见度只是等式的一半。在编译着色器时强制进行一致的内存访问并不能解决工作组中跨线程的实际执行顺序问题。要确保工作组中的所有执行都已 finished 处理到着色器中的特定点,您必须使用 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.
}
在 GLSL 之外,在 GL 命令级别 (glMemoryBarrier (...)
) 也存在障碍。在允许 GL 执行取决于其结果的操作之前需要计算着色器完成执行的情况下,您将使用它们。
在传统的渲染管道中,GL 可以隐式地找出哪些命令必须等待其他命令完成(例如 glReadPixels (...)
会停止,直到所有命令完成写入帧缓冲区) .但是,对于计算着色器和图像 load/store,隐式同步不再起作用,您必须告诉 GL 哪些管道内存操作必须完成并且对下一个命令可见。
我可以定义一个共享数据结构(例如数组):
shared float [gl_WorkGroupSize.x]
每个工作组。工作组内的执行顺序未定义,因此在某些时候我可能需要同步所有使用共享数组的线程,例如所有线程都必须在计算之前将一些数据写入共享数组。我找到了两种实现此目的的方法:
OpenGL 超级圣经:
barrier();
memoryBarrierShared();
OpenGL 4 着色语言手册:
barrier();
我应该在 barrier 之后调用 memoryBarrierShared 吗?当我可以使用 memoryBarrierShared 或 memoryBarrier 而不使用 barrier 时,你能给我一些实际的例子吗?
内存屏障确保 可见性 在其他不连贯的内存访问中。
这真正的意思是不允许调用您的计算着色器尝试进行某种优化,即读取 and/or 写入缓存内存。
写入着色器存储缓冲区之类的东西是通常不连贯的内存访问的一个例子,没有内存屏障,在一次调用中所做的更改只能保证在该调用中可见。允许其他调用维护它们自己的内存缓存视图,除非您告诉 GLSL 编译器强制执行一致的内存访问以及在何处执行此操作 (memoryBarrier* ()
)。
这里有一个严重的警告,那就是能见度只是等式的一半。在编译着色器时强制进行一致的内存访问并不能解决工作组中跨线程的实际执行顺序问题。要确保工作组中的所有执行都已 finished 处理到着色器中的特定点,您必须使用 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.
}
在 GLSL 之外,在 GL 命令级别 (glMemoryBarrier (...)
) 也存在障碍。在允许 GL 执行取决于其结果的操作之前需要计算着色器完成执行的情况下,您将使用它们。
在传统的渲染管道中,GL 可以隐式地找出哪些命令必须等待其他命令完成(例如 glReadPixels (...)
会停止,直到所有命令完成写入帧缓冲区) .但是,对于计算着色器和图像 load/store,隐式同步不再起作用,您必须告诉 GL 哪些管道内存操作必须完成并且对下一个命令可见。