st/mesa: optimize pipe_sampler_view validation
authorBrian Paul <brianp@vmware.com>
Fri, 30 Sep 2016 22:41:46 +0000 (16:41 -0600)
committerBrian Paul <brianp@vmware.com>
Thu, 6 Oct 2016 17:29:32 +0000 (11:29 -0600)
Before, st_get_texture_sampler_view_from_stobj() did a lot of work to
check if the texture parameters matched the sampler view (format,
swizzle, min/max lod, first/last layer, etc).  We did this every time
we validated the texture state.

Now, we use a ctx->Driver.TexParameter() callback and a couple other
checks to proactively release texture views when we know that
view-related parameters have changed.  Then, the validation step is
simplified:
- Search the texture's list of sampler views (just match the context).
- If found, we're done.
- Else, create a new sampler view.

There will never be old, out-of-date sampler views attached to texture
objects that we have to test.

Most apps create textures and set the texture parameters once.  This
make sampler view validation much cheaper for that case.

Note that the old texture/sampler comparison code has been converted
into a set of assertions to verify that the sampler view is in fact
consistent with the texture parameters.  This should help to spot any
potential regressions.

Reviewed-by: Edward O'Callaghan <funfunctor@folklore1984.net>
Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
src/mesa/state_tracker/st_atom_texture.c
src/mesa/state_tracker/st_cb_texture.c
src/mesa/state_tracker/st_texture.c
src/mesa/state_tracker/st_texture.h

