mesa/dlist: shortcircuit some redundant statechanges at compile time
[mesa.git] / src / mesa / main / arrayobj.c
index b04095fd16b6fb9514bbe2289103a1ff12a11623..0fa5f0de55188b5d98107a3d9b804352d56990a3 100644 (file)
@@ -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.
  * 
@@ -94,10 +120,70 @@ 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)
@@ -129,6 +215,9 @@ _mesa_initialize_array_object( GLcontext *ctx,
 
    obj->Name = name;
 
+   _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);
@@ -177,15 +266,6 @@ _mesa_remove_array_object( GLcontext *ctx, struct gl_array_object *obj )
 }
 
 
-static void
-unbind_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
-{
-   if (bufObj != ctx->Array.NullBufferObj) {
-      _mesa_reference_buffer_object(ctx, &bufObj, NULL);
-   }
-}
-
-
 /**********************************************************************/
 /* API Functions                                                      */
 /**********************************************************************/
@@ -212,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
@@ -226,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");
@@ -236,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)
@@ -274,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."
@@ -283,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.
-         */
-        unbind_buffer_object( ctx, obj->Vertex.BufferObj );
-        unbind_buffer_object( ctx, obj->Normal.BufferObj );
-        unbind_buffer_object( ctx, obj->Color.BufferObj );
-        unbind_buffer_object( ctx, obj->SecondaryColor.BufferObj );
-        unbind_buffer_object( ctx, obj->FogCoord.BufferObj );
-        unbind_buffer_object( ctx, obj->Index.BufferObj );
-        for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
-           unbind_buffer_object( ctx, obj->TexCoord[i].BufferObj );
-        }
-        unbind_buffer_object( ctx, obj->EdgeFlag.BufferObj );
-        for (i = 0; i < VERT_ATTRIB_MAX; i++) {
-           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);
       }
    }