memoryBarrierShared vs groupMemoryBarrier in GLSL
In OpenGL Shading Language (GLSL) compute shaders, managing the order
of read and write operations across threads is critical for avoiding
race conditions. While both memoryBarrierShared() and
groupMemoryBarrier() are memory ordering intrinsics
designed for use within compute workgroups, they differ in the types of
memory they affect: memoryBarrierShared() synchronizes
accesses specifically to shared memory variables, whereas
groupMemoryBarrier() synchronizes accesses across all
memory resources—including shared memory, shader storage buffer objects
(SSBOs), and image variables—relative to the calling workgroup.
Execution Barriers vs. Memory Barriers
Before comparing the two functions, it is important to distinguish
memory barriers from execution barriers. Functions like
memoryBarrierShared() and groupMemoryBarrier()
only ensure that memory transactions issued before the call are
committed and visible before operations issued after the call. They do
not halt thread execution or synchronize the progress of threads.
To pause execution until all invocations in the workgroup reach the
same point in the code, GLSL provides the execution barrier
barrier(). Consequently, memory barriers are often paired
with barrier() when sharing data between different
invocations.
What is memoryBarrierShared()?
The memoryBarrierShared() function enforces ordering
exclusively for variables declared with the shared storage
qualifier.
When a thread calls memoryBarrierShared():
- Any writes to
sharedvariables issued prior to the barrier are guaranteed to be committed before any memory transactions issued after the barrier. - It does not guarantee ordering for writes to buffers (SSBOs) or
images (
image2D,image3D, etc.).
This narrow scope makes memoryBarrierShared() lighter
weight than broader barrier functions, as the GPU only needs to flush
the local on-chip shared memory cache or registers associated with
workgroup data.
What is groupMemoryBarrier()?
The groupMemoryBarrier() function provides a broader
synchronization scope. It orders memory transactions across all memory
types accessed by the shader that could be observed by other invocations
in the same workgroup.
When a thread calls groupMemoryBarrier():
- Writes to
sharedmemory variables are ordered. - Writes to shader storage buffer objects (SSBOs via
bufferblocks) are ordered. - Writes to images (via
imageStore) are ordered.
Effectively, groupMemoryBarrier() acts as a combined
barrier for memoryBarrierShared(),
memoryBarrierBuffer(), and
memoryBarrierImage(), ensuring that any modification to
global or shared data made by the thread is ordered relative to
subsequent operations.
Key Differences
- Scope of Memory:
memoryBarrierShared()strictly affects workgroupsharedvariables.groupMemoryBarrier()affectssharedvariables, SSBOs, and image loads/stores simultaneously. - Performance:
memoryBarrierShared()typically incurs lower overhead because shared memory is local to the compute unit.groupMemoryBarrier()may force the GPU to wait for global memory controllers and L2 caches to resolve writes to global buffers and textures. - Intended Use Case: Use
memoryBarrierShared()when an algorithm only shares intermediate data between workgroup threads using localsharedarrays (such as in local reductions or blur filters). UsegroupMemoryBarrier()when an algorithm writes to both shared variables and global buffers or images, and subsequent steps depend on all of those writes being committed.