summaryrefslogtreecommitdiff
path: root/src/mesa/main/arrayobj.c
diff options
context:
space:
mode:
authorIan Romanick <idr@us.ibm.com>2006-06-12 16:26:29 +0000
committerIan Romanick <idr@us.ibm.com>2006-06-12 16:26:29 +0000
commitee34e6ef716bb630440299ac1efbc2055ef09ffd (patch)
tree561a6314f8115c8dfafc7a3336c89d43f21a301a /src/mesa/main/arrayobj.c
parent6254d5904366ae17cb707ee70ff1ce76092f9c81 (diff)
Add support for GL_APPLE_vertex_array_object. Several test programs
and demos are also added. Adding basic support to drivers should be as easy as just enabling the extension, though thorough test would also be required.
Diffstat (limited to 'src/mesa/main/arrayobj.c')
-rw-r--r--src/mesa/main/arrayobj.c426
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 0000000000..86f2e16319
--- /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 <idr@us.ibm.com>
+ * \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;
+}