gl_InvocationID in GLSL Tessellation Control Shaders
In modern OpenGL, the Tessellation Control Shader (TCS) processes
geometry patches to determine tessellation levels and compute output
control points. This article explains how the built-in variable
gl_InvocationID operates within the tessellation pipeline,
how it maps parallel execution instances to individual output vertices,
and how it is used to manage both per-vertex and per-patch data.
Parallel Execution and gl_InvocationID
When a patch primitive is sent to the Tessellation Control Shader, the pipeline executes the shader multiple times in parallel for that single patch. The exact number of invocations per patch is declared at the top of the shader using the output layout qualifier:
layout(vertices = N) out;Here, N represents the number of output control points
the shader must generate. The GPU launches N concurrent
invocations of the TCS for that patch. The built-in variable
gl_InvocationID is an integer
(in int gl_InvocationID;) that uniquely identifies which
specific invocation is currently executing. Its value ranges from
0 to N - 1.
Mapping Invocations to Output Control Points
The primary role of gl_InvocationID is to serve as an
array index for writing per-vertex output attributes. The TCS writes its
results to the built-in output array gl_out[], as well as
any user-defined output arrays declared with the out
keyword.
Because all invocations execute the same shader code simultaneously,
gl_InvocationID ensures that each thread writes to its
corresponding output slot without causing race conditions:
// Assign the position for the specific control point being processed
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;In this context, invocation 0 computes and writes output
control point 0, invocation 1 writes control
point 1, and so on up to N - 1.
Accessing Input Control Points
While each invocation is responsible for writing the output control
point corresponding to its gl_InvocationID, it is not
restricted to reading from the same index. The input array
gl_in[] contains all control points provided by the vertex
shader (sized by the input patch size defined on the CPU via
glPatchParameteri).
An invocation with gl_InvocationID equal to
0 can read from gl_in[0],
gl_in[1], or any other valid input index. This capability
is essential for operations like Bézier surface evaluation, where an
output point's position depends on multiple input points across the
patch.
Handling Patch-Constant Data
In addition to per-vertex outputs, the TCS must calculate the inner
and outer tessellation levels (gl_TessLevelInner and
gl_TessLevelOuter). These levels apply to the entire patch
rather than individual control points.
To avoid redundant computations across all N
invocations, developers use gl_InvocationID to restrict the
calculation to a single invocation—typically invocation
0:
if (gl_InvocationID == 0) {
gl_TessLevelInner[0] = 4.0;
gl_TessLevelInner[1] = 4.0;
gl_TessLevelOuter[0] = 4.0;
gl_TessLevelOuter[1] = 4.0;
gl_TessLevelOuter[2] = 4.0;
gl_TessLevelOuter[3] = 4.0;
}By branching on gl_InvocationID == 0, the hardware
executes the tessellation factor logic once per patch, while all other
invocations bypass the block and focus solely on generating their
designated output control points.