mesa/dlist: shortcircuit some redundant statechanges at compile time
[mesa.git] / src / mesa / main / arrayobj.c
index f08f99d8e17fb5e62dca9851f1c835d94c435749..0fa5f0de55188b5d98107a3d9b804352d56990a3 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5
+ * Version:  7.2
  *
- * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  * (C) Copyright IBM Corporation 2006
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -68,6 +68,32 @@ lookup_arrayobj(GLcontext *ctx, GLuint id)
 }
 
 
+/**
+ * For all the vertex arrays in the array object, unbind any pointers
+ * to any buffer objects (VBOs).
+ * This is done just prior to array object destruction.
+ */
+static void
+unbind_array_object_vbos(GLcontext *ctx, struct gl_array_object *obj)
+{
+   GLuint i;
+
+   _mesa_reference_buffer_object(ctx, &obj->Vertex.BufferObj, NULL);
+   _mesa_reference_buffer_object(ctx, &obj->Normal.BufferObj, NULL);
+   _mesa_reference_buffer_object(ctx, &obj->Color.BufferObj, NULL);
+   _mesa_reference_buffer_object(ctx, &obj->SecondaryColor.BufferObj, NULL);
+   _mesa_reference_buffer_object(ctx, &obj->FogCoord.BufferObj, NULL);
+   _mesa_reference_buffer_object(ctx, &obj->Index.BufferObj, NULL);
+   _mesa_reference_buffer_object(ctx, &obj->EdgeFlag.BufferObj, NULL);
+
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++)
+      _mesa_reference_buffer_object(ctx, &obj->TexCoord[i].BufferObj, NULL);
+
+   for (i = 0; i < VERT_ATTRIB_MAX; i++)
+      _mesa_reference_buffer_object(ctx, &obj->VertexAttrib[i].BufferObj,NULL);
+}
+
+
 /**
  * Allocate and initialize a new vertex array object.
  * 
@@ -77,7 +103,7 @@ lookup_arrayobj(GLcontext *ctx, GLuint id)
 struct gl_array_object *
 _mesa_new_array_object( GLcontext *ctx, GLuint name )
 {
-   struct gl_array_object *obj = MALLOC_STRUCT(gl_array_object);
+   struct gl_array_object *obj = CALLOC_STRUCT(gl_array_object);
    if (obj)
       _mesa_initialize_array_object(ctx, obj, name);
    return obj;
@@ -94,10 +120,92 @@ void
 _mesa_delete_array_object( GLcontext *ctx, struct gl_array_object *obj )
 {
    (void) ctx;
+   unbind_array_object_vbos(ctx, obj);
+   _glthread_DESTROY_MUTEX(obj->Mutex);
    _mesa_free(obj);
 }
 
 
+/**
+ * Set ptr to arrayObj w/ reference counting.
+ */
+void
+_mesa_reference_array_object(GLcontext *ctx,
+                             struct gl_array_object **ptr,
+                             struct gl_array_object *arrayObj)
+{
+   if (*ptr == arrayObj)
+      return;
+
+   if (*ptr) {
+      /* Unreference the old array object */
+      GLboolean deleteFlag = GL_FALSE;
+      struct gl_array_object *oldObj = *ptr;
+
+      _glthread_LOCK_MUTEX(oldObj->Mutex);
+      ASSERT(oldObj->RefCount > 0);
+      oldObj->RefCount--;
+#if 0
+      printf("ArrayObj %p %d DECR to %d\n",
+             (void *) oldObj, oldObj->Name, oldObj->RefCount);
+#endif
+      deleteFlag = (oldObj->RefCount == 0);
+      _glthread_UNLOCK_MUTEX(oldObj->Mutex);
+
+      if (deleteFlag) {
+        ASSERT(ctx->Driver.DeleteArrayObject);
+         ctx->Driver.DeleteArrayObject(ctx, oldObj);
+      }
+
+      *ptr = NULL;
+   }
+   ASSERT(!*ptr);
+
+   if (arrayObj) {
+      /* reference new array object */
+      _glthread_LOCK_MUTEX(arrayObj->Mutex);
+      if (arrayObj->RefCount == 0) {
+         /* this array's being deleted (look just above) */
+         /* Not sure this can every really happen.  Warn if it does. */
+         _mesa_problem(NULL, "referencing deleted array object");
+         *ptr = NULL;
+      }
+      else {
+         arrayObj->RefCount++;
+#if 0
+         printf("ArrayObj %p %d INCR to %d\n",
+                (void *) arrayObj, arrayObj->Name, arrayObj->RefCount);
+#endif
+         *ptr = arrayObj;
+      }
+      _glthread_UNLOCK_MUTEX(arrayObj->Mutex);
+   }
+}
+
+
+
+static void
+init_array(GLcontext *ctx,
+           struct gl_client_array *array, GLint size, GLint type)
+{
+   array->Size = size;
+   array->Type = type;
+   array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */
+   array->Stride = 0;
+   array->StrideB = 0;
+   array->Ptr = NULL;
+   array->Enabled = GL_FALSE;
+   array->Normalized = GL_FALSE;
+#if FEATURE_ARB_vertex_buffer_object
+   /* Vertex array buffers */
+   array->BufferObj = ctx->Array.NullBufferObj;
+#endif
+}
+
+
+/**
+ * Initialize a gl_array_object's arrays.
+ */
 void
 _mesa_initialize_array_object( GLcontext *ctx,
                               struct gl_array_object *obj,
@@ -107,78 +215,26 @@ _mesa_initialize_array_object( GLcontext *ctx,
 
    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->Normal.Type = GL_FLOAT;
-   obj->Normal.Stride = 0;
-   obj->Normal.StrideB = 0;
-   obj->Normal.Ptr = NULL;
-   obj->Normal.Enabled = GL_FALSE;
-   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->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->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->Index.Type = GL_FLOAT;
-   obj->Index.Stride = 0;
-   obj->Index.StrideB = 0;
-   obj->Index.Ptr = NULL;
-   obj->Index.Enabled = GL_FALSE;
-   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;
+   _glthread_INIT_MUTEX(obj->Mutex);
+   obj->RefCount = 1;
+
+   /* Init the individual arrays */
+   init_array(ctx, &obj->Vertex, 4, GL_FLOAT);
+   init_array(ctx, &obj->Normal, 3, GL_FLOAT);
+   init_array(ctx, &obj->Color, 4, GL_FLOAT);
+   init_array(ctx, &obj->SecondaryColor, 4, GL_FLOAT);
+   init_array(ctx, &obj->FogCoord, 1, GL_FLOAT);
+   init_array(ctx, &obj->Index, 1, GL_FLOAT);
+   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
+      init_array(ctx, &obj->TexCoord[i], 4, GL_FLOAT);
    }
-   obj->EdgeFlag.Stride = 0;
-   obj->EdgeFlag.StrideB = 0;
-   obj->EdgeFlag.Ptr = NULL;
-   obj->EdgeFlag.Enabled = GL_FALSE;
+   init_array(ctx, &obj->EdgeFlag, 1, GL_BOOL);
    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;
+      init_array(ctx, &obj->VertexAttrib[i], 4, GL_FLOAT);
    }
 
