GLSL subgroupMemoryBarrier Guarantees Explained
The subgroupMemoryBarrier() function in GLSL enforces
memory ordering and visibility for invocations within the same subgroup,
ensuring that pending memory transactions become visible to peer
invocations before execution proceeds to subsequent memory accesses.
While it provides strong ordering constraints across buffer, shared, and
image memory within a single subgroup, it is strictly a memory barrier
rather than an execution barrier. This article details the specific
guarantees provided by subgroupMemoryBarrier(), the memory
spaces it affects, and how it contrasts with full execution
synchronization.
Memory Ordering and Visibility
When an invocation calls subgroupMemoryBarrier(), it
ensures that:
- Ordering of Operations: All memory writes issued by the calling invocation prior to the barrier are ordered before any memory reads or writes issued after the barrier.
- Subgroup-Wide Visibility: Memory stores performed by any invocation in the subgroup prior to the barrier become visible to all other invocations within the same subgroup that execute memory loads after their corresponding barrier.
Without this barrier, the compiler or GPU hardware may reorder memory operations, or cache lines may not flush or invalidate appropriately, resulting in race conditions and stale reads between threads in the same subgroup.
Affected Memory Types
subgroupMemoryBarrier() is a comprehensive memory
barrier that applies to all writable memory types accessible to the
shader:
- Buffer Memory: Writes to shader storage buffer objects (SSBOs).
- Shared Memory: Writes to
sharedworkgroup variables. - Image Memory: Writes performed via image store operations.
If finer control is needed to limit overhead, GLSL provides
specialized variants such as subgroupMemoryBarrierBuffer(),
subgroupMemoryBarrierShared(), and
subgroupMemoryBarrierImage().
Subgroup Scope Limitation
The visibility guarantees of subgroupMemoryBarrier() are
strictly confined to the calling subgroup (typically mapped to a
hardware warp or wavefront, such as 32 or 64 threads).
It does not guarantee that memory modifications are visible to:
- Invocations in other subgroups within the same workgroup (which
requires workgroup-scoped barriers such as
memoryBarrierShared()orgroupMemoryBarrier()). - Invocations in other workgroups (which requires device-level memory
barriers and appropriate memory qualifiers like
coherent).
Memory Barrier vs. Execution Barrier
subgroupMemoryBarrier() only controls memory
consistency; it does not synchronize instruction execution. Invocations
in the subgroup are not guaranteed to pause and wait for each other to
arrive at the barrier instruction.
If both execution synchronization (a lockstep pause) and memory
ordering are required, subgroupBarrier() must be used
instead. subgroupBarrier() functions as both an execution
barrier and an implicit memory barrier for the subgroup.