GLSL layout(stream = N) Transform Feedback Guide
The layout(stream = N) qualifier in the OpenGL Shading
Language (GLSL) allows geometry shaders to distribute emitted vertices
across up to four distinct transform feedback streams (numbered 0 to 3).
Introduced with OpenGL 4.0 and the ARB_transform_feedback3
extension, this qualifier directs distinct vertex attributes into
separate transform feedback buffer bindings simultaneously. This guide
details how the qualifier routes vertex data, the functions required to
emit data to designated streams, the constraints on output primitive
types, and how these streams interact with the rasterizer.
Declaring Streams in the Geometry Shader
By default, any output variable declared in a geometry shader is
assigned to stream 0. To redirect a variable to a different stream,
apply the layout(stream = N) qualifier to individual output
declarations or apply a global layout qualifier that sets the default
for all subsequent declarations.
#version 400 core
layout(triangles) in;
layout(points, max_vertices = 4) out;
// Explicit assignment per output variable
layout(stream = 0) out vec4 positionForRasterizer;
layout(stream = 1) out vec3 velocityToFeedback;
layout(stream = 2) out float particleLifetime;
// Setting a default stream for subsequent declarations
layout(stream = 3) out;
out vec2 auxData; // Automatically assigned to stream 3Each active output stream corresponds to a distinct transform
feedback stream index configured on the CPU side through
glTransformFeedbackVaryings using the special separator
token "gl_NextBuffer" or indexed recording layouts.
Emitting Vertices to Specific Streams
When using multiple vertex streams, standard emission functions like
EmitVertex() and EndPrimitive() cannot be
used, as they implicitly target stream 0. Instead, GLSL provides
specialized built-in functions that accept the stream index as an
argument:
EmitStreamVertex(int stream): Writes current values of all output variables associated with the specifiedstreaminto a new vertex for that stream.EndStreamPrimitive(int stream): Completes the primitive being assembled on the designatedstream.
Variables associated with other streams remain unaffected when
EmitStreamVertex is executed for an alternate stream:
void main() {
// Emit a vertex to stream 0
positionForRasterizer = gl_in[0].gl_Position;
EmitStreamVertex(0);
EndStreamPrimitive(0);
// Emit physics data to stream 1
velocityToFeedback = vec3(0.0, 1.0, 0.0);
EmitStreamVertex(1);
EndStreamPrimitive(1);
}Rasterization Pipeline Rules
The graphics hardware handles streams unevenly relative to the rasterizer:
- Stream 0: This is the only stream capable of passing primitives down the rest of the graphics pipeline to the rasterizer and fragment shader. If rasterization is enabled, stream 0 renders to the framebuffer while optionally recording to transform feedback buffers.
- Streams 1, 2, and 3: These streams bypass rasterization completely. Vertices emitted to streams 1 through 3 can only be captured via transform feedback buffer objects. Attempting to feed these streams into the rasterizer is not supported by the hardware pipeline.
- Rasterizer Discard: If rendering is not needed,
glEnable(GL_RASTERIZER_DISCARD)can disable rasterization entirely, allowing stream 0 to act exclusively as an additional transform feedback stream.
Hardware Limitations and Constraints
Using multiple output streams introduces hardware-level constraints:
- Primitive Type Restriction: If any output stream
index greater than 0 is used, the geometry shader output primitive type
must be declared as
points. Geometry shaders cannot output lines or triangles when writing to multiple streams. - Variable Grouping: A single vertex output variable cannot belong to multiple streams. Duplicate outputs must be declared separately if identical data needs to be captured across different streams.
- Resource Limits: The maximum number of streams is
queried via
GL_MAX_VERTEX_STREAMS, which is guaranteed to be at least 4 in implementations supporting OpenGL 4.0 or higher. The total number of output vertices across all streams cannot exceedgl_MaxGeometryOutputVertices.