More GL_EXT_framebuffer_object: rename some things, added device driver hooks.
[mesa.git] / src / mesa / main / texobj.c
index cdcc5acc7547186316f9a88b0fc5aa84a05e1564..488edab8725af070b46c6f361ec8d80d47910e33 100644 (file)
@@ -5,9 +5,9 @@
 
 /*
  * Mesa 3-D graphics library
- * Version:  6.1
+ * Version:  6.3
  *
- * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -64,6 +64,7 @@ struct gl_texture_object *
 _mesa_new_texture_object( GLcontext *ctx, GLuint name, GLenum target )
 {
    struct gl_texture_object *obj;
+   (void) ctx;
    obj = MALLOC_STRUCT(gl_texture_object);
    _mesa_initialize_texture_object(obj, name, target);
    return obj;
@@ -71,7 +72,7 @@ _mesa_new_texture_object( GLcontext *ctx, GLuint name, GLenum target )
 
 
 /**
- * Initialize a texture object to default values.
+ * Initialize a new texture object to default values.
  * \param obj  the texture object
  * \param name  the texture name
  * \param target  the texture target
@@ -87,9 +88,9 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj,
           target == GL_TEXTURE_CUBE_MAP_ARB ||
           target == GL_TEXTURE_RECTANGLE_NV);
 
+   _mesa_bzero(obj, sizeof(*obj));
    /* init the non-zero fields */
    _glthread_INIT_MUTEX(obj->Mutex);
-   _mesa_bzero(obj, sizeof(*obj));
    obj->RefCount = 1;
    obj->Name = name;
    obj->Target = target;
@@ -137,8 +138,6 @@ _mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj )
 
    (void) ctx;
 
-   assert(texObj);
-
    _mesa_free_colortable_data(&texObj->Palette);
 
    /* free the texture images */
@@ -158,63 +157,11 @@ _mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj )
 }
 
 
-/**
- * Add the given texture object to the texture object pool.
- */
-void
-_mesa_save_texture_object( GLcontext *ctx, struct gl_texture_object *texObj )
-{
-   /* insert into linked list */
-   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
-   texObj->Next = ctx->Shared->TexObjectList;
-   ctx->Shared->TexObjectList = texObj;
-   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
-
-   if (texObj->Name > 0) {
-      /* insert into hash table */
-      _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
-   }
-}
 
 
-/**
- * Remove the given texture object from the texture object pool.
- * Do not deallocate the texture object though.
- */
-void
-_mesa_remove_texture_object( GLcontext *ctx, struct gl_texture_object *texObj )
-{
-   struct gl_texture_object *tprev, *tcurr;
-
-   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
-
-   /* unlink from the linked list */
-   tprev = NULL;
-   tcurr = ctx->Shared->TexObjectList;
-   while (tcurr) {
-      if (tcurr == texObj) {
-         if (tprev) {
-            tprev->Next = texObj->Next;
-         }
-         else {
-            ctx->Shared->TexObjectList = texObj->Next;
-         }
-         break;
-      }
-      tprev = tcurr;
-      tcurr = tcurr->Next;
-   }
-
-   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
-
-   if (texObj->Name > 0) {
-      /* remove from hash table */
-      _mesa_HashRemove(ctx->Shared->TexObjects, texObj->Name);
-   }
-}
-
 /**
  * Copy texture object state from one texture object to another.
+ * Use for glPush/PopAttrib.
  *
  * \param dest destination texture object.
  * \param src source texture object.
@@ -580,16 +527,16 @@ _glthread_DECLARE_STATIC_MUTEX(GenTexturesLock);
  * Generate texture names.
  *
  * \param n number of texture names to be generated.
- * \param texName an array in which will hold the generated texture names.
+ * \param textures an array in which will hold the generated texture names.
  *
  * \sa glGenTextures().
  *
  * While holding the GenTexturesLock lock, calls _mesa_HashFindFreeKeyBlock()
- * to find a block of free texture IDs which are stored in \p texName.
+ * to find a block of free texture IDs which are stored in \p textures.
  * Corresponding empty texture objects are also generated.
  */ 
 void GLAPIENTRY
-_mesa_GenTextures( GLsizei n, GLuint *texName )
+_mesa_GenTextures( GLsizei n, GLuint *textures )
 {
    GET_CURRENT_CONTEXT(ctx);
    GLuint first;
@@ -601,7 +548,7 @@ _mesa_GenTextures( GLsizei n, GLuint *texName )
       return;
    }
 
-   if (!texName)
+   if (!textures)
       return;
 
    /*
@@ -618,45 +565,55 @@ _mesa_GenTextures( GLsizei n, GLuint *texName )
       GLenum target = 0;
       texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target);
       if (!texObj) {
+         _glthread_UNLOCK_MUTEX(GenTexturesLock);
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures");
          return;
       }
-      _mesa_save_texture_object(ctx, texObj);
-      texName[i] = name;
+
+      /* insert into hash table */
+      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+      _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
+      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+
+      textures[i] = name;
    }
 
    _glthread_UNLOCK_MUTEX(GenTexturesLock);
 }
 
+
 /**
  * Delete named textures.
  *
  * \param n number of textures to be deleted.
- * \param texName array of textures names to be deleted.
+ * \param textures array of texture IDs to be deleted.
  *
  * \sa glDeleteTextures().
  *
- * For each texture checks if its bound to any of the texture units, unbinding
- * it and decrementing the reference count if so. If the texture reference
- * count is zero, delete its object.
+ * If we're about to delete a texture that's currently bound to any
+ * texture unit, unbind the texture first.  Decrement the reference
+ * count on the texture object and delete it if it's zero.
+ * Recall that texture objects can be shared among several rendering
+ * contexts.
  */
 void GLAPIENTRY
