arrayobj.c revision 4a49301e
17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 34a49301eSmrg * Version: 7.6 47117f1b4Smrg * 5c1f859d4Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 67117f1b4Smrg * (C) Copyright IBM Corporation 2006 74a49301eSmrg * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 87117f1b4Smrg * 97117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 107117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 117117f1b4Smrg * to deal in the Software without restriction, including without limitation 127117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 137117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 147117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 157117f1b4Smrg * 167117f1b4Smrg * The above copyright notice and this permission notice shall be included 177117f1b4Smrg * in all copies or substantial portions of the Software. 187117f1b4Smrg * 197117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 207117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 217117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 227117f1b4Smrg * BRIAN PAUL OR IBM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 237117f1b4Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 247117f1b4Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 257117f1b4Smrg * SOFTWARE. 267117f1b4Smrg */ 277117f1b4Smrg 287117f1b4Smrg 297117f1b4Smrg/** 307117f1b4Smrg * \file arrayobj.c 317117f1b4Smrg * Functions for the GL_APPLE_vertex_array_object extension. 327117f1b4Smrg * 337117f1b4Smrg * \todo 347117f1b4Smrg * The code in this file borrows a lot from bufferobj.c. There's a certain 357117f1b4Smrg * amount of cruft left over from that origin that may be unnecessary. 367117f1b4Smrg * 377117f1b4Smrg * \author Ian Romanick <idr@us.ibm.com> 387117f1b4Smrg * \author Brian Paul 397117f1b4Smrg */ 407117f1b4Smrg 417117f1b4Smrg 427117f1b4Smrg#include "glheader.h" 437117f1b4Smrg#include "hash.h" 447117f1b4Smrg#include "imports.h" 457117f1b4Smrg#include "context.h" 467117f1b4Smrg#if FEATURE_ARB_vertex_buffer_object 477117f1b4Smrg#include "bufferobj.h" 487117f1b4Smrg#endif 497117f1b4Smrg#include "arrayobj.h" 504a49301eSmrg#include "macros.h" 51c1f859d4Smrg#include "glapi/dispatch.h" 527117f1b4Smrg 537117f1b4Smrg 547117f1b4Smrg/** 557117f1b4Smrg * Look up the array object for the given ID. 567117f1b4Smrg * 577117f1b4Smrg * \returns 587117f1b4Smrg * Either a pointer to the array object with the specified ID or \c NULL for 597117f1b4Smrg * a non-existent ID. The spec defines ID 0 as being technically 607117f1b4Smrg * non-existent. 617117f1b4Smrg */ 627117f1b4Smrg 637117f1b4Smrgstatic INLINE struct gl_array_object * 647117f1b4Smrglookup_arrayobj(GLcontext *ctx, GLuint id) 657117f1b4Smrg{ 664a49301eSmrg if (id == 0) 674a49301eSmrg return NULL; 684a49301eSmrg else 694a49301eSmrg return (struct gl_array_object *) 704a49301eSmrg _mesa_HashLookup(ctx->Array.Objects, id); 714a49301eSmrg} 724a49301eSmrg 734a49301eSmrg 744a49301eSmrg/** 754a49301eSmrg * For all the vertex arrays in the array object, unbind any pointers 764a49301eSmrg * to any buffer objects (VBOs). 774a49301eSmrg * This is done just prior to array object destruction. 784a49301eSmrg */ 794a49301eSmrgstatic void 804a49301eSmrgunbind_array_object_vbos(GLcontext *ctx, struct gl_array_object *obj) 814a49301eSmrg{ 824a49301eSmrg GLuint i; 834a49301eSmrg 844a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->Vertex.BufferObj, NULL); 854a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->Weight.BufferObj, NULL); 864a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->Normal.BufferObj, NULL); 874a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->Color.BufferObj, NULL); 884a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->SecondaryColor.BufferObj, NULL); 894a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->FogCoord.BufferObj, NULL); 904a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->Index.BufferObj, NULL); 914a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->EdgeFlag.BufferObj, NULL); 924a49301eSmrg 934a49301eSmrg for (i = 0; i < Elements(obj->TexCoord); i++) 944a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->TexCoord[i].BufferObj, NULL); 954a49301eSmrg 964a49301eSmrg for (i = 0; i < Elements(obj->VertexAttrib); i++) 974a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->VertexAttrib[i].BufferObj,NULL); 984a49301eSmrg 994a49301eSmrg#if FEATURE_point_size_array 1004a49301eSmrg _mesa_reference_buffer_object(ctx, &obj->PointSize.BufferObj, NULL); 1014a49301eSmrg#endif 1027117f1b4Smrg} 1037117f1b4Smrg 1047117f1b4Smrg 1057117f1b4Smrg/** 1067117f1b4Smrg * Allocate and initialize a new vertex array object. 1077117f1b4Smrg * 1087117f1b4Smrg * This function is intended to be called via 1097117f1b4Smrg * \c dd_function_table::NewArrayObject. 1107117f1b4Smrg */ 1117117f1b4Smrgstruct gl_array_object * 1127117f1b4Smrg_mesa_new_array_object( GLcontext *ctx, GLuint name ) 1137117f1b4Smrg{ 114c1f859d4Smrg struct gl_array_object *obj = CALLOC_STRUCT(gl_array_object); 1157117f1b4Smrg if (obj) 1167117f1b4Smrg _mesa_initialize_array_object(ctx, obj, name); 1177117f1b4Smrg return obj; 1187117f1b4Smrg} 1197117f1b4Smrg 1207117f1b4Smrg 1217117f1b4Smrg/** 1227117f1b4Smrg * Delete an array object. 1237117f1b4Smrg * 1247117f1b4Smrg * This function is intended to be called via 1257117f1b4Smrg * \c dd_function_table::DeleteArrayObject. 1267117f1b4Smrg */ 1277117f1b4Smrgvoid 1287117f1b4Smrg_mesa_delete_array_object( GLcontext *ctx, struct gl_array_object *obj ) 1297117f1b4Smrg{ 1307117f1b4Smrg (void) ctx; 1314a49301eSmrg unbind_array_object_vbos(ctx, obj); 1324a49301eSmrg _glthread_DESTROY_MUTEX(obj->Mutex); 1337117f1b4Smrg _mesa_free(obj); 1347117f1b4Smrg} 1357117f1b4Smrg 1367117f1b4Smrg 1374a49301eSmrg/** 1384a49301eSmrg * Set ptr to arrayObj w/ reference counting. 1394a49301eSmrg */ 1404a49301eSmrgvoid 1414a49301eSmrg_mesa_reference_array_object(GLcontext *ctx, 1424a49301eSmrg struct gl_array_object **ptr, 1434a49301eSmrg struct gl_array_object *arrayObj) 1444a49301eSmrg{ 1454a49301eSmrg if (*ptr == arrayObj) 1464a49301eSmrg return; 1474a49301eSmrg 1484a49301eSmrg if (*ptr) { 1494a49301eSmrg /* Unreference the old array object */ 1504a49301eSmrg GLboolean deleteFlag = GL_FALSE; 1514a49301eSmrg struct gl_array_object *oldObj = *ptr; 1524a49301eSmrg 1534a49301eSmrg _glthread_LOCK_MUTEX(oldObj->Mutex); 1544a49301eSmrg ASSERT(oldObj->RefCount > 0); 1554a49301eSmrg oldObj->RefCount--; 1564a49301eSmrg#if 0 1574a49301eSmrg printf("ArrayObj %p %d DECR to %d\n", 1584a49301eSmrg (void *) oldObj, oldObj->Name, oldObj->RefCount); 1594a49301eSmrg#endif 1604a49301eSmrg deleteFlag = (oldObj->RefCount == 0); 1614a49301eSmrg _glthread_UNLOCK_MUTEX(oldObj->Mutex); 1624a49301eSmrg 1634a49301eSmrg if (deleteFlag) { 1644a49301eSmrg ASSERT(ctx->Driver.DeleteArrayObject); 1654a49301eSmrg ctx->Driver.DeleteArrayObject(ctx, oldObj); 1664a49301eSmrg } 1674a49301eSmrg 1684a49301eSmrg *ptr = NULL; 1694a49301eSmrg } 1704a49301eSmrg ASSERT(!*ptr); 1714a49301eSmrg 1724a49301eSmrg if (arrayObj) { 1734a49301eSmrg /* reference new array object */ 1744a49301eSmrg _glthread_LOCK_MUTEX(arrayObj->Mutex); 1754a49301eSmrg if (arrayObj->RefCount == 0) { 1764a49301eSmrg /* this array's being deleted (look just above) */ 1774a49301eSmrg /* Not sure this can every really happen. Warn if it does. */ 1784a49301eSmrg _mesa_problem(NULL, "referencing deleted array object"); 1794a49301eSmrg *ptr = NULL; 1804a49301eSmrg } 1814a49301eSmrg else { 1824a49301eSmrg arrayObj->RefCount++; 1834a49301eSmrg#if 0 1844a49301eSmrg printf("ArrayObj %p %d INCR to %d\n", 1854a49301eSmrg (void *) arrayObj, arrayObj->Name, arrayObj->RefCount); 1864a49301eSmrg#endif 1874a49301eSmrg *ptr = arrayObj; 1884a49301eSmrg } 1894a49301eSmrg _glthread_UNLOCK_MUTEX(arrayObj->Mutex); 1904a49301eSmrg } 1914a49301eSmrg} 1924a49301eSmrg 1934a49301eSmrg 1944a49301eSmrg 1954a49301eSmrgstatic void 1964a49301eSmrginit_array(GLcontext *ctx, 1974a49301eSmrg struct gl_client_array *array, GLint size, GLint type) 1984a49301eSmrg{ 1994a49301eSmrg array->Size = size; 2004a49301eSmrg array->Type = type; 2014a49301eSmrg array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */ 2024a49301eSmrg array->Stride = 0; 2034a49301eSmrg array->StrideB = 0; 2044a49301eSmrg array->Ptr = NULL; 2054a49301eSmrg array->Enabled = GL_FALSE; 2064a49301eSmrg array->Normalized = GL_FALSE; 2074a49301eSmrg#if FEATURE_ARB_vertex_buffer_object 2084a49301eSmrg /* Vertex array buffers */ 2094a49301eSmrg _mesa_reference_buffer_object(ctx, &array->BufferObj, 2104a49301eSmrg ctx->Shared->NullBufferObj); 2114a49301eSmrg#endif 2124a49301eSmrg} 2134a49301eSmrg 2144a49301eSmrg 2154a49301eSmrg/** 2164a49301eSmrg * Initialize a gl_array_object's arrays. 2174a49301eSmrg */ 2187117f1b4Smrgvoid 2197117f1b4Smrg_mesa_initialize_array_object( GLcontext *ctx, 2207117f1b4Smrg struct gl_array_object *obj, 2217117f1b4Smrg GLuint name ) 2227117f1b4Smrg{ 2237117f1b4Smrg GLuint i; 2247117f1b4Smrg 2257117f1b4Smrg obj->Name = name; 2267117f1b4Smrg 2274a49301eSmrg _glthread_INIT_MUTEX(obj->Mutex); 2284a49301eSmrg obj->RefCount = 1; 2294a49301eSmrg 2304a49301eSmrg /* Init the individual arrays */ 2314a49301eSmrg init_array(ctx, &obj->Vertex, 4, GL_FLOAT); 2324a49301eSmrg init_array(ctx, &obj->Weight, 1, GL_FLOAT); 2334a49301eSmrg init_array(ctx, &obj->Normal, 3, GL_FLOAT); 2344a49301eSmrg init_array(ctx, &obj->Color, 4, GL_FLOAT); 2354a49301eSmrg init_array(ctx, &obj->SecondaryColor, 4, GL_FLOAT); 2364a49301eSmrg init_array(ctx, &obj->FogCoord, 1, GL_FLOAT); 2374a49301eSmrg init_array(ctx, &obj->Index, 1, GL_FLOAT); 2384a49301eSmrg for (i = 0; i < Elements(obj->TexCoord); i++) { 2394a49301eSmrg init_array(ctx, &obj->TexCoord[i], 4, GL_FLOAT); 2407117f1b4Smrg } 2414a49301eSmrg init_array(ctx, &obj->EdgeFlag, 1, GL_BOOL); 2424a49301eSmrg for (i = 0; i < Elements(obj->VertexAttrib); i++) { 2434a49301eSmrg init_array(ctx, &obj->VertexAttrib[i], 4, GL_FLOAT); 2447117f1b4Smrg } 2457117f1b4Smrg 246c1f859d4Smrg#if FEATURE_point_size_array 2474a49301eSmrg init_array(ctx, &obj->PointSize, 1, GL_FLOAT); 2487117f1b4Smrg#endif 2497117f1b4Smrg} 2507117f1b4Smrg 2517117f1b4Smrg 2527117f1b4Smrg/** 2537117f1b4Smrg * Add the given array object to the array object pool. 2547117f1b4Smrg */ 2554a49301eSmrgstatic void 2564a49301eSmrgsave_array_object( GLcontext *ctx, struct gl_array_object *obj ) 2577117f1b4Smrg{ 2587117f1b4Smrg if (obj->Name > 0) { 2597117f1b4Smrg /* insert into hash table */ 2604a49301eSmrg _mesa_HashInsert(ctx->Array.Objects, obj->Name, obj); 2617117f1b4Smrg } 2627117f1b4Smrg} 2637117f1b4Smrg 2647117f1b4Smrg 2657117f1b4Smrg/** 2667117f1b4Smrg * Remove the given array object from the array object pool. 2677117f1b4Smrg * Do not deallocate the array object though. 2687117f1b4Smrg */ 2694a49301eSmrgstatic void 2704a49301eSmrgremove_array_object( GLcontext *ctx, struct gl_array_object *obj ) 2717117f1b4Smrg{ 2727117f1b4Smrg if (obj->Name > 0) { 2737117f1b4Smrg /* remove from hash table */ 2744a49301eSmrg _mesa_HashRemove(ctx->Array.Objects, obj->Name); 2757117f1b4Smrg } 2767117f1b4Smrg} 2777117f1b4Smrg 2787117f1b4Smrg 2794a49301eSmrg 2804a49301eSmrg/** 2814a49301eSmrg * Compute the index of the last array element that can be safely accessed 2824a49301eSmrg * in a vertex array. We can really only do this when the array lives in 2834a49301eSmrg * a VBO. 2844a49301eSmrg * The array->_MaxElement field will be updated. 2854a49301eSmrg * Later in glDrawArrays/Elements/etc we can do some bounds checking. 2864a49301eSmrg */ 287c1f859d4Smrgstatic void 2884a49301eSmrgcompute_max_element(struct gl_client_array *array) 289c1f859d4Smrg{ 2904a49301eSmrg if (array->BufferObj->Name) { 2914a49301eSmrg /* Compute the max element we can access in the VBO without going 2924a49301eSmrg * out of bounds. 2934a49301eSmrg */ 2944a49301eSmrg array->_MaxElement = ((GLsizeiptrARB) array->BufferObj->Size 2954a49301eSmrg - (GLsizeiptrARB) array->Ptr + array->StrideB 2964a49301eSmrg - array->_ElementSize) / array->StrideB; 2974a49301eSmrg if (0) 2984a49301eSmrg _mesa_printf("%s Object %u Size %u MaxElement %u\n", 2994a49301eSmrg __FUNCTION__, 3004a49301eSmrg array->BufferObj->Name, 3014a49301eSmrg (GLuint) array->BufferObj->Size, 3024a49301eSmrg array->_MaxElement); 303c1f859d4Smrg } 3044a49301eSmrg else { 3054a49301eSmrg /* user-space array, no idea how big it is */ 3064a49301eSmrg array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */ 3074a49301eSmrg } 3084a49301eSmrg} 3094a49301eSmrg 3104a49301eSmrg 3114a49301eSmrg/** 3124a49301eSmrg * Helper for update_arrays(). 3134a49301eSmrg * \return min(current min, array->_MaxElement). 3144a49301eSmrg */ 3154a49301eSmrgstatic GLuint 3164a49301eSmrgupdate_min(GLuint min, struct gl_client_array *array) 3174a49301eSmrg{ 3184a49301eSmrg compute_max_element(array); 3194a49301eSmrg if (array->Enabled) 3204a49301eSmrg return MIN2(min, array->_MaxElement); 3214a49301eSmrg else 3224a49301eSmrg return min; 3234a49301eSmrg} 3244a49301eSmrg 3254a49301eSmrg 3264a49301eSmrg/** 3274a49301eSmrg * Examine vertex arrays to update the gl_array_object::_MaxElement field. 3284a49301eSmrg */ 3294a49301eSmrgvoid 3304a49301eSmrg_mesa_update_array_object_max_element(GLcontext *ctx, 3314a49301eSmrg struct gl_array_object *arrayObj) 3324a49301eSmrg{ 3334a49301eSmrg GLuint i, min = ~0; 3344a49301eSmrg 3354a49301eSmrg min = update_min(min, &arrayObj->Vertex); 3364a49301eSmrg min = update_min(min, &arrayObj->Weight); 3374a49301eSmrg min = update_min(min, &arrayObj->Normal); 3384a49301eSmrg min = update_min(min, &arrayObj->Color); 3394a49301eSmrg min = update_min(min, &arrayObj->SecondaryColor); 3404a49301eSmrg min = update_min(min, &arrayObj->FogCoord); 3414a49301eSmrg min = update_min(min, &arrayObj->Index); 3424a49301eSmrg min = update_min(min, &arrayObj->EdgeFlag); 3434a49301eSmrg#if FEATURE_point_size_array 3444a49301eSmrg min = update_min(min, &arrayObj->PointSize); 3454a49301eSmrg#endif 3464a49301eSmrg for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) 3474a49301eSmrg min = update_min(min, &arrayObj->TexCoord[i]); 3484a49301eSmrg for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) 3494a49301eSmrg min = update_min(min, &arrayObj->VertexAttrib[i]); 3504a49301eSmrg 3514a49301eSmrg /* _MaxElement is one past the last legal array element */ 3524a49301eSmrg arrayObj->_MaxElement = min; 353c1f859d4Smrg} 354c1f859d4Smrg 355c1f859d4Smrg 3567117f1b4Smrg/**********************************************************************/ 3577117f1b4Smrg/* API Functions */ 3587117f1b4Smrg/**********************************************************************/ 3597117f1b4Smrg 3604a49301eSmrg 3617117f1b4Smrg/** 3624a49301eSmrg * Helper for _mesa_BindVertexArray() and _mesa_BindVertexArrayAPPLE(). 3634a49301eSmrg * \param genRequired specifies behavour when id was not generated with 3644a49301eSmrg * glGenVertexArrays(). 3657117f1b4Smrg */ 3664a49301eSmrgstatic void 3674a49301eSmrgbind_vertex_array(GLcontext *ctx, GLuint id, GLboolean genRequired) 3687117f1b4Smrg{ 3697117f1b4Smrg struct gl_array_object * const oldObj = ctx->Array.ArrayObj; 3707117f1b4Smrg struct gl_array_object *newObj = NULL; 3717117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 3727117f1b4Smrg 3737117f1b4Smrg ASSERT(oldObj != NULL); 3747117f1b4Smrg 3757117f1b4Smrg if ( oldObj->Name == id ) 3767117f1b4Smrg return; /* rebinding the same array object- no change */ 3777117f1b4Smrg 3787117f1b4Smrg /* 3794a49301eSmrg * Get pointer to new array object (newObj) 3807117f1b4Smrg */ 3817117f1b4Smrg if (id == 0) { 3827117f1b4Smrg /* The spec says there is no array object named 0, but we use 3837117f1b4Smrg * one internally because it simplifies things. 3847117f1b4Smrg */ 3857117f1b4Smrg newObj = ctx->Array.DefaultArrayObj; 3867117f1b4Smrg } 3877117f1b4Smrg else { 3887117f1b4Smrg /* non-default array object */ 3897117f1b4Smrg newObj = lookup_arrayobj(ctx, id); 3907117f1b4Smrg if (!newObj) { 3914a49301eSmrg if (genRequired) { 3924a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBindVertexArray(id)"); 3934a49301eSmrg return; 3944a49301eSmrg } 3957117f1b4Smrg 3964a49301eSmrg /* For APPLE version, generate a new array object now */ 3977117f1b4Smrg newObj = (*ctx->Driver.NewArrayObject)(ctx, id); 3987117f1b4Smrg if (!newObj) { 3997117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindVertexArrayAPPLE"); 4007117f1b4Smrg return; 4017117f1b4Smrg } 4024a49301eSmrg save_array_object(ctx, newObj); 4037117f1b4Smrg } 4047117f1b4Smrg } 4057117f1b4Smrg 4067117f1b4Smrg ctx->NewState |= _NEW_ARRAY; 4077117f1b4Smrg ctx->Array.NewState |= _NEW_ARRAY_ALL; 4084a49301eSmrg _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, newObj); 4097117f1b4Smrg 4107117f1b4Smrg /* Pass BindVertexArray call to device driver */ 4117117f1b4Smrg if (ctx->Driver.BindArrayObject && newObj) 4124a49301eSmrg ctx->Driver.BindArrayObject(ctx, newObj); 4134a49301eSmrg} 4144a49301eSmrg 4154a49301eSmrg 4164a49301eSmrg/** 4174a49301eSmrg * ARB version of glBindVertexArray() 4184a49301eSmrg * This function behaves differently from glBindVertexArrayAPPLE() in 4194a49301eSmrg * that this function requires all ids to have been previously generated 4204a49301eSmrg * by glGenVertexArrays[APPLE](). 4214a49301eSmrg */ 4224a49301eSmrgvoid GLAPIENTRY 4234a49301eSmrg_mesa_BindVertexArray( GLuint id ) 4244a49301eSmrg{ 4254a49301eSmrg GET_CURRENT_CONTEXT(ctx); 4264a49301eSmrg bind_vertex_array(ctx, id, GL_TRUE); 4274a49301eSmrg} 4284a49301eSmrg 4294a49301eSmrg 4304a49301eSmrg/** 4314a49301eSmrg * Bind a new array. 4324a49301eSmrg * 4334a49301eSmrg * \todo 4344a49301eSmrg * The binding could be done more efficiently by comparing the non-NULL 4354a49301eSmrg * pointers in the old and new objects. The only arrays that are "dirty" are 4364a49301eSmrg * the ones that are non-NULL in either object. 4374a49301eSmrg */ 4384a49301eSmrgvoid GLAPIENTRY 4394a49301eSmrg_mesa_BindVertexArrayAPPLE( GLuint id ) 4404a49301eSmrg{ 4414a49301eSmrg GET_CURRENT_CONTEXT(ctx); 4424a49301eSmrg bind_vertex_array(ctx, id, GL_FALSE); 4437117f1b4Smrg} 4447117f1b4Smrg 4457117f1b4Smrg 4467117f1b4Smrg/** 4477117f1b4Smrg * Delete a set of array objects. 4487117f1b4Smrg * 4497117f1b4Smrg * \param n Number of array objects to delete. 4507117f1b4Smrg * \param ids Array of \c n array object IDs. 4517117f1b4Smrg */ 4527117f1b4Smrgvoid GLAPIENTRY 4537117f1b4Smrg_mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids) 4547117f1b4Smrg{ 4557117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4567117f1b4Smrg GLsizei i; 4577117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 4587117f1b4Smrg 4597117f1b4Smrg if (n < 0) { 4607117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArrayAPPLE(n)"); 4617117f1b4Smrg return; 4627117f1b4Smrg } 4637117f1b4Smrg 4647117f1b4Smrg for (i = 0; i < n; i++) { 4657117f1b4Smrg struct gl_array_object *obj = lookup_arrayobj(ctx, ids[i]); 4667117f1b4Smrg 4677117f1b4Smrg if ( obj != NULL ) { 4687117f1b4Smrg ASSERT( obj->Name == ids[i] ); 4697117f1b4Smrg 4707117f1b4Smrg /* If the array object is currently bound, the spec says "the binding 4717117f1b4Smrg * for that object reverts to zero and the default vertex array 4727117f1b4Smrg * becomes current." 4737117f1b4Smrg */ 4747117f1b4Smrg if ( obj == ctx->Array.ArrayObj ) { 4757117f1b4Smrg CALL_BindVertexArrayAPPLE( ctx->Exec, (0) ); 4767117f1b4Smrg } 4777117f1b4Smrg 4787117f1b4Smrg /* The ID is immediately freed for re-use */ 4794a49301eSmrg remove_array_object(ctx, obj); 4804a49301eSmrg 4814a49301eSmrg /* Unreference the array object. 4824a49301eSmrg * If refcount hits zero, the object will be deleted. 4834a49301eSmrg */ 4844a49301eSmrg _mesa_reference_array_object(ctx, &obj, NULL); 4857117f1b4Smrg } 4867117f1b4Smrg } 4877117f1b4Smrg} 4887117f1b4Smrg 4897117f1b4Smrg 4907117f1b4Smrg/** 4917117f1b4Smrg * Generate a set of unique array object IDs and store them in \c arrays. 4924a49301eSmrg * Helper for _mesa_GenVertexArrays[APPLE]() functions below. 4937117f1b4Smrg * \param n Number of IDs to generate. 4947117f1b4Smrg * \param arrays Array of \c n locations to store the IDs. 4954a49301eSmrg * \param vboOnly Will arrays have to reside in VBOs? 4967117f1b4Smrg */ 4974a49301eSmrgstatic void 4984a49301eSmrggen_vertex_arrays(GLcontext *ctx, GLsizei n, GLuint *arrays, GLboolean vboOnly) 4997117f1b4Smrg{ 5007117f1b4Smrg GLuint first; 5017117f1b4Smrg GLint i; 5027117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 5037117f1b4Smrg 5047117f1b4Smrg if (n < 0) { 5057117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArraysAPPLE"); 5067117f1b4Smrg return; 5077117f1b4Smrg } 5087117f1b4Smrg 5097117f1b4Smrg if (!arrays) { 5107117f1b4Smrg return; 5117117f1b4Smrg } 5127117f1b4Smrg 5134a49301eSmrg first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n); 5147117f1b4Smrg 5157117f1b4Smrg /* Allocate new, empty array objects and return identifiers */ 5167117f1b4Smrg for (i = 0; i < n; i++) { 5177117f1b4Smrg struct gl_array_object *obj; 5187117f1b4Smrg GLuint name = first + i; 5197117f1b4Smrg 5207117f1b4Smrg obj = (*ctx->Driver.NewArrayObject)( ctx, name ); 5217117f1b4Smrg if (!obj) { 5227117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArraysAPPLE"); 5237117f1b4Smrg return; 5247117f1b4Smrg } 5254a49301eSmrg obj->VBOonly = vboOnly; 5264a49301eSmrg save_array_object(ctx, obj); 5277117f1b4Smrg arrays[i] = first + i; 5287117f1b4Smrg } 5294a49301eSmrg} 5304a49301eSmrg 5314a49301eSmrg 5324a49301eSmrg/** 5334a49301eSmrg * ARB version of glGenVertexArrays() 5344a49301eSmrg * All arrays will be required to live in VBOs. 5354a49301eSmrg */ 5364a49301eSmrgvoid GLAPIENTRY 5374a49301eSmrg_mesa_GenVertexArrays(GLsizei n, GLuint *arrays) 5384a49301eSmrg{ 5394a49301eSmrg GET_CURRENT_CONTEXT(ctx); 5404a49301eSmrg gen_vertex_arrays(ctx, n, arrays, GL_TRUE); 5414a49301eSmrg} 5424a49301eSmrg 5437117f1b4Smrg 5444a49301eSmrg/** 5454a49301eSmrg * APPLE version of glGenVertexArraysAPPLE() 5464a49301eSmrg * Arrays may live in VBOs or ordinary memory. 5474a49301eSmrg */ 5484a49301eSmrgvoid GLAPIENTRY 5494a49301eSmrg_mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays) 5504a49301eSmrg{ 5514a49301eSmrg GET_CURRENT_CONTEXT(ctx); 5524a49301eSmrg gen_vertex_arrays(ctx, n, arrays, GL_FALSE); 5537117f1b4Smrg} 5547117f1b4Smrg 5557117f1b4Smrg 5567117f1b4Smrg/** 5577117f1b4Smrg * Determine if ID is the name of an array object. 5587117f1b4Smrg * 5597117f1b4Smrg * \param id ID of the potential array object. 5607117f1b4Smrg * \return \c GL_TRUE if \c id is the name of a array object, 5617117f1b4Smrg * \c GL_FALSE otherwise. 5627117f1b4Smrg */ 5637117f1b4SmrgGLboolean GLAPIENTRY 5647117f1b4Smrg_mesa_IsVertexArrayAPPLE( GLuint id ) 5657117f1b4Smrg{ 5667117f1b4Smrg struct gl_array_object * obj; 5677117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5687117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 5697117f1b4Smrg 5707117f1b4Smrg if (id == 0) 5717117f1b4Smrg return GL_FALSE; 5727117f1b4Smrg 5737117f1b4Smrg obj = lookup_arrayobj(ctx, id); 5747117f1b4Smrg 5757117f1b4Smrg return (obj != NULL) ? GL_TRUE : GL_FALSE; 5767117f1b4Smrg} 577