[Mesa-dev] [PATCH] mesa: per-texture locking

Frank Henigman fjhenigman at google.com
Mon Jun 10 13:35:15 PDT 2013


Replace the one texture lock with a lock per texture.  This allows
uploading textures from one thread concurrently with drawing in another
thread.  _mesa_lock_context_textures() was used to check for texture
updates from other contexts and also to acquire the texture lock.
It's been replaced with _mesa_check_context_textures() which only does
the checking.  Code sections that were between
_mesa_lock_context_textures() and _mesa_unlock_context_textures()
have been updated to lock individual textures as needed.

No piglit regressions on pineview with intel driver.
Passes new piglit test glx-multithread-texture.

Signed-off-by: Frank Henigman <fjhenigman at google.com>
---
 src/mesa/drivers/dri/i915/i915_texstate.c | 23 +++++++++++++++--------
 src/mesa/drivers/dri/i915/intel_tris.c    |  6 ++----
 src/mesa/main/attrib.c                    | 16 ++++++++--------
 src/mesa/main/mtypes.h                    |  7 +++----
 src/mesa/main/state.c                     |  7 +++----
 src/mesa/main/state.h                     |  5 ++---
 src/mesa/main/teximage.h                  | 10 +++++-----
 src/mesa/main/texobj.c                    | 21 ++++-----------------
 src/mesa/main/texobj.h                    |  5 +----
 src/mesa/main/texparam.c                  |  2 +-
 src/mesa/main/texstate.c                  |  6 ++++--
 11 files changed, 48 insertions(+), 60 deletions(-)

diff --git a/src/mesa/drivers/dri/i915/i915_texstate.c b/src/mesa/drivers/dri/i915/i915_texstate.c
index 43c802b..bf701c3 100644
--- a/src/mesa/drivers/dri/i915/i915_texstate.c
+++ b/src/mesa/drivers/dri/i915/i915_texstate.c
@@ -30,6 +30,7 @@
 #include "main/macros.h"
 #include "main/colormac.h"
 #include "main/samplerobj.h"
+#include "main/teximage.h"
 
 #include "intel_mipmap_tree.h"
 #include "intel_tex.h"
@@ -150,6 +151,7 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
    GLint lodbias, aniso = 0;
    GLubyte border[4];
    GLfloat maxlod;
+   bool rc = false;
 
    memset(state, 0, sizeof(*state));
 
@@ -160,8 +162,10 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
        i915->state.tex_buffer[unit] = NULL;
    }
 
+   _mesa_lock_texture(ctx, tObj);
+
    if (!intel_finalize_mipmap_tree(intel, unit))
-      return false;
+      goto finish;
 
    /* Get first image here, since intelObj->firstLevel will get set in
     * the intel_finalize_mipmap_tree() call above.
@@ -226,7 +230,7 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
          mipFilt = MIPFILTER_LINEAR;
          break;
       default:
-         return false;
+         goto finish;
       }
 
       if (sampler->MaxAnisotropy > 1.0) {
@@ -246,7 +250,7 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
             magFilt = FILTER_LINEAR;
             break;
          default:
-            return false;
+            goto finish;
          }
       }
 
@@ -269,7 +273,7 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
       if (sampler->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB &&
           tObj->Target != GL_TEXTURE_3D) {
          if (tObj->Target == GL_TEXTURE_1D) 
-            return false;
+            goto finish;
 
          state[I915_TEXREG_SS2] |=
             (SS2_SHADOW_ENABLE |
@@ -313,7 +317,7 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
            wr == GL_CLAMP ||
            ws == GL_CLAMP_TO_BORDER ||
            wt == GL_CLAMP_TO_BORDER || wr == GL_CLAMP_TO_BORDER))
-         return false;
+         goto finish;
 
       /* Only support TEXCOORDMODE_CLAMP_EDGE and TEXCOORDMODE_CUBE (not 
        * used) when using cube map texture coordinates
@@ -321,7 +325,7 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
       if (tObj->Target == GL_TEXTURE_CUBE_MAP_ARB &&
           (((ws != GL_CLAMP) && (ws != GL_CLAMP_TO_EDGE)) ||
            ((wt != GL_CLAMP) && (wt != GL_CLAMP_TO_EDGE))))
-          return false;
+          goto finish;
 
       /*
        * According to 3DSTATE_MAP_STATE at page of 104 in Bspec
@@ -343,7 +347,7 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
        */
       if (tObj->Target == GL_TEXTURE_CUBE_MAP_ARB &&
           !is_power_of_two(firstImage->Height))
