diff options
Diffstat (limited to 'src/mesa/main/arrayobj.c')
-rw-r--r-- | src/mesa/main/arrayobj.c | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/src/mesa/main/arrayobj.c b/src/mesa/main/arrayobj.c new file mode 100644 index 00000000000..86f2e163194 --- /dev/null +++ b/src/mesa/main/arrayobj.c @@ -0,0 +1,426 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. + * (C) Copyright IBM Corporation 2006 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL OR IBM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +/** + * \file arrayobj.c + * Functions for the GL_APPLE_vertex_array_object extension. + * + * \todo + * The code in this file borrows a lot from bufferobj.c. There's a certain + * amount of cruft left over from that origin that may be unnecessary. + * + * \author Ian Romanick <[email protected]> + * \author Brian Paul + */ + + +#include "glheader.h" +#include "hash.h" +#include "imports.h" +#include "context.h" +#if FEATURE_ARB_vertex_buffer_object +#include "bufferobj.h" +#endif +#include "arrayobj.h" +#include "dispatch.h" + + +/** + * Look up the array object for the given ID. + * + * \returns + * Either a pointer to the array object with the specified ID or \c NULL for + * a non-existent ID. The spec defines ID 0 as being technically + * non-existent. + */ + +static INLINE struct gl_array_object * +lookup_arrayobj(GLcontext *ctx, GLuint id) +{ + return (id == 0) + ? NULL + : (struct gl_array_object *) _mesa_HashLookup(ctx->Shared->ArrayObjects, + id); +} + + +/** + * Allocate and initialize a new array object. + * + * This function is intended to be called via + * \c dd_function_table::NewArrayObject. + */ +struct gl_array_object * +_mesa_new_array_object( GLcontext *ctx, GLuint name ) +{ + struct gl_array_object *obj; + + (void) ctx; + + obj = MALLOC_STRUCT(gl_array_object); + _mesa_initialize_array_object(ctx, obj, name); + return obj; +} + + +/** + * Delete an array object. + * + * This function is intended to be called via + * \c dd_function_table::DeleteArrayObject. + */ +void +_mesa_delete_array_object( GLcontext *ctx, struct gl_array_object *obj ) +{ + (void) ctx; + + _mesa_free(obj); +} + + +void +_mesa_initialize_array_object( GLcontext *ctx, + struct gl_array_object *obj, + GLuint name ) +{ + GLuint i; + + + obj->Name = name; + + /* Vertex arrays */ + obj->Vertex.Size = 4; + obj->Vertex.Type = GL_FLOAT; + obj->Vertex.Stride = 0; + obj->Vertex.StrideB = 0; + obj->Vertex.Ptr = NULL; + obj->Vertex.Enabled = GL_FALSE; + obj->Vertex.Flags = CA_CLIENT_DATA; + obj->Normal.Type = GL_FLOAT; + obj->Normal.Stride = 0; + obj->Normal.StrideB = 0; + obj->Normal.Ptr = NULL; + obj->Normal.Enabled = GL_FALSE; + obj->Normal.Flags = CA_CLIENT_DATA; + obj->Color.Size = 4; + obj->Color.Type = GL_FLOAT; + obj->Color.Stride = 0; + obj->Color.StrideB = 0; + obj->Color.Ptr = NULL; + obj->Color.Enabled = GL_FALSE; + obj->Color.Flags = CA_CLIENT_DATA; + obj->SecondaryColor.Size = 4; + obj->SecondaryColor.Type = GL_FLOAT; + obj->SecondaryColor.Stride = 0; + obj->SecondaryColor.StrideB = 0; + obj->SecondaryColor.Ptr = NULL; + obj->SecondaryColor.Enabled = GL_FALSE; + obj->SecondaryColor.Flags = CA_CLIENT_DATA; + obj->FogCoord.Size = 1; + obj->FogCoord.Type = GL_FLOAT; + obj->FogCoord.Stride = 0; + obj->FogCoord.StrideB = 0; + obj->FogCoord.Ptr = NULL; + obj->FogCoord.Enabled = GL_FALSE; + obj->FogCoord.Flags = CA_CLIENT_DATA; + obj->Index.Type = GL_FLOAT; + obj->Index.Stride = 0; + obj->Index.StrideB = 0; + obj->Index.Ptr = NULL; + obj->Index.Enabled = GL_FALSE; + obj->Index.Flags = CA_CLIENT_DATA; + for (i = 0; i < MAX_TEXTURE_UNITS; i++) { + obj->TexCoord[i].Size = 4; + obj->TexCoord[i].Type = GL_FLOAT; + obj->TexCoord[i].Stride = 0; + obj->TexCoord[i].StrideB = 0; + obj->TexCoord[i].Ptr = NULL; + obj->TexCoord[i].Enabled = GL_FALSE; + obj->TexCoord[i].Flags = CA_CLIENT_DATA; + } + obj->EdgeFlag.Stride = 0; + obj->EdgeFlag.StrideB = 0; + obj->EdgeFlag.Ptr = NULL; + obj->EdgeFlag.Enabled = GL_FALSE; + obj->EdgeFlag.Flags = CA_CLIENT_DATA; + for (i = 0; i < VERT_ATTRIB_MAX; i++) { + obj->VertexAttrib[i].Size = 4; + obj->VertexAttrib[i].Type = GL_FLOAT; + obj->VertexAttrib[i].Stride = 0; + obj->VertexAttrib[i].StrideB = 0; + obj->VertexAttrib[i].Ptr = NULL; + obj->VertexAttrib[i].Enabled = GL_FALSE; + obj->VertexAttrib[i].Normalized = GL_FALSE; + obj->VertexAttrib[i].Flags = CA_CLIENT_DATA; + } + + +#if FEATURE_ARB_vertex_buffer_object + /* Vertex array buffers */ + obj->Vertex.BufferObj = ctx->Array.NullBufferObj; + obj->Normal.BufferObj = ctx->Array.NullBufferObj; + obj->Color.BufferObj = ctx->Array.NullBufferObj; + obj->SecondaryColor.BufferObj = ctx->Array.NullBufferObj; + obj->FogCoord.BufferObj = ctx->Array.NullBufferObj; + obj->Index.BufferObj = ctx->Array.NullBufferObj; + for (i = 0; i < MAX_TEXTURE_UNITS; i++) { + obj->TexCoord[i].BufferObj = ctx->Array.NullBufferObj; + } + obj->EdgeFlag.BufferObj = ctx->Array.NullBufferObj; + for (i = 0; i < VERT_ATTRIB_MAX; i++) { + obj->VertexAttrib[i].BufferObj = ctx->Array.NullBufferObj; + } +#endif +} + + +/** + * Add the given array object to the array object pool. + */ +void +_mesa_save_array_object( GLcontext *ctx, struct gl_array_object *obj ) +{ + if (obj->Name > 0) { + /* insert into hash table */ + _mesa_HashInsert(ctx->Shared->ArrayObjects, obj->Name, obj); + } +} + + +/** + * Remove the given array object from the array object pool. + * Do not deallocate the array object though. + */ +void +_mesa_remove_array_object( GLcontext *ctx, struct gl_array_object *obj ) +{ + if (obj->Name > 0) { + /* remove from hash table */ + _mesa_HashRemove(ctx->Shared->ArrayObjects, obj->Name); + } +} + + +/**********************************************************************/ +/* API Functions */ +/**********************************************************************/ + +/** + * Bind a new array. + * + * \todo + * The binding could be done more efficiently by comparing the non-NULL + * pointers in the old and new objects. The only arrays that are "dirty" are + * the ones that are non-NULL in either object. + */ +void GLAPIENTRY +_mesa_BindVertexArrayAPPLE( GLuint id ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_array_object * const oldObj = ctx->Array.ArrayObj; + struct gl_array_object *newObj = NULL; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + + ASSERT(oldObj != NULL); + + if ( oldObj->Name == id ) + return; /* rebinding the same array object- no change */ + + /* + * Get pointer to new array object (newBufObj) + */ + if (id == 0) { + /* The spec says there is no array object named 0, but we use + * one internally because it simplifies things. + */ + newObj = ctx->Array.DefaultArrayObj; + } + else { + /* non-default array object */ + newObj = lookup_arrayobj(ctx, id); + if (!newObj) { + /* If this is a new array object id, allocate an array object now. + */ + + newObj = (*ctx->Driver.NewArrayObject)(ctx, id); + if (!newObj) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindVertexArrayAPPLE"); + return; + } + _mesa_save_array_object(ctx, newObj); + } + } + + + ctx->NewState |= _NEW_ARRAY; + ctx->Array.NewState |= _NEW_ARRAY_ALL; + ctx->Array.ArrayObj = newObj; + + + /* Pass BindVertexArray call to device driver */ + if (ctx->Driver.BindArrayObject && newObj) + (*ctx->Driver.BindArrayObject)( ctx, newObj ); +} + + +/** + * Delete a set of array objects. + * + * \param n Number of array objects to delete. + * \param ids Array of \c n array object IDs. + */ +void GLAPIENTRY +_mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids) +{ + GET_CURRENT_CONTEXT(ctx); + GLsizei i; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArrayAPPLE(n)"); + return; + } + + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + + for (i = 0; i < n; i++) { + struct gl_array_object *obj = lookup_arrayobj(ctx, ids[i]); + + if ( obj != NULL ) { + ASSERT( obj->Name == ids[i] ); + + + /* If the array object is currently bound, the spec says "the binding + * for that object reverts to zero and the default vertex array + * becomes current." + */ + if ( obj == ctx->Array.ArrayObj ) { + CALL_BindVertexArrayAPPLE( ctx->Exec, (0) ); + } + +#if FEATURE_ARB_vertex_buffer_object + /* Unbind any buffer objects that might be bound to arrays in + * this array object. + */ + _mesa_unbind_buffer_object( ctx, obj->Vertex.BufferObj ); + _mesa_unbind_buffer_object( ctx, obj->Normal.BufferObj ); + _mesa_unbind_buffer_object( ctx, obj->Color.BufferObj ); + _mesa_unbind_buffer_object( ctx, obj->SecondaryColor.BufferObj ); + _mesa_unbind_buffer_object( ctx, obj->FogCoord.BufferObj ); + _mesa_unbind_buffer_object( ctx, obj->Index.BufferObj ); + for (i = 0; i < MAX_TEXTURE_UNITS; i++) { + _mesa_unbind_buffer_object( ctx, obj->TexCoord[i].BufferObj ); + } + _mesa_unbind_buffer_object( ctx, obj->EdgeFlag.BufferObj ); + for (i = 0; i < VERT_ATTRIB_MAX; i++) { + _mesa_unbind_buffer_object( ctx, obj->VertexAttrib[i].BufferObj ); + } +#endif + + /* The ID is immediately freed for re-use */ + _mesa_remove_array_object(ctx, obj); + ctx->Driver.DeleteArrayObject(ctx, obj); + } + } + + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); +} + + +/** + * Generate a set of unique array object IDs and store them in \c buffer. + * + * \param n Number of IDs to generate. + * \param buffer Array of \c n locations to store the IDs. + */ +void GLAPIENTRY +_mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *buffer) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint first; + GLint i; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArraysAPPLE"); + return; + } + + if (!buffer) { + return; + } + + /* + * This must be atomic (generation and allocation of array object IDs) + */ + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ArrayObjects, n); + + /* Allocate new, empty array objects and return identifiers */ + for (i = 0; i < n; i++) { + struct gl_array_object *obj; + GLuint name = first + i; + + obj = (*ctx->Driver.NewArrayObject)( ctx, name ); + if (!obj) { + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArraysAPPLE"); + return; + } + _mesa_save_array_object(ctx, obj); + buffer[i] = first + i; + } + + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); +} + + +/** + * Determine if ID is the name of an array object. + * + * \param id ID of the potential array object. + * \return \c GL_TRUE if \c id is the name of a array object, + * \c GL_FALSE otherwise. + */ +GLboolean GLAPIENTRY +_mesa_IsVertexArrayAPPLE( GLuint id ) +{ + struct gl_array_object * obj; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + if (id == 0) + return GL_FALSE; + + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + obj = lookup_arrayobj(ctx, id); + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + + return (obj != NULL) ? GL_TRUE : GL_FALSE; +} |