Understanding gl_MaxComputeWorkGroupSize in GLSL

This article provides an overview of the built-in GLSL constant gl_MaxComputeWorkGroupSize, detailing its purpose in regulating compute shader thread execution. You will learn how this variable defines hardware-specific thread count limits along individual dimensions, how it interacts with overall invocation limits, and why it is essential for writing portable compute shaders across different graphics hardware.

What is gl_MaxComputeWorkGroupSize?

In OpenGL Shading Language (GLSL), gl_MaxComputeWorkGroupSize is a built-in constant of type ivec3. It defines the maximum number of local work items (threads) that the underlying GPU can execute along each individual dimension—X, Y, and Z—within a single compute shader work-group.

When writing a compute shader, you define the layout of the local work-group using an input layout qualifier:

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

gl_MaxComputeWorkGroupSize establishes the absolute ceiling for these individual dimensions:

  • local_size_x must be less than or equal to gl_MaxComputeWorkGroupSize.x
  • local_size_y must be less than or equal to gl_MaxComputeWorkGroupSize.y
  • local_size_z must be less than or equal to gl_MaxComputeWorkGroupSize.z

Exceeding any of these dimensional limits results in a compile-time or link-time error.

Axis-Specific Limits vs. Total Invocations

A common point of confusion is the difference between dimensional limits and total thread capacity. While gl_MaxComputeWorkGroupSize limits the extent of any single axis, it does not guarantee that the product of all three axes is valid.

GLSL defines a separate built-in constant, gl_MaxComputeWorkGroupInvocations, which dictates the maximum total number of threads in a single work-group:

\[\text{Total Invocations} = \text{local\_size\_x} \times \text{local\_size\_y} \times \text{local\_size\_z} \le \text{gl\_MaxComputeWorkGroupInvocations}\]

For example, a GPU might report a gl_MaxComputeWorkGroupSize of (1024, 1024, 64), but specify a gl_MaxComputeWorkGroupInvocations limit of 1024. While you could theoretically launch a 1D work-group with 1024 threads on the X axis, you cannot launch a 2D work-group of 32 x 64 (2048 threads), even though 32 and 64 are well within the individual axis limits.

Why gl_MaxComputeWorkGroupSize is Critical

  1. Hardware Portability: Compute capabilities vary widely between integrated GPUs, mobile chipsets, and high-end discrete graphics cards. Relying on gl_MaxComputeWorkGroupSize ensures that compute algorithms adapt to the host platform without exceeding physical execution limits.
  2. Resource Allocation: Compute units contain fixed-size hardware registers and shared memory. The dimensions specified by gl_MaxComputeWorkGroupSize reflect how hardware schedulers map threads onto physical execution units (such as warps or wavefronts).
  3. Validation and Dynamic Configuration: While accessible inside shaders, this metric corresponds directly to the host-side OpenGL query GL_MAX_COMPUTE_WORK_GROUP_SIZE using glGetIntegeri_v. Host applications typically query this value at runtime to select the optimal work-group dimensions before compiling specialized shader variants.

To ensure correct execution across all devices, compute shader layouts must satisfy both the individual axis boundaries set by gl_MaxComputeWorkGroupSize and the cumulative capacity set by gl_MaxComputeWorkGroupInvocations.