arrayobj.c revision 7117f1b4
17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * Version: 6.5 47117f1b4Smrg * 57117f1b4Smrg * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. 67117f1b4Smrg * (C) Copyright IBM Corporation 2006 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 217117f1b4Smrg * BRIAN PAUL OR IBM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 227117f1b4Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 237117f1b4Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 247117f1b4Smrg * SOFTWARE. 257117f1b4Smrg */ 267117f1b4Smrg 277117f1b4Smrg 287117f1b4Smrg/** 297117f1b4Smrg * \file arrayobj.c 307117f1b4Smrg * Functions for the GL_APPLE_vertex_array_object extension. 317117f1b4Smrg * 327117f1b4Smrg * \todo 337117f1b4Smrg * The code in this file borrows a lot from bufferobj.c. There's a certain 347117f1b4Smrg * amount of cruft left over from that origin that may be unnecessary. 357117f1b4Smrg * 367117f1b4Smrg * \author Ian Romanick <idr@us.ibm.com> 377117f1b4Smrg * \author Brian Paul 387117f1b4Smrg */ 397117f1b4Smrg 407117f1b4Smrg 417117f1b4Smrg#include "glheader.h" 427117f1b4Smrg#include "hash.h" 437117f1b4Smrg#include "imports.h" 447117f1b4Smrg#include "context.h" 457117f1b4Smrg#if FEATURE_ARB_vertex_buffer_object 467117f1b4Smrg#include "bufferobj.h" 477117f1b4Smrg#endif 487117f1b4Smrg#include "arrayobj.h" 497117f1b4Smrg#include "dispatch.h" 507117f1b4Smrg 517117f1b4Smrg 527117f1b4Smrg/** 537117f1b4Smrg * Look up the array object for the given ID. 547117f1b4Smrg * 557117f1b4Smrg * \returns 567117f1b4Smrg * Either a pointer to the array object with the specified ID or \c NULL for 577117f1b4Smrg * a non-existent ID. The spec defines ID 0 as being technically 587117f1b4Smrg * non-existent. 597117f1b4Smrg */ 607117f1b4Smrg 617117f1b4Smrgstatic INLINE struct gl_array_object * 627117f1b4Smrglookup_arrayobj(GLcontext *ctx, GLuint id) 637117f1b4Smrg{ 647117f1b4Smrg return (id == 0) 657117f1b4Smrg ? NULL 667117f1b4Smrg : (struct gl_array_object *) _mesa_HashLookup(ctx->Shared->ArrayObjects, 677117f1b4Smrg id); 687117f1b4Smrg} 697117f1b4Smrg 707117f1b4Smrg 717117f1b4Smrg/** 727117f1b4Smrg * Allocate and initialize a new vertex array object. 737117f1b4Smrg * 747117f1b4Smrg * This function is intended to be called via 757117f1b4Smrg * \c dd_function_table::NewArrayObject. 767117f1b4Smrg */ 777117f1b4Smrgstruct gl_array_object * 787117f1b4Smrg_mesa_new_array_object( GLcontext *ctx, GLuint name ) 797117f1b4Smrg{ 807117f1b4Smrg struct gl_array_object *obj = MALLOC_STRUCT(gl_array_object); 817117f1b4Smrg if (obj) 827117f1b4Smrg _mesa_initialize_array_object(ctx, obj, name); 837117f1b4Smrg return obj; 847117f1b4Smrg} 857117f1b4Smrg 867117f1b4Smrg 877117f1b4Smrg/** 887117f1b4Smrg * Delete an array object. 897117f1b4Smrg * 907117f1b4Smrg * This function is intended to be called via 917117f1b4Smrg * \c dd_function_table::DeleteArrayObject. 927117f1b4Smrg */ 937117f1b4Smrgvoid 947117f1b4Smrg_mesa_delete_array_object( GLcontext *ctx, struct gl_array_object *obj ) 957117f1b4Smrg{ 967117f1b4Smrg (void) ctx; 977117f1b4Smrg _mesa_free(obj); 987117f1b4Smrg} 997117f1b4Smrg 1007117f1b4Smrg 1017117f1b4Smrgvoid 1027117f1b4Smrg_mesa_initialize_array_object( GLcontext *ctx, 1037117f1b4Smrg struct gl_array_object *obj, 1047117f1b4Smrg GLuint name ) 1057117f1b4Smrg{ 1067117f1b4Smrg GLuint i; 1077117f1b4Smrg 1087117f1b4Smrg obj->Name = name; 1097117f1b4Smrg 1107117f1b4Smrg /* Vertex arrays */ 1117117f1b4Smrg obj->Vertex.Size = 4; 1127117f1b4Smrg obj->Vertex.Type = GL_FLOAT; 1137117f1b4Smrg obj->Vertex.Stride = 0; 1147117f1b4Smrg obj->Vertex.StrideB = 0; 1157117f1b4Smrg obj->Vertex.Ptr = NULL; 1167117f1b4Smrg obj->Vertex.Enabled = GL_FALSE; 1177117f1b4Smrg obj->Normal.Type = GL_FLOAT; 1187117f1b4Smrg obj->Normal.Stride = 0; 1197117f1b4Smrg obj->Normal.StrideB = 0; 1207117f1b4Smrg obj->Normal.Ptr = NULL; 1217117f1b4Smrg obj->Normal.Enabled = GL_FALSE; 1227117f1b4Smrg obj->Color.Size = 4; 1237117f1b4Smrg obj->Color.Type = GL_FLOAT; 1247117f1b4Smrg obj->Color.Stride = 0; 1257117f1b4Smrg obj->Color.StrideB = 0; 1267117f1b4Smrg obj->Color.Ptr = NULL; 1277117f1b4Smrg obj->Color.Enabled = GL_FALSE; 1287117f1b4Smrg obj->SecondaryColor.Size = 4; 1297117f1b4Smrg obj->SecondaryColor.Type = GL_FLOAT; 1307117f1b4Smrg obj->SecondaryColor.Stride = 0; 1317117f1b4Smrg obj->SecondaryColor.StrideB = 0; 1327117f1b4Smrg obj->SecondaryColor.Ptr = NULL; 1337117f1b4Smrg obj->SecondaryColor.Enabled = GL_FALSE; 1347117f1b4Smrg obj->FogCoord.Size = 1; 1357117f1b4Smrg obj->FogCoord.Type = GL_FLOAT; 1367117f1b4Smrg obj->FogCoord.Stride = 0; 1377117f1b4Smrg obj->FogCoord.StrideB = 0; 1387117f1b4Smrg obj->FogCoord.Ptr = NULL; 1397117f1b4Smrg obj->FogCoord.Enabled = GL_FALSE; 1407117f1b4Smrg obj->Index.Type = GL_FLOAT; 1417117f1b4Smrg obj->Index.Stride = 0; 1427117f1b4Smrg obj->Index.StrideB = 0; 1437117f1b4Smrg obj->Index.Ptr = NULL; 1447117f1b4Smrg obj->Index.Enabled = GL_FALSE; 1457117f1b4Smrg for (i = 0; i < MAX_TEXTURE_UNITS; i++) { 1467117f1b4Smrg obj->TexCoord[i].Size = 4; 1477117f1b4Smrg obj->TexCoord[i].Type = GL_FLOAT; 1487117f1b4Smrg obj->TexCoord[i].Stride = 0; 1497117f1b4Smrg obj->TexCoord[i].StrideB = 0; 1507117f1b4Smrg obj->TexCoord[i].Ptr = NULL; 1517117f1b4Smrg obj->TexCoord[i].Enabled = GL_FALSE; 1527117f1b4Smrg } 1537117f1b4Smrg obj->EdgeFlag.Stride = 0; 1547117f1b4Smrg obj->EdgeFlag.StrideB = 0; 1557117f1b4Smrg obj->EdgeFlag.Ptr = NULL; 1567117f1b4Smrg obj->EdgeFlag.Enabled = GL_FALSE; 1577117f1b4Smrg for (i = 0; i < VERT_ATTRIB_MAX; i++) { 1587117f1b4Smrg obj->VertexAttrib[i].Size = 4; 1597117f1b4Smrg obj->VertexAttrib[i].Type = GL_FLOAT; 1607117f1b4Smrg obj->VertexAttrib[i].Stride = 0; 1617117f1b4Smrg obj->VertexAttrib[i].StrideB = 0; 1627117f1b4Smrg obj->VertexAttrib[i].Ptr = NULL; 1637117f1b4Smrg obj->VertexAttrib[i].Enabled = GL_FALSE; 1647117f1b4Smrg obj->VertexAttrib[i].Normalized = GL_FALSE; 1657117f1b4Smrg } 1667117f1b4Smrg 1677117f1b4Smrg#if FEATURE_ARB_vertex_buffer_object 1687117f1b4Smrg /* Vertex array buffers */ 1697117f1b4Smrg obj->Vertex.BufferObj = ctx->Array.NullBufferObj; 1707117f1b4Smrg obj->Normal.BufferObj = ctx->Array.NullBufferObj; 1717117f1b4Smrg obj->Color.BufferObj = ctx->Array.NullBufferObj; 1727117f1b4Smrg obj->SecondaryColor.BufferObj = ctx->Array.NullBufferObj; 1737117f1b4Smrg obj->FogCoord.BufferObj = ctx->Array.NullBufferObj; 1747117f1b4Smrg obj->Index.BufferObj = ctx->Array.NullBufferObj; 1757117f1b4Smrg for (i = 0; i < MAX_TEXTURE_UNITS; i++) { 1767117f1b4Smrg obj->TexCoord[i].BufferObj = ctx->Array.NullBufferObj; 1777117f1b4Smrg } 1787117f1b4Smrg obj->EdgeFlag.BufferObj = ctx->Array.NullBufferObj; 1797117f1b4Smrg for (i = 0; i < VERT_ATTRIB_MAX; i++) { 1807117f1b4Smrg obj->VertexAttrib[i].BufferObj = ctx->Array.NullBufferObj; 1817117f1b4Smrg } 1827117f1b4Smrg#endif 1837117f1b4Smrg} 1847117f1b4Smrg 1857117f1b4Smrg 1867117f1b4Smrg/** 1877117f1b4Smrg * Add the given array object to the array object pool. 1887117f1b4Smrg */ 1897117f1b4Smrgvoid 1907117f1b4Smrg_mesa_save_array_object( GLcontext *ctx, struct gl_array_object *obj ) 1917117f1b4Smrg{ 1927117f1b4Smrg if (obj->Name > 0) { 1937117f1b4Smrg /* insert into hash table */ 1947117f1b4Smrg _mesa_HashInsert(ctx->Shared->ArrayObjects, obj->Name, obj); 1957117f1b4Smrg } 1967117f1b4Smrg} 1977117f1b4Smrg 1987117f1b4Smrg 1997117f1b4Smrg/** 2007117f1b4Smrg * Remove the given array object from the array object pool. 2017117f1b4Smrg * Do not deallocate the array object though. 2027117f1b4Smrg */ 2037117f1b4Smrgvoid 2047117f1b4Smrg_mesa_remove_array_object( GLcontext *ctx, struct gl_array_object *obj ) 2057117f1b4Smrg{ 2067117f1b4Smrg if (obj->Name > 0) { 2077117f1b4Smrg /* remove from hash table */ 2087117f1b4Smrg _mesa_HashRemove(ctx->Shared->ArrayObjects, obj->Name); 2097117f1b4Smrg } 2107117f1b4Smrg} 2117117f1b4Smrg 2127117f1b4Smrg 2137117f1b4Smrg/**********************************************************************/ 2147117f1b4Smrg/* API Functions */ 2157117f1b4Smrg/**********************************************************************/ 2167117f1b4Smrg 2177117f1b4Smrg/** 2187117f1b4Smrg * Bind a new array. 2197117f1b4Smrg * 2207117f1b4Smrg * \todo 2217117f1b4Smrg * The binding could be done more efficiently by comparing the non-NULL 2227117f1b4Smrg * pointers in the old and new objects. The only arrays that are "dirty" are 2237117f1b4Smrg * the ones that are non-NULL in either object. 2247117f1b4Smrg */ 2257117f1b4Smrgvoid GLAPIENTRY 2267117f1b4Smrg_mesa_BindVertexArrayAPPLE( GLuint id ) 2277117f1b4Smrg{ 2287117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 2297117f1b4Smrg struct gl_array_object * const oldObj = ctx->Array.ArrayObj; 2307117f1b4Smrg struct gl_array_object *newObj = NULL; 2317117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 2327117f1b4Smrg 2337117f1b4Smrg ASSERT(oldObj != NULL); 2347117f1b4Smrg 2357117f1b4Smrg if ( oldObj->Name == id ) 2367117f1b4Smrg return; /* rebinding the same array object- no change */ 2377117f1b4Smrg 2387117f1b4Smrg /* 2397117f1b4Smrg * Get pointer to new array object (newBufObj) 2407117f1b4Smrg */ 2417117f1b4Smrg if (id == 0) { 2427117f1b4Smrg /* The spec says there is no array object named 0, but we use 2437117f1b4Smrg * one internally because it simplifies things. 2447117f1b4Smrg */ 2457117f1b4Smrg newObj = ctx->Array.DefaultArrayObj; 2467117f1b4Smrg } 2477117f1b4Smrg else { 2487117f1b4Smrg /* non-default array object */ 2497117f1b4Smrg newObj = lookup_arrayobj(ctx, id); 2507117f1b4Smrg if (!newObj) { 2517117f1b4Smrg /* If this is a new array object id, allocate an array object now. 2527117f1b4Smrg */ 2537117f1b4Smrg 2547117f1b4Smrg newObj = (*ctx->Driver.NewArrayObject)(ctx, id); 2557117f1b4Smrg if (!newObj) { 2567117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindVertexArrayAPPLE"); 2577117f1b4Smrg return; 2587117f1b4Smrg } 2597117f1b4Smrg _mesa_save_array_object(ctx, newObj); 2607117f1b4Smrg } 2617117f1b4Smrg } 2627117f1b4Smrg 2637117f1b4Smrg 2647117f1b4Smrg ctx->NewState |= _NEW_ARRAY; 2657117f1b4Smrg ctx->Array.NewState |= _NEW_ARRAY_ALL; 2667117f1b4Smrg ctx->Array.ArrayObj = newObj; 2677117f1b4Smrg 2687117f1b4Smrg 2697117f1b4Smrg /* Pass BindVertexArray call to device driver */ 2707117f1b4Smrg if (ctx->Driver.BindArrayObject && newObj) 2717117f1b4Smrg (*ctx->Driver.BindArrayObject)( ctx, newObj ); 2727117f1b4Smrg} 2737117f1b4Smrg 2747117f1b4Smrg 2757117f1b4Smrg/** 2767117f1b4Smrg * Delete a set of array objects. 2777117f1b4Smrg * 2787117f1b4Smrg * \param n Number of array objects to delete. 2797117f1b4Smrg * \param ids Array of \c n array object IDs. 2807117f1b4Smrg */ 2817117f1b4Smrgvoid GLAPIENTRY 2827117f1b4Smrg_mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids) 2837117f1b4Smrg{ 2847117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 2857117f1b4Smrg GLsizei i; 2867117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 2877117f1b4Smrg 2887117f1b4Smrg if (n < 0) { 2897117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArrayAPPLE(n)"); 2907117f1b4Smrg return; 2917117f1b4Smrg } 2927117f1b4Smrg 2937117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 2947117f1b4Smrg 2957117f1b4Smrg for (i = 0; i < n; i++) { 2967117f1b4Smrg struct gl_array_object *obj = lookup_arrayobj(ctx, ids[i]); 2977117f1b4Smrg 2987117f1b4Smrg if ( obj != NULL ) { 2997117f1b4Smrg ASSERT( obj->Name == ids[i] ); 3007117f1b4Smrg 3017117f1b4Smrg 3027117f1b4Smrg /* If the array object is currently bound, the spec says "the binding 3037117f1b4Smrg * for that object reverts to zero and the default vertex array 3047117f1b4Smrg * becomes current." 3057117f1b4Smrg */ 3067117f1b4Smrg if ( obj == ctx->Array.ArrayObj ) { 3077117f1b4Smrg CALL_BindVertexArrayAPPLE( ctx->Exec, (0) ); 3087117f1b4Smrg } 3097117f1b4Smrg 3107117f1b4Smrg#if FEATURE_ARB_vertex_buffer_object 3117117f1b4Smrg /* Unbind any buffer objects that might be bound to arrays in 3127117f1b4Smrg * this array object. 3137117f1b4Smrg */ 3147117f1b4Smrg _mesa_unbind_buffer_object( ctx, obj->Vertex.BufferObj ); 3157117f1b4Smrg _mesa_unbind_buffer_object( ctx, obj->Normal.BufferObj ); 3167117f1b4Smrg _mesa_unbind_buffer_object( ctx, obj->Color.BufferObj ); 3177117f1b4Smrg _mesa_unbind_buffer_object( ctx, obj->SecondaryColor.BufferObj ); 3187117f1b4Smrg _mesa_unbind_buffer_object( ctx, obj->FogCoord.BufferObj ); 3197117f1b4Smrg _mesa_unbind_buffer_object( ctx, obj->Index.BufferObj ); 3207117f1b4Smrg for (i = 0; i < MAX_TEXTURE_UNITS; i++) { 3217117f1b4Smrg _mesa_unbind_buffer_object( ctx, obj->TexCoord[i].BufferObj ); 3227117f1b4Smrg } 3237117f1b4Smrg _mesa_unbind_buffer_object( ctx, obj->EdgeFlag.BufferObj ); 3247117f1b4Smrg for (i = 0; i < VERT_ATTRIB_MAX; i++) { 3257117f1b4Smrg _mesa_unbind_buffer_object( ctx, obj->VertexAttrib[i].BufferObj ); 3267117f1b4Smrg } 3277117f1b4Smrg#endif 3287117f1b4Smrg 3297117f1b4Smrg /* The ID is immediately freed for re-use */ 3307117f1b4Smrg _mesa_remove_array_object(ctx, obj); 3317117f1b4Smrg ctx->Driver.DeleteArrayObject(ctx, obj); 3327117f1b4Smrg } 3337117f1b4Smrg } 3347117f1b4Smrg 3357117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 3367117f1b4Smrg} 3377117f1b4Smrg 3387117f1b4Smrg 3397117f1b4Smrg/** 3407117f1b4Smrg * Generate a set of unique array object IDs and store them in \c arrays. 3417117f1b4Smrg * 3427117f1b4Smrg * \param n Number of IDs to generate. 3437117f1b4Smrg * \param arrays Array of \c n locations to store the IDs. 3447117f1b4Smrg */ 3457117f1b4Smrgvoid GLAPIENTRY 3467117f1b4Smrg_mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays) 3477117f1b4Smrg{ 3487117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3497117f1b4Smrg GLuint first; 3507117f1b4Smrg GLint i; 3517117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 3527117f1b4Smrg 3537117f1b4Smrg if (n < 0) { 3547117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArraysAPPLE"); 3557117f1b4Smrg return; 3567117f1b4Smrg } 3577117f1b4Smrg 3587117f1b4Smrg if (!arrays) { 3597117f1b4Smrg return; 3607117f1b4Smrg } 3617117f1b4Smrg 3627117f1b4Smrg /* 3637117f1b4Smrg * This must be atomic (generation and allocation of array object IDs) 3647117f1b4Smrg */ 3657117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 3667117f1b4Smrg 3677117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ArrayObjects, n); 3687117f1b4Smrg 3697117f1b4Smrg /* Allocate new, empty array objects and return identifiers */ 3707117f1b4Smrg for (i = 0; i < n; i++) { 3717117f1b4Smrg struct gl_array_object *obj; 3727117f1b4Smrg GLuint name = first + i; 3737117f1b4Smrg 3747117f1b4Smrg obj = (*ctx->Driver.NewArrayObject)( ctx, name ); 3757117f1b4Smrg if (!obj) { 3767117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 3777117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArraysAPPLE"); 3787117f1b4Smrg return; 3797117f1b4Smrg } 3807117f1b4Smrg _mesa_save_array_object(ctx, obj); 3817117f1b4Smrg arrays[i] = first + i; 3827117f1b4Smrg } 3837117f1b4Smrg 3847117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 3857117f1b4Smrg} 3867117f1b4Smrg 3877117f1b4Smrg 3887117f1b4Smrg/** 3897117f1b4Smrg * Determine if ID is the name of an array object. 3907117f1b4Smrg * 3917117f1b4Smrg * \param id ID of the potential array object. 3927117f1b4Smrg * \return \c GL_TRUE if \c id is the name of a array object, 3937117f1b4Smrg * \c GL_FALSE otherwise. 3947117f1b4Smrg */ 3957117f1b4SmrgGLboolean GLAPIENTRY 3967117f1b4Smrg_mesa_IsVertexArrayAPPLE( GLuint id ) 3977117f1b4Smrg{ 3987117f1b4Smrg struct gl_array_object * obj; 3997117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4007117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 4017117f1b4Smrg 4027117f1b4Smrg if (id == 0) 4037117f1b4Smrg return GL_FALSE; 4047117f1b4Smrg 4057117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 4067117f1b4Smrg obj = lookup_arrayobj(ctx, id); 4077117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 4087117f1b4Smrg 4097117f1b4Smrg return (obj != NULL) ? GL_TRUE : GL_FALSE; 4107117f1b4Smrg} 411