Name

    ARB_vertex_attrib_binding

Name Strings

    GL_ARB_vertex_attrib_binding

Contact

    Jeff Bolz, NVIDIA Corporation (jbolz 'at' nvidia.com)

Contributors

    Pat Brown, NVIDIA
    Bruce Merry
    Mark Kilgard

Notice

    Copyright (c) 2012-2013 The Khronos Group Inc. Copyright terms at
        http://www.khronos.org/registry/speccopyright.html

Status

    Complete.
    Approved by the ARB on 2012/06/12.

Version

    Last Modified Date: October 22, 2013
    Revision: 5

    EXT_direct_state_access interacton added with revision 3.

Number

    ARB Extension #125

Dependencies

    This extension is written against the OpenGL 4.2 Core specification.

    NV_vertex_buffer_unified_memory affects the definition of this 
    extension.

    EXT_direct_state_access affects the definition of this extension.

    The Compatibility specification affects the definition of this extension.

Overview

    OpenGL currently supports (at least) 16 vertex attributes and 16 vertex 
    buffer bindings, with a fixed mapping between vertex attributes and 
    vertex buffer bindings. This extension allows the application to change
    the mapping between attributes and bindings, which can make it more 
    efficient to update vertex buffer bindings for interleaved vertex formats
    where many attributes share the same buffer.

    This extension also separates the vertex binding update from the vertex
    attribute format update, which saves applications the effort of 
    redundantly specifying the same format state over and over.

    Conceptually, this extension splits the state for generic vertex attribute
    arrays into:

    - An array of vertex buffer binding points, each of which specifies:

      - a bound buffer object,

      - a starting offset for the vertex attribute data in that buffer object,

      - a stride used by all attributes using that binding point, and

      - a frequency divisor used by all attributes using that binding point.

    - An array of generic vertex attribute format information records, each of
      which specifies:

      - a reference to one of the new buffer binding points above,

      - a component count and format, and a normalization flag for the
        attribute data, and

      - the offset of the attribute data relative to the base offset of each
        vertex found at the associated binding point.


New Procedures and Functions

    void BindVertexBuffer(uint bindingindex, uint buffer, intptr offset, 
                          sizei stride);
    
    void VertexAttribFormat(uint attribindex, int size, enum type, 
                            boolean normalized, uint relativeoffset);
    void VertexAttribIFormat(uint attribindex, int size, enum type, 
                             uint relativeoffset);
    void VertexAttribLFormat(uint attribindex, int size, enum type, 
                             uint relativeoffset);

    void VertexAttribBinding(uint attribindex, uint bindingindex);

    void VertexBindingDivisor(uint bindingindex, uint divisor);

    When EXT_direct_state_access is present:

        void VertexArrayBindVertexBufferEXT(uint vaobj, uint bindingindex, uint buffer, intptr offset, 
                                            sizei stride);
    
        void VertexArrayVertexAttribFormatEXT(uint vaobj, uint attribindex, int size, enum type, 
                                boolean normalized, uint relativeoffset);
        void VertexArrayVertexAttribIFormatEXT(uint vaobj, uint attribindex, int size, enum type, 
                                 uint relativeoffset);
        void VertexArrayVertexAttribLFormatEXT(uint vaobj, uint attribindex, int size, enum type, 
                                 uint relativeoffset);

        void VertexArrayVertexAttribBindingEXT(uint vaobj, uint attribindex, uint bindingindex);

        void VertexArrayVertexBindingDivisorEXT(uint vaobj, uint bindingindex, uint divisor);

New Tokens

    Accepted by the <pname> parameter of GetVertexAttrib*v:

        VERTEX_ATTRIB_BINDING                           0x82D4  
        VERTEX_ATTRIB_RELATIVE_OFFSET                   0x82D5  

    Accepted by the <target> parameter of GetBooleani_v, GetIntegeri_v,
    GetFloati_v, GetDoublei_v, and GetInteger64i_v:

        VERTEX_BINDING_DIVISOR                          0x82D6  
        VERTEX_BINDING_OFFSET                           0x82D7  
        VERTEX_BINDING_STRIDE                           0x82D8  
        VERTEX_BINDING_BUFFER                           0x8F4F

    Accepted by the <pname> parameter of GetIntegerv, ...

        MAX_VERTEX_ATTRIB_RELATIVE_OFFSET               0x82D9  
        MAX_VERTEX_ATTRIB_BINDINGS                      0x82DA  


