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