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 <divisor>
    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 <pname> 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 <instanceID> is a 32-bit integer value which
    may be read by a vertex shader as <gl_InstanceIDNV>, 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 <divisor> is zero, the attribute at slot <index> advances once
    per vertex.  If <divisor> is non-zero, the attribute advances once
    per <divisor> instances of the set(s) of vertices being rendered.
    An attribute is referred to as "instanced" if its <divisor> 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.
    <mode> specifies what kind of primitives are constructed, as defined
    in section 2.6.1. Elements <first> through <first> + <count> - 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 <divisor> as specified by VertexAttribDivisorNV), the
    element that is transferred to the GL is given by:

        floor( <instance> / <divisor> ).

    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 <first> < 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 <primcount>
    instances of the range of elements are executed, the value of
    <instanceID> advances for each iteration, and the instance advances
    between each set. Instanced attributes that have <divisor> 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 <count>
    elements whose indices are stored in <indices>. <type> must be one
    of UNSIGNED_BYTE, UNSIGNED_SHORT, or UNSIGNED_INT, indicating that
    the values in <indices> are indices of GL type ubyte, ushort, or
    uint respectively. <mode> 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 <divisor> as specified by VertexAttribDivisorNV), the
    element that is transferred to the GL is given by:

        floor( <instance> / <divisor> );

    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 <instance> 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 <primcount>
    instances of the set of elements are executed, the value of
    <instanceID> 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 <n>, then the client state required to
    implement vertex arrays consists of <n> boolean values, <n> memory
    pointers, <n> integer stride values, <n> symbolic constants
    representing array types, <n> integers representing values per
    element, <n> boolean values indicating normalization, and <n>
    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 <index>
    is greater than or equal to MAX_VERTEX_ATTRIBS.

    INVALID_ENUM is generated by DrawElementsInstancedNV if <type> is
    not one of UNSIGNED_BYTE, UNSIGNED_SHORT or UNSIGNED_INT.

    INVALID_VALUE is generated by DrawArraysInstancedNV if <first>,
    <count>, or <primcount> is less than zero.

    INVALID_ENUM is generated by DrawArraysInstancedNV or
    DrawElementsInstancedNV if <mode> is not one of the modes described in
    section 2.6.1.

    INVALID_VALUE is generated by DrawElementsInstancedNV if <count> or
    <primcount> 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
