GLSL layout(xfb_stride) for Transform Feedback

This article examines the role of the layout(xfb_stride = S) qualifier in OpenGL Shading Language (GLSL), which explicitly defines the byte stride between consecutive vertex records in transform feedback buffers. You will learn how this qualifier functions within the shader, why it is critical for managing interleaved buffer layouts and custom padding, and the structural rules governing its use in modern OpenGL pipelines.

Understanding Transform Feedback Layout Qualifiers

Transform feedback allows OpenGL applications to capture vertex or geometry shader outputs directly into GPU buffer objects before rasterization. Traditionally, the mapping of captured variables to buffer offsets and strides was configured entirely on the CPU using glTransformFeedbackVaryings.

With the introduction of the ARB_enhanced_layouts extension (core in OpenGL 4.4 and GLSL 4.40), developers can define transform feedback layout parameters directly inside the shader code using layout qualifiers such as xfb_buffer, xfb_offset, and xfb_stride.

The Core Role of layout(xfb_stride = S)

The qualifier layout(xfb_stride = S) sets the explicit distance in bytes between the start of one captured vertex record and the start of the next in a specified transform feedback buffer. Here, S is an unsigned integer representing the byte count.

Its primary functions include:

  • Defining Interleaved Buffer Strides: When multiple shader outputs are written to the same buffer index (xfb_buffer), xfb_stride defines the complete size of the combined vertex structure. This ensures each write cycle advances the write pointer by the exact byte length of the interleaved record.
  • Adding Explicit Padding: If your application requires data structures aligned to specific byte boundaries (such as 16-byte alignment for SIMD operations or specific uniform/storage block standards), xfb_stride allows you to introduce trailing padding beyond the total byte size of the captured components.
  • Synchronizing CPU and GPU Structures: Setting an explicit stride in GLSL ensures the generated memory layout matches the corresponding C/C++ struct layout on the host side without relying on driver-specific automatic packing.

Syntax and Implementation Rules

The xfb_stride qualifier is assigned to a specific buffer index and must adhere to several validation rules:

  1. Multiple of Four: The stride value S must be a multiple of 4 bytes.
  2. Sufficient Capacity: S must be greater than or equal to the highest component offset written to that buffer plus the size of that component. In other words, variables cannot overlap outside the designated stride.
  3. Consistency per Buffer: All declarations targeting the same xfb_buffer index within the same shader stage must specify the identical xfb_stride value.

The qualifier can be declared globally for an entire buffer index or attached directly to output variables:

#version 440 core

// Globally specify that buffer 0 advances 32 bytes per vertex
layout(xfb_buffer = 0, xfb_stride = 32) out;

// Output 1: 12 bytes (vec3), starts at offset 0
layout(xfb_buffer = 0, xfb_offset = 0) out vec3 outPosition;

// Output 2: 16 bytes (vec4), starts at offset 16 (leaving 4 bytes of padding between position and color)
layout(xfb_buffer = 0, xfb_offset = 16) out vec4 outColor;

In this setup, each vertex consumes 32 bytes in Buffer 0:

  • Bytes 0–11: outPosition
  • Bytes 12–15: Unused padding
  • Bytes 16–31: outColor

The write pointer will increment by exactly 32 bytes for each processed vertex.

Explicit vs. Implicit Strides

If you omit xfb_stride while specifying explicit xfb_offset values, the driver will not automatically infer the stride; you must explicitly provide xfb_stride when manual offsets are used. Conversely, if variables are captured without explicit offsets, the driver packs variables contiguously and assigns an implicit stride equal to the total size of the captured components. Using layout(xfb_stride = S) removes ambiguity, ensuring deterministic memory layouts across different GPU hardware and driver implementations.