-#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;
-   }
+#if FEATURE_point_size_array
+   init_array(ctx, &obj->PointSize, 1, GL_FLOAT);
 #endif
 }
 
@@ -236,7 +292,7 @@ _mesa_BindVertexArrayAPPLE( GLuint id )
       return;   /* rebinding the same array object- no change */
 
    /*
-    * Get pointer to new array object (newBufObj)
+    * Get pointer to new array object (newObj)
     */
    if (id == 0) {
       /* The spec says there is no array object named 0, but we use
@@ -250,7 +306,6 @@ _mesa_BindVertexArrayAPPLE( GLuint 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");
@@ -260,11 +315,9 @@ _mesa_BindVertexArrayAPPLE( GLuint id )
       }
    }
 
-
    ctx->NewState |= _NEW_ARRAY;
    ctx->Array.NewState |= _NEW_ARRAY_ALL;
-   ctx->Array.ArrayObj = newObj;
-
+   _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, newObj);
 
    /* Pass BindVertexArray call to device driver */
    if (ctx->Driver.BindArrayObject && newObj)
@@ -298,7 +351,6 @@ _mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids)
       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."
@@ -307,28 +359,13 @@ _mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids)
            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);
+
+         /* Unreference the array object. 
+          * If refcount hits zero, the object will be deleted.
+          */
+         _mesa_reference_array_object(ctx, &obj, NULL);
       }
    }