GLSL layout(point_mode) in Tessellation
In OpenGL Shading Language (GLSL), declaring
layout(point_mode) within a Tessellation Evaluation Shader
(TES) instructs the fixed-function primitive generator to output
independent point primitives rather than connected surfaces or lines.
This article explains how layout(point_mode) alters the
tessellation pipeline, transforms primitive assembly, and modifies the
final rasterization behavior from standard polygons to individual
fragments.
The Role of layout(point_mode)
In a standard tessellation pipeline, the Tessellation Primitive
Generator (TPG) subdivides an abstract domain—such as triangles
(triangles), quadrilaterals (quads), or lines
(isolines)—based on inner and outer tessellation levels set
by the Tessellation Control Shader (TCS). Typically, the TPG organizes
the resulting domain coordinates \((u,
v)\) or \((u, v, w)\) into
connected topologies, assembling them into triangles or line strips.
When you add the point_mode layout qualifier to the TES
input declaration:
layout(triangles, equal_spacing, ccw, point_mode) in;The TPG still evaluates the domain coordinates according to the specified spacing and domain type, but it completely discards the topological connectivity. Instead of generating indices for triangle strips or line segments, the stage outputs each evaluated coordinate as a separate, individual point.
Alteration of Primitive Assembly
The immediate consequence of point_mode occurs during
primitive assembly, which sits directly between the tessellation
evaluation stage and the subsequent pipeline stages (geometry shading,
transform feedback, or rasterization):
Primitive Classification: The primitive type emitted from the tessellation stage becomes equivalent to
GL_POINTS.Downstream Shader Expectations: If a Geometry Shader is active after the TES, it must declare its input primitive type as
points:layout(points) in;Transform Feedback: If transform feedback is captured directly after tessellation, the captured primitives are recorded as individual points rather than triangles or lines.
Impact on Rasterization
Because the primitives are classified as points, rasterization rules diverge completely from normal polygon or line rasterization:
- Discarding Surface Rasterization: Standard polygon
rasterization generates fragments across the continuous 2D surface
bounded by the interpolated edges. With
point_mode, no interior surface is recognized; only the vertices themselves are rasterized. - Point Sizing: The rasterizer renders each point as
a screen-aligned square centered on the vertex's window coordinates. The
dimensions of this square are determined by either
gl_PointSize(ifGL_PROGRAM_POINT_SIZEis enabled in the OpenGL context) or the globalglPointSizestate. - Face Culling Invalidation: Polygon face culling
(
GL_CULL_FACE) no longer applies. Because there are no winding orders (clockwise or counter-clockwise) for isolated vertices, points cannot be classified as front-facing or back-facing. All points within the view frustum survive to the fragment stage unless clipped by custom clip planes or the depth boundaries. - Fragment Shader Semantics: The Fragment Shader can
access point-specific built-in variables, such as
gl_PointCoord, which provides 2D normalized coordinates \(([0, 1] \times [0, 1])\) across the point primitive. This enables rendering procedural shapes, such as circular particles or point-sprites, directly on the evaluated tessellation grid.
Practical Applications
layout(point_mode) is primarily used for:
- Tessellation Debugging: Visualizing the exact density, distribution, and clustering of vertices produced by tessellation factor calculations without the visual obstruction of overlapping wireframes or solid fills.
- Point Cloud and Particle Generation: Dynamically sampling smooth parametric surfaces (such as Bézier patches or terrain heightmaps) to generate dense particle systems directly on the GPU without additional compute passes.