Additions to Chapter 2 of the OpenGL 2.0 Specification (OpenGL Operation)

    Modify Section 2.8, "Vertex Arrays"

    Vertex data are placed into arrays that are stored in the server's address 
    space (described in section 2.9). Blocks of data in these arrays may then 
    be used to specify multiple geometric primitives through the execution of 
    a single GL command. The client may specify up to the value of 
    MAX_VERTEX_ATTRIBS arrays to store one or more generic vertex attributes. 
    A generic vertex attribute array is described by an index into an array of 
    vertex buffer bindings which contain the vertex data and state describing 
    how that data is organized.
    
    The commands

      [Compatibility profile only: Keep the named attribute *Pointer
                                   commands in this list]

      void VertexAttribFormat(uint attribindex, int size, enum type, 
                              boolean normalized, uint relativeoffset);
      void VertexAttribIFormat(uint attribindex, int size, enum type, 
                               uint relativeoffset);

    describe the organizations of vertex arrays. For each command, <type> 
    specifies the data type of the values stored in the array. <size> 
    indicates the number of values per vertex that are stored in the array as 
    well as their component ordering. Table 2.5 indicates the allowable values
    for <size> and <type> (when present). For <type> the values BYTE, SHORT, 
    INT, FIXED, FLOAT, HALF_FLOAT, and DOUBLE indicate types byte, short, int, 
    fixed, float, half, and double, respectively; the values UNSIGNED_BYTE, 
    UNSIGNED_SHORT, and UNSIGNED_INT indicate types ubyte, ushort, and uint, 
    respectively; and the values INT_2_10_10_10_REV and UNSIGNED_INT_2_-
    10_10_10_REV, indicating respectively four signed or unsigned elements 
    packed into a single uint, both correspond to the term <packed> in that 
    table. <relativeoffset> is a byte offset of the first element relative 
    to the start of the vertex buffer binding this attribute fetches from.

    An INVALID_VALUE error is generated if <size> is not one of the values 
    allowed in table 2.5 for the corresponding command.

    An INVALID_OPERATION error is generated under any of the following 
    conditions:
     - if no vertex array object is currently bound (see section 2.10);
     - <size> is BGRA and <type> is not UNSIGNED_BYTE, INT_2_10_10_10_REV or
       UNSIGNED_INT_2_10_10_10_REV;
     - <type> is INT_2_10_10_10_REV or UNSIGNED_INT_2_10_10_10_REV, and <size>
       is neither 4 or BGRA;
     - <size> is BGRA and <normalized> is FALSE;

    An INVALID_VALUE error is generated if <relativeoffset> is larger than
    the value of MAX_VERTEX_ATTRIB_RELATIVE_OFFSET.

    The <attribIndex> parameter in the VertexAttribFormat and VertexAttribIFormat
    commands identifies the generic vertex attribute array being described. 
    The error INVALID_VALUE is generated if index is greater than or equal to 
    the value of MAX_VERTEX_ATTRIBS. Generic attribute arrays with integer 
    type arguments can be handled in one of three ways: converted to float by 
    normalizing to [0, 1] or [-1, 1] as described in equations 2.1 and 2.2, 
    respectively; converted directly to float, or left as integers. Data for 
    an array specified by VertexAttribPointer will be converted to floating-
    point by normalizing if <normalized> is TRUE, and converted directly to 
    floating-point otherwise. Data for an array specified by 
    VertexAttribIFormat will always be left as integer values; such data are 
    referred to as pure integers.

    The command

      void BindVertexBuffer(uint bindingindex, uint buffer, intptr offset,
                            sizei stride);

    binds a buffer indicated by <buffer> to the vertex buffer bind point 
    indicated by <bindingindex>, and sets the <stride> between elements 
    and <offset> (in basic machine units) of the first element in the buffer.
    The error INVALID_VALUE is generated if <stride> or <offset> are negative.
    Otherwise pointers to the ith and (i + 1)st elements of an array differ 
    by stride basic machine units (typically unsigned bytes), the pointer to 
    the (i + 1)st element being greater. An INVALID_OPERATION error is 
    generated if no vertex array object is bound. If <buffer> is zero, any
    buffer object attached to this bindpoint is detached. An INVALID_VALUE 
    error is generated if <bindingindex> is greater than the value of 
    MAX_VERTEX_ATTRIB_BINDINGS.
      [Core profile only:]
    An INVALID_OPERATION error is generated if buffer is not zero or a
    name returned from a previous call to GenBuffers, or if such a name
    has since been deleted with DeleteBuffers.
    
    The association between a vertex attribute and the vertex buffer binding
    used by that attribute is set by the command

      void VertexAttribBinding(uint attribindex, uint bindingindex);

    <attribindex> must be less than the value of MAX_VERTEX_ATTRIBS and 
    <bindingindex> must be less than the value of MAX_VERTEX_ATTRIB_BINDINGS, 
    otherwise the error INVALID_VALUE is generated. An INVALID_OPERATION error
    is generated if no vertex array object is bound.

    Modify Table 2.5 to add the command VertexAttribFormat to the first row 
    and VertexAttribIFormat to the second row.

    The one, two, three, or four values in an array that correspond to a 
    single vertex comprise an array element. When size is BGRA, it indicates 
    four values. The values within each array element are stored sequentially 
    in memory. However, if size is BGRA, the first, second, third, and fourth 
    values of each array element are taken from the third, second, first, and 
    fourth values in memory respectively.
        [Compatibility profile only:]
    For each *Pointer command, <pointer> specifies the location in
    memory of the first value of the first element of the array being
    specified.

    The command

      void VertexAttribLFormat(uint attribindex, int size, enum type, 
                               uint relativeoffset);

    specifies state for a generic vertex attribute array associated with a 
    shader attribute variable declared with 64-bit double precision components.
    <type> must be DOUBLE. <attribindex> and <size> behave as defined in all 
    other VertexAttrib*Format commands; <size> may be one, two, three or four.

    Each component of an array specified by VertexAttribLFormat will be 
    encoded into one or more generic attribute components as specified for the
    VertexAttribL* commands in section 2.7. The error INVALID_VALUE is 
    generated if <attribindex> is greater than or equal to the value of 
    MAX_VERTEX_ATTRIBS. 
    
    The commands 
        
      void VertexAttribPointer(uint index, int size, enum type,
                               boolean normalized, sizei stride, 
                               const void *pointer);
      void VertexAttribIPointer(uint index, int size, enum type,
                                sizei stride, const void *pointer);
      void VertexAttribLPointer(uint index, int size, enum type,
                                sizei stride, const void *pointer);
    
    control vertex attribute state, a vertex buffer binding, and the mapping
    between a vertex attribute and a vertex buffer binding. They are 
    equivalent to (assuming no errors are generated):

      if (no buffer is bound to ARRAY_BUFFER and pointer != NULL) {
        generate INVALID_OPERATION;
      }
      VertexAttrib*Format(index, size, type, {normalized, }, 0);
      VertexAttribBinding(index, index);
      if (stride != 0) {
        effectiveStride = stride;
      } else {
        compute effectiveStride based on size/type;
      }
      VERTEX_ATTRIB_ARRAY_STRIDE[index] = stride;
      // VERTEX_BINDING_STRIDE will be set to effectiveStride
      // by BindVertexBuffer.
      BindVertexBuffer(index, <buffer bound to ARRAY_BUFFER>, 
                       (char *)pointer - (char *)NULL, effectiveStride);

    If <stride> is specified as zero, then array elements are stored 
    sequentially. 
    
    An individual generic vertex attribute array is 
    enabled or disabled by calling one of

      void EnableVertexAttribArray(uint index);
      void DisableVertexAttribArray(uint index);

    where <index> identifies the generic vertex attribute array to enable or 
    disable. An INVALID_VALUE error is generated if <index> is greater than or 
    equal to MAX_VERTEX_ATTRIBS.

    An INVALID_OPERATION error is generated if no vertex array object is 
    bound.

    The command

      void VertexBindingDivisor(uint bindingindex, 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 attributes using the buffer bound to <bindingindex>
    advance once per vertex. If <divisor> is non-zero, the attributes advance 
    once per <divisor> instances of the set(s) of vertices being rendered. An 
    attribute is referred to as <instanced> if the corresponding <divisor> 
    value is non-zero.

    An INVALID_VALUE error is generated if <bindingindex> is greater than or 
    equal to the value of MAX_VERTEX_ATTRIB_BINDINGS.

    An INVALID_OPERATION error is generated if no vertex array object is 
    bound.

    The command

      void VertexAttribDivisor(uint index, uint divisor);

    is equivalent to (assuming no errors are generated):

      VertexAttribBinding(index, index);
      VertexBindingDivisor(index, divisor);

    An INVALID_VALUE error is generated if <attribindex> is greater than or 
    equal to the value of MAX_VERTEX_ATTRIBS.


    Modify Section 2.8.3, "Drawing Commands"

    For any vertex attribute whose divisor is non-zero as set by 
    VertexBindingDivisor, the value "baseinstance" is used to determine the 
    element of the enabled instanced attribute arrays that will be transferred
    for all vertices transferred by this function.

    ...

    Those attributes that have divisor N where N is other than zero (as 
    specified by VertexBindingDivisor) advance once every N instances.

    ...

    If an enabled vertex attribute array is instanced (it has a non-zero 
    binding divisor as specified by VertexAttribBinding and 
    VertexBindingDivisor), the element that is transferred to the GL is given 
    by:

      floor(instance/divisor) + baseinstance

    ...

    If the number of supported generic vertex attributes (the value of MAX_-
    VERTEX_ATTRIBS) is <n> and the number of vertex attribute bindings (the 
    value of MAX_VERTEX_ATTRIB_BINDINGS) is <k>, then the state required to 
    implement vertex arrays consists of <n> boolean values (enables), <n> 
    memory pointers, <n> integer stride values (VERTEX_ATTRIB_ARRAY_STRIDE),
    <n> symbolic constants representing array types, <n> integers representing
    values per element, <n> boolean values indicating normalization, <n> 
    boolean values indicating whether the attribute values are pure integers, 
    <k> integers representing vertex attribute divisors, <n> integer vertex 
    attribute binding indices, <n> integer relative offsets, <k> integer stride
    values (VERTEX_BINDING_STRIDE), <k> 64-bit integer buffer offsets, and an 
    unsigned integer representing the restart index.

    In the initial state, the boolean values are each false, the memory 
    pointers are each NULL, the VERTEX_ATTRIB_ARRAY_STRIDE strides are each 
    zero, the array types are each FLOAT, the integers representing values per
    element are each four, the normalized and pure integer flags are each 
    false, the divisors are each zero, the vertex attribute binding indices 
    are <i> for attribute <i>, the relative offsets are each zero, the 
    VERTEX_BINDING_STRIDE values are each 16, the buffer offsets are each zero,
    and the restart index is zero.


    Modify Section 2.9.6, "Vertex Arrays in Buffer Objects"

    When an array is sourced from a buffer object, the vertex attribute's 
    VERTEX_ATTRIB_BINDING indicates which vertex buffer binding is used. The 
    sum of the attribute's VERTEX_ATTRIB_RELATIVE_OFFSET and the vertex 
    buffer binding's VERTEX_BINDING_OFFSET is used as the offset (in basic 
    machine units) of the first element in that buffer's data store.

    (Compatibility Only) Add to the final paragraph:

    Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
    That is, the logic for computing the address of the base of a vertex array
    is:

        bindingIndex = VERTEX_ATTRIB_BINDING[attribIndex];
        buffer = VERTEX_BINDING_BUFFER[bindingIndex];

        if (buffer->name != 0) {
            address = buffer->baseAddress + 
                      VERTEX_BINDING_OFFSET[bindingIndex] + 
                      VERTEX_ATTRIB_RELATIVE_OFFSET[attribIndex];
        } else {
            address = VERTEX_ATTRIB_ARRAY_POINTER[attribIndex];
        }


