Guide to gl_PrimitiveLineIndicesEXT in Mesh Shaders

In GLSL mesh shaders utilizing the GL_EXT_mesh_shader extension, gl_PrimitiveLineIndicesEXT is a built-in output array used to define line topology. When a mesh shader is configured to output lines instead of triangles or points, this array specifies the index pairs that connect vertices together into distinct line primitives. This article explains the purpose, declaration, and mechanics of using gl_PrimitiveLineIndicesEXT to construct indexed line geometry directly on the GPU.

The Role of gl_PrimitiveLineIndicesEXT

Mesh shaders operate by decoupling per-vertex data generation from primitive assembly. Rather than relying on a fixed-function primitive assembler, the mesh shader explicitly produces a list of output vertices and an index list specifying how those vertices assemble into primitives.

When generating line primitives, each line requires exactly two vertex indices. The gl_PrimitiveLineIndicesEXT built-in array serves as the primitive index buffer. Each element in the array represents an individual line segment and points to two vertices generated within the same mesh shader workgroup.

Declaration and Type

The array is available when the mesh shader defines its primitive output type as lines:

#extension GL_EXT_mesh_shader : require

layout(lines) out;
layout(max_vertices = 64, max_primitives = 64) out;

Under this layout, the shader runtime provides the built-in output:

out uvec2 gl_PrimitiveLineIndicesEXT[];

The array size corresponds to the max_primitives value declared in the layout. Each element is a two-component unsigned integer vector (uvec2), where the x and y components represent the zero-based indices of the start and end vertices stored in the vertex output arrays (such as gl_MeshVerticesEXT).

How It Works in Practice

During execution, a mesh shader workgroup calculates per-vertex attributes and writes them into output arrays indexed from 0 to vertex_count - 1. Concurrently, threads assign connectivity by writing to gl_PrimitiveLineIndicesEXT.

For example, to draw a connected line strip between three generated vertices:

// Define 3 vertices
SetMeshOutputsEXT(3, 2);

// Write vertex positions into gl_MeshVerticesEXT...

// Define primitive indices
gl_PrimitiveLineIndicesEXT[0] = uvec2(0, 1); // Line 0 connects vertex 0 to vertex 1
gl_PrimitiveLineIndicesEXT[1] = uvec2(1, 2); // Line 1 connects vertex 1 to vertex 2

Key Benefits

  1. Vertex Reuse: Without an index array, shared vertices along connected paths or wireframe networks would have to be duplicated. gl_PrimitiveLineIndicesEXT allows adjacent lines to reference the same vertex, reducing vertex attribute calculations and memory footprint within the workgroup.
  2. Dynamic Topology: The shader can compute arbitrary line topologies on the fly—such as wireframe overlays, vector field visualizers, hair strands, or dynamic debug bounding boxes—without requiring pre-assembled index buffers from the CPU.
  3. Hardware Efficiency: Modern GPU hardware uses these indices directly to schedule rasterization for wide or anti-aliased lines without routing primitive assembly through fixed-function geometry pipeline stages.