-_mesa_DeleteTextures( GLsizei n, const GLuint *texName)
+_mesa_DeleteTextures( GLsizei n, const GLuint *textures)
 {
    GET_CURRENT_CONTEXT(ctx);
    GLint i;
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */
 
-   if (!texName)
+   if (!textures)
       return;
 
-   for (i=0;i<n;i++) {
-      if (texName[i] > 0) {
+   for (i = 0; i < n; i++) {
+      if (textures[i] > 0) {
          struct gl_texture_object *delObj = (struct gl_texture_object *)
-            _mesa_HashLookup(ctx->Shared->TexObjects, texName[i]);
+            _mesa_HashLookup(ctx->Shared->TexObjects, textures[i]);
          if (delObj) {
             /* First check if this texture is currently bound.
              * If so, unbind it and decrement the reference count.
+             * XXX all RefCount accesses should be protected by a mutex.
              */
             GLuint u;
             for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
@@ -699,13 +656,20 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *texName)
             }
             ctx->NewState |= _NEW_TEXTURE;
 
-            /* Decrement reference count and delete if zero */
-            delObj->RefCount--;
-            ASSERT(delObj->RefCount >= 0);
+            /* The texture _name_ is now free for re-use.
+             * Remove it from the hash table now.
+             */
+            _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+            _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
+            _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
 
+            /* The actual texture object will not be freed until it's no
+             * longer bound in any context.
+             * XXX all RefCount accesses should be protected by a mutex.
+             */
+            delObj->RefCount--;
             if (delObj->RefCount == 0) {
-               ASSERT(delObj->Name != 0);
-               _mesa_remove_texture_object(ctx, delObj);
+               ASSERT(delObj->Name != 0); /* Never delete default tex objs */
                ASSERT(ctx->Driver.DeleteTexture);
                (*ctx->Driver.DeleteTexture)(ctx, delObj);
             }
@@ -714,6 +678,7 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *texName)
    }
 }
 
+
 /**
  * Bind a named texture to a texturing target.
  * 
@@ -736,13 +701,16 @@ _mesa_BindTexture( GLenum target, GLuint texName )
    GLuint unit = ctx->Texture.CurrentUnit;
    struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
    struct gl_texture_object *oldTexObj;
-   struct gl_texture_object *newTexObj = 0;
+   struct gl_texture_object *newTexObj = NULL;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
       _mesa_debug(ctx, "glBindTexture %s %d\n",
                   _mesa_lookup_enum_by_nr(target), (GLint) texName);
 
+   /*
+    * Get pointer to currently bound texture object (oldTexObj)
+    */
    switch (target) {
       case GL_TEXTURE_1D:
          oldTexObj = texUnit->Current1D;
@@ -773,6 +741,10 @@ _mesa_BindTexture( GLenum target, GLuint texName )
    }
 
    if (oldTexObj->Name == texName)
+      /* XXX this might be wrong.  If the texobj is in use by another
+       * context and a texobj parameter was changed, this might be our
+       * only chance to update this context's hardware state.
+       */
       return;   /* rebinding the same texture- no change */
 
    /*
@@ -818,6 +790,14 @@ _mesa_BindTexture( GLenum target, GLuint texName )
             newTexObj->WrapT = GL_CLAMP_TO_EDGE;
             newTexObj->WrapR = GL_CLAMP_TO_EDGE;
             newTexObj->MinFilter = GL_LINEAR;
+            if (ctx->Driver.TexParameter) {
+               static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE};
+               static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR};
+               (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_S, fparam_wrap );
+               (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_T, fparam_wrap );
+               (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_R, fparam_wrap );
+               (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_MIN_FILTER, fparam_filter );
+            }
          }
       }
       else {
@@ -827,11 +807,16 @@ _mesa_BindTexture( GLenum target, GLuint texName )
             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
             return;
          }
-         _mesa_save_texture_object(ctx, newTexObj);
+
+         /* and insert it into hash table */
+         _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+         _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
+         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
       }
       newTexObj->Target = target;
    }
 
+   /* XXX all RefCount accesses should be protected by a mutex. */
    newTexObj->RefCount++;
 
    /* do the actual binding, but first flush outstanding vertices:
@@ -863,16 +848,20 @@ _mesa_BindTexture( GLenum target, GLuint texName )
    if (ctx->Driver.BindTexture)
       (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
 
+   /* Decrement the reference count on the old texture and check if it's
+    * time to delete it.
+    */
+   /* XXX all RefCount accesses should be protected by a mutex. */
    oldTexObj->RefCount--;
-   assert(oldTexObj->RefCount >= 0);
+   ASSERT(oldTexObj->RefCount >= 0);
    if (oldTexObj->RefCount == 0) {
-      assert(oldTexObj->Name != 0);
-      _mesa_remove_texture_object(ctx, oldTexObj);
+      ASSERT(oldTexObj->Name != 0);
       ASSERT(ctx->Driver.DeleteTexture);
       (*ctx->Driver.DeleteTexture)( ctx, oldTexObj );
    }
 }
 
+
 /**
  * Set texture priorities.
  * 
@@ -994,9 +983,18 @@ _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
 GLboolean GLAPIENTRY
 _mesa_IsTexture( GLuint texture )
 {
+   struct gl_texture_object *t;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
-   return texture > 0 && _mesa_HashLookup(ctx->Shared->TexObjects, texture);
+
+   if (!texture)
+      return GL_FALSE;
+
+   t = (struct gl_texture_object *)
+      _mesa_HashLookup(ctx->Shared->TexObjects, texture);
+
+   /* IsTexture is true only after object has been bound once. */
+   return t && t->Target;
 }
 
 /*@}*/