Additions to Chapter 3 of the OpenGL 2.0 Specification (Rasterization)

    None.

Additions to Chapter 4 of the OpenGL 2.0 Specification (Per-Fragment
Operations and the Frame Buffer)

    None.

Additions to Chapter 5 of the OpenGL 2.0 Specification (Special Functions)

    None.

Additions to Chapter 6 of the OpenGL 2.0 Specification (State and
State Requests)

    Modify Section 6.1.18, "Shader and Program Queries", p. 500

    (Append to the description of GetVertexAttrib)

    Queries of VERTEX_ATTRIB_ARRAY_BUFFER_BINDING and VERTEX_ATTRIB_ARRAY_-
    DIVISOR first map the requested attribute index to a binding index via
    the VERTEX_ATTRIB_BINDING state, and then return the value of 
    VERTEX_BINDING_BUFFER or VERTEX_BINDING_DIVISOR, respectively.

Additions to the AGL/GLX/WGL Specifications

    None.

GLX Protocol

    TBD

Dependencies on NV_vertex_buffer_unified_memory

    When this extension is present, the GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 
    state is modified to correspond to the <i>'th vertex buffer binding
    rather than vertex attribute. Additionally, while the <buffer> and 
    <offset> set by BindVertexBuffer are irrelevant while 
    GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV is enabled, the command 
    
        BindVertexBuffer(bindingindex, 0, 0, stride);

    can still be used to set the stride for a particular binding.

    Note that NV_vertex_buffer_unified_memory uses the same function names 
    (VertexAttrib*FormatNV) as this extension, however the behavior of the 
    these functions is different.

