GLSL Transform Feedback: Capturing Vertex Output
Transform feedback in OpenGL and GLSL allows developers to capture primitive data generated by vertex processing stages—such as vertex, tessellation, and geometry shaders—and write it directly into buffer objects on the GPU. By disabling the rasterization stage entirely, the pipeline can completely bypass fragment rendering, effectively turning the graphics pipeline into a dedicated, high-performance general-purpose computation engine. This article explains the architectural mechanics of transform feedback, how to eliminate the fragment processing stage, and the operational steps required to record vertex output data.
The Pipeline Architecture of Transform Feedback
In a traditional graphics pipeline, processed vertices pass through primitive assembly, get rasterized into fragments, and are ultimately processed by the fragment shader before reaching the framebuffer.
Transform feedback sits between the post-processing vertex stages
(geometry or vertex execution) and the primitive assembly/rasterization
stage. Instead of allowing primitives to continue downstream toward the
screen, the GPU intercepts the output varyings defined in your GLSL
shaders and redirects them into one or more bound Buffer Objects
(GL_TRANSFORM_FEEDBACK_BUFFER).
Bypassing Fragment Rendering with Rasterizer Discard
Capturing vertex data without executing fragment shaders relies on
the OpenGL state toggle GL_RASTERIZER_DISCARD.
Under normal execution, the pipeline requires a fragment shader to evaluate colors and depths for every generated pixel. When you enable rasterizer discard using:
glEnable(GL_RASTERIZER_DISCARD);the hardware completely turns off the rasterization stage. Primitives
processed by vertex or geometry shaders do not generate fragments,
rendering the fragment shader idle and skipping it entirely. This
eliminates the performance cost of depth testing, blending, stencil
tests, and fragment execution. Once the capture pass is complete,
rasterization can be re-enabled using
glDisable(GL_RASTERIZER_DISCARD) if rendering to a
framebuffer is later required.
Configuring the GLSL Shader and Program
To record specific outputs, the OpenGL program must identify which
GLSL output variables to capture before the shader program is linked.
This is accomplished using glTransformFeedbackVaryings.
- Declare outputs in the Vertex Shader:
#version 330 core
layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec3 inVelocity;
out vec3 outPosition;
out vec3 outVelocity;
uniform float deltaTime;
void main() {
outPosition = inPosition + inVelocity * deltaTime;
outVelocity = inVelocity; // update or apply forces
}- Specify varyings before linking:
const char* varyings[] = { "outPosition", "outVelocity" };
glTransformFeedbackVaryings(shaderProgram, 2, varyings, GL_INTERLEAVED_ATTRIBS);
glLinkProgram(shaderProgram);Outputs can be written into a single buffer using
GL_INTERLEAVED_ATTRIBS or separated across distinct buffers
using GL_SEPARATE_ATTRIBS.
Executing the Capture Loop
The actual recording process requires binding an output buffer and wrapping the draw call in transform feedback execution markers:
- Bind Buffer to Feedback Target: Bind the
destination buffer to the indexed transform feedback binding point using
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, index, bufferID). - Disable Rasterization: Call
glEnable(GL_RASTERIZER_DISCARD). - Begin Feedback: Call
glBeginTransformFeedback(GL_POINTS). The primitive type must match the output topology generated by the preceding shader stages. - Issue Draw Calls: Execute standard draw commands
such as
glDrawArraysorglDrawElements. The GPU executes the vertex shader, captures the specified output variables into the bound buffer, and immediately drops the primitives before rasterization. - End Feedback: Call
glEndTransformFeedback(). - Restore Pipeline State: Call
glDisable(GL_RASTERIZER_DISCARD)if subsequent render passes need to draw to the screen.
Practical Applications
By eliminating the rasterization and fragment stages, transform feedback creates an efficient GPU-to-GPU data pipeline. The captured buffer can immediately serve as a vertex buffer object (VBO) for a subsequent render pass or feed into another transform feedback pass in a ping-pong buffer configuration. This approach is widely used for particle systems, cloth physics simulations, and iterative computational algorithms where keeping data entirely in GPU memory delivers maximum performance.