Understanding gl_MaxFragmentInputComponents in GLSL
This article explains how the built-in GLSL constant
gl_MaxFragmentInputComponents dictates the maximum amount
of interpolated data that can pass from earlier pipeline stages into a
fragment shader. It covers how the OpenGL specification defines
component counts, how hardware interpolators map to these values, and
the rules governing packing and shader linkage limitations.
Components Versus Variables
In GLSL, gl_MaxFragmentInputComponents defines the upper
bound for the total number of scalar values—floats, integers, or
booleans—that a fragment shader can receive as inputs (in
variables). This limit does not count the number of declared variables,
but the individual scalar components they consume.
Each data type consumes components based on its underlying scalar elements:
- A
floatorintconsumes 1 component. - A
vec2consumes 2 components. - A
vec3consumes 3 components. - A
vec4consumes 4 components. - A
mat4consumes 16 components (treated as four 4-component vectors). - Arrays multiply the base type's footprint by the array length (e.g.,
float[4]consumes 4 components).
Hardware Interpolators and the Packing Model
During rasterization, the GPU relies on dedicated hardware interpolators to compute perspective-correct or flat values across the surface of a primitive. Physical interpolation hardware is generally arranged into 4-wide vector registers (often referred to in older specifications as varying vectors).
The value of gl_MaxFragmentInputComponents directly
reflects the capacity of these physical registers. For example, a system
exposing a limit of 64 components provides the equivalent of 16
four-component interpolator registers (since \(64 \div 4 = 16\)).
The GLSL compiler performs varying packing, attempting to merge
smaller variables (such as multiple float or
vec2 declarations) into single 4-component slots to
conserve hardware resources. However, if explicit layout locations or
interpolation qualifiers (such as flat,
noperspective, or smooth) prevent efficient
packing, fragmentation can occur. Regardless of how the compiler packs
them, the total active component count must remain at or below
gl_MaxFragmentInputComponents.
Built-in Inputs and Linkage
User-defined inputs are not the only values that consume
interpolation resources. Depending on the driver and hardware
architecture, certain built-in variables—such as
gl_FragCoord, gl_PointCoord, or clip
distances—may also count against this component ceiling or share the
same physical routing resources.
If the combined sum of declared active fragment inputs exceeds
gl_MaxFragmentInputComponents, the OpenGL driver cannot
allocate enough interpolator registers. As a result, the shader program
will fail at the link stage, generating a compile-time or link-time
error detectable via glGetProgramiv with
GL_LINK_STATUS.
Practical Considerations
To prevent exceeding this limit across different GPUs, developers can
query the hardware capability at runtime using
glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &value).
While the OpenGL specification mandates a minimum baseline (typically 60
or 128 components depending on the core version), complex shaders with
extensive vertex-to-fragment data transfers can easily exhaust this
budget. In such cases, data that does not vary across a primitive should
be migrated to Uniform Buffer Objects (UBOs) or Shader Storage Buffer
Objects (SSBOs) rather than passing through the interpolator
pipeline.