Transform Feedback/In Shader Specification

From OpenGL Wiki
< Transform Feedback
Revision as of 14:06, 20 August 2013 by Alfonse (talk | contribs) (Separated feedback routing to a new page.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Layout qualifiers can be used to define which output variables are captured in Transform Feedback operations. When these qualifiers are set in a shader, they completely override any attempt to set the transform feedback outputs from OpenGL via glTransformFeedbackVaryings.

Any output variable or output interface block declared with the xfb_offset layout qualifier will be part of the transform feedback output. This qualifier must be specified with an integer byte offset. The offset is the number of bytes from the beginning of a vertex to be written to the current buffer to this particular output variable.

The offsets of contained values (whether in arrays, structs, or members of an interface block if the whole block has an offset) are computed, based on the sizes of prior components to pack them in the order specified. Any explicitly provided offsets are not allowed to violate alignment restrictions. So if a definition contains a double (either directly or indirectly), the offset must be 8-byte aligned.

Members of interface blocks can have their offsets specified directly on them, which overrides any computed offsets. Also, all members of an interface block are not required to be written to outputs (though that will happens if you set the xfb_offset on the block itself). Stream assignments for a geometry shader are required to be the same for all members of a block, but offsets are not.

Different variables being captured are assigned to buffer binding indices. Offset assignments are separate for the separate buffers. It is a linker error for two variables captured by the same buffer to have overlapping byte offsets, whether automatically computed or explicitly assigned.

An explicit buffer assignment is made by using the xfb_buffer qualifier on the same declaration as the offset qualifier. This takes an integer which defines the buffer binding index that the captured output(s) is/are associated with. The integer must be less than GL_MAX_TRANSFORM_FEEDBACK_BUFFERS.

Any offsets for global variables or interface blocks that do not specify a buffer explicitly will use the current buffer. The current buffer is set as follows:

layout(xfb_buffer = #) out;

All following offsets for globals that do not explicitly specify a buffer will use # as their buffer. The initial current buffer for a shader is 0.

Variables can have xfb_buffer assigned to them without xfb_offset. This does nothing and will be ignored.

Interface blocks have a special association with buffers. Each interface block is associated with a buffer, regardless of whether any of its members are captured. The buffer is either the current buffer as defined above or a buffer explicitly specified by xfb_buffer.

As previously stated, all members of a block do not have to be captured. However, if any members of a block are captured, they must all be captured to the same buffer. Specifically, the buffer associated with that block. It is an error to use xfb_buffer on a member if the buffer index you provide is different from the index used by the block.

As an example:

layout(xfb_buffer = 2) out; //Default buffer of 2.

out OutputBlock1            //Block buffer index is implicitly 2.
  float val1;
  layout(xfb_buffer = 2, xfb_offset = 0) first;  //The provided index is the same as the block's index.
  layout(xfb_buffer = 1, xfb_offset = 0) other;  //Compile error, due to changing the buffer index for a block member.

Each buffer has the concept of a stride. This represents the byte count from the beginning of one captured vertex to the beginning of the next. It is computed by taking the output with the highest xfb_offset value, adding its size to that offset, and then aligning the computed value to the base alignment of the buffer. The buffer's alignment is 4, unless it captures any double-precision values in which case it is 8. This means you do not need to manually pad structures for alignment, as you did with outside shader setting.

The stride for a buffer can also be explicitly set using the xfb_stride layout qualifier. This allows you to add extra space at the end, perhaps to skip data that will not change. A compilation error will result if the stride you specify is:

  • Too small, given the offsets and computed sizes of the captured data for that buffer.
  • Not properly aligned. It must be at least 4 byte aligned, and it must be 8 byte aligned if the buffer captures any double-precision values.

The stride for a buffer is set as follows:

layout(xfb_buffer = 1, xfb_stride = 32) out; //Sets stride of buffer 1 to 32. Also, sets buffer 1 to be current.

Linking errors will result if any captured outputs within a buffer overlap in space or violate padding. For example:

layout(xfb_buffer = 0) out Data
  layout(xfb_offset = 0) float val1;
  layout(xfb_offset = 4) vec4 val2;
  layout(xfb_offset = 16) float val3;  //Compiler error. val2 covers bytes on the range [4, 20).

Compiler/linker errors will result if you are using Geometry Shader output streams and two outputs from different streams are routed to the same buffer.

Note: When using ARB_enhanced_layout as an extension (on older hardware), if ARB_transform_feedback3 is not also available, you may only output to a single buffer. You can still use offsets to put space between vertex attribute data, but you cannot set xbf_buffer to any value other than 0.