Using EmitStreamVertex in GLSL Geometry Shaders

In OpenGL Shading Language (GLSL), geometry shaders can separate and direct generated primitives into multiple independent vertex streams for transform feedback. This article explains how the built-in EmitStreamVertex function operates, how it routes primitive data to specific transform feedback streams, and the layout requirements necessary to implement multiple output streams in geometry shaders.

The Role of EmitStreamVertex

The built-in function that routes primitive data to a specific transform feedback stream is EmitStreamVertex(int stream).

In standard single-stream pipelines, geometry shaders emit vertices using EmitVertex(). However, when utilizing multiple transform feedback streams (introduced in OpenGL 4.0 and the ARB_gpu_shader5 extension), EmitStreamVertex allows developers to explicitly assign an emitted vertex to a designated stream index, ranging from 0 to gl_MaxVertexStreams - 1.

Along with EmitStreamVertex(int stream), GLSL provides EndStreamPrimitive(int stream) to signal the completion of a primitive on that specific stream, matching the behavior of EndPrimitive() in single-stream configurations.

Syntax and Layout Requirements

To use multiple streams, output variables in the geometry shader must be bound to specific streams using the stream layout qualifier. If an output variable does not specify a stream, it defaults to stream 0.

#version 400 core

layout(triangles) in;
layout(points, max_vertices = 4) out;

// Assigning specific outputs to different streams
layout(stream = 0) out vec4 stream0_position;
layout(stream = 1) out vec3 stream1_normal;

void main() {
    // Emit to Stream 0
    stream0_position = gl_in[0].gl_Position;
    EmitStreamVertex(0);
    EndStreamPrimitive(0);

    // Emit to Stream 1
    stream1_normal = vec3(0.0, 1.0, 0.0);
    EmitStreamVertex(1);
    EndStreamPrimitive(1);
}

Key Constraints

When routing data to specific transform feedback streams via EmitStreamVertex, several pipeline limitations apply:

  • Primitive Types: If any geometry shader output stream uses an index greater than 0, the output primitive type for the geometry shader must be declared as points.
  • Rasterization: Only stream 0 can be passed down the standard rendering pipeline for rasterization. All other streams (1 and higher) are strictly used for transform feedback buffer capture.
  • Stream Indexing: The stream parameter in EmitStreamVertex(int stream) must be a compile-time constant expression. It cannot be dynamically indexed at runtime.