Dependencies on EXT_direct_state_access

    When this extension is not present, ignore references to

        VertexArrayBindVertexBufferEXT
        VertexArrayVertexAttribFormatEXT
        VertexArrayVertexAttribIFormatEXT
        VertexArrayVertexAttribLFormatEXT
        VertexArrayVertexAttribBindingEXT
        VertexArrayVertexBindingDivisorEXT

    When EXT_direct_state_access is present, add new entry points that take a
    vertex array object handle:

        void VertexArrayBindVertexBufferEXT(uint vaobj, uint bindingindex, uint buffer, intptr offset, 
                              sizei stride);
        
        void VertexArrayVertexAttribFormatEXT(uint vaobj, uint attribindex, int size, enum type, 
                                boolean normalized, uint relativeoffset);
        void VertexArrayVertexAttribIFormatEXT(uint vaobj, uint attribindex, int size, enum type, 
                                 uint relativeoffset);
        void VertexArrayVertexAttribLFormatEXT(uint vaobj, uint attribindex, int size, enum type, 
                                 uint relativeoffset);
    
        void VertexArrayVertexAttribBindingEXT(uint vaobj, uint attribindex, uint bindingindex);
    
        void VertexArrayVertexBindingDivisorEXT(uint vaobj, uint bindingindex, uint divisor);

    These commands behave identically to their
    non-VertexArray/EXT-suffixed commands except they modify the state
    of the vertex array object named by their initial vaobj parameter
    (rather than the currently bound vertex array object).  The vertex
    array object named by vaobj must be generated by GenVertexArrays
    (and not since deleted); otherwise an INVALID_OPERATION error is
    generated.

    Modify the description of GetVertexArrayIntegeri_vEXT to allow
    queries of VERTEX_BINDING_OFFSET and VERTEX_BINDING_STRIDE state:
    
    "For GetVertexArrayIntegeri_vEXT, <pname> must be one of the
    'Get value' tokens in tables 6.8 and 6.9 that use GetVertexAttribiv
    or GetVertexAttribPointerv (so allowing only the VERTEX_ATTRIB_* and
    VERTEX_BINDING_* tokens) or a token of the form TEXTURE_COORD_ARRAY_*; 
    <index> identifies the vertex attribute array to query, vertex binding to
    query, or texture coordinate set index."

