Home | History | Annotate | Download | only in main
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
      5  * (C) Copyright IBM Corporation 2006
      6  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the "Software"),
     10  * to deal in the Software without restriction, including without limitation
     11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     12  * and/or sell copies of the Software, and to permit persons to whom the
     13  * Software is furnished to do so, subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice shall be included
     16  * in all copies or substantial portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     24  * OTHER DEALINGS IN THE SOFTWARE.
     25  */
     26 
     27 
     28 /**
     29  * \file arrayobj.c
     30  *
     31  * Implementation of Vertex Array Objects (VAOs), from OpenGL 3.1+ /
     32  * the GL_ARB_vertex_array_object extension.
     33  *
     34  * \todo
     35  * The code in this file borrows a lot from bufferobj.c.  There's a certain
     36  * amount of cruft left over from that origin that may be unnecessary.
     37  *
     38  * \author Ian Romanick <idr (at) us.ibm.com>
     39  * \author Brian Paul
     40  */
     41 
     42 
     43 #include "glheader.h"
     44 #include "hash.h"
     45 #include "image.h"
     46 #include "imports.h"
     47 #include "context.h"
     48 #include "bufferobj.h"
     49 #include "arrayobj.h"
     50 #include "macros.h"
     51 #include "mtypes.h"
     52 #include "varray.h"
     53 #include "main/dispatch.h"
     54 #include "util/bitscan.h"
     55 
     56 
     57 /**
     58  * Look up the array object for the given ID.
     59  *
     60  * \returns
     61  * Either a pointer to the array object with the specified ID or \c NULL for
     62  * a non-existent ID.  The spec defines ID 0 as being technically
     63  * non-existent.
     64  */
     65 
     66 struct gl_vertex_array_object *
     67 _mesa_lookup_vao(struct gl_context *ctx, GLuint id)
     68 {
     69    if (id == 0) {
     70       return NULL;
     71    } else {
     72       struct gl_vertex_array_object *vao;
     73 
     74       if (ctx->Array.LastLookedUpVAO &&
     75           ctx->Array.LastLookedUpVAO->Name == id) {
     76          vao = ctx->Array.LastLookedUpVAO;
     77       } else {
     78          vao = (struct gl_vertex_array_object *)
     79             _mesa_HashLookupLocked(ctx->Array.Objects, id);
     80 
     81          _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao);
     82       }
     83 
     84       return vao;
     85    }
     86 }
     87 
     88 
     89 /**
     90  * Looks up the array object for the given ID.
     91  *
     92  * Unlike _mesa_lookup_vao, this function generates a GL_INVALID_OPERATION
     93  * error if the array object does not exist. It also returns the default
     94  * array object when ctx is a compatibility profile context and id is zero.
     95  */
     96 struct gl_vertex_array_object *
     97 _mesa_lookup_vao_err(struct gl_context *ctx, GLuint id, const char *caller)
     98 {
     99    /* The ARB_direct_state_access specification says:
    100     *
    101     *    "<vaobj> is [compatibility profile:
    102     *     zero, indicating the default vertex array object, or]
    103     *     the name of the vertex array object."
    104     */
    105    if (id == 0) {
    106       if (ctx->API == API_OPENGL_CORE) {
    107          _mesa_error(ctx, GL_INVALID_OPERATION,
    108                      "%s(zero is not valid vaobj name in a core profile "
    109                      "context)", caller);
    110          return NULL;
    111       }
    112 
    113       return ctx->Array.DefaultVAO;
    114    } else {
    115       struct gl_vertex_array_object *vao;
    116 
    117       if (ctx->Array.LastLookedUpVAO &&
    118           ctx->Array.LastLookedUpVAO->Name == id) {
    119          vao = ctx->Array.LastLookedUpVAO;
    120       } else {
    121          vao = (struct gl_vertex_array_object *)
    122             _mesa_HashLookupLocked(ctx->Array.Objects, id);
    123 
    124          /* The ARB_direct_state_access specification says:
    125           *
    126           *    "An INVALID_OPERATION error is generated if <vaobj> is not
    127           *     [compatibility profile: zero or] the name of an existing
    128           *     vertex array object."
    129           */
    130          if (!vao || !vao->EverBound) {
    131             _mesa_error(ctx, GL_INVALID_OPERATION,
    132                         "%s(non-existent vaobj=%u)", caller, id);
    133             return NULL;
    134          }
    135 
    136          _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao);
    137       }
    138 
    139       return vao;
    140    }
    141 }
    142 
    143 
    144 /**
    145  * For all the vertex binding points in the array object, unbind any pointers
    146  * to any buffer objects (VBOs).
    147  * This is done just prior to array object destruction.
    148  */
    149 static void
    150 unbind_array_object_vbos(struct gl_context *ctx, struct gl_vertex_array_object *obj)
    151 {
    152    GLuint i;
    153 
    154    for (i = 0; i < ARRAY_SIZE(obj->BufferBinding); i++)
    155       _mesa_reference_buffer_object(ctx, &obj->BufferBinding[i].BufferObj, NULL);
    156 
    157    for (i = 0; i < ARRAY_SIZE(obj->_VertexAttrib); i++)
    158       _mesa_reference_buffer_object(ctx, &obj->_VertexAttrib[i].BufferObj, NULL);
    159 }
    160 
    161 
    162 /**
    163  * Allocate and initialize a new vertex array object.
    164  */
    165 struct gl_vertex_array_object *
    166 _mesa_new_vao(struct gl_context *ctx, GLuint name)
    167 {
    168    struct gl_vertex_array_object *obj = CALLOC_STRUCT(gl_vertex_array_object);
    169    if (obj)
    170       _mesa_initialize_vao(ctx, obj, name);
    171    return obj;
    172 }
    173 
    174 
    175 /**
    176  * Delete an array object.
    177  */
    178 void
    179 _mesa_delete_vao(struct gl_context *ctx, struct gl_vertex_array_object *obj)
    180 {
    181    unbind_array_object_vbos(ctx, obj);
    182    _mesa_reference_buffer_object(ctx, &obj->IndexBufferObj, NULL);
    183    free(obj->Label);
    184    free(obj);
    185 }
    186 
    187 
    188 /**
    189  * Set ptr to vao w/ reference counting.
    190  * Note: this should only be called from the _mesa_reference_vao()
    191  * inline function.
    192  */
    193 void
    194 _mesa_reference_vao_(struct gl_context *ctx,
    195                      struct gl_vertex_array_object **ptr,
    196                      struct gl_vertex_array_object *vao)
    197 {
    198    assert(*ptr != vao);
    199 
    200    if (*ptr) {
    201       /* Unreference the old array object */
    202       struct gl_vertex_array_object *oldObj = *ptr;
    203 
    204       assert(oldObj->RefCount > 0);
    205       oldObj->RefCount--;
    206 
    207       if (oldObj->RefCount == 0)
    208          _mesa_delete_vao(ctx, oldObj);
    209 
    210       *ptr = NULL;
    211    }
    212    assert(!*ptr);
    213 
    214    if (vao) {
    215       /* reference new array object */
    216       assert(vao->RefCount > 0);
    217 
    218       vao->RefCount++;
    219       *ptr = vao;
    220    }
    221 }
    222 
    223 
    224 /**
    225  * Initialize attribtes of a vertex array within a vertex array object.
    226  * \param vao  the container vertex array object
    227  * \param index  which array in the VAO to initialize
    228  * \param size  number of components (1, 2, 3 or 4) per attribute
    229  * \param type  datatype of the attribute (GL_FLOAT, GL_INT, etc).
    230  */
    231 static void
    232 init_array(struct gl_context *ctx,
    233            struct gl_vertex_array_object *vao,
    234            GLuint index, GLint size, GLint type)
    235 {
    236    struct gl_array_attributes *array = &vao->VertexAttrib[index];
    237    struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[index];
    238 
    239    array->Size = size;
    240    array->Type = type;
    241    array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */
    242    array->Stride = 0;
    243    array->Ptr = NULL;
    244    array->RelativeOffset = 0;
    245    array->Enabled = GL_FALSE;
    246    array->Normalized = GL_FALSE;
    247    array->Integer = GL_FALSE;
    248    array->Doubles = GL_FALSE;
    249    array->_ElementSize = size * _mesa_sizeof_type(type);
    250    array->BufferBindingIndex = index;
    251 
    252    binding->Offset = 0;
    253    binding->Stride = array->_ElementSize;
    254    binding->BufferObj = NULL;
    255    binding->_BoundArrays = BITFIELD_BIT(index);
    256 
    257    /* Vertex array buffers */
    258    _mesa_reference_buffer_object(ctx, &binding->BufferObj,
    259                                  ctx->Shared->NullBufferObj);
    260 }
    261 
    262 
    263 /**
    264  * Initialize a gl_vertex_array_object's arrays.
    265  */
    266 void
    267 _mesa_initialize_vao(struct gl_context *ctx,
    268                      struct gl_vertex_array_object *vao,
    269                      GLuint name)
    270 {
    271    GLuint i;
    272 
    273    vao->Name = name;
    274 
    275    vao->RefCount = 1;
    276 
    277    /* Init the individual arrays */
    278    for (i = 0; i < ARRAY_SIZE(vao->VertexAttrib); i++) {
    279       switch (i) {
    280       case VERT_ATTRIB_NORMAL:
    281          init_array(ctx, vao, VERT_ATTRIB_NORMAL, 3, GL_FLOAT);
    282          break;
    283       case VERT_ATTRIB_COLOR1:
    284          init_array(ctx, vao, VERT_ATTRIB_COLOR1, 3, GL_FLOAT);
    285          break;
    286       case VERT_ATTRIB_FOG:
    287          init_array(ctx, vao, VERT_ATTRIB_FOG, 1, GL_FLOAT);
    288          break;
    289       case VERT_ATTRIB_COLOR_INDEX:
    290          init_array(ctx, vao, VERT_ATTRIB_COLOR_INDEX, 1, GL_FLOAT);
    291          break;
    292       case VERT_ATTRIB_EDGEFLAG:
    293          init_array(ctx, vao, VERT_ATTRIB_EDGEFLAG, 1, GL_BOOL);
    294          break;
    295       case VERT_ATTRIB_POINT_SIZE:
    296          init_array(ctx, vao, VERT_ATTRIB_POINT_SIZE, 1, GL_FLOAT);
    297          break;
    298       default:
    299          init_array(ctx, vao, i, 4, GL_FLOAT);
    300          break;
    301       }
    302    }
    303 
    304    _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj,
    305                                  ctx->Shared->NullBufferObj);
    306 }
    307 
    308 
    309 /**
    310  * Updates the derived gl_vertex_arrays when a gl_vertex_attrib_array
    311  * or a gl_vertex_buffer_binding has changed.
    312  */
    313 void
    314 _mesa_update_vao_client_arrays(struct gl_context *ctx,
    315                                struct gl_vertex_array_object *vao)
    316 {
    317    GLbitfield arrays = vao->NewArrays;
    318 
    319    while (arrays) {
    320       const int attrib = u_bit_scan(&arrays);
    321       struct gl_vertex_array *client_array = &vao->_VertexAttrib[attrib];
    322       const struct gl_array_attributes *attrib_array =
    323          &vao->VertexAttrib[attrib];
    324       const struct gl_vertex_buffer_binding *buffer_binding =
    325          &vao->BufferBinding[attrib_array->BufferBindingIndex];
    326 
    327       _mesa_update_client_array(ctx, client_array, attrib_array,
    328                                 buffer_binding);
    329    }
    330 }
    331 
    332 
    333 bool
    334 _mesa_all_varyings_in_vbos(const struct gl_vertex_array_object *vao)
    335 {
    336    /* Walk those enabled arrays that have the default vbo attached */
    337    GLbitfield mask = vao->_Enabled & ~vao->VertexAttribBufferMask;
    338 
    339    while (mask) {
    340       /* Do not use u_bit_scan64 as we can walk multiple
    341        * attrib arrays at once
    342        */
    343       const int i = ffs(mask) - 1;
    344       const struct gl_array_attributes *attrib_array =
    345          &vao->VertexAttrib[i];
    346       const struct gl_vertex_buffer_binding *buffer_binding =
    347          &vao->BufferBinding[attrib_array->BufferBindingIndex];
    348 
    349       /* Only enabled arrays shall appear in the _Enabled bitmask */
    350       assert(attrib_array->Enabled);
    351       /* We have already masked out vao->VertexAttribBufferMask  */
    352       assert(!_mesa_is_bufferobj(buffer_binding->BufferObj));
    353 
    354       /* Bail out once we find the first non vbo with a non zero stride */
    355       if (buffer_binding->Stride != 0)
    356          return false;
    357 
    358       /* Note that we cannot use the xor variant since the _BoundArray mask
    359        * may contain array attributes that are bound but not enabled.
    360        */
    361       mask &= ~buffer_binding->_BoundArrays;
    362    }
    363 
    364    return true;
    365 }
    366 
    367 bool
    368 _mesa_all_buffers_are_unmapped(const struct gl_vertex_array_object *vao)
    369 {
    370    /* Walk the enabled arrays that have a vbo attached */
    371    GLbitfield mask = vao->_Enabled & vao->VertexAttribBufferMask;
    372 
    373    while (mask) {
    374       const int i = ffs(mask) - 1;
    375       const struct gl_array_attributes *attrib_array =
    376          &vao->VertexAttrib[i];
    377       const struct gl_vertex_buffer_binding *buffer_binding =
    378          &vao->BufferBinding[attrib_array->BufferBindingIndex];
    379 
    380       /* Only enabled arrays shall appear in the _Enabled bitmask */
    381       assert(attrib_array->Enabled);
    382       /* We have already masked with vao->VertexAttribBufferMask  */
    383       assert(_mesa_is_bufferobj(buffer_binding->BufferObj));
    384 
    385       /* Bail out once we find the first disallowed mapping */
    386       if (_mesa_check_disallowed_mapping(buffer_binding->BufferObj))
    387          return false;
    388 
    389       /* We have handled everything that is bound to this buffer_binding. */
    390       mask &= ~buffer_binding->_BoundArrays;
    391    }
    392 
    393    return true;
    394 }
    395 
    396 /**********************************************************************/
    397 /* API Functions                                                      */
    398 /**********************************************************************/
    399 
    400 
    401 /**
    402  * ARB version of glBindVertexArray()
    403  */
    404 static ALWAYS_INLINE void
    405 bind_vertex_array(struct gl_context *ctx, GLuint id, bool no_error)
    406 {
    407    struct gl_vertex_array_object *const oldObj = ctx->Array.VAO;
    408    struct gl_vertex_array_object *newObj = NULL;
    409 
    410    assert(oldObj != NULL);
    411 
    412    if (oldObj->Name == id)
    413       return;   /* rebinding the same array object- no change */
    414 
    415    /*
    416     * Get pointer to new array object (newObj)
    417     */
    418    if (id == 0) {
    419       /* The spec says there is no array object named 0, but we use
    420        * one internally because it simplifies things.
    421        */
    422       newObj = ctx->Array.DefaultVAO;
    423    }
    424    else {
    425       /* non-default array object */
    426       newObj = _mesa_lookup_vao(ctx, id);
    427       if (!no_error && !newObj) {
    428          _mesa_error(ctx, GL_INVALID_OPERATION,
    429                      "glBindVertexArray(non-gen name)");
    430          return;
    431       }
    432 
    433       newObj->EverBound = GL_TRUE;
    434    }
    435 
    436    if (ctx->Array.DrawMethod == DRAW_ARRAYS) {
    437       /* The _DrawArrays pointer is pointing at the VAO being unbound and
    438        * that VAO may be in the process of being deleted. If it's not going
    439        * to be deleted, this will have no effect, because the pointer needs
    440        * to be updated by the VBO module anyway.
    441        *
    442        * Before the VBO module can update the pointer, we have to set it
    443        * to NULL for drivers not to set up arrays which are not bound,
    444        * or to prevent a crash if the VAO being unbound is going to be
    445        * deleted.
    446        */
    447       ctx->Array._DrawArrays = NULL;
    448       ctx->Array.DrawMethod = DRAW_NONE;
    449    }
    450 
    451    ctx->NewState |= _NEW_ARRAY;
    452    _mesa_reference_vao(ctx, &ctx->Array.VAO, newObj);
    453 }
    454 
    455 
    456 void GLAPIENTRY
    457 _mesa_BindVertexArray_no_error(GLuint id)
    458 {
    459    GET_CURRENT_CONTEXT(ctx);
    460    bind_vertex_array(ctx, id, true);
    461 }
    462 
    463 
    464 void GLAPIENTRY
    465 _mesa_BindVertexArray(GLuint id)
    466 {
    467    GET_CURRENT_CONTEXT(ctx);
    468    bind_vertex_array(ctx, id, false);
    469 }
    470 
    471 
    472 /**
    473  * Delete a set of array objects.
    474  *
    475  * \param n      Number of array objects to delete.
    476  * \param ids    Array of \c n array object IDs.
    477  */
    478 static void
    479 delete_vertex_arrays(struct gl_context *ctx, GLsizei n, const GLuint *ids)
    480 {
    481    GLsizei i;
    482 
    483    for (i = 0; i < n; i++) {
    484       struct gl_vertex_array_object *obj = _mesa_lookup_vao(ctx, ids[i]);
    485 
    486       if (obj) {
    487          assert(obj->Name == ids[i]);
    488 
    489          /* If the array object is currently bound, the spec says "the binding
    490           * for that object reverts to zero and the default vertex array
    491           * becomes current."
    492           */
    493          if (obj == ctx->Array.VAO)
    494             _mesa_BindVertexArray_no_error(0);
    495 
    496          /* The ID is immediately freed for re-use */
    497          _mesa_HashRemoveLocked(ctx->Array.Objects, obj->Name);
    498 
    499          if (ctx->Array.LastLookedUpVAO == obj)
    500             _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, NULL);
    501 
    502          /* Unreference the array object.
    503           * If refcount hits zero, the object will be deleted.
    504           */
    505          _mesa_reference_vao(ctx, &obj, NULL);
    506       }
    507    }
    508 }
    509 
    510 
    511 void GLAPIENTRY
    512 _mesa_DeleteVertexArrays_no_error(GLsizei n, const GLuint *ids)
    513 {
    514    GET_CURRENT_CONTEXT(ctx);
    515    delete_vertex_arrays(ctx, n, ids);
    516 }
    517 
    518 
    519 void GLAPIENTRY
    520 _mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids)
    521 {
    522    GET_CURRENT_CONTEXT(ctx);
    523 
    524    if (n < 0) {
    525       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArray(n)");
    526       return;
    527    }
    528 
    529    delete_vertex_arrays(ctx, n, ids);
    530 }
    531 
    532 
    533 /**
    534  * Generate a set of unique array object IDs and store them in \c arrays.
    535  * Helper for _mesa_GenVertexArrays() and _mesa_CreateVertexArrays()
    536  * below.
    537  *
    538  * \param n       Number of IDs to generate.
    539  * \param arrays  Array of \c n locations to store the IDs.
    540  * \param create  Indicates that the objects should also be created.
    541  * \param func    The name of the GL entry point.
    542  */
    543 static void
    544 gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays,
    545                   bool create, const char *func)
    546 {
    547    GLuint first;
    548    GLint i;
    549 
    550    if (!arrays)
    551       return;
    552 
    553    first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n);
    554 
    555    /* For the sake of simplicity we create the array objects in both
    556     * the Gen* and Create* cases.  The only difference is the value of
    557     * EverBound, which is set to true in the Create* case.
    558     */
    559    for (i = 0; i < n; i++) {
    560       struct gl_vertex_array_object *obj;
    561       GLuint name = first + i;
    562 
    563       obj = _mesa_new_vao(ctx, name);
    564       if (!obj) {
    565          _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
    566          return;
    567       }
    568       obj->EverBound = create;
    569       _mesa_HashInsertLocked(ctx->Array.Objects, obj->Name, obj);
    570       arrays[i] = first + i;
    571    }
    572 }
    573 
    574 
    575 static void
    576 gen_vertex_arrays_err(struct gl_context *ctx, GLsizei n, GLuint *arrays,
    577                       bool create, const char *func)
    578 {
    579    if (n < 0) {
    580       _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
    581       return;
    582    }
    583 
    584    gen_vertex_arrays(ctx, n, arrays, create, func);
    585 }
    586 
    587 
    588 /**
    589  * ARB version of glGenVertexArrays()
    590  * All arrays will be required to live in VBOs.
    591  */
    592 void GLAPIENTRY
    593 _mesa_GenVertexArrays_no_error(GLsizei n, GLuint *arrays)
    594 {
    595    GET_CURRENT_CONTEXT(ctx);
    596    gen_vertex_arrays(ctx, n, arrays, false, "glGenVertexArrays");
    597 }
    598 
    599 
    600 void GLAPIENTRY
    601 _mesa_GenVertexArrays(GLsizei n, GLuint *arrays)
    602 {
    603    GET_CURRENT_CONTEXT(ctx);
    604    gen_vertex_arrays_err(ctx, n, arrays, false, "glGenVertexArrays");
    605 }
    606 
    607 
    608 /**
    609  * ARB_direct_state_access
    610  * Generates ID's and creates the array objects.
    611  */
    612 void GLAPIENTRY
    613 _mesa_CreateVertexArrays_no_error(GLsizei n, GLuint *arrays)
    614 {
    615    GET_CURRENT_CONTEXT(ctx);
    616    gen_vertex_arrays(ctx, n, arrays, true, "glCreateVertexArrays");
    617 }
    618 
    619 
    620 void GLAPIENTRY
    621 _mesa_CreateVertexArrays(GLsizei n, GLuint *arrays)
    622 {
    623    GET_CURRENT_CONTEXT(ctx);
    624    gen_vertex_arrays_err(ctx, n, arrays, true, "glCreateVertexArrays");
    625 }
    626 
    627 
    628 /**
    629  * Determine if ID is the name of an array object.
    630  *
    631  * \param id  ID of the potential array object.
    632  * \return  \c GL_TRUE if \c id is the name of a array object,
    633  *          \c GL_FALSE otherwise.
    634  */
    635 GLboolean GLAPIENTRY
    636 _mesa_IsVertexArray( GLuint id )
    637 {
    638    struct gl_vertex_array_object * obj;
    639    GET_CURRENT_CONTEXT(ctx);
    640    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
    641 
    642    obj = _mesa_lookup_vao(ctx, id);
    643 
    644    return obj != NULL && obj->EverBound;
    645 }
    646 
    647 
    648 /**
    649  * Sets the element array buffer binding of a vertex array object.
    650  *
    651  * This is the ARB_direct_state_access equivalent of
    652  * glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer).
    653  */
    654 static ALWAYS_INLINE void
    655 vertex_array_element_buffer(struct gl_context *ctx, GLuint vaobj, GLuint buffer,
    656                             bool no_error)
    657 {
    658    struct gl_vertex_array_object *vao;
    659    struct gl_buffer_object *bufObj;
    660 
    661    ASSERT_OUTSIDE_BEGIN_END(ctx);
    662 
    663    if (!no_error) {
    664       /* The GL_ARB_direct_state_access specification says:
    665        *
    666        *    "An INVALID_OPERATION error is generated by
    667        *     VertexArrayElementBuffer if <vaobj> is not [compatibility profile:
    668        *     zero or] the name of an existing vertex array object."
    669        */
    670       vao =_mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayElementBuffer");
    671       if (!vao)
    672          return;
    673    } else {
    674       vao = _mesa_lookup_vao(ctx, vaobj);
    675    }
    676 
    677    if (buffer != 0) {
    678       if (!no_error) {
    679          /* The GL_ARB_direct_state_access specification says:
    680           *
    681           *    "An INVALID_OPERATION error is generated if <buffer> is not zero
    682           *     or the name of an existing buffer object."
    683           */
    684          bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
    685                                              "glVertexArrayElementBuffer");
    686       } else {
    687          bufObj = _mesa_lookup_bufferobj(ctx, buffer);
    688       }
    689    } else {
    690       bufObj = ctx->Shared->NullBufferObj;
    691    }
    692 
    693    if (bufObj)
    694       _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj, bufObj);
    695 }
    696 
    697 
    698 void GLAPIENTRY
    699 _mesa_VertexArrayElementBuffer_no_error(GLuint vaobj, GLuint buffer)
    700 {
    701    GET_CURRENT_CONTEXT(ctx);
    702    vertex_array_element_buffer(ctx, vaobj, buffer, true);
    703 }
    704 
    705 
    706 void GLAPIENTRY
    707 _mesa_VertexArrayElementBuffer(GLuint vaobj, GLuint buffer)
    708 {
    709    GET_CURRENT_CONTEXT(ctx);
    710    vertex_array_element_buffer(ctx, vaobj, buffer, false);
    711 }
    712 
    713 
    714 void GLAPIENTRY
    715 _mesa_GetVertexArrayiv(GLuint vaobj, GLenum pname, GLint *param)
    716 {
    717    GET_CURRENT_CONTEXT(ctx);
    718    struct gl_vertex_array_object *vao;
    719 
    720    ASSERT_OUTSIDE_BEGIN_END(ctx);
    721 
    722    /* The GL_ARB_direct_state_access specification says:
    723     *
    724     *   "An INVALID_OPERATION error is generated if <vaobj> is not
    725     *    [compatibility profile: zero or] the name of an existing
    726     *    vertex array object."
    727     */
    728    vao =_mesa_lookup_vao_err(ctx, vaobj, "glGetVertexArrayiv");
    729    if (!vao)
    730       return;
    731 
    732    /* The GL_ARB_direct_state_access specification says:
    733     *
    734     *   "An INVALID_ENUM error is generated if <pname> is not
    735     *    ELEMENT_ARRAY_BUFFER_BINDING."
    736     */
    737    if (pname != GL_ELEMENT_ARRAY_BUFFER_BINDING) {
    738       _mesa_error(ctx, GL_INVALID_ENUM,
    739                   "glGetVertexArrayiv(pname != "
    740                   "GL_ELEMENT_ARRAY_BUFFER_BINDING)");
    741       return;
    742    }
    743 
    744    param[0] = vao->IndexBufferObj->Name;
    745 }
    746