GLSL Tessellation Control Shader Patch Out Variables

This article provides an overview of the role and mechanics of patch out variables within OpenGL Shading Language (GLSL) Tessellation Control Shaders (TCS). It clarifies how the patch qualifier manages data across geometric primitives, highlights the technical distinction between per-control-point and per-patch attributes, and explains how this data is routed efficiently to the Tessellation Evaluation Shader (TES).

In the OpenGL tessellation pipeline, the Tessellation Control Shader (TCS) processes an input patch of vertices and emits an output patch containing a specified number of control points. While standard output variables in a TCS are structured as arrays corresponding to each output control point, the patch out qualifier designates attributes that belong to the patch as an entire entity rather than to individual control points.

Distinguishing Per-Control-Point from Per-Patch Data

Standard TCS output variables represent per-vertex control point data (such as positions, normals, or UV coordinates). These outputs are implicitly or explicitly declared as arrays sized by gl_OutputVerticesDeclaration:

layout(vertices = 4) out;

out vec3 vPosition[]; // Indexed per control point via gl_InvocationID

In contrast, declaring an output with the patch qualifier removes the association with individual control points. A patch out variable represents patch-level metadata derived from the control points:

patch out vec4 vPatchColor;
patch out float vSubdivisionBias;

Purpose and Function of patch out Variables

  1. Elimination of Redundant Storage and Bandwidth: If a property applies to the entire primitive—such as dynamic level-of-detail flags, patch-level bounding volumes, or material identifiers derived from control point positions—storing it in standard per-vertex outputs duplicates the value across every control point. Using patch out ensures the value is stored and transferred only once per patch, reducing memory footprint and cross-stage bandwidth.

  2. Facilitating Uniform Access in the Evaluation Shader: In the Tessellation Evaluation Shader (TES), control point outputs must be sampled using the patch vertex indices (e.g., gl_in[i].vPosition). Variables declared as patch out in the TCS are matched with patch in declarations in the TES. This allows the TES to access patch-wide constants directly, without indexing by vertex ID, ensuring clear separation between interpolative vertex data and primitive-wide constants.

  3. Writing Rules and Invocation Control: Because a TCS runs once per output control point (gl_InvocationID), all invocations within the same workgroup share the patch-level outputs. Writing to a patch out variable requires careful synchronization. It is standard practice to restrict writes to a single invocation to prevent race conditions:

    if (gl_InvocationID == 0) {
        vPatchColor = calculatePatchMetadata();
    }

By distinguishing per-patch state from control point geometry, patch out variables streamline how data is gathered from incoming control points and transmitted downstream, optimizing execution and maintainability across the tessellation stages.