michael@0: Name michael@0: michael@0: ANGLE_instanced_arrays michael@0: michael@0: Name Strings michael@0: michael@0: GL_ANGLE_instanced_arrays michael@0: michael@0: Contributors michael@0: michael@0: Contributors to ARB_instanced_arrays michael@0: Nicolas Capens, TransGaming Inc. michael@0: James Helferty, TransGaming Inc. michael@0: Kenneth Russell, Google Inc. michael@0: Vangelis Kokkevis, Google Inc. michael@0: michael@0: Contact michael@0: michael@0: Daniel Koch, TransGaming Inc. (daniel 'at' transgaming.com) michael@0: michael@0: Status michael@0: michael@0: Implemented in ANGLE r976. michael@0: michael@0: Version michael@0: michael@0: Last Modified Date: February 8, 2012 michael@0: Author Revision: 3 michael@0: michael@0: Number michael@0: michael@0: OpenGL ES Extension #109 michael@0: michael@0: Dependencies michael@0: michael@0: OpenGL ES 2.0 is required. michael@0: michael@0: This extension is written against the OpenGL ES 2.0 Specification. michael@0: michael@0: Overview michael@0: michael@0: A common use case in GL for some applications is to be able to michael@0: draw the same object, or groups of similar objects that share michael@0: vertex data, primitive count and type, multiple times. This michael@0: extension provides a means of accelerating such use cases while michael@0: restricting the number of API calls, and keeping the amount of michael@0: duplicate data to a minimum. michael@0: michael@0: This extension introduces an array "divisor" for generic michael@0: vertex array attributes, which when non-zero specifies that the michael@0: attribute is "instanced." An instanced attribute does not michael@0: advance per-vertex as usual, but rather after every michael@0: conceptual draw calls. michael@0: michael@0: (Attributes which aren't instanced are repeated in their entirety michael@0: for every conceptual draw call.) michael@0: michael@0: By specifying transform data in an instanced attribute or series michael@0: of instanced attributes, vertex shaders can, in concert with the michael@0: instancing draw calls, draw multiple instances of an object with michael@0: one draw call. michael@0: michael@0: IP Status michael@0: michael@0: No known IP claims. michael@0: michael@0: New Tokens michael@0: michael@0: Accepted by the parameters of GetVertexAttribfv and michael@0: GetVertexAttribiv: michael@0: michael@0: VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE michael@0: michael@0: New Procedures and Functions michael@0: michael@0: void DrawArraysInstancedANGLE(enum mode, int first, sizei count, michael@0: sizei primcount); michael@0: michael@0: void DrawElementsInstancedANGLE(enum mode, sizei count, enum type, michael@0: const void *indices, sizei primcount); michael@0: michael@0: void VertexAttribDivisorANGLE(uint index, uint divisor); michael@0: michael@0: Additions to Chapter 2 of the OpenGL ES 2.0 Specification michael@0: (OpenGL ES Operation) michael@0: michael@0: Modify section 2.8 (Vertex Arrays), p. 21 michael@0: michael@0: After description of EnableVertexAttribArray / DisableVertexAttribArray michael@0: add the following: michael@0: michael@0: "The command michael@0: michael@0: void VertexAttribDivisorANGLE(uint index, uint divisor); michael@0: michael@0: modifies the rate at which generic vertex attributes advance when michael@0: rendering multiple instances of primitives in a single draw call michael@0: (see DrawArraysInstancedANGLE and DrawElementsInstancedANGLE below). michael@0: If is zero, the attribute at slot advances once michael@0: per vertex. If is non-zero, the attribute advances once michael@0: per instances of the primitives being rendered. michael@0: An attribute is referred to as "instanced" if its value is michael@0: non-zero." michael@0: michael@0: Replace the text describing DrawArrays and DrawElements in the michael@0: "Transferring Array Elements" subsection of 2.8, from the second paragraph michael@0: through the end of the section with the following: michael@0: michael@0: "The command michael@0: michael@0: void DrawArraysOneInstance( enum mode, int first, sizei count, int instance ); michael@0: michael@0: does not exist in the GL, but is used to describe functionality in michael@0: the rest of this section. This function constructs a sequence of michael@0: geometric primitives by transferring elements through + michael@0: - 1 of each enabled non-instanced array to the GL. michael@0: specifies what kind of primitives are constructed, as defined in section michael@0: 2.6.1. michael@0: michael@0: If an enabled vertex attribute array is instanced (it has a non-zero michael@0: attribute as specified by VertexAttribDivisorANGLE), the element michael@0: that is transferred to the GL is given by: michael@0: michael@0: floor( / ). michael@0: michael@0: If an array corresponding to a generic attribute required by a vertex shader michael@0: is not enabled, then the corresponding element is taken from the current michael@0: generic attribute state (see section 2.7). michael@0: michael@0: If an array corresponding to a generic attribute required by a vertex shader michael@0: is enabled, the corresponding current generic attribute value is unaffected michael@0: by the execution of DrawArraysOneInstance. michael@0: michael@0: Specifying < 0 results in undefined behavior. Generating the error michael@0: INVALID_VALUE is recommended in this case. michael@0: michael@0: The command michael@0: michael@0: void DrawArrays( enum mode, int first, sizei count ); michael@0: michael@0: is equivalent to the command sequence michael@0: michael@0: DrawArraysOneInstance(mode, first, count, 0); michael@0: michael@0: The command michael@0: michael@0: void DrawArraysInstancedANGLE(enum mode, int first, sizei count, michael@0: sizei primcount); michael@0: michael@0: behaves identically to DrawArrays except that michael@0: instances of the range of elements are executed, and the michael@0: advances for each iteration. Instanced attributes that michael@0: have N, (where N > 0, as specified by michael@0: VertexAttribDivisorANGLE) advance once every N instances. michael@0: michael@0: It has the same effect as: michael@0: michael@0: if (mode, count, or primcount is invalid) michael@0: generate appropriate error michael@0: else { michael@0: for (i = 0; i < primcount; i++) { michael@0: DrawArraysOneInstance(mode, first, count, i); michael@0: } michael@0: } michael@0: michael@0: The command michael@0: michael@0: void DrawElementsOneInstance( enum mode, sizei count, enum type, michael@0: void *indices, int instance ); michael@0: michael@0: does not exist in the GL, but is used to describe functionality in michael@0: the rest of this section. This command constructs a sequence of michael@0: geometric primitives by successively transferring the elements michael@0: whose indices are stored in the currently bound element array buffer michael@0: (see section 2.9.2) at the offset defined by to the GL. michael@0: The -th element transferred by DrawElementsOneInstance will be taken michael@0: from element [i] of each enabled non-instanced array. michael@0: must be one of UNSIGNED_BYTE, UNSIGNED_SHORT, or UNSIGNED_INT, michael@0: indicating that the index values are of GL type ubyte, ushort, or uint michael@0: respectively. specifies what kind of primitives are constructed, michael@0: as defined in section 2.6.1. michael@0: michael@0: If an enabled vertex attribute array is instanced (it has a non-zero michael@0: attribute as specified by VertexAttribDivisorANGLE), the element michael@0: that is transferred to the GL is given by: michael@0: michael@0: floor( / ); michael@0: michael@0: If an array corresponding to a generic attribute required by a vertex michael@0: shader is not enabled, then the corresponding element is taken from the michael@0: current generic attribute state (see section 2.7). Otherwise, if an array michael@0: is enabled, the corresponding current generic attribute value is michael@0: unaffected by the execution of DrawElementsOneInstance. michael@0: michael@0: The command michael@0: michael@0: void DrawElements( enum mode, sizei count, enum type, michael@0: const void *indices); michael@0: michael@0: behaves identically to DrawElementsOneInstance with the michael@0: parameter set to zero; the effect of calling michael@0: michael@0: DrawElements(mode, count, type, indices); michael@0: michael@0: is equivalent to the command sequence: michael@0: michael@0: if (mode, count or type is invalid ) michael@0: generate appropriate error michael@0: else michael@0: DrawElementsOneInstance(mode, count, type, indices, 0); michael@0: michael@0: The command michael@0: michael@0: void DrawElementsInstancedANGLE(enum mode, sizei count, enum type, michael@0: const void *indices, sizei primcount); michael@0: michael@0: behaves identically to DrawElements except that michael@0: instances of the set of elements are executed and the instance michael@0: advances between each set. Instanced attributes are advanced as they do michael@0: during the execution of DrawArraysInstancedANGLE. It has the same effect as: michael@0: michael@0: if (mode, count, primcount, or type is invalid ) michael@0: generate appropriate error michael@0: else { michael@0: for (int i = 0; i < primcount; i++) { michael@0: DrawElementsOneInstance(mode, count, type, indices, i); michael@0: } michael@0: } michael@0: michael@0: If the number of supported generic vertex attributes (the value of michael@0: MAX_VERTEX_ATTRIBS) is , then the client state required to implement michael@0: vertex arrays consists of boolean values, memory pointers, michael@0: integer stride values, symbolic constants representing array types, michael@0: integers representing values per element, boolean values michael@0: indicating normalization, and integers representing vertex attribute michael@0: divisors. michael@0: michael@0: In the initial state, the boolean values are each false, the memory michael@0: pointers are each NULL, the strides are each zero, the array types are michael@0: each FLOAT, the integers representing values per element are each four, michael@0: and the divisors are each zero." michael@0: michael@0: Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization) michael@0: michael@0: None michael@0: michael@0: Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment michael@0: Operations and the Framebuffer) michael@0: michael@0: None michael@0: michael@0: Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions) michael@0: michael@0: None michael@0: michael@0: Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State michael@0: Requests) michael@0: michael@0: In section 6.1.8, add VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE to the list of michael@0: pnames accepted by GetVertexAttribfv and GetVertexAttribiv. michael@0: michael@0: Additions to the AGL/EGL/GLX/WGL Specifications michael@0: michael@0: None michael@0: michael@0: Dependencies on OES_element_index_uint michael@0: michael@0: If OES_element_index_uint is not supported, removed all references michael@0: to UNSIGNED_INT indices and the associated GL data type uint in michael@0: the description of DrawElementsOneInstance. michael@0: michael@0: Errors michael@0: michael@0: INVALID_VALUE is generated by VertexAttribDivisorANGLE if michael@0: is greater than or equal to MAX_VERTEX_ATTRIBS. michael@0: michael@0: INVALID_ENUM is generated by DrawElementsInstancedANGLE if is michael@0: not one of UNSIGNED_BYTE, UNSIGNED_SHORT or UNSIGNED_INT. michael@0: michael@0: INVALID_VALUE is generated by DrawArraysInstancedANGLE if , michael@0: , or is less than zero. michael@0: michael@0: INVALID_ENUM is generated by DrawArraysInstancedANGLE or michael@0: DrawElementsInstancedANGLE if is not one of the modes described in michael@0: section 2.6.1. michael@0: michael@0: INVALID_VALUE is generated by DrawElementsInstancedANGLE if or michael@0: is less than zero. michael@0: michael@0: INVALID_OPERATION is generated by DrawArraysInstancedANGLE or michael@0: DrawElementsInstancedANGLE if there is not at least one enabled michael@0: vertex attribute array that has a of zero and is bound to an michael@0: active generic attribute value in the program used for the draw command. michael@0: michael@0: New State michael@0: michael@0: Changes to table 6.7, p. 268 (Vertex Array Data) michael@0: michael@0: Initial michael@0: Get Value Type Get Command Value Description Sec. michael@0: --------- ----- ----------- ------- ----------- ---- michael@0: VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 8*xZ+ GetVertexAttrib 0 Instance Divisor 2.8 michael@0: michael@0: Issues michael@0: michael@0: 1) Should vertex attribute zero be instance-able? michael@0: michael@0: Resolved: Yes. michael@0: Discussion: In Direct3D 9 stream 0 must be specified as indexed data michael@0: and it cannot be instanced. In ANGLE we can work around this by michael@0: remapping any other stream that does have indexed data (ie a zero michael@0: attribute divisor) to stream 0 in D3D9. This works because the HLSL michael@0: vertex shader matches attributes against the stream by using the michael@0: shader semantic index. michael@0: michael@0: 2) Can all vertex attributes be instanced simultaneously? michael@0: michael@0: Resolved: No michael@0: Discussion: In rare cases it is possible for no attribute to have a michael@0: divisor of 0, meaning that all attributes are instanced and none of michael@0: them are regularly indexed. This in turn means each instance can only michael@0: have a single position element, and so it only actually renders michael@0: something when rendering point primitives. This is not a very michael@0: meaningful way of using instancing (which is likely why D3D restricts michael@0: stream 0 to be indexed regularly for position data in the first place). michael@0: We could implement it by drawing these points one at a time (essentially michael@0: emulating instancing), but it would not be very efficient and there michael@0: seems to be little-to-no value in doing so. michael@0: michael@0: If all of the enabled vertex attribute arrays that are bound to active michael@0: generic attributes in the program have a non-zero divisor, the draw michael@0: call should return INVALID_OPERATION. michael@0: michael@0: 3) Direct3D 9 only supports instancing for DrawIndexedPrimitive which michael@0: corresponds to DrawElementsInstanced. Should we support michael@0: DrawArraysInstanced? michael@0: michael@0: Resolved: Yes michael@0: Discussion: This can be supported easily enough by simply manufacturing michael@0: a linear index buffer of sufficient size and using that to do indexed michael@0: D3D9 drawing. michael@0: michael@0: 4) How much data is needed in a buffer for an instanced attribute? michael@0: michael@0: Resolved: Where stride is the value passed to VertexAttribPointer: michael@0: michael@0: if stride > 0 michael@0: size = stride * ceil(primcount / divisor); michael@0: else michael@0: size = elementsize * ceil(primcount / divisor); michael@0: michael@0: Revision History michael@0: michael@0: #3 February 8, 2012 dgkoch michael@0: - clarify Issue 3 and the error condition for no indexed attributes michael@0: #2 January 24, 2012 dgkoch michael@0: - fix typos, add clarifications, and more errors michael@0: #1 January 17, 2012 dgkoch michael@0: - initial GLES2 version from ARB_instanced_arrays