How EndStreamPrimitive Works in GLSL Streams

In OpenGL Shading Language (GLSL), EndStreamPrimitive is a built-in geometry shader function used to finalize and complete the current primitive on a designated output stream. When working with geometry shaders that support multiple output streams—typically for transform feedback—this function acts as a stream-specific delimiter. It signals the GPU's primitive assembly stage that the sequence of vertices previously emitted to that targeted stream is finished, allowing subsequent emitted vertices on that stream to begin a new primitive.

Context of Multiple Output Streams

Modern geometry shaders can route generated vertices to multiple output streams (from index 0 up to gl_MaxVertexStreams - 1). Stream 0 can be routed either to the rasterizer for rendering or captured via transform feedback, while streams 1 and higher are strictly designated for transform feedback.

To manage independent topologies across these distinct pipelines, GLSL replaces single-stream control functions (EmitVertex and EndPrimitive) with their stream-aware equivalents: EmitStreamVertex(int stream) and EndStreamPrimitive(int stream).

Mechanism of Primitive Completion

When EndStreamPrimitive(int stream) is called, it executes the following operations for the specified stream:

  1. Topology Termination: Geometry shaders typically emit primitives using strip topologies, such as triangle_strip or line_strip. EndStreamPrimitive breaks the current strip on the target stream. The next vertex pushed to this stream via EmitStreamVertex will not connect to the preceding vertices, starting a fresh strip instead.
  2. Primitive Assembly Trigger: For closed topologies like triangles or lines, the primitive assembler requires an explicit signal to package the accumulated vertices into a complete primitive. Calling EndStreamPrimitive confirms that no more vertices will be appended to the current shape on that stream, allowing the GPU to pass the completed primitive down the pipeline.
  3. Stream Isolation: The execution of EndStreamPrimitive on one stream operates independently of any other active streams. Calling EndStreamPrimitive(1) terminates the current primitive on stream 1 without affecting an in-progress primitive or strip being generated on stream 0.

Syntax and Implementation Requirements

The function signature is defined as:

void EndStreamPrimitive(int stream);

To use EndStreamPrimitive correctly, several GLSL constraints must be satisfied:

  • Compile-Time Constant: The stream parameter must be an integral constant expression known at compile time. It cannot be an index determined dynamically at runtime.
  • Valid Range: The stream index must lie within the range [0, gl_MaxVertexStreams - 1].
  • Topology Restrictions on Higher Streams: Under the core OpenGL specification, streams with an index greater than 0 must output point primitives (points). While EndStreamPrimitive can still be invoked on these streams to maintain pipeline consistency, its functional necessity is most pronounced when breaking continuous strips on stream 0.

By invoking EndStreamPrimitive(stream), developers maintain granular control over primitive boundaries across parallel transform feedback buffers and the main rasterization path within a single geometry shader invocation.