arrayobj.c revision af69d88d
17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 4c1f859d4Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 57117f1b4Smrg * (C) Copyright IBM Corporation 2006 64a49301eSmrg * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 77117f1b4Smrg * 87117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 97117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 107117f1b4Smrg * to deal in the Software without restriction, including without limitation 117117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 127117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 137117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 147117f1b4Smrg * 157117f1b4Smrg * The above copyright notice and this permission notice shall be included 167117f1b4Smrg * in all copies or substantial portions of the Software. 177117f1b4Smrg * 187117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 197117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 207117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 257117f1b4Smrg */ 267117f1b4Smrg 277117f1b4Smrg 287117f1b4Smrg/** 297117f1b4Smrg * \file arrayobj.c 30af69d88dSmrg * 31af69d88dSmrg * Implementation of Vertex Array Objects (VAOs), from OpenGL 3.1+, 32af69d88dSmrg * the GL_ARB_vertex_array_object extension, or the older 33af69d88dSmrg * GL_APPLE_vertex_array_object extension. 347117f1b4Smrg * 357117f1b4Smrg * \todo 367117f1b4Smrg * The code in this file borrows a lot from bufferobj.c. There's a certain 377117f1b4Smrg * amount of cruft left over from that origin that may be unnecessary. 387117f1b4Smrg * 397117f1b4Smrg * \author Ian Romanick <idr@us.ibm.com> 407117f1b4Smrg * \author Brian Paul 417117f1b4Smrg */ 427117f1b4Smrg 437117f1b4Smrg 447117f1b4Smrg#include "glheader.h" 457117f1b4Smrg#include "hash.h" 463464ebd5Sriastradh#include "image.h" 477117f1b4Smrg#include "imports.h" 487117f1b4Smrg#include "context.h" 497117f1b4Smrg#include "bufferobj.h" 507117f1b4Smrg#include "arrayobj.h" 514a49301eSmrg#include "macros.h" 523464ebd5Sriastradh#include "mtypes.h" 533464ebd5Sriastradh#include "varray.h" 54cdc920a0Smrg#include "main/dispatch.h" 557117f1b4Smrg 567117f1b4Smrg 577117f1b4Smrg/** 587117f1b4Smrg * Look up the array object for the given ID. 59af69d88dSmrg * 607117f1b4Smrg * \returns 617117f1b4Smrg * Either a pointer to the array object with the specified ID or \c NULL for 627117f1b4Smrg * a non-existent ID. The spec defines ID 0 as being technically 637117f1b4Smrg * non-existent. 647117f1b4Smrg */ 657117f1b4Smrg 66af69d88dSmrgstruct gl_vertex_array_object * 67af69d88dSmrg_mesa_lookup_vao(struct gl_context *ctx, GLuint id) 687117f1b4Smrg{ 694a49301eSmrg if (id == 0) 704a49301eSmrg return NULL; 714a49301eSmrg else 72af69d88dSmrg return (struct gl_vertex_array_object *) 734a49301eSmrg _mesa_HashLookup(ctx->Array.Objects, id); 744a49301eSmrg} 754a49301eSmrg 764a49301eSmrg 774a49301eSmrg/** 78af69d88dSmrg * For all the vertex binding points in the array object, unbind any pointers 794a49301eSmrg * to any buffer objects (VBOs). 804a49301eSmrg * This is done just prior to array object destruction. 814a49301eSmrg */ 824a49301eSmrgstatic void 83af69d88dSmrgunbind_array_object_vbos(struct gl_context *ctx, struct gl_vertex_array_object *obj) 844a49301eSmrg{ 854a49301eSmrg GLuint i; 864a49301eSmrg 87af69d88dSmrg for (i = 0; i < Elements(obj->VertexBinding); i++) 88af69d88dSmrg _mesa_reference_buffer_object(ctx, &obj->VertexBinding[i].BufferObj, NULL); 894a49301eSmrg 90af69d88dSmrg for (i = 0; i < Elements(obj->_VertexAttrib); i++) 91af69d88dSmrg _mesa_reference_buffer_object(ctx, &obj->_VertexAttrib[i].BufferObj, NULL); 927117f1b4Smrg} 937117f1b4Smrg 947117f1b4Smrg 957117f1b4Smrg/** 967117f1b4Smrg * Allocate and initialize a new vertex array object. 97af69d88dSmrg * 987117f1b4Smrg * This function is intended to be called via 997117f1b4Smrg * \c dd_function_table::NewArrayObject. 1007117f1b4Smrg */ 101af69d88dSmrgstruct gl_vertex_array_object * 102af69d88dSmrg_mesa_new_vao(struct gl_context *ctx, GLuint name) 1037117f1b4Smrg{ 104af69d88dSmrg struct gl_vertex_array_object *obj = CALLOC_STRUCT(gl_vertex_array_object); 1057117f1b4Smrg if (obj) 106af69d88dSmrg _mesa_initialize_vao(ctx, obj, name); 1077117f1b4Smrg return obj; 1087117f1b4Smrg} 1097117f1b4Smrg 1107117f1b4Smrg 1117117f1b4Smrg/** 1127117f1b4Smrg * Delete an array object. 113af69d88dSmrg * 1147117f1b4Smrg * This function is intended to be called via 1157117f1b4Smrg * \c dd_function_table::DeleteArrayObject. 1167117f1b4Smrg */ 1177117f1b4Smrgvoid 118af69d88dSmrg_mesa_delete_vao(struct gl_context *ctx, struct gl_vertex_array_object *obj) 1197117f1b4Smrg{ 1204a49301eSmrg unbind_array_object_vbos(ctx, obj); 121af69d88dSmrg _mesa_reference_buffer_object(ctx, &obj->IndexBufferObj, NULL); 122af69d88dSmrg mtx_destroy(&obj->Mutex); 123af69d88dSmrg free(obj->Label); 124cdc920a0Smrg free(obj); 1257117f1b4Smrg} 1267117f1b4Smrg 1277117f1b4Smrg 1284a49301eSmrg/** 129af69d88dSmrg * Set ptr to vao w/ reference counting. 130af69d88dSmrg * Note: this should only be called from the _mesa_reference_vao() 131af69d88dSmrg * inline function. 1324a49301eSmrg */ 1334a49301eSmrgvoid 134af69d88dSmrg_mesa_reference_vao_(struct gl_context *ctx, 135af69d88dSmrg struct gl_vertex_array_object **ptr, 136af69d88dSmrg struct gl_vertex_array_object *vao) 1374a49301eSmrg{ 138af69d88dSmrg assert(*ptr != vao); 1394a49301eSmrg 1404a49301eSmrg if (*ptr) { 1414a49301eSmrg /* Unreference the old array object */ 1424a49301eSmrg GLboolean deleteFlag = GL_FALSE; 143af69d88dSmrg struct gl_vertex_array_object *oldObj = *ptr; 1444a49301eSmrg 145af69d88dSmrg mtx_lock(&oldObj->Mutex); 1464a49301eSmrg ASSERT(oldObj->RefCount > 0); 1474a49301eSmrg oldObj->RefCount--; 1484a49301eSmrg#if 0 1494a49301eSmrg printf("ArrayObj %p %d DECR to %d\n", 1504a49301eSmrg (void *) oldObj, oldObj->Name, oldObj->RefCount); 1514a49301eSmrg#endif 1524a49301eSmrg deleteFlag = (oldObj->RefCount == 0); 153af69d88dSmrg mtx_unlock(&oldObj->Mutex); 1544a49301eSmrg 1554a49301eSmrg if (deleteFlag) { 1564a49301eSmrg ASSERT(ctx->Driver.DeleteArrayObject); 1574a49301eSmrg ctx->Driver.DeleteArrayObject(ctx, oldObj); 1584a49301eSmrg } 1594a49301eSmrg 1604a49301eSmrg *ptr = NULL; 1614a49301eSmrg } 1624a49301eSmrg ASSERT(!*ptr); 1634a49301eSmrg 164af69d88dSmrg if (vao) { 1654a49301eSmrg /* reference new array object */ 166af69d88dSmrg mtx_lock(&vao->Mutex); 167af69d88dSmrg if (vao->RefCount == 0) { 1684a49301eSmrg /* this array's being deleted (look just above) */ 1694a49301eSmrg /* Not sure this can every really happen. Warn if it does. */ 1704a49301eSmrg _mesa_problem(NULL, "referencing deleted array object"); 1714a49301eSmrg *ptr = NULL; 1724a49301eSmrg } 1734a49301eSmrg else { 174af69d88dSmrg vao->RefCount++; 1754a49301eSmrg#if 0 1764a49301eSmrg printf("ArrayObj %p %d INCR to %d\n", 177af69d88dSmrg (void *) vao, vao->Name, vao->RefCount); 1784a49301eSmrg#endif 179af69d88dSmrg *ptr = vao; 1804a49301eSmrg } 181af69d88dSmrg mtx_unlock(&vao->Mutex); 1824a49301eSmrg } 1834a49301eSmrg} 1844a49301eSmrg 1854a49301eSmrg 1864a49301eSmrg 1874a49301eSmrgstatic void 1883464ebd5Sriastradhinit_array(struct gl_context *ctx, 189af69d88dSmrg struct gl_vertex_array_object *obj, GLuint index, GLint size, GLint type) 1904a49301eSmrg{ 191af69d88dSmrg struct gl_vertex_attrib_array *array = &obj->VertexAttrib[index]; 192af69d88dSmrg struct gl_vertex_buffer_binding *binding = &obj->VertexBinding[index]; 193af69d88dSmrg 1944a49301eSmrg array->Size = size; 1954a49301eSmrg array->Type = type; 1964a49301eSmrg array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */ 1974a49301eSmrg array->Stride = 0; 1984a49301eSmrg array->Ptr = NULL; 199af69d88dSmrg array->RelativeOffset = 0; 2004a49301eSmrg array->Enabled = GL_FALSE; 2014a49301eSmrg array->Normalized = GL_FALSE; 202af69d88dSmrg array->Integer = GL_FALSE; 2033464ebd5Sriastradh array->_ElementSize = size * _mesa_sizeof_type(type); 204af69d88dSmrg array->VertexBinding = index; 205af69d88dSmrg 206af69d88dSmrg binding->Offset = 0; 207af69d88dSmrg binding->Stride = array->_ElementSize; 208af69d88dSmrg binding->BufferObj = NULL; 209af69d88dSmrg binding->_BoundArrays = BITFIELD64_BIT(index); 210af69d88dSmrg 2114a49301eSmrg /* Vertex array buffers */ 212af69d88dSmrg _mesa_reference_buffer_object(ctx, &binding->BufferObj, 2134a49301eSmrg ctx->Shared->NullBufferObj); 2144a49301eSmrg} 2154a49301eSmrg 2164a49301eSmrg 2174a49301eSmrg/** 218af69d88dSmrg * Initialize a gl_vertex_array_object's arrays. 2194a49301eSmrg */ 2207117f1b4Smrgvoid 221af69d88dSmrg_mesa_initialize_vao(struct gl_context *ctx, 222af69d88dSmrg struct gl_vertex_array_object *obj, 223af69d88dSmrg GLuint name) 2247117f1b4Smrg{ 2257117f1b4Smrg GLuint i; 2267117f1b4Smrg 2277117f1b4Smrg obj->Name = name; 2287117f1b4Smrg 229af69d88dSmrg mtx_init(&obj->Mutex, mtx_plain); 2304a49301eSmrg obj->RefCount = 1; 2314a49301eSmrg 2324a49301eSmrg /* Init the individual arrays */ 233af69d88dSmrg for (i = 0; i < Elements(obj->_VertexAttrib); i++) { 234af69d88dSmrg switch (i) { 235af69d88dSmrg case VERT_ATTRIB_WEIGHT: 236af69d88dSmrg init_array(ctx, obj, VERT_ATTRIB_WEIGHT, 1, GL_FLOAT); 237af69d88dSmrg break; 238af69d88dSmrg case VERT_ATTRIB_NORMAL: 239af69d88dSmrg init_array(ctx, obj, VERT_ATTRIB_NORMAL, 3, GL_FLOAT); 240af69d88dSmrg break; 241af69d88dSmrg case VERT_ATTRIB_COLOR1: 242af69d88dSmrg init_array(ctx, obj, VERT_ATTRIB_COLOR1, 3, GL_FLOAT); 243af69d88dSmrg break; 244af69d88dSmrg case VERT_ATTRIB_FOG: 245af69d88dSmrg init_array(ctx, obj, VERT_ATTRIB_FOG, 1, GL_FLOAT); 246af69d88dSmrg break; 247af69d88dSmrg case VERT_ATTRIB_COLOR_INDEX: 248af69d88dSmrg init_array(ctx, obj, VERT_ATTRIB_COLOR_INDEX, 1, GL_FLOAT); 249af69d88dSmrg break; 250af69d88dSmrg case VERT_ATTRIB_EDGEFLAG: 251af69d88dSmrg init_array(ctx, obj, VERT_ATTRIB_EDGEFLAG, 1, GL_BOOL); 252af69d88dSmrg break; 253af69d88dSmrg case VERT_ATTRIB_POINT_SIZE: 254af69d88dSmrg init_array(ctx, obj, VERT_ATTRIB_POINT_SIZE, 1, GL_FLOAT); 255af69d88dSmrg break; 256af69d88dSmrg default: 257af69d88dSmrg init_array(ctx, obj, i, 4, GL_FLOAT); 258af69d88dSmrg break; 259af69d88dSmrg } 2607117f1b4Smrg } 2617117f1b4Smrg 262af69d88dSmrg _mesa_reference_buffer_object(ctx, &obj->IndexBufferObj, 263af69d88dSmrg ctx->Shared->NullBufferObj); 2647117f1b4Smrg} 2657117f1b4Smrg 2667117f1b4Smrg 2677117f1b4Smrg/** 2687117f1b4Smrg * Add the given array object to the array object pool. 2697117f1b4Smrg */ 2704a49301eSmrgstatic void 271af69d88dSmrgsave_array_object( struct gl_context *ctx, struct gl_vertex_array_object *obj ) 2727117f1b4Smrg{ 2737117f1b4Smrg if (obj->Name > 0) { 2747117f1b4Smrg /* insert into hash table */ 2754a49301eSmrg _mesa_HashInsert(ctx->Array.Objects, obj->Name, obj); 2767117f1b4Smrg } 2777117f1b4Smrg} 2787117f1b4Smrg 2797117f1b4Smrg 2807117f1b4Smrg/** 2817117f1b4Smrg * Remove the given array object from the array object pool. 2827117f1b4Smrg * Do not deallocate the array object though. 2837117f1b4Smrg */ 2844a49301eSmrgstatic void 285af69d88dSmrgremove_array_object( struct gl_context *ctx, struct gl_vertex_array_object *obj ) 2867117f1b4Smrg{ 2877117f1b4Smrg if (obj->Name > 0) { 2887117f1b4Smrg /* remove from hash table */ 2894a49301eSmrg _mesa_HashRemove(ctx->Array.Objects, obj->Name); 2907117f1b4Smrg } 2917117f1b4Smrg} 2927117f1b4Smrg 2937117f1b4Smrg 2944a49301eSmrg 2954a49301eSmrg/** 296af69d88dSmrg * Helper for _mesa_update_vao_max_element(). 297af69d88dSmrg * \return min(vao->_VertexAttrib[*]._MaxElement). 2984a49301eSmrg */ 2994a49301eSmrgstatic GLuint 300af69d88dSmrgcompute_max_element(struct gl_vertex_array_object *vao, GLbitfield64 enabled) 3014a49301eSmrg{ 302af69d88dSmrg GLuint min = ~((GLuint)0); 303af69d88dSmrg 304af69d88dSmrg while (enabled) { 305af69d88dSmrg struct gl_client_array *client_array; 306af69d88dSmrg GLint attrib = ffsll(enabled) - 1; 307af69d88dSmrg enabled ^= BITFIELD64_BIT(attrib); 308af69d88dSmrg 309af69d88dSmrg client_array = &vao->_VertexAttrib[attrib]; 310af69d88dSmrg assert(client_array->Enabled); 311af69d88dSmrg _mesa_update_array_max_element(client_array); 312af69d88dSmrg min = MIN2(min, client_array->_MaxElement); 3133464ebd5Sriastradh } 314af69d88dSmrg 315af69d88dSmrg return min; 3164a49301eSmrg} 3174a49301eSmrg 3184a49301eSmrg 3194a49301eSmrg/** 320af69d88dSmrg * Examine vertex arrays to update the gl_vertex_array_object::_MaxElement field. 3214a49301eSmrg */ 3224a49301eSmrgvoid 323af69d88dSmrg_mesa_update_vao_max_element(struct gl_context *ctx, 324af69d88dSmrg struct gl_vertex_array_object *vao) 3254a49301eSmrg{ 326af69d88dSmrg GLbitfield64 enabled; 327af69d88dSmrg 328af69d88dSmrg if (!ctx->VertexProgram._Current || 329af69d88dSmrg ctx->VertexProgram._Current == ctx->VertexProgram._TnlProgram) { 330af69d88dSmrg enabled = _mesa_array_object_get_enabled_ff(vao); 331af69d88dSmrg } else { 332af69d88dSmrg enabled = _mesa_array_object_get_enabled_arb(vao); 333af69d88dSmrg } 3344a49301eSmrg 3354a49301eSmrg /* _MaxElement is one past the last legal array element */ 336af69d88dSmrg vao->_MaxElement = compute_max_element(vao, enabled); 337af69d88dSmrg} 338af69d88dSmrg 339af69d88dSmrg 340af69d88dSmrg/** 341af69d88dSmrg * Updates the derived gl_client_arrays when a gl_vertex_attrib_array 342af69d88dSmrg * or a gl_vertex_buffer_binding has changed. 343af69d88dSmrg */ 344af69d88dSmrgvoid 345af69d88dSmrg_mesa_update_vao_client_arrays(struct gl_context *ctx, 346af69d88dSmrg struct gl_vertex_array_object *vao) 347af69d88dSmrg{ 348af69d88dSmrg GLbitfield64 arrays = vao->NewArrays; 349af69d88dSmrg 350af69d88dSmrg while (arrays) { 351af69d88dSmrg struct gl_client_array *client_array; 352af69d88dSmrg struct gl_vertex_attrib_array *attrib_array; 353af69d88dSmrg struct gl_vertex_buffer_binding *buffer_binding; 354af69d88dSmrg 355af69d88dSmrg GLint attrib = ffsll(arrays) - 1; 356af69d88dSmrg arrays ^= BITFIELD64_BIT(attrib); 357af69d88dSmrg 358af69d88dSmrg attrib_array = &vao->VertexAttrib[attrib]; 359af69d88dSmrg buffer_binding = &vao->VertexBinding[attrib_array->VertexBinding]; 360af69d88dSmrg client_array = &vao->_VertexAttrib[attrib]; 361af69d88dSmrg 362af69d88dSmrg _mesa_update_client_array(ctx, client_array, attrib_array, 363af69d88dSmrg buffer_binding); 364af69d88dSmrg } 365c1f859d4Smrg} 366c1f859d4Smrg 367c1f859d4Smrg 3687117f1b4Smrg/**********************************************************************/ 3697117f1b4Smrg/* API Functions */ 3707117f1b4Smrg/**********************************************************************/ 3717117f1b4Smrg 3724a49301eSmrg 3737117f1b4Smrg/** 3744a49301eSmrg * Helper for _mesa_BindVertexArray() and _mesa_BindVertexArrayAPPLE(). 3754a49301eSmrg * \param genRequired specifies behavour when id was not generated with 3764a49301eSmrg * glGenVertexArrays(). 3777117f1b4Smrg */ 3784a49301eSmrgstatic void 3793464ebd5Sriastradhbind_vertex_array(struct gl_context *ctx, GLuint id, GLboolean genRequired) 3807117f1b4Smrg{ 381af69d88dSmrg struct gl_vertex_array_object * const oldObj = ctx->Array.VAO; 382af69d88dSmrg struct gl_vertex_array_object *newObj = NULL; 3837117f1b4Smrg 3847117f1b4Smrg ASSERT(oldObj != NULL); 3857117f1b4Smrg 3867117f1b4Smrg if ( oldObj->Name == id ) 3877117f1b4Smrg return; /* rebinding the same array object- no change */ 3887117f1b4Smrg 3897117f1b4Smrg /* 3904a49301eSmrg * Get pointer to new array object (newObj) 3917117f1b4Smrg */ 3927117f1b4Smrg if (id == 0) { 3937117f1b4Smrg /* The spec says there is no array object named 0, but we use 3947117f1b4Smrg * one internally because it simplifies things. 3957117f1b4Smrg */ 396af69d88dSmrg newObj = ctx->Array.DefaultVAO; 3977117f1b4Smrg } 3987117f1b4Smrg else { 3997117f1b4Smrg /* non-default array object */ 400af69d88dSmrg newObj = _mesa_lookup_vao(ctx, id); 4017117f1b4Smrg if (!newObj) { 4024a49301eSmrg if (genRequired) { 403af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 404af69d88dSmrg "glBindVertexArray(non-gen name)"); 4054a49301eSmrg return; 4064a49301eSmrg } 4077117f1b4Smrg 4084a49301eSmrg /* For APPLE version, generate a new array object now */ 4097117f1b4Smrg newObj = (*ctx->Driver.NewArrayObject)(ctx, id); 4107117f1b4Smrg if (!newObj) { 4117117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindVertexArrayAPPLE"); 4127117f1b4Smrg return; 4137117f1b4Smrg } 414af69d88dSmrg 4154a49301eSmrg save_array_object(ctx, newObj); 4167117f1b4Smrg } 417af69d88dSmrg 418af69d88dSmrg if (!newObj->EverBound) { 419af69d88dSmrg /* The "Interactions with APPLE_vertex_array_object" section of the 420af69d88dSmrg * GL_ARB_vertex_array_object spec says: 421af69d88dSmrg * 422af69d88dSmrg * "The first bind call, either BindVertexArray or 423af69d88dSmrg * BindVertexArrayAPPLE, determines the semantic of the object." 424af69d88dSmrg */ 425af69d88dSmrg newObj->ARBsemantics = genRequired; 426af69d88dSmrg newObj->EverBound = GL_TRUE; 427af69d88dSmrg } 428af69d88dSmrg } 429af69d88dSmrg 430af69d88dSmrg if (ctx->Array.DrawMethod == DRAW_ARRAYS) { 431af69d88dSmrg /* The _DrawArrays pointer is pointing at the VAO being unbound and 432af69d88dSmrg * that VAO may be in the process of being deleted. If it's not going 433af69d88dSmrg * to be deleted, this will have no effect, because the pointer needs 434af69d88dSmrg * to be updated by the VBO module anyway. 435af69d88dSmrg * 436af69d88dSmrg * Before the VBO module can update the pointer, we have to set it 437af69d88dSmrg * to NULL for drivers not to set up arrays which are not bound, 438af69d88dSmrg * or to prevent a crash if the VAO being unbound is going to be 439af69d88dSmrg * deleted. 440af69d88dSmrg */ 441af69d88dSmrg ctx->Array._DrawArrays = NULL; 442af69d88dSmrg ctx->Array.DrawMethod = DRAW_NONE; 4437117f1b4Smrg } 4447117f1b4Smrg 4457117f1b4Smrg ctx->NewState |= _NEW_ARRAY; 446af69d88dSmrg _mesa_reference_vao(ctx, &ctx->Array.VAO, newObj); 4477117f1b4Smrg 4487117f1b4Smrg /* Pass BindVertexArray call to device driver */ 4497117f1b4Smrg if (ctx->Driver.BindArrayObject && newObj) 4504a49301eSmrg ctx->Driver.BindArrayObject(ctx, newObj); 4514a49301eSmrg} 4524a49301eSmrg 4534a49301eSmrg 4544a49301eSmrg/** 4554a49301eSmrg * ARB version of glBindVertexArray() 4564a49301eSmrg * This function behaves differently from glBindVertexArrayAPPLE() in 4574a49301eSmrg * that this function requires all ids to have been previously generated 4584a49301eSmrg * by glGenVertexArrays[APPLE](). 4594a49301eSmrg */ 4604a49301eSmrgvoid GLAPIENTRY 4614a49301eSmrg_mesa_BindVertexArray( GLuint id ) 4624a49301eSmrg{ 4634a49301eSmrg GET_CURRENT_CONTEXT(ctx); 4644a49301eSmrg bind_vertex_array(ctx, id, GL_TRUE); 4654a49301eSmrg} 4664a49301eSmrg 4674a49301eSmrg 4684a49301eSmrg/** 4694a49301eSmrg * Bind a new array. 4704a49301eSmrg * 4714a49301eSmrg * \todo 4724a49301eSmrg * The binding could be done more efficiently by comparing the non-NULL 4734a49301eSmrg * pointers in the old and new objects. The only arrays that are "dirty" are 4744a49301eSmrg * the ones that are non-NULL in either object. 4754a49301eSmrg */ 4764a49301eSmrgvoid GLAPIENTRY 4774a49301eSmrg_mesa_BindVertexArrayAPPLE( GLuint id ) 4784a49301eSmrg{ 4794a49301eSmrg GET_CURRENT_CONTEXT(ctx); 4804a49301eSmrg bind_vertex_array(ctx, id, GL_FALSE); 4817117f1b4Smrg} 4827117f1b4Smrg 4837117f1b4Smrg 4847117f1b4Smrg/** 4857117f1b4Smrg * Delete a set of array objects. 486af69d88dSmrg * 4877117f1b4Smrg * \param n Number of array objects to delete. 4887117f1b4Smrg * \param ids Array of \c n array object IDs. 4897117f1b4Smrg */ 4907117f1b4Smrgvoid GLAPIENTRY 491af69d88dSmrg_mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids) 4927117f1b4Smrg{ 4937117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4947117f1b4Smrg GLsizei i; 4957117f1b4Smrg 4967117f1b4Smrg if (n < 0) { 497af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArray(n)"); 4987117f1b4Smrg return; 4997117f1b4Smrg } 5007117f1b4Smrg 5017117f1b4Smrg for (i = 0; i < n; i++) { 502af69d88dSmrg struct gl_vertex_array_object *obj = _mesa_lookup_vao(ctx, ids[i]); 5037117f1b4Smrg 5047117f1b4Smrg if ( obj != NULL ) { 5057117f1b4Smrg ASSERT( obj->Name == ids[i] ); 5067117f1b4Smrg 5077117f1b4Smrg /* If the array object is currently bound, the spec says "the binding 5087117f1b4Smrg * for that object reverts to zero and the default vertex array 5097117f1b4Smrg * becomes current." 5107117f1b4Smrg */ 511af69d88dSmrg if ( obj == ctx->Array.VAO ) { 512af69d88dSmrg _mesa_BindVertexArray(0); 5137117f1b4Smrg } 5147117f1b4Smrg 5157117f1b4Smrg /* The ID is immediately freed for re-use */ 5164a49301eSmrg remove_array_object(ctx, obj); 5174a49301eSmrg 5184a49301eSmrg /* Unreference the array object. 5194a49301eSmrg * If refcount hits zero, the object will be deleted. 5204a49301eSmrg */ 521af69d88dSmrg _mesa_reference_vao(ctx, &obj, NULL); 5227117f1b4Smrg } 5237117f1b4Smrg } 5247117f1b4Smrg} 5257117f1b4Smrg 5267117f1b4Smrg 5277117f1b4Smrg/** 5287117f1b4Smrg * Generate a set of unique array object IDs and store them in \c arrays. 5294a49301eSmrg * Helper for _mesa_GenVertexArrays[APPLE]() functions below. 5307117f1b4Smrg * \param n Number of IDs to generate. 5317117f1b4Smrg * \param arrays Array of \c n locations to store the IDs. 5324a49301eSmrg * \param vboOnly Will arrays have to reside in VBOs? 5337117f1b4Smrg */ 534af69d88dSmrgstatic void 535af69d88dSmrggen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays) 5367117f1b4Smrg{ 5377117f1b4Smrg GLuint first; 5387117f1b4Smrg GLint i; 5397117f1b4Smrg 5407117f1b4Smrg if (n < 0) { 541af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArrays"); 5427117f1b4Smrg return; 5437117f1b4Smrg } 5447117f1b4Smrg 5457117f1b4Smrg if (!arrays) { 5467117f1b4Smrg return; 5477117f1b4Smrg } 5487117f1b4Smrg 5494a49301eSmrg first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n); 5507117f1b4Smrg 5517117f1b4Smrg /* Allocate new, empty array objects and return identifiers */ 5527117f1b4Smrg for (i = 0; i < n; i++) { 553af69d88dSmrg struct gl_vertex_array_object *obj; 5547117f1b4Smrg GLuint name = first + i; 5557117f1b4Smrg 5567117f1b4Smrg obj = (*ctx->Driver.NewArrayObject)( ctx, name ); 5577117f1b4Smrg if (!obj) { 558af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArrays"); 5597117f1b4Smrg return; 5607117f1b4Smrg } 5614a49301eSmrg save_array_object(ctx, obj); 5627117f1b4Smrg arrays[i] = first + i; 5637117f1b4Smrg } 5644a49301eSmrg} 5654a49301eSmrg 5664a49301eSmrg 5674a49301eSmrg/** 5684a49301eSmrg * ARB version of glGenVertexArrays() 5694a49301eSmrg * All arrays will be required to live in VBOs. 5704a49301eSmrg */ 5714a49301eSmrgvoid GLAPIENTRY 5724a49301eSmrg_mesa_GenVertexArrays(GLsizei n, GLuint *arrays) 5734a49301eSmrg{ 5744a49301eSmrg GET_CURRENT_CONTEXT(ctx); 575af69d88dSmrg gen_vertex_arrays(ctx, n, arrays); 5764a49301eSmrg} 5774a49301eSmrg 5787117f1b4Smrg 5794a49301eSmrg/** 5804a49301eSmrg * APPLE version of glGenVertexArraysAPPLE() 5814a49301eSmrg * Arrays may live in VBOs or ordinary memory. 5824a49301eSmrg */ 5834a49301eSmrgvoid GLAPIENTRY 5844a49301eSmrg_mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays) 5854a49301eSmrg{ 5864a49301eSmrg GET_CURRENT_CONTEXT(ctx); 587af69d88dSmrg gen_vertex_arrays(ctx, n, arrays); 5887117f1b4Smrg} 5897117f1b4Smrg 5907117f1b4Smrg 5917117f1b4Smrg/** 5927117f1b4Smrg * Determine if ID is the name of an array object. 593af69d88dSmrg * 5947117f1b4Smrg * \param id ID of the potential array object. 595af69d88dSmrg * \return \c GL_TRUE if \c id is the name of a array object, 5967117f1b4Smrg * \c GL_FALSE otherwise. 5977117f1b4Smrg */ 5987117f1b4SmrgGLboolean GLAPIENTRY 599af69d88dSmrg_mesa_IsVertexArray( GLuint id ) 6007117f1b4Smrg{ 601af69d88dSmrg struct gl_vertex_array_object * obj; 6027117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 6037117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 6047117f1b4Smrg 6057117f1b4Smrg if (id == 0) 6067117f1b4Smrg return GL_FALSE; 6077117f1b4Smrg 608af69d88dSmrg obj = _mesa_lookup_vao(ctx, id); 609af69d88dSmrg if (obj == NULL) 610af69d88dSmrg return GL_FALSE; 6117117f1b4Smrg 612af69d88dSmrg return obj->EverBound; 6137117f1b4Smrg} 614