-         return false;
+         goto finish;
 
       state[I915_TEXREG_SS3] = ss3;     /* SS3_NORMALIZED_COORDS */
 
@@ -404,7 +408,10 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
    DBG(TEXTURE, "state[I915_TEXREG_MS4] = 0x%x\n", state[I915_TEXREG_MS4]);
 #endif
 
-   return true;
+   rc = true;
+   finish:
+   _mesa_unlock_texture(ctx, tObj);
+   return rc;
 }
 
 
diff --git a/src/mesa/drivers/dri/i915/intel_tris.c b/src/mesa/drivers/dri/i915/intel_tris.c
index 7c60d84..f09ecbd 100644
--- a/src/mesa/drivers/dri/i915/intel_tris.c
+++ b/src/mesa/drivers/dri/i915/intel_tris.c
@@ -1070,10 +1070,10 @@ intelRunPipeline(struct gl_context * ctx)
 {
    struct intel_context *intel = intel_context(ctx);
 
-   _mesa_lock_context_textures(ctx);
+   _mesa_check_context_textures(ctx);
    
    if (ctx->NewState)
-      _mesa_update_state_locked(ctx);
+      _mesa_update_state_checked(ctx);
 
    /* We need to get this done before we start the pipeline, or a
     * change in the INTEL_FALLBACK() of its intel_draw_buffers() call
@@ -1098,8 +1098,6 @@ intelRunPipeline(struct gl_context * ctx)
    intel->tnl_pipeline_running = true;
    _tnl_run_pipeline(ctx);
    intel->tnl_pipeline_running = false;
-
-   _mesa_unlock_context_textures(ctx);
 }
 
 static void
diff --git a/src/mesa/main/attrib.c b/src/mesa/main/attrib.c
index 9358e69..593ed2f 100644
--- a/src/mesa/main/attrib.c
+++ b/src/mesa/main/attrib.c
@@ -51,6 +51,7 @@
 #include "stencil.h"
 #include "texenv.h"
 #include "texgen.h"
+#include "teximage.h"
 #include "texobj.h"
 #include "texparam.h"
 #include "texstate.h"
@@ -424,7 +425,7 @@ _mesa_PushAttrib(GLbitfield mask)
          goto end;
       }
 
-      _mesa_lock_context_textures(ctx);
+      _mesa_check_context_textures(ctx);
 
       /* copy/save the bulk of texture state here */
       memcpy(&texstate->Texture, &ctx->Texture, sizeof(ctx->Texture));
@@ -442,15 +443,16 @@ _mesa_PushAttrib(GLbitfield mask)
       /* copy state/contents of the currently bound texture objects */
       for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
          for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
-            _mesa_copy_texture_object(&texstate->SavedObj[u][tex],
-                                      ctx->Texture.Unit[u].CurrentTex[tex]);
+            struct gl_texture_object *texObj =
+               ctx->Texture.Unit[u].CurrentTex[tex];
+            _mesa_lock_texture(ctx, texObj);
+            _mesa_copy_texture_object(&texstate->SavedObj[u][tex], texObj);
+            _mesa_unlock_texture(ctx, texObj);
          }
       }
 
       _mesa_reference_shared_state(ctx, &texstate->SharedRef, ctx->Shared);
 
-      _mesa_unlock_context_textures(ctx);
-
       save_attrib_data(&head, GL_TEXTURE_BIT, texstate);
    }
 
