How Does GLSL Invariant Stop Z-Fighting?

In multi-pass rendering pipelines, subtle floating-point variations across different shader programs can cause identical geometry to produce slightly different depth coordinates, resulting in severe visual artifacting known as Z-fighting. The invariant qualifier in GLSL addresses this by instructing the shader compiler and GPU driver to guarantee bit-for-bit identical evaluation of targeted output variables across different shader objects. By enforcing exact computational repeatability on gl_Position, developers can run depth pre-passes, lighting passes, and post-effects using GL_EQUAL depth tests without surface flicker or non-deterministic depth test failures.

The Cause of Multi-Pass Depth Inconsistencies

Multi-pass rendering relies on drawing the exact same geometric mesh multiple times across distinct shader programs. A standard pattern involves rendering depth in an initial baseline pass, followed by subsequent passes that compute forward lighting, ambient occlusion, or volumetric effects. To avoid redundant depth writing and preserve performance, secondary passes typically configure the depth function to GL_EQUAL or GL_LEQUAL.

Even when separate vertex shaders execute mathematically identical matrix transformations—such as transforming an object-space vertex by identical model, view, and projection matrices—the resulting floating-point values can diverge:

Because the depth buffer operates at high precision, a discrepancy of a single Unit in the Last Place (ULP) causes fragments to fail depth equality tests, producing noisy rendering artifacts and missing geometry.

How the Invariant Qualifier Enforces Bit-Exact Precision

The invariant qualifier acts as a binding contract with the GLSL compiler. When an output variable—most commonly the built-in gl_Position—is marked as invariant, the compiler is restricted from applying optimizations that compromise deterministic output.

Specifically, the compiler ensures:

  1. The exact sequence of machine instructions generated for computing the marked variable is consistent across separate shader binaries.
  2. Target calculations bypass aggressive floating-point contraction or tree-balancing that depends on variable lifetime or surrounding context.
  3. The generated output coordinate matches identically across draw calls, provided the source inputs and order of calculations are consistent.

Syntax and Implementation Patterns

GLSL allows applying the invariant qualifier either to specific variables or globally across the entire compilation unit.

Selective Variable Invariance

The standard and most performant approach is to mark specific vertex outputs. You can declare invariance directly at output definition or retroactively declare built-in variables:

#version 330 core

// Retroactively marking the built-in position output as invariant
invariant gl_Position;

uniform mat4 u_ModelViewProjection;
layout(location = 0) in vec3 a_Position;

void main()
{
    gl_Position = u_ModelViewProjection * vec4(a_Position, 1.0);
}

This ensures that any other shader in the pipeline using identical transformation logic for gl_Position will produce the exact same depth value.

Global Invariance Pragma

GLSL also supports forcing invariance on all shader outputs via a preprocessor pragma:

#pragma STDGL invariant(all)

While convenient, applying global invariance is generally discouraged. Forcing invariance across every color, normal, and texture coordinate disables global compiler optimizations, which can degrade execution efficiency.

Requirements for Guaranteed Determinism

The invariant qualifier prevents compiler-induced non-determinism, but it cannot fix application-level discrepancies. For invariance to successfully eliminate Z-fighting, the host application must satisfy several criteria:

In modern OpenGL (GLSL 4.0+) and Vulkan (via SPIR-V), developers often supplement or replace invariant with the precise qualifier, which provides fine-grained control over intermediate operation order, preventing FMA contraction on arbitrary variable assignments.