index bfa16dc5ac707a18217e9ff59375ec28c6b00780..45f1f6b02f19edc1251b6de0edfa667b522401b4 100644 (file)
@@ -370,7 +370,7 @@ st_create_texture_sampler_view_from_stobj(struct st_context *st,
 static struct pipe_sampler_view *
 st_get_texture_sampler_view_from_stobj(struct st_context *st,
                                        struct st_texture_object *stObj,
-                                      enum pipe_format format,
+                                       const struct gl_sampler_object *samp,
                                        unsigned glsl_version)
 {
    struct pipe_sampler_view **sv;
@@ -381,34 +381,42 @@ st_get_texture_sampler_view_from_stobj(struct st_context *st,
 
    sv = st_texture_get_sampler_view(st, stObj);
 
-   /* if sampler view has changed dereference it */
    if (*sv) {
-      if (check_sampler_swizzle(st, stObj, *sv, glsl_version) ||
-         (format != (*sv)->format) ||
-          gl_target_to_pipe(stObj->base.Target) != (*sv)->target ||
-          stObj->base.MinLevel + stObj->base.BaseLevel != (*sv)->u.tex.first_level ||
-          last_level(stObj) != (*sv)->u.tex.last_level ||
-          stObj->base.MinLayer != (*sv)->u.tex.first_layer ||
-          last_layer(stObj) != (*sv)->u.tex.last_layer) {
-        pipe_sampler_view_reference(sv, NULL);
+      /* Debug check: make sure that the sampler view's parameters are
+       * what they're supposed to be.
+       */
+      struct pipe_sampler_view *view = *sv;
+      assert(!check_sampler_swizzle(st, stObj, view, glsl_version));
+      assert(get_sampler_view_format(st, stObj, samp) == view->format);
+      assert(gl_target_to_pipe(stObj->base.Target) == view->target);
+      if (stObj->base.Target == GL_TEXTURE_BUFFER) {
+         unsigned base = stObj->base.BufferOffset;
+         unsigned size = MIN2(stObj->pt->width0 - base,
+                              (unsigned) stObj->base.BufferSize);
+         assert(view->u.buf.offset == base);
+         assert(view->u.buf.size == size);
+      }
+      else {
+         assert(stObj->base.MinLevel + stObj->base.BaseLevel ==
+                view->u.tex.first_level);
+         assert(last_level(stObj) == view->u.tex.last_level);
+         assert(stObj->base.MinLayer == view->u.tex.first_layer);
+         assert(last_layer(stObj) == view->u.tex.last_layer);
       }
    }
+   else {
+      /* create new sampler view */
+      enum pipe_format format = get_sampler_view_format(st, stObj, samp);
 
-   if (!*sv) {
       *sv = st_create_texture_sampler_view_from_stobj(st, stObj,
                                                       format, glsl_version);
 
-   } else if ((*sv)->context != st->pipe) {
-      /* Recreate view in correct context, use existing view as template */
-      struct pipe_sampler_view *new_sv =
-         st->pipe->create_sampler_view(st->pipe, stObj->pt, *sv);
-      pipe_sampler_view_reference(sv, NULL);
-      *sv = new_sv;
    }
 
    return *sv;
 }
 
+
 static GLboolean
 update_single_texture(struct st_context *st,
                       struct pipe_sampler_view **sampler_view,
@@ -418,7 +426,6 @@ update_single_texture(struct st_context *st,
    const struct gl_sampler_object *samp;
    struct gl_texture_object *texObj;
    struct st_texture_object *stObj;
-   enum pipe_format view_format;
    GLboolean retval;
 
    samp = _mesa_get_samplerobj(ctx, texUnit);
@@ -437,11 +444,20 @@ update_single_texture(struct st_context *st,
       return GL_FALSE;
    }
 
-   view_format = get_sampler_view_format(st, stObj, samp);
+   /* Check a few pieces of state outside the texture object to see if we
+    * need to force revalidation.
+    */
+   if (stObj->prev_glsl_version != glsl_version ||
+       stObj->prev_sRGBDecode != samp->sRGBDecode) {
+
+      st_texture_release_all_sampler_views(st, stObj);
+
+      stObj->prev_glsl_version = glsl_version;
+      stObj->prev_sRGBDecode = samp->sRGBDecode;
+   }
 
    *sampler_view =
-      st_get_texture_sampler_view_from_stobj(st, stObj, view_format,
-                                             glsl_version);
+      st_get_texture_sampler_view_from_stobj(st, stObj, samp, glsl_version);
    return GL_TRUE;
 }
 
index fa360b9fed41e476ed38f3f0357b7faaad139875..392b2a4b512fd9161494088437725ae1a1b8e3f2 100644 (file)
@@ -176,6 +176,8 @@ static void
 st_FreeTextureImageBuffer(struct gl_context *ctx,
                           struct gl_texture_image *texImage)
 {
+   struct st_context *st = st_context(ctx);
+   struct st_texture_object *stObj = st_texture_object(texImage->TexObject);
    struct st_texture_image *stImage = st_texture_image(texImage);
 
    DBG("%s\n", __func__);
@@ -192,6 +194,11 @@ st_FreeTextureImageBuffer(struct gl_context *ctx,
       free(stImage->etc_data);
       stImage->etc_data = NULL;
    }
+
+   /* if the texture image is being deallocated, the structure of the
+    * texture is changing so we'll likely need a new sampler view.
+    */
+   st_texture_release_all_sampler_views(st, stObj);
 }
 
 bool
@@ -2778,6 +2785,7 @@ st_TextureView(struct gl_context *ctx,
                struct gl_texture_object *texObj,
                struct gl_texture_object *origTexObj)
 {
+   struct st_context *st = st_context(ctx);
    struct st_texture_object *orig = st_texture_object(origTexObj);
    struct st_texture_object *tex = st_texture_object(texObj);
    struct gl_texture_image *image = texObj->Image[0][0];
@@ -2805,6 +2813,11 @@ st_TextureView(struct gl_context *ctx,
 
    tex->lastLevel = numLevels - 1;
 
+   /* free texture sampler views.  They need to be recreated when we
+    * change the texture view parameters.
+    */
+   st_texture_release_all_sampler_views(st, tex);
+
    return GL_TRUE;
 }
 
@@ -2839,6 +2852,43 @@ st_ClearTexSubImage(struct gl_context *ctx,
    pipe->clear_texture(pipe, pt, level, &box, clearValue ? clearValue : zeros);
 }
 
+
+/**
+ * Called via the glTexParam*() function, but only when some texture object
+ * state has actually changed.
+ */
+static void
+st_TexParameter(struct gl_context *ctx,
+                struct gl_texture_object *texObj,
+                GLenum pname, const GLfloat *params)
+{
+   struct st_context *st = st_context(ctx);
+   struct st_texture_object *stObj = st_texture_object(texObj);
+
+   switch (pname) {
+   case GL_TEXTURE_BASE_LEVEL:
+   case GL_TEXTURE_MAX_LEVEL:
+   case GL_DEPTH_TEXTURE_MODE:
+   case GL_DEPTH_STENCIL_TEXTURE_MODE:
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+   case GL_TEXTURE_SWIZZLE_R:
+   case GL_TEXTURE_SWIZZLE_G:
+   case GL_TEXTURE_SWIZZLE_B:
+   case GL_TEXTURE_SWIZZLE_A:
+   case GL_TEXTURE_SWIZZLE_RGBA:
+   case GL_TEXTURE_BUFFER_SIZE:
+   case GL_TEXTURE_BUFFER_OFFSET:
+      /* changing any of these texture parameters means we must create
+       * new sampler views.
+       */
+      st_texture_release_all_sampler_views(st, stObj);
+      break;
+   default:
+      ; /* nothing */
+   }
+}
+
+
 void
 st_init_texture_functions(struct dd_function_table *functions)
 {
@@ -2871,4 +2921,6 @@ st_init_texture_functions(struct dd_function_table *functions)
    functions->AllocTextureStorage = st_AllocTextureStorage;
    functions->TextureView = st_TextureView;
    functions->ClearTexSubImage = st_ClearTexSubImage;
+
+   functions->TexParameter = st_TexParameter;
 }
index 42616ca4cb4c4cbd01add8d1b43a4a3c08e291c5..32e5b84a5af7b788042655dbc79946f266a45771 100644 (file)
@@ -428,19 +428,17 @@ struct pipe_sampler_view **
 st_texture_get_sampler_view(struct st_context *st,
                             struct st_texture_object *stObj)
 {
-   struct pipe_sampler_view *used = NULL, **free = NULL;
+   struct pipe_sampler_view **free = NULL;
    GLuint i;
 
    for (i = 0; i < stObj->num_sampler_views; ++i) {
       struct pipe_sampler_view **sv = &stObj->sampler_views[i];
       /* Is the array entry used ? */
       if (*sv) {
-         /* Yes, check if it's the right one */
-         if ((*sv)->context == st->pipe)
+         /* check if the context matches */
+         if ((*sv)->context == st->pipe) {
             return sv;
-
-         /* Wasn't the right one, but remember it as template */
-         used = *sv;
+         }
       } else {
          /* Found a free slot, remember that */
          free = sv;
@@ -458,9 +456,7 @@ st_texture_get_sampler_view(struct st_context *st,
       *free = NULL;
    }
 
-   /* Add just any sampler view to be used as a template */
-   if (used)
-      pipe_sampler_view_reference(free, used);
+   assert(*free == NULL);
 
    return free;
 }
@@ -512,4 +508,6 @@ st_texture_free_sampler_views(struct st_texture_object *stObj)
     * those two headers we can trash the heap.
     */
    FREE(stObj->sampler_views);
+   stObj->sampler_views = NULL;
+   stObj->num_sampler_views = 0;
 }
index d2c4f3f880c4bc62b859935203969067da9eed8a..9c9a05b5605dc4eb2826a789130d9b976be68b74 100644 (file)
@@ -107,6 +107,11 @@ struct st_texture_object
     * views and surfaces instead of pt->format.
     */
    enum pipe_format surface_format;
+
+   /** The glsl version of the shader seen during the previous validation */
+   unsigned prev_glsl_version;
+   /** The value of the sampler's sRGBDecode state at the previous validation */
+   GLenum prev_sRGBDecode;
 };