@@ -670,7 +672,7 @@ pop_texture_group(struct gl_context *ctx, struct texture_state *texstate)
 {
    GLuint u;
 
-   _mesa_lock_context_textures(ctx);
+   _mesa_check_context_textures(ctx);
 
    for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
       const struct gl_texture_unit *unit = &texstate->Texture.Unit[u];
@@ -824,8 +826,6 @@ pop_texture_group(struct gl_context *ctx, struct texture_state *texstate)
    _mesa_ActiveTexture(GL_TEXTURE0_ARB + texstate->Texture.CurrentUnit);
 
    _mesa_reference_shared_state(ctx, &texstate->SharedRef, NULL);
-
-   _mesa_unlock_context_textures(ctx);
 }
 
 
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 92a70f4..96503ab 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -1156,7 +1156,8 @@ struct gl_sampler_object
  */
 struct gl_texture_object
 {
-   _glthread_Mutex Mutex;	/**< for thread safety */
+   _glthread_Mutex DataMutex;	/**< data lock */
+   _glthread_Mutex Mutex;	/**< RefCount lock */
    GLint RefCount;		/**< reference count */
    GLuint Name;			/**< the user-visible texture object ID */
    GLenum Target;               /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */
@@ -2519,11 +2520,9 @@ struct gl_shared_state
    /**
     * \name Thread safety and statechange notification for texture
     * objects. 
-    *
-    * \todo Improve the granularity of locking.
     */
    /*@{*/
-   _glthread_Mutex TexMutex;		/**< texobj thread safety */
+   _glthread_Mutex TexMutex;		/**< TextureStateStamp lock */
    GLuint TextureStateStamp;	        /**< state notification for shared tex */
    /*@}*/
 
diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c
index 2392641..f4f15a4 100644
--- a/src/mesa/main/state.c
+++ b/src/mesa/main/state.c
@@ -327,7 +327,7 @@ update_twoside(struct gl_context *ctx)
  * _mesa_update_lighting() and _mesa_update_tnl_spaces().
  */
 void
-_mesa_update_state_locked( struct gl_context *ctx )
+_mesa_update_state_checked( struct gl_context *ctx )
 {
    GLbitfield new_state = ctx->NewState;
    GLbitfield prog_flags = _NEW_PROGRAM;
@@ -438,9 +438,8 @@ _mesa_update_state_locked( struct gl_context *ctx )
 void
 _mesa_update_state( struct gl_context *ctx )
 {
-   _mesa_lock_context_textures(ctx);
-   _mesa_update_state_locked(ctx);
-   _mesa_unlock_context_textures(ctx);
+   _mesa_check_context_textures(ctx);
+   _mesa_update_state_checked(ctx);
 }
 
 
diff --git a/src/mesa/main/state.h b/src/mesa/main/state.h
index c57dc0e..4cd6ce0 100644
--- a/src/mesa/main/state.h
+++ b/src/mesa/main/state.h
@@ -31,11 +31,10 @@
 extern void
 _mesa_update_state(struct gl_context *ctx);
 
-/* As above but can only be called between _mesa_lock_context_textures() and 
- * _mesa_unlock_context_textures().
+/* As above but should only be called after _mesa_check_context_textures().
  */
 extern void
-_mesa_update_state_locked(struct gl_context *ctx);
+_mesa_update_state_checked(struct gl_context *ctx);
 
 
 extern void
diff --git a/src/mesa/main/teximage.h b/src/mesa/main/teximage.h
index 8895247..4a24c0c 100644
--- a/src/mesa/main/teximage.h
+++ b/src/mesa/main/teximage.h
@@ -148,21 +148,21 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target,
                                GLint depth, GLint border);
 
 /**
- * Lock a texture for updating.  See also _mesa_lock_context_textures().
+ * Lock/unlock a texture for updating.  See also _mesa_check_context_textures().
  */
 static inline void
 _mesa_lock_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
 {
-   _glthread_LOCK_MUTEX(ctx->Shared->TexMutex);
-   ctx->Shared->TextureStateStamp++;
-   (void) texObj;
+   _glthread_LOCK_MUTEX(texObj->DataMutex);
 }
 
 static inline void
 _mesa_unlock_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
 {
-   (void) texObj;
+   _glthread_LOCK_MUTEX(ctx->Shared->TexMutex);
+   ctx->Shared->TextureStateStamp++;
    _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex);
+   _glthread_UNLOCK_MUTEX(texObj->DataMutex);
 }
 
 /*@}*/
diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c
index 2168bff..1b6a48f 100644
--- a/src/mesa/main/texobj.c
+++ b/src/mesa/main/texobj.c
@@ -115,6 +115,7 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj,
    memset(obj, 0, sizeof(*obj));
    /* init the non-zero fields */
    _glthread_INIT_MUTEX(obj->Mutex);
+   _glthread_INIT_MUTEX(obj->DataMutex);
    obj->RefCount = 1;
    obj->Name = name;
    obj->Target = target;
