GLSL Compute: Workgroup Size, Registers, and Occupancy

In GLSL compute shaders, selecting smaller workgroup sizes directly influences how the GPU schedules execution units, distributes physical register space, and maximizes hardware throughput. While register allocation per thread is determined at compile time, smaller workgroup sizes modify the aggregate register footprint of each group, allowing for finer scheduling granularity across hardware compute units. However, reducing workgroup dimensions too drastically can introduce hardware slot bottlenecks and underutilize SIMD execution lanes, creating complex trade-offs between thread occupancy and execution efficiency.

Register Allocation Dynamics

In GPU hardware architectures, general-purpose registers (GPRs) are physically organized into large register files shared across a Compute Unit (AMD) or Streaming Multiprocessor (NVIDIA). The GLSL compiler statically determines the number of registers an individual invocation (thread) requires based on variable lifespans and arithmetic complexity.

Selecting a smaller workgroup size does not automatically allow individual threads to use more registers. Instead, it reduces the total register footprint required by any single workgroup:

\[\text{Workgroup Register Demand} = \text{Registers Per Thread} \times \text{Threads Per Workgroup}\]

When a shader has high register pressure, large workgroups (such as 512 or 1024 threads) demand an immense block of the register file all at once. If the available register space on a compute unit cannot satisfy this bulk requirement, the hardware cannot schedule the workgroup, leading to zero occupancy. By shrinking the workgroup size (for example, to 64 or 128 threads), the hardware can allocate register blocks in smaller increments, fitting active workgroups into fragmented spaces within the register file.

Impact on Thread Occupancy

Occupancy represents the ratio of active warps or wavefronts to the maximum theoretical warps a compute unit can support simultaneously. High occupancy helps hide memory latency by allowing the scheduler to swap out stalled threads waiting for global memory with active threads ready to execute arithmetic instructions.

Smaller workgroup sizes affect occupancy in two distinct ways:

  1. Mitigating Resource Quantization: Smaller groups provide finer scheduling granularity. If a hardware unit supports 2048 threads and a workgroup requires high register counts that cap occupancy at 1200 threads, smaller workgroups (e.g., 64 threads) allow the scheduler to allocate up to 18 workgroups (1152 threads). A large workgroup size (e.g., 1024 threads) would force the scheduler to allocate only one workgroup (1024 threads), leaving nearly half the compute unit's potential capacity completely idle.
  2. Workgroup Allocation Limits: Every GPU architecture enforces a strict maximum limit on the number of concurrently active workgroups per compute unit (often between 16 and 32). If workgroup sizes are set too small (e.g., 32 threads), you will hit the hardware workgroup limit long before reaching maximum thread occupancy. For instance, an architecture with a 16-workgroup limit running 32-thread workgroups can only schedule 512 concurrent threads, severely depressing overall occupancy regardless of register availability.

Wavefront and Warp Alignment

Workgroup sizes must always be evaluated in the context of the underlying hardware execution width. NVIDIA hardware schedules threads in warps of 32, while AMD hardware schedules threads in wavefronts of either 32 or 64.

Defining a GLSL compute workgroup that is not a multiple of the native execution width results in underfilled warps or wavefronts. Inactive lanes must still execute instructions as masked operations, wasting power and computing potential. For instance, choosing a workgroup size of 16 on a 32-thread warp architecture immediately cuts effective compute efficiency in half, regardless of positive register allocation conditions.

Optimization Strategy

To achieve the optimal balance between register usage and occupancy in GLSL compute:

  • Ensure workgroup sizes are direct multiples of the native warp or wavefront size (typically 64 is a safe, portable baseline across AMD, NVIDIA, and Intel).
  • Use sizes between 64 and 256 invocations for shaders with moderate to high register pressure to grant the hardware scheduler maximum flexibility.
  • Avoid sizes under 64 to prevent hitting hardware-defined maximum workgroup allocation ceilings.
  • Profile shaders using vendor-specific analysis tools to verify whether register constraints or workgroup slot ceilings are the primary bottleneck constraining theoretical occupancy.