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 float or int consumes 1 component.
  • A vec2 consumes 2 components.
  • A vec3 consumes 3 components.
  • A vec4 consumes 4 components.
  • A mat4 consumes 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.