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