gl_SubgroupSize in GLSL Across GPU Architectures

In modern GLSL, the gl_SubgroupSize built-in variable reports the execution width of the current subgroup—the collection of invocations that execute concurrently on a single hardware compute unit. While developers often look for a universal standard, this value varies fundamentally depending on underlying GPU architectures, hardware generations, and shader compilation flags. This guide breaks down what gl_SubgroupSize represents and how its value differs across NVIDIA, AMD, Intel, and mobile GPUs.

Understanding gl_SubgroupSize

gl_SubgroupSize is a built-in constant within the scope of a subgroup, indicating the number of invocations in that specific subgroup. In compute and graphics pipelines, hardware schedules threads in lockstep groups, commonly referred to as warps, wavefronts, or SIMD vectors.

The gl_SubgroupSize variable reflects this hardware vector width. Unlike gl_SubgroupInvocationID (which indexes an individual thread from 0 to gl_SubgroupSize - 1), gl_SubgroupSize gives the total active width for that execution slice, allowing developers to write efficient intra-group algorithms like parallel reductions, ballot operations, and prefix sums without relying on shared memory.

NVIDIA Architecture (Warps)

On NVIDIA hardware, subgroups map directly to warps.

  • Standard Value: 32
  • Across virtually all modern NVIDIA architectures—from Kepler and Maxwell through Turing, Ampere, Ada Lovelace, and Blackwell—the hardware warp size is fixed at 32 threads.
  • Consequently, gl_SubgroupSize on NVIDIA GPUs will consistently evaluate to 32.

AMD Architecture (Wavefronts)

AMD hardware implements subgroups as wavefronts, where the size depends on both the generation and the compile-time configuration.

  • GCN (Graphics Core Next): Evaluates to 64. GCN architectures natively process wavefronts of 64 threads.
  • RDNA, RDNA 2, and RDNA 3: Evaluates to either 32 or 64. RDNA introduced dual-mode execution units that natively support Wave32 and Wave64.
  • By default, RDNA compilers typically target 32 for compute and pixel shaders to improve occupancy and lower register pressure, but the compiler or specific pipeline creation flags can configure it to 64. Developers should never hardcode an assumption of 32 or 64 on AMD hardware.

Intel Architecture (Execution Units / Xe-Cores)

Intel GPUs take a dynamic, compiler-driven approach to subgroup widths.

  • Standard Values: 8, 16, or 32
  • On Intel Gen9, Gen11, and Xe architectures (including Arc discrete GPUs), the execution units (EUs) or Xe Vector Engines (XVEs) support variable SIMD execution widths.
  • The driver's shader compiler selects the subgroup size based on register pressure, shader complexity, and target hardware profile. A simple compute shader might execute with a gl_SubgroupSize of 32, while a register-heavy shader may fall back to 16 or 8 to maintain thread occupancy.

Mobile and Embedded Architectures

Mobile graphics architectures exhibit significant diversity in their SIMD pipeline designs:

  • Apple Silicon: Evaluates to 32. On Apple M-series and A-series GPUs (when running via Vulkan or MoltenVK translation layers), subgroups map to SIMDgroups, which are standardized at 32 threads.
  • ARM Mali: Evaluates to 4 or 16. Older Midgard/Bifrost designs operated on smaller vector or quad widths (often reporting 4 or 8), whereas newer Valhall and 5th Gen Mali architectures standardize on 16-wide warps.
  • Qualcomm Adreno: Evaluates typically to 32 or 64, depending on the specific GPU tier, shader stage, and driver implementation.

Practical Implications for Shader Design

Because gl_SubgroupSize can vary from 4 up to 64 across devices, cross-platform GLSL code should never assume a fixed warp size of 32. Portable subgroup algorithms must either query gl_SubgroupSize dynamically at runtime or enforce a required subgroup size via pipeline extensions (such as VK_EXT_subgroup_size_control in Vulkan) when a specific execution width is mathematically required.