Name AMD_transform_feedback4 Name Strings GL_AMD_transform_feedback4 Contributors Graham Sellers, AMD Eric Zolnowski, AMD Contact Graham Sellers (graham.sellers 'at' amd.com) Status Shipping Version Last Modified Date: 31/04/2014 Author Revision: 5 Number OpenGL Extension #450 Dependencies OpenGL 4.0 or ARB_transform_feedback3 is required. This extension is written against the OpenGL Specification, Version 4.4 (Core Profile). This extension is written against the OpenGL Shading Language (GLSL) Specification, Version 4.40 Overview Transform feedback is a mechanism to record the output of the vertex, tessellation evaluation or geometry shader into one or more buffers for further processing, recursive rendering or read-back by the client. ARB_transform_feedback3 (and OpenGL 4.0) extended the transform feedback subsystem to allow multiple streams of primitive information to be captured. However, it imposed a limitation that the primitive type for all streams must be POINTS if more than one stream is to be captured. AMD_transform_feedback3_lines_triangles relaxed that restriction to allow lines or triangles to be captured, in the case where multiple streams are to be processed. However, it still required that all streams share the same primitive type. Additionally, with all current extensions to transform feedback, only a single primitive stream may be rasterized. This extension enhances transform feedback in two significant ways. First, it allows multiple transform feedback streams to be captured, each with its own, independent primitve type. Second, it allows any combination of streams to be rasterized. As an example, this enables the geometry shader to take a single stream of triangle geometry and emit filled triangles with a wireframe outline and a point at each vertex, all in a single pass through the input vertices. Combined with features such those provided by ARB_viewport_array, layered rendering, shader subroutines and so on, an application can render several views of its geoemtry, each with a radically different style, all in a single pass. IP Status None. New Procedures and Functions None. New Tokens Accepted by the parameter of Enablei, Disablei and IsEnabledi: STREAM_RASTERIZATION_AMD 0x91A0 Additions to Chapter 11 of the OpenGL 4.4 (Core Profile) Specification (Programmable Vertex Processing) Modify subsection 11.3.4.3, "Geometry Shader Vertex Streams": Replace the second to last paragraph of the subsection with: The primitives emitted to all vertex streams are passed to the transform feedback stage to be captured and written to buffer objects in the manner specified by the transform feedback state. The primitives emitted to vertex streams for which rasterization is enabled are then passed to subsequent pipeline stages for clipping, rasterization, and subsequent fragment processing. Replace the last paragraph of the subsection with: Geometry shaders that emit vertices to multiple vertex streams may generate a different primitive type on each stream. Any combination of streams may be rasterized (see Section 3.1). This allows a geometry shader to transform a single input vertex stream into multiple primitives of different types, all of which may be rasterized. Additions to Chapter 14 of the OpenGL 4.4 (Core Profile) Specification (Fixed-Function Primitive Assembly and Rasterization) Modify Section 14.1 "Discarding Primitives Before Rasterization", p. 409: Primitives sent to any vertex stream (see section 13.2) may be processed further. When geometry shaders are disabled, all vertices are considered to be emitted to stream zero. Primitives can be optionally discarded before rasterization but after the optional transform feedback stage (see section 13.2). All primitives may be discarded by calling Enable with RASTERIZER_DISCARD. When enabled, primitives emitted to any stream are discarded. When enabled, RASTERIZER_DISCARD also causes the Clear and ClearBuffer* commands to be ignored. When RASTERIZER_DISCARD is disabled, primitives emitted on streams for which rasterization is enabled are passed through to the rasterization stage to be processed normally. Rasterization for specific streams may be enabled by calling Enablei (or disabled by calling Disablei) with the constant STREAM_RASTERIZATION_AMD and the index of the selected stream. Initially, rasterization is enabled for stream zero and is disabled for all other streams. If primitives are emitted on more than one stream for which rasterization is enabled, the order of rasterization of primitives on different streams is undefined. However, it is guaranteed that all primitives emitted on a single stream are rasterized in the order in which they are generated, and that all primitives generated by a single invocation of a geometry shader are rasterized in stream order, starting with the lowest numbered stream. Additions to Chapter 15 of the OpenGL 4.4 (Core Profile) Specification (Programmable Fragment Processing) Modify Section 15.2, "Shader Execution" Insert the following paragraph to subsection 15.2.2, "Shader Inputs", after the paragraph describing gl_SamplePosition on p. 433: The built-in read-only variable gl_StreamID contains the index of the vertex stream from which the vertices forming the primitive currently being rasterized were taken. User defined input varying variables belonging to this stream have defined values, whilst all other user defined input variables are undefined. When no geometry shader is active, gl_StreamID is zero. When a geometry shader is active and writes to multiple output vertex streams for which rasterization is enabled, gl_StreamID may range from zero to the value of MAX_VERTEX_STREAMS - 1. Modifications to Chapter 4 of the OpenGL Shading Language Specification, Version 4.40 (Variables and Types) Append to the end of Section 4.4.1 "Input Layout Qualifiers" The identifier is used to specify that a fragment shader input variable or block is associated with a particular vertex stream (numbered beginning with zero). A default stream number may be declared at global scope by qualifying interface qualifier out as in this example: layout (stream = 1) in; The stream number specified in such a declaration replaces any previous default and applies to all subsequent block and variable declarations until a new default is established. The initial default stream number is zero. Each input block or non-block input variable is associated with a vertex stream. If the block or variable is declared with the identifier, it is associated with the specified stream; otherwise, it is associated with the current default stream. A block member may be declared with a stream identifier, but the specified stream must match the stream associated with the containing block. One example: layout (stream = 1) in; // default is now stream 1 out vec4 var1; // var1 belongs to default stream (1) layout (stream = 2) in Block1 { // "Block1" belongs to stream 2 layout (stream = 2) vec4 var2; // redundant block member stream decl layout (stream = 3) vec2 var3; // ILLEGAL (must match block stream) vec3 var4; // belongs to stream 2 }; layout (stream = 0) in; // default is now stream 0 in vec4 var5; // var5 belongs to default stream (0) in Block2 { // "Block2" belongs to default stream (0) vec4 var6; }; layout ( stream = 3) in vec4 var7; // var7 belongs to stream 3 Each fragment processed by the fragment shader receives its input variables from a specific stream corresponding to the stream upon which the source vertices were emitted in the geometry shader. Each invocation of the fragment shader processes a fragment belonging to a primitive generated from vertices emitted to a single stream. The index of the stream to which these vertices belong is available in the built-in variable gl_StreamID (see Section 7.1, "Built-in Language Variables"). Only those input variables belonging to the current stream have defined values. Reading from a variable belonging to any other stream may cause undefined behavior, including program termination. Modifications to Chapter 7 of the OpenGL Shading Language Specification, Version 4.40 (Built-in Variables) Add to the list of built-in variables in the fragment language, sec. 7.1, p.122. in int gl_StreamID; Insert the following paragraph after the description of gl_SamplePosition on p.122: The input variable gl_StreamID indicates the vertex stream from which vertices were taken to generate the primitive to which the current fragment belongs. This information may be used to deduce which of the fragment shader input variables contain defined values. Reading from input variables belonging to a vertex stream other than that indicated by gl_StreamID may produce undefined behavior, possibly including application termination. Modifications to Chapter 8 of the OpenGL Shading Language Specification, Version 4.40 (Built-in Functions) Remove the final paragraph of section 8.15 "Geometry Shader Functions" on p.180, which disallows shaders with multiple streams that are not all set to POINTS primitive type. Additions to the AGL/GLX/WGL Specifications None. GLX Protocol None. Errors INVALID_VALUE is generated by Enablei, Disablei and IsEnabledi if is STREAM_RASTERIZATION_AMD and is greater than or equal to MAX_VERTEX_STREAMS_AMD. New State Append to table 23.9, Rasterization +---------------------------------------------------+-----------+-------------------+---------------+-----------------------------------------------+-------+ | | | Get | Initial | | | | Get Value | Type | Command | Value | Description | Sec. | +---------------------------------------------------+-----------+-------------------+---------------+-----------------------------------------------+-------+ | STREAM_RASTERIZATION_AMD | nxB | GetBoolean | See 14.1 | Per stream rasterizer enable | 14.1 | +---------------------------------------------------+-----------+-------------------+---------------+-----------------------------------------------+-------+ Issues 1) Why is rasterization order undefined? DISCUSSION: Implementations typically break large draws into chunks and process each separately. Within each chunk, the rasterization order is guaranteed. Between chunks, ordering is also guaranteed - everything in early chunks is rasterized before later chunks. However, this means that primitives emitted to higher numbered streams in early chunks will be rasterized before primitives emitted to lower numbered streams in later chunks. Because the boundaries between chunks are not necessarily in fixed positions, it is not possible to specify where they will be and therefore guarantee rasterization order. 2) Is this still useful then? RESOLVED: Yes, sure. If rendering is order independent (depth test on, blending off for example), or can be guaranteed to not overlap (viewport arrays, layered rendering and so on), it makes no difference whether rasterization order between streams is guaranteed or not. 3) What's the need for multiple 'streams' in the fragment shader? DISCUSSION: In unextended OpenGL, the inputs to the fragment shader are derived from the vertices generated on stream 0 in the geometry shader (the vertex shader always writes to stream 0). When multiple streams can be rasterized, the fragment shader can be invoked as part of a primitive on any stream. As each stream can have wildly different outputs in the geometry shader, it is really not possible to have only a single set of inputs in the fragment shader. Therefore, we expose each stream independently. Only those variables written by the geometry shader on the stream from which the current primitive was generated will be defined, and the others will likely have garbage in them (aliases of the real variables). That stream is given by the new gl_StreamID built-in in the fragment shader. Other built-in variables (such as gl_FragCoord) are always available on any stream. Revision History Rev. Date Author Changes ---- ---------- -------- ----------------------------------------- 5 31/04/2014 gsellers Update for OpenGL 4.4, ready for posting. 4 12/03/2012 gsellers Update against OpenGL 4.3. 3 05/01/2011 gsellers Assign enumerants 2 10/14/2010 gsellers Add fragment shader streams. 1 10/11/2010 gsellers Initial revision