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