Dependencies on the Compatibility profile

    If the context is created with a compatibility profile, remove the 
    INVALID_OPERATION errors from all new commands if no vertex array 
    object is currently bound, and remove the INVALID_OPERATION error
    from VertexAttrib*Pointer if no buffer is bound to ARRAY_BUFFER and 
    pointer != NULL.

    Client vertex arrays are not changed to use the new state, that is, 
    VERTEX_ATTRIB_ARRAY_POINTER is still attribute state. 

Errors

    !!!TODO

New State

    (Modify Table 6.5 -- Vertex Array Object State)

                                                           Initial
    Get Value                    Type    Get Command       Value    Description                Sec.  
    ---------                    ------- -----------       -------  ------------------------   ------
    VERTEX_ATTRIB_BINDING        16*Z16* GetVertexAttribiv <i>[fn1] Vertex buffer binding      2.8   
                                                                    used by vertex attrib <i>
    VERTEX_ATTRIB_RELATIVE_      16*Z+   GetVertexAttribiv    0     Byte offset added to       2.8
      OFFSET                                                        vertex binding offset
                                                                    for this attribute
    VERTEX_BINDING_OFFSET        16*Z    GetInteger64i_v      0     Byte offset of the first   2.8
                                                                    element in data store of
                                                                    the buffer bound to vertex
                                                                    binding <i>
    VERTEX_BINDING_STRIDE        16*Z    GetIntegeri_v       16     Stride between elements in 2.8
                                                                    vertex binding <i>
    VERTEX_BINDING_DIVISOR       16*Z+   GetIntegeri_v        0     Instance divisor used for  2.8
                                                                    vertex binding <i>
    VERTEX_BINDING_BUFFER        16*Z+   GetIntegeri_v        0     Name of buffer bound to    2.8
                                                                    vertex binding <i>

    [fn1] The <i>'th attribute defaults to a value of <i>.

    If the compatibility profile is supported, then all of these new state 
    values belong to the 'vertex-array' attribute.