@@ -236,6 +237,7 @@ _mesa_delete_texture_object(struct gl_context *ctx,
 
    /* destroy the mutex -- it may have allocated memory (eg on bsd) */
    _glthread_DESTROY_MUTEX(texObj->Mutex);
+   _glthread_DESTROY_MUTEX(texObj->DataMutex);
 
    /* free this object */
    free(texObj);
@@ -1442,21 +1444,13 @@ _mesa_IsTexture( GLuint texture )
 
 
 /**
- * Simplest implementation of texture locking: grab the shared tex
- * mutex.  Examine the shared context state timestamp and if there has
- * been a change, set the appropriate bits in ctx->NewState.
- *
- * This is used to deal with synchronizing things when a texture object
- * is used/modified by different contexts (or threads) which are sharing
- * the texture.
+ * Check for changes made in other contexts with which we might share textures.
  *
  * See also _mesa_lock/unlock_texture() in teximage.h
  */
 void
-_mesa_lock_context_textures( struct gl_context *ctx )
+_mesa_check_context_textures( struct gl_context *ctx )
 {
-   _glthread_LOCK_MUTEX(ctx->Shared->TexMutex);
-
    if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) {
       ctx->NewState |= _NEW_TEXTURE;
       ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp;
@@ -1464,13 +1458,6 @@ _mesa_lock_context_textures( struct gl_context *ctx )
 }
 
 
-void
-_mesa_unlock_context_textures( struct gl_context *ctx )
-{
-   assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp);
-   _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex);
-}
-
 void GLAPIENTRY
 _mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset,
                             GLint yoffset, GLint zoffset, GLsizei width,
diff --git a/src/mesa/main/texobj.h b/src/mesa/main/texobj.h
index a99f45b..54a0c6e 100644
--- a/src/mesa/main/texobj.h
+++ b/src/mesa/main/texobj.h
@@ -135,10 +135,7 @@ extern GLuint
 _mesa_total_texture_memory(struct gl_context *ctx);
 
 extern void
-_mesa_unlock_context_textures( struct gl_context *ctx );
-
-extern void
-_mesa_lock_context_textures( struct gl_context *ctx );
+_mesa_check_context_textures( struct gl_context *ctx );
 
 /*@}*/
 
diff --git a/src/mesa/main/texparam.c b/src/mesa/main/texparam.c
index 9507bc3..d584c7b 100644
--- a/src/mesa/main/texparam.c
+++ b/src/mesa/main/texparam.c
@@ -1414,7 +1414,7 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params )
             goto invalid_pname;
 
          if (ctx->NewState & (_NEW_BUFFERS | _NEW_FRAG_CLAMP))
-            _mesa_update_state_locked(ctx);
+            _mesa_update_state(ctx);
          if (_mesa_get_clamp_fragment_color(ctx)) {
             params[0] = CLAMP(obj->Sampler.BorderColor.f[0], 0.0F, 1.0F);
             params[1] = CLAMP(obj->Sampler.BorderColor.f[1], 0.0F, 1.0F);
diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c
index 741985c..c99c05d 100644
--- a/src/mesa/main/texstate.c
+++ b/src/mesa/main/texstate.c
@@ -102,13 +102,12 @@ _mesa_copy_texture_state( const struct gl_context *src, struct gl_context *dst )
        */
       if (dst->Shared == src->Shared) {
          /* copy texture object bindings, not contents of texture objects */
-         _mesa_lock_context_textures(dst);
+         _mesa_check_context_textures(dst);
 
          for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
             _mesa_reference_texobj(&dst->Texture.Unit[u].CurrentTex[tex],
                                    src->Texture.Unit[u].CurrentTex[tex]);
          }
-         _mesa_unlock_context_textures(dst);
       }
    }
 }
@@ -604,14 +603,17 @@ update_texture_state( struct gl_context *ctx )
             struct gl_sampler_object *sampler = texUnit->Sampler ?
                texUnit->Sampler : &texObj->Sampler;
 
+            _mesa_lock_texture(ctx, texObj);
             if (!_mesa_is_texture_complete(texObj, sampler)) {
                _mesa_test_texobj_completeness(ctx, texObj);
             }
             if (_mesa_is_texture_complete(texObj, sampler)) {
                texUnit->_ReallyEnabled = 1 << texIndex;
                _mesa_reference_texobj(&texUnit->_Current, texObj);
+               _mesa_unlock_texture(ctx, texObj);
                break;
             }
+            _mesa_unlock_texture(ctx, texObj);
          }
       }
 
-- 
1.8.3



More information about the mesa-dev mailing list