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:
- 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[]). - 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:
- TCS Assignment: The TCS calculates and writes the
value to the
patch outvariable. 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. - 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. - 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 inattributes 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.