New Implementation Dependent State

                                                      Minimum
    Get Value                    Type    Get Command  Value   Description            Sec.  
    ---------                    ------- -----------  ------- --------------------   ------
    MAX_VERTEX_ATTRIB_           Z       GetIntegerv  2047    Maximum offset added   2.8
      RELATIVE_OFFSET                                         to vertex buffer 
                                                              binding offset
    MAX_VERTEX_ATTRIB_BINDINGS   Z16*    GetIntegerv  16      Maxmimum number of     2.8
                                                              vertex buffers

NVIDIA Implementation Details

    The VertexArrayVertexBindingDivisorEXT function was not missing
    from early versions of this specification's interactions with
    EXT_direct_state_access (an oversight).  NVIDIA driver implementations
    (prior to Release 330.00, August 2013) do not advertise the function a
    GetProcAddress call for the function name will return NULL.

Examples

    The following code will set up two interleaved vertex buffers, where 
    attribs 0 and 1 are vec3 position and vec3 color in buffer0, and attribs 
    2 and 3 come from are vec2 texcoords in buffer1.

        // Set up formats and relative offsets within the interleaved data.
        VertexAttribFormat(0, 3, FLOAT, FALSE, 0);
        VertexAttribFormat(1, 3, FLOAT, FALSE, 12);
        VertexAttribFormat(2, 2, FLOAT, FALSE, 0);
        VertexAttribFormat(3, 2, FLOAT, FALSE, 8);

        // Set up attrib->binding mapping
        VertexAttribBinding(0, 0);
        VertexAttribBinding(1, 0);
        VertexAttribBinding(2, 1);
        VertexAttribBinding(3, 1);

        // Bind the vertex buffers to binding index 0 and 1.
        BindVertexBuffer(0, buffer0, 0, 24);
        BindVertexBuffer(1, buffer1, 0, 16);

Issues

    (1) Should the instance divisor (previously VertexAttribDivisor) be 
        attribute state or binding state?

      RESOLVED: Make it per-binding, since some hardware requires this.

    (2) How is a stride of zero interpreted in BindVertexBuffer?

      RESOLVED: No error is generated, all array elements for a given 
      attribute will be sourced from the same location in the buffer.

    (3) How is a stride of zero handled in VertexAttribPointer?

      RESOLVED: BindVertexBuffer has no knowledge of the attrib format,
      so VertexAttribPointer needs to compute the stride itself. However,
      if an application specifies a stride of zero and then queries 
      VERTEX_ATTRIB_ARRAY_STRIDE, it returns zero. So the derived stride 
      that's passed to BindVertexBuffer must be tracked separately from the
      stride originally passed to VertexAttribPointer, so this spec introduces
      a separate piece of state (VERTEX_BINDING_STRIDE). Rendering always uses
      VERTEX_BINDING_STRIDE.

      This can potentially lead to misleading state queries if the API is 
      abused. For example:

        VertexAttribPointer(0, 3, FLOAT, FALSE, 12, 0);
        // VERTEX_ATTRIB_ARRAY_STRIDE = 12
        // VERTEX_BINDING_STRIDE = 12
        BindVertexBuffer(0, buffer, 0, 16)
        // now VERTEX_ATTRIB_ARRAY_STRIDE is still 12, but
        // VERTEX_BINDING_STRIDE = 16. 

    (4) How should the attrib->binding mapping be handled for legacy commands?

      RESOLVED: Redefine legacy commands to reset the mapping to its initial 
      state for the attribute being operated on. This allows legacy code to 
      coexist in the same context/VAO with use of this extension even though 
      that code is oblivious to the fact that this mapping is now flexible. 
      As long as the legacy code sets up each attribute it wants to use, it 
      should operate as expected. This may be useful for applications using 
      middleware that they can't control.

    (5) What is the minimum maximum value for VERTEX_ATTRIB_RELATIVE_OFFSET?

      RESOLVED: Agreed on 2047 (inclusive).

    (6) Can MAX_VERTEX_ATTRIBS and MAX_VERTEX_ATTRIB_BINDINGS have different 
    values?

      RESOLVED: Decided that it's nice to have them be separate queries, but
      that we don't want to deal with all the complexities that arise if the
      two values are different. So this spec assumes that the two values are
      the same.

    (7) How does this extension interact with EXT_direct_state_access?

      RESOLVED:  The EXT commands in this specification are available only when
      EXT_direct_state_access is also advertised.

      Note:  Early versions of this specification failed to document
      the EXT_direct_state_access commands.  Revision 3 (August 2013)
      corrects this oversight.

    (8) Which state queries return information from attributes vs from 
        bindings?

      RESOLVED: The general convention is that tokens starting with 
      VERTEX_BINDING return information corresponding to a buffer binding and
      are queried with GetIntegeri_v, whereas tokens starting with 
      VERTEX_ATTRIB_ARRAY return information corresponding to a vertex 
      attribute index and are queried with GetVertexAttribiv.

      For cases where there is both an "attribute" and "binding" token for the
      same state, the "attribute" query returns state for the binding that 
      attribute is currently using (set via VertexAttribBinding). Specifically,
      VERTEX_ATTRIB_ARRAY_BUFFER_BINDING returns a value from VERTEX_BINDING_-
      BUFFER, and VERTEX_ATTRIB_ARRAY_DIVISOR returns a value from VERTEX_-
      BINDING_DIVISOR.

      A notable exception to this is for VERTEX_BINDING_STRIDE and 
      VERTEX_ATTRIB_ARRAY_STRIDE. As described in issue (3), these tokens track
      separate state.


Revision History

    Rev.    Date    Author    Changes
    ----  --------  --------  ------------------------------------------
      5   10/22/13  jbolz     Added missing definition of 
                              VERTEX_BINDING_DIVISOR, and added 
                              VERTEX_BINDING_BUFFER, to keep things consistent.
      4   08/06/13  mjk       Added EXT_direct_state_access interactions
      3   07/19/13  Jon Leech Add error to BindVertexBuffer for the core
                              profile if <buffer> is not a name returned
                              by GenBuffers (Bug 10486).
      2   08/13/12  Jon Leech Renumbered from #143 to #125
      1             jbolz     Internal revisions.
