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= 1024gl_MaxComputeWorkGroupSize.y= 1024gl_MaxComputeWorkGroupSize.z= 64gl_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:
- Register Allocation: Every thread allocates a set of vector and scalar registers. Larger workgroups consume more register space simultaneously.
- Shared Memory (
sharedvariables): 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. - 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.