gl_MaxComputeWorkGroupInvocations Limit in GLSL

This article explains how the built-in GLSL constant gl_MaxComputeWorkGroupInvocations restricts the total number of execution threads within a compute shader workgroup. Compute shaders organize parallel execution into local workgroups defined across three dimensions, and this constant serves as a hard limit on their combined product. Understanding how this limitation interacts with per-dimension size limits, shader compilation, and underlying GPU hardware architecture is essential for writing valid, high-performance compute shaders.

The Definition and Mathematical Constraint

In OpenGL compute shaders, you define the dimensions of a local workgroup using the layout qualifier in your GLSL code:

layout (local_size_x = X, local_size_y = Y, local_size_z = Z) in;

The built-in constant gl_MaxComputeWorkGroupInvocations dictates the maximum total number of invocations (threads) allowed in a single workgroup. The OpenGL specification mandates that the product of the workgroup dimensions must not exceed this value:

\[X \times Y \times Z \le \text{gl\_MaxComputeWorkGroupInvocations}\]

If the product of your dimensions exceeds this limit, the shader compiler or linker will issue an error and fail to create the shader program.

Distinction from gl_MaxComputeWorkGroupSize

A common source of confusion is the difference between gl_MaxComputeWorkGroupInvocations and gl_MaxComputeWorkGroupSize. They govern workgroup boundaries differently:

  • gl_MaxComputeWorkGroupSize (an array of three integers): Sets the maximum allowable size along each individual axis (\(X\), \(Y\), or \(Z\)).
  • gl_MaxComputeWorkGroupInvocations (a single integer): Sets the absolute cap on the total volume (\(X \times Y \times Z\)) of the workgroup.

For example, a typical modern GPU might report:

  • gl_MaxComputeWorkGroupSize.x = 1024
  • gl_MaxComputeWorkGroupSize.y = 1024
  • gl_MaxComputeWorkGroupSize.z = 64
  • gl_MaxComputeWorkGroupInvocations = 1024

Under these hardware limits, setting a workgroup layout to (local_size_x = 1024, local_size_y = 1, local_size_z = 1) is valid because \(1024 \le 1024\). However, setting the layout to (local_size_x = 32, local_size_y = 33, local_size_z = 1) violates the limit, because \(32 \times 33 = 1056\), which exceeds the 1024 invocation ceiling—even though individual \(X\) and \(Y\) values are well within their respective 1024 limits.

Hardware Rationale

GPU hardware imposes gl_MaxComputeWorkGroupInvocations due to physical resource allocation within execution units (such as NVIDIA Streaming Multiprocessors or AMD Compute Units). Every invocation within a workgroup requires physical resources:

  1. Register Allocation: Every thread allocates a set of vector and scalar registers. Larger workgroups consume more register space simultaneously.
  2. Shared Memory (shared variables): Workgroups share a block of high-speed, on-chip SRAM. Hardware schedulers can only coordinate a fixed maximum number of threads accessing this block at one time.
  3. Warp/Wavefront Scheduling: GPUs group invocations into warps (32 threads) or wavefronts (32 or 64 threads). The hardware scheduler limits how many active warps or wavefronts can belong to a single cooperative thread block.

The core OpenGL 4.3 specification requires implementations to support a minimum gl_MaxComputeWorkGroupInvocations value of at least 1024, matching standard hardware architecture requirements across major vendors.

Querying the Limit

To ensure your application creates portable compute shaders, you should query this limit on the CPU side before dispatching compute workloads:

GLint maxInvocations;
glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &maxInvocations);

Within GLSL, the constant is automatically available as a compile-time value, enabling static checks and sizing of shared data structures:

shared float sharedData[gl_MaxComputeWorkGroupInvocations];

Designing workgroup dimensions that conform to gl_MaxComputeWorkGroupInvocations—while keeping total threads as multiples of native warp or wavefront sizes (typically 32 or 64)—ensures maximum hardware occupancy and optimal shader compilation across different graphics hardware.