Name AMD_interleaved_elements Name Strings GL_AMD_interleaved_elements Contact Graham Sellers (graham.sellers 'at' amd.com) Contributors Sergey Leontyev, AMD Status Shipping Version Last Modified Date: 2 May 2013 Revision: 3 Number 431 Dependencies This extension is written against version 4.3 of the Core Profile OpenGL Specification, dated August 6, 2012. Overview The glDrawElements function and its variants (instanced and indirect, for example) allow OpenGL to draw indexed arrays of vertices. Since its inception, OpenGL has supported unsigned bytes, unsigned shorts and unsigned integers as index types. However, all enabled vertex arrays may be represented by at most one shared index. A common scenario in graphics rendering is that several faces share a vertex where, for each face some properties of a vertex (position and texture coordinates, for example) should be common but others must be unique (colors, normals, and so on). Consider a mesh of a cube with per-face normals, for example. There are 8 vertices and 6 normals, and 12 triangles (where each face of the cube is represented as two triangles). To render this cube, we must compute the 24 unique permutations of position and normal and build a new element list to index into it. In fact, any advantage of indexed draw is lost here as the number of required permutations is equal to the final vertex count required to draw the object. This extension allows OpenGL to process multi-component packed element data. The maximum size of a vertex's index data is not increased, but the facility to store 2 16-bit or 2 or 4 8-bit indices per vertex is introduced. Each vertex attribute is given a swizzle property to allow its index to be sourced from one of up to 4 channels of index data. This effectively allows an application to supply multiple interleaved streams of index data to OpenGL. Each vertex attribute is given a 'channel selector' to select one of the up to 4 channels of vertex index information presented to OpenGL. This enables the use-case described above and many more. The swizzle parameter is also applied to vertex indices passed to shaders, and updates to the definition of base vertex parameters and primitive restart are applied. New Procedures and Functions void VertexAttribParameteriAMD(uint index, enum pname, int param); New Tokens Accepted by the parameter of VertexAttribParameteriAMD and GetVertexAttrib{iv|dv|fv|Iiv|Iuiv|Ldv}: VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4 Selected by the parameter of ProgramParameteri and GetProgramiv: VERTEX_ID_SWIZZLE_AMD 0x91A5 Accepted by the parameter of VertexAttribParameteriAMD: RED 0x1903 GREEN 0x1904 BLUE 0x1905 ALPHA 0x1906 Accepted by the parameter of DrawElements, DrawElementsInstanced, DrawElementsInstancedBaseInstance and DrawElementsIndirect: RG8UI 0x8238 RG16UI 0x823A RGBA8UI 0x8D7C IP Status None. Additions to Chapter 7 of the OpenGL Core Profile Specification, Version 4.3, "Programs and Shaders" Add to the parameters accepted by ProgramParameteri, p.82: If is VERTEX_ID_SWIZZLE_AMD, should be set to RED, GREEN, BLUE or ALPHA to indicate that the first, second, third or fourth component of the vertex element vector be propagated to the gl_VertexID vertex shader input as described in subsection 11.1.3.9. The initial value of VERTEX_ID_SWIZZLE_AMD is RED. Additions to Chapter 10 of the OpenGL Core Profile Specification, Version 4.3, "Vertex Specification and Drawing Commands" Insert Subsection 10.3.2, "Vertex Attribute Parameters", renumber subsequent sections: Each vertex attribute possesses a set of parameters that control its behavior. Parameters for a vertex attribute may be set by calling: void VertexAttribParameteriAMD(uint index, enum pname, int param); where identifies the generic vertex attribute array whose parameter to modify. If is VERTEX_ELEMENT_SWIZZLE_AMD, then specifies the component of the vertex element that is to be used to source the vertex indices for the selected vertex attribute. Its value may be RED, GREEN, BLUE or ALPHA to select the first, second, third or fourth component of the vertex element. In section 10.3.2, "Primitive Restart", modify the language describing how the restart index is compared to the vertex element index, p.302 as follows: When one of the Draw* commands transfers a set of generic attribute array elements to the GL, if all present index channels in the passed element index are equal to the primitive restart index, then the GL does not process those elements as a vertex. Instead ... *include remainder of section verbatim.* In the description of DrawElementsOneInstance (p. 311), replace the sentence beginning "The ith element transferred by..." with: For each enabled vertex attribute, the ith element transferred by DrawElementsOneInstance will be taken from that attribute's selected channel of the element whose values are stored currently bound element array buffer at offset indices + i. Replace the paragraph explaining the parameter to DrawElementsOneIntance (p. 311): may be UNSIGNED_BYTE, UNSIGNED_SHORT or UNSIGNED_INT, indicating that the index values are of GL type ubyte, ushort or uint, respectively, RG8UI or RG16UI, indicating that the index values are pairs of GL type ubyte or ushort, respectively, or RGBA8UI, indicating that index values are quadruplets of GL type ubyte. ... Modify the language describing the DrawElements*BaseVertex* functions on p.314 as follows: ... are equivalent to the commands with the same base name (without the BaseVertex suffix), except that the ith element transferred by the corresponding draw call will be taken from the selected channel of the element vector indices[i] + . That is, the value of is added to the vertex index after channel selection. ... *include remainder of description verbatim.* Add to the list of accepted values for the parameter to GetVertexAttrib* in Section 10.6, "Vertex Array and Vertex Array Object Queries", p. 317: ... VERTEX_ELEMENT_SWIZZLE_AMD. Additions to Chapter 11 of the OpenGL Core Profile Specification, Version 4.3, "Programmable Vertex Processing" In Subsection 11.1.3.9, "Shader Inputs", p.338, modify the description of gl_VertexID as follows: gl_VertexID holds the integer index i stored in the selected component of the element implicitly passed by DrawArrays or one of the other drawing commands defined in section 10.5. The component of the element data stored in gl_VertexID may be specified by calling ProgramParameteri with set to VERTEX_ID_SWIZZLE_AMD as specified in section 7.3. New State Append to Table 23.4, "Vertex Array Object State (cont.)": +------------------------------+----------+---------------------+----------------+---------------------------------------------+----------+ | Get Value | Type | Get Command | Initial Value | Description | Sec | +------------------------------+----------+---------------------+----------------+---------------------------------------------+----------+ | VERTEX_ELEMENT_SWIZZLE_AMD | 16 * x E | GetVertexAttribiv | RED | Channel selector for vertex attribute index | 10.3.2 | +------------------------------+----------+---------------------+----------------+---------------------------------------------+----------+ Append to Table 23.39, "Program Object State (cont.)": +------------------------+-------+---------------+----------------+------------------------------------+----------+ | Get Value | Type | Get Command | Initial Value | Description | Sec | +------------------------+-------+---------------+----------------+------------------------------------+----------+ | VERTEX_ID_SWIZZLE_AMD | E | GetProgramiv | RED | Channel selector for gl_VertexID | 11.1.3.9 | +------------------------+-------+---------------+----------------+------------------------------------+----------+ New Implementation Dependent State None. Errors INVALID_ENUM is generated by VertexAttribParameteri if is not an accepted token. INVALID_VALUE is generated by VertexAttribParameteri if is not an acceptable value for the specified value of . Examples // Basic per-face normals // Normal data static const float normals[] = { 0.0f, 0.0f, 1.0f, // Positive Z 0.0f, 0.0f, -1.0f, // Negative Z 0.0f, 1.0f, 0.0f, // Positive Y 0.0f, -1.0f, 0.0f, // Negative Y 1.0f, 0.0f, 0.0f, // Positive X -1.0f, 0.0f, 0.0f, // Negative X }; // Position data static const float positions[] = { -1.0f, -1.0f, -1.0f, // 1.0f, 1.0f, 1.0f }; // Put the above data into a buffer and bind them as separate vertex // attributes. GLuint vertex_buffer; glGenBuffers(1, &vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals), NULL, GL_STATIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), positions); glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(normals), normals); // ... etc. Set up vertex attributes. // Index data static const unsigned short indices[] = { 0, 0, // vertex 0: position index, normal index 1, 0, // vertex 1: position index, normal index 2, 0, // vertex 2: position index, normal index 1, 0, // vertex 3: position index, normal index 2, 0, // ... six vertices, forming 3, 0, // ... two complete triangles, all using normals[0] 0, 1, 2, 1, 3, 1, 3, 1, 4, 1, // ... six more vertices, forming 2, 1, // ... two more triangles, all using normals[1] // etc... }; GLuint index_buffer; glGenBuffers(1, &index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // Okay... here's the new code. Set up vertex attribute 0 (position) to // consume the RED channel of the vertex index and attribute 1 (normal) // to consume the GREEN (second) channel of the vertex index. Then // draw with GL_RG16UI (two channel, 16-bit unsigned int) as the index // type. glVertexAttribParameteriAMD(0, GL_VERTEX_ELEMENT_SWIZZLE_AMD, GL_RED); glVertexAttribParameteriAMD(1, GL_VERTEX_ELEMENT_SWIZZLE_AMD, GL_GREEN); glDrawElements(GL_TRIANGLES, sizeof(indices) / (2 * sizeof(unsigned short)), GL_RG16UI, NULL); Issues 1) What is the effect of multi-channel vertex indices on gl_VertexID? RESOLVED: The VERTEX_ID_SWIZZLE_AMD program parameter selects the channel of vector element types to be passed to gl_VertexID. By default, this is RED, which is backwards compatible with single-channel types. 2) How does this interact with primitive-restart indices? RESOLVED: If all present channels of the vertex index vector match the restart index, then the element index is considered to match. 3) How does baseVertex affect this? RESOLVED: The same base vertex value is added to each each vertex element component after channel selection for each of the enabled vertex attributes. This choice is primarily motivated by the behavior of base vertex elements encoded in indirect draw commands. 4) Does this feature disable potential optimizations such as vertex reuse? RESOVLED: No, vertex reuse should continue to function correctly. Each unique vector of indices should produce a unique set of vertex shader outputs (modulo side effects) and will hit a naive vertex reuse cache. Nothing precludes more advanced optimization strategies from being implemented, however. 5) Is it possible to get at all two or four channels of the vertex index using a built-in input to the vertex shader? RESOLVED: No. A single channel selection is provided. Providing more data could be implemented by introducing a new built-in integer vector input to the shader, but we have chosen not to do at this time. 6) What is the value of missing channels? For example, if we render with GL_RG16UI indices but set certain attributes to GL_BLUE or GL_ALPHA swizzle, what index value is used for those channels? RESOLVED: Zero. 7) Are the traditional GL_RED, GL_GREEN, GL_BLUE, and GL_ALPHA terms appropriate for this use? RESOLVED: Not really, but are they appropriate for normals? g-buffers? Any other arbitrary data that might be in a buffer or texture? It's not worth introducing new enumerants just for this - we'll use R, G, B, A. Revision History Rev. Date Author Changes ---- -------- -------- ----------------------------------------- 3 05/02/2013 gsellers Shipping. Finalize spec ready for posting. 2 01/25/2013 gsellers Resolve issues 1, 2, 3. Polish spec. 1 01/17/2013 gsellers Initial draft