How Patch In Works in GLSL Tessellation Evaluation

In OpenGL, the Tessellation Evaluation Shader (TES) relies on the patch in qualifier to read per-patch attributes produced by the Tessellation Control Shader (TCS). This article explains how per-patch data flows across the tessellation pipeline, how the patch in syntax interfaces with TCS outputs, and how the GPU makes patch-wide data accessible to every generated vertex without per-control-point indexing.

Per-Vertex vs. Per-Patch Attributes

During tessellation, the pipeline distinguishes between two classes of output data coming from the Tessellation Control Shader:

  1. Per-Vertex Attributes: These correspond to individual control points of the output patch. In the TES, these are received as arrays sized to the number of control points (for example, in vec3 vPosition[]).
  2. Per-Patch Attributes: These represent properties shared by the entire patch, such as shared material properties, displacement factors, or custom tessellation metadata. Rather than varying per control point, a per-patch attribute holds a single value for the whole patch.

Syntax and Declaration Matching

To transmit a custom per-patch attribute, the TCS declares the variable using the patch out storage qualifier:

// In Tessellation Control Shader (TCS)
patch out vec4 vPatchColor;

In the Tessellation Evaluation Shader, the variable is received using the matching patch in qualifier:

// In Tessellation Evaluation Shader (TES)
patch in vec4 vPatchColor;

Unlike normal inputs in the TES, variables qualified with patch in are not implicitly sized arrays. Unless the variable was explicitly defined as an array type in the TCS (such as patch out float values[4];), the variable in the TES is a singular type. The link between the TCS and TES is resolved either by matching variable names or by matching explicit layout locations (e.g., layout(location = 0)).

Pipeline Data Flow and Execution

The transition of per-patch attributes through the hardware occurs across several distinct steps:

  1. TCS Assignment: The TCS calculates and writes the value to the patch out variable. Typically, this write is guarded so that only the first invocation executes it (e.g., if (gl_InvocationID == 0)), preventing redundant writes by other control point invocations.
  2. Primitive Generation: The fixed-function Tessellation Primitive Generator creates a mesh of abstract vertices (represented by barycentric or UV coordinates in gl_TessCoord) based on the inner and outer tessellation levels. The per-patch attributes bypass this stage unaltered.
  3. TES Invocation: The TES executes once for every abstract vertex generated by the primitive generator. When an invocation runs, the hardware automatically routes the patch's stored patch in attributes into the shader register space.

Because the data is uniform across the entire patch, every TES invocation processing vertices from that patch reads the exact same value from the patch in variable without needing to index using gl_PrimitiveID or control point indices.

Built-in Per-Patch Inputs

GLSL also provides built-in per-patch inputs in the TES that operate under the same mechanism. The tessellation levels defined by the TCS—gl_TessLevelOuter and gl_TessLevelInner—are implicitly passed to the TES as patch-constant inputs. They are available in the TES under the same names and provide access to the tessellation factors that determined the geometry of the current patch.