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:

  1. 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.
  2. 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 shared workgroup 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() or groupMemoryBarrier()).
  • 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.