What Is Shared Memory in GLSL Compute Shaders?

In GLSL compute shaders, the shared memory qualifier declares variables that are allocated in fast on-chip memory and shared among all invocations within a single workgroup. This article explains the role of shared memory, how it drastically reduces high-latency global memory access, the synchronization mechanisms required to prevent race conditions, and practical best practices for optimizing compute shader performance.

Understanding Shared Memory Storage

When executing compute shaders in OpenGL or Vulkan, invocations are grouped into local workgroups. By default, variables declared globally or within shader storage buffer objects (SSBOs) either reside in private registers or global device memory (VRAM).

Declaring a variable with the shared storage qualifier allocates it in high-speed, on-chip scratchpad memory (often termed Local Data Share or Shared Memory in GPU hardware architectures).

#version 450

layout(local_size_x = 16, local_size_y = 16) in;

// Shared memory array accessible by all 256 invocations in this workgroup
shared float tileData[16][16];

void main() {
    // Each invocation accesses the shared data
    uint x = gl_LocalInvocationID.x;
    uint y = gl_LocalInvocationID.y;
    
    tileData[x][y] = 1.0;
}

Primary Functions and Benefits

The shared memory storage qualifier provides several essential capabilities for compute pipelines:

  • Inter-Thread Communication: It serves as a scratchpad allowing threads inside the same workgroup to exchange intermediate calculation results without round-tripping through global memory.
  • Latency Reduction (Tiling/Caching): Global GPU memory bandwidth is often the main performance bottleneck. Threads can cooperatively load a patch of data (a tile) from an SSBO or texture into shared memory once, reuse it multiple times for local stencils or convolutions, and avoid redundant global memory reads.
  • Cooperative Algorithms: It enables workgroup-wide algorithms such as parallel reductions (finding min/max/sum), prefix sums (scan operations), sorting, and matrix multiplication.

Synchronization and Memory Barriers

Because shared memory is concurrently read and written by multiple invocations running asynchronously, uncoordinated access causes data race conditions. GLSL provides built-in barrier functions to coordinate execution and memory visibility:

  • barrier(): Acts as an execution barrier. Every invocation in the workgroup must reach this instruction before any invocation is allowed to proceed.
  • memoryBarrierShared(): Ensures that all previous writes to shared variables by the calling invocation are completed and visible to other invocations in the workgroup.
  • groupMemoryBarrier(): Combines ordering for shared variables and all other memory accesses across the local workgroup.

In typical compute algorithms, threads load data into shared arrays, execute barrier(), process the shared data, and often synchronize again before writing results back to global buffers.

Limitations and Constraints

While shared memory is substantially faster than global memory, it is a finite resource:

  • Capacity Limits: Hardware limits the maximum size of shared storage (often 32 KB or 64 KB per workgroup, queryable via GL_MAX_COMPUTE_SHARED_MEMORY_SIZE). Exceeding this limit causes shader compilation failures.
  • Occupancy Impact: Allocating large amounts of shared memory per workgroup limits how many active workgroups the GPU can schedule concurrently on a single compute unit or streaming multiprocessor, potentially lowering overall GPU occupancy.
  • Scope Restriction: Shared variables cannot be initialized at declaration and are strictly isolated to the executing workgroup; threads in different workgroups cannot read or write to each other's shared storage.
  • Bank Conflicts: Shared memory is organized into memory banks. If multiple threads within the same execution sub-group (warp or wavefront) access different memory addresses located on the same memory bank simultaneously, access is serialized, reducing throughput.