Name NV_instanced_arrays Name Strings GL_NV_instanced_arrays Contributors Contributors to ARB_instanced_arrays and ANGLE_instanced_arrays Mathias Heyer, NVIDIA Greg Roth, NVIDIA Contact Greg Roth, NVIDIA (groth 'at' nvidia 'dot' com) Status Complete Version Last Modified Date: Aug 28, 2012 Author Revision: 4 Number OpenGL ES Extension #145 Dependencies OpenGL ES 2.0 is required. This extension is written against the OpenGL ES 2.0.25 Specification. NV_draw_instanced affects the definition of this extension. OES_element_index_uint affects the definition of this extension. OES_vertex_array_object affects the definition of this extension. Overview A common use case in GL for some applications is to be able to draw the same object, or groups of similar objects that share vertex data, primitive count and type, multiple times. This extension provides a means of accelerating such use cases while limiting the number of required API calls, and keeping the amount of duplicate data to a minimum. In particular, this extension specifies an alternative to the read-only shader variable introduced by NV_draw_instanced. It uses the same draw calls introduced by that extension, but redefines them so that a vertex shader can instead use vertex array attributes as a source of instance data. This extension introduces an array "divisor" for generic vertex array attributes, which when non-zero specifies that the attribute is "instanced." An instanced attribute does not advance per-vertex as usual, but rather after every conceptual draw calls. (Attributes which aren't instanced are repeated in their entirety for every conceptual draw call.) By specifying transform data in an instanced attribute or series of instanced attributes, vertex shaders can, in concert with the instancing draw calls, draw multiple instances of an object with one draw call. New Procedures and Functions void VertexAttribDivisorNV(uint index, uint divisor); New Tokens Accepted by the parameters of GetVertexAttribfv, and GetVertexAttribiv: VERTEX_ATTRIB_ARRAY_DIVISOR_NV 0x88FE Additions to Chapter 2 of the OpenGL ES 2.0.25 Specification (OpenGL ES Operation) Modify section 2.8 (Vertex Arrays) After description of EnableVertexAttribArray / DisableVertexAttribArray add the following: The internal counter is a 32-bit integer value which may be read by a vertex shader as , as described in section 2.10.5.2. The value of this counter is always zero, except as noted below. The command void VertexAttribDivisorNV(uint index, uint divisor); modifies the rate at which generic vertex attributes advance when rendering multiple instances of primitives in a single draw call. If is zero, the attribute at slot advances once per vertex. If is non-zero, the attribute advances once per instances of the set(s) of vertices being rendered. An attribute is referred to as "instanced" if its value is non-zero. Replace the text describing DrawArrays and DrawElements in the "Transferring Array Elements" subsection of 2.8, from the second paragraph through the end of the section with the following: The function void DrawArraysOneInstance( enum mode, int first, sizei count, int instance ); does not exist in the GL, but is used to describe functionality in the rest of this section. This function constructs a sequence of geometric primitives using the indicated elements of enabled arrays. specifies what kind of primitives are constructed, as defined in section 2.6.1. Elements through + - 1 of enabled non-instanced arrays are transferred to the GL. If an enabled vertex attribute array is instanced (it has a non-zero attribute as specified by VertexAttribDivisorNV), the element that is transferred to the GL is given by: floor( / ). If an array corresponding to a generic attribute required by a vertex shader is not enabled, then the corresponding element is taken from the current generic attribute state (see section 2.7). If an array corresponding to a attribute required by a vertex shader is enabled, the corresponding current generic attribute value is unaffected by the execution of DrawArraysOneInstance. Specifying < 0 results in undefined behavior. Generating the error INVALID_VALUE is recommended in this case. The command void DrawArrays( enum mode, int first, sizei count ); behaves identically to DrawArraysOneInstance with the instance set to zero; the effect of calling DrawArrays(mode, first, count); is equivalent to the command sequence: if (mode or count is invalid ) generate appropriate error else DrawArraysOneInstance(mode, first, count, 0); The command void DrawArraysInstancedNV(enum mode, int first, sizei count, sizei primcount); behaves identically to DrawArrays except that instances of the range of elements are executed, the value of advances for each iteration, and the instance advances between each set. Instanced attributes that have N, (where N > 0, as specified by VertexAttribDivisorNV advance once every N instances. It has the same effect as: if (mode, count, or primcount is invalid) generate appropriate error else { for (i = 0; i < primcount; i++) { instanceID = i; DrawArraysOneInstance(mode, first, count, i); } instanceID = 0; } The function void DrawElementsOneInstance( enum mode, sizei count, enum type, void *indices, int instance ); does not exist in the GL, but is used to describe functionality in the rest of this section. This function constructs a sequence of geometric primitives by successively transferring the elements whose indices are stored in . must be one of UNSIGNED_BYTE, UNSIGNED_SHORT, or UNSIGNED_INT, indicating that the values in are indices of GL type ubyte, ushort, or uint respectively. specifies what kind of primitives are constructed, as defined in section 2.6.1. If an enabled vertex attribute array is instanced (it has a non-zero attribute as specified by VertexAttribDivisorNV), the element that is transferred to the GL is given by: floor( / ); If an array corresponding to a generic attribute required by a vertex shader is not enabled, then the corresponding element is taken from the current generic attribute state (see section 2.7). Otherwise, if an array is enabled, the corresponding current generic attribute value is unaffected by the execution of DrawElementsOneInstance. The command void DrawElements( enum mode, sizei count, enum type, void *indices ); behaves identically to DrawElementsOneInstance with set to zero; the effect of calling DrawElements(mode, count, type, indices); is equivalent to the command sequence: if (mode, count or type is invalid ) generate appropriate error else DrawElementsOneInstance(mode, count, type, indices, 0); The command void DrawElementsInstancedNV(enum mode, sizei count, enum type, const void *indices, sizei primcount); behaves identically to DrawElements except that instances of the set of elements are executed, the value of advances for each iteration, and the instance advances between each set. Instanced attributes are advanced as they do during the execution of DrawArraysInstancedNV. It has the same effect as: if (mode, count, primcount, or type is invalid ) generate appropriate error else { for (int i = 0; i < primcount; i++) { instanceID = i; DrawElementsOneInstance(mode, count, type, indices, i); } instanceID = 0; } If the number of supported generic vertex attributes (the value of MAX_VERTEX_ATTRIBS) is , then the client state required to implement vertex arrays consists of boolean values, memory pointers, integer stride values, symbolic constants representing array types, integers representing values per element, boolean values indicating normalization, and integers representing vertex attribute divisors. In the initial state, the boolean values are each false, the memory pointers are each NULL, the strides are each zero, the array types are each FLOAT, the integers representing values per element are each four, and the divisors are each zero. Modify section 2.10, "Vertex Array Objects" (Added by OES_vertex_array_object) Add VERTEX_ATTRIB_ARRAY_DIVISOR_NV to the list of state included in the vertex array object type vector. Additions to Chapter 6 of the OpenGL ES 2.0.25 Specification (State and State Requests) In section 6.1.8, add VERTEX_ATTRIB_ARRAY_DIVISOR_NV to the list of pnames accepted by GetVertexAttribfv and GetVertexAttribiv: Dependencies on OES_element_index_uint If OES_element_index_uint is not supported, removed all references to UNSIGNED_INT indices and the associated GL data type uint in the description of DrawElementsOneInstance. Dependencies on NV_draw_instanced If NV_draw_instanced is not supported, all references to instanceID should be removed from section 2.8. This extension will introduce the following additional New Procedures and Functions: void DrawArraysInstancedNV(enum mode, int first, sizei count, sizei primcount); void DrawElementsInstancedNV(enum mode, sizei count, enum type, const void *indices, sizei primcount); Dependencies on OES_vertex_array_object If OES_vertex_array_object is not supported, ignore all edits to section 2.10, "Vertex Array Objects". Errors INVALID_VALUE is generated by VertexAttribDivisorNV if is greater than or equal to MAX_VERTEX_ATTRIBS. INVALID_ENUM is generated by DrawElementsInstancedNV if is not one of UNSIGNED_BYTE, UNSIGNED_SHORT or UNSIGNED_INT. INVALID_VALUE is generated by DrawArraysInstancedNV if , , or is less than zero. INVALID_ENUM is generated by DrawArraysInstancedNV or DrawElementsInstancedNV if is not one of the modes described in section 2.6.1. INVALID_VALUE is generated by DrawElementsInstancedNV if or is less than zero. New State Changes to table 6.2 (Vertex Array Data) Initial Get Value Type Get Command Value Description Sec. Attribute --------- ---- --------------- ------- ----------- ---- --------- VERTEX_ATTRIB_ARRAY_DIVISOR_NV 8xZ+ GetVertexAttrib 0 Instance Divisor 2.8 vertex-array Issues 1) Should generic attrib zero be instance-able? Resolved: Yes. Attribute zero does not necessarily contain position information. 2) This extension must elaborate on the definition of functions added by NV_draw_instanced. How do we do this in a manner such that both extensions may coexist? Resolved: This extension is specified so that it applies on top of NV_draw_instanced. As a result, some portions modified by that extension are replaced in this extension. In the event that NV_draw_instanced is not supported, this extension reintroduces the draw calls from NV_draw_instanced. 3) Should current generic attributes be affected by the execution of DrawArraysOneInstance? Resolved: No. ANGLE says no. ARB says maybe. Defined behavior is always better. The wishy washy ARB language is likely to permit a software implementation without excessive state resetting. This Is not terribly useful if implemented in software. 4) Can all vertex attributes be instanced simultaneously? Resolved: No. In rare cases it is possible for no attribute to have a divisor of 0, meaning that all attributes are instanced and none of them are regularly indexed. This in turn means each instance can only have a single position element, and so it only actually renders something when rendering point primitives. This is not a very meaningful way of using instancing (which is likely why D3D restricts stream 0 to be indexed regularly for position data in the first place). Revision History Rev. Date Author Changes ---- ------------- --------- ---------------------------------------- 4 28 Aug 2012 groth Various spelling corrections and minor clarifications 3 20 Aug 2012 groth Add interaction with VAOs 2 19 Aug 2012 groth Correct section number 1 12 Aug 2012 groth Initial GLES2 version from ARB_instanced_arrays with inspiration from ANGLE_instanced_arrays