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):

  1. Primitive Classification: The primitive type emitted from the tessellation stage becomes equivalent to GL_POINTS.

  2. Downstream Shader Expectations: If a Geometry Shader is active after the TES, it must declare its input primitive type as points:

    layout(points) in;
  3. 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 (if GL_PROGRAM_POINT_SIZE is enabled in the OpenGL context) or the global glPointSize state.
  • 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.