Mesa (master): st/mesa: implement "zombie" shaders list

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Mar 18 02:19:19 UTC 2019


Module: Mesa
Branch: master
Commit: 41c4c49463f65cd6c564b2a66634ba6572a824fb
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=41c4c49463f65cd6c564b2a66634ba6572a824fb

Author: Brian Paul <brianp at vmware.com>
Date:   Tue Mar 12 16:01:56 2019 -0600

st/mesa: implement "zombie" shaders list

As with the preceding patch for sampler views, this patch does
basically the same thing but for shaders.  However, reference counting
isn't needed here (instead of calling cso_delete_XXX_shader() we call
st_save_zombie_shader().

The Redway3D Watch is one app/demo that needs this change.  Otherwise,
the vmwgfx driver generates an error about trying to destroy a shader
ID that doesn't exist in the context.

Note that if PIPE_CAP_SHAREABLE_SHADERS = TRUE, then we can use/delete
any shader with any context and this mechanism is not used.

Tested with: google-chrome, google earth, Redway3D Watch/Turbine demos
and a few Linux games.

Reviewed-by: Roland Scheidegger <sroland at vmware.com>
Reviewed-by: Neha Bhende <bhenden at vmware.com>
Reviewed-by: Mathias Fröhlich <Mathias.Froehlich at web.de>
Reviewed-By: Jose Fonseca <jfonseca at vmware.com>

---

 src/mesa/state_tracker/st_context.c | 86 +++++++++++++++++++++++++++++++++++++
 src/mesa/state_tracker/st_context.h | 23 ++++++++++
 src/mesa/state_tracker/st_program.c | 77 ++++++++++++++++++++++++---------
 3 files changed, 166 insertions(+), 20 deletions(-)

diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
index c38f8e50187..de2264da589 100644
--- a/src/mesa/state_tracker/st_context.c
+++ b/src/mesa/state_tracker/st_context.c
@@ -294,6 +294,39 @@ st_save_zombie_sampler_view(struct st_context *st,
 
 
 /*
+ * Since OpenGL shaders may be shared among contexts, we can wind up
+ * with variants of a shader created with different contexts.
+ * When we go to destroy a gallium shader, we want to free it with the
+ * same context that it was created with, unless the driver reports
+ * PIPE_CAP_SHAREABLE_SHADERS = TRUE.
+ */
+void
+st_save_zombie_shader(struct st_context *st,
+                      enum pipe_shader_type type,
+                      struct pipe_shader_state *shader)
+{
+   struct st_zombie_shader_node *entry;
+
+   /* we shouldn't be here if the driver supports shareable shaders */
+   assert(!st->has_shareable_shaders);
+
+   entry = MALLOC_STRUCT(st_zombie_shader_node);
+   if (!entry)
+      return;
+
+   entry->shader = shader;
+   entry->type = type;
+
+   /* We need a mutex since this function may be called from one thread
+    * while free_zombie_shaders() is called from another.
+    */
+   mtx_lock(&st->zombie_shaders.mutex);
+   LIST_ADDTAIL(&entry->node, &st->zombie_shaders.list.node);
+   mtx_unlock(&st->zombie_shaders.mutex);
+}
+
+
+/*
  * Free any zombie sampler views that may be attached to this context.
  */
 static void
@@ -324,6 +357,55 @@ free_zombie_sampler_views(struct st_context *st)
 
 
 /*
+ * Free any zombie shaders that may be attached to this context.
+ */
+static void
+free_zombie_shaders(struct st_context *st)
+{
+   struct st_zombie_shader_node *entry, *next;
+
+   if (LIST_IS_EMPTY(&st->zombie_shaders.list.node)) {
+      return;
+   }
+
+   mtx_lock(&st->zombie_shaders.mutex);
+
+   LIST_FOR_EACH_ENTRY_SAFE(entry, next,
+                            &st->zombie_shaders.list.node, node) {
+      LIST_DEL(&entry->node);  // remove this entry from the list
+
+      switch (entry->type) {
+      case PIPE_SHADER_VERTEX:
+         cso_delete_vertex_shader(st->cso_context, entry->shader);
+         break;
+      case PIPE_SHADER_FRAGMENT:
+         cso_delete_fragment_shader(st->cso_context, entry->shader);
+         break;
+      case PIPE_SHADER_GEOMETRY:
+         cso_delete_geometry_shader(st->cso_context, entry->shader);
+         break;
+      case PIPE_SHADER_TESS_CTRL:
+         cso_delete_tessctrl_shader(st->cso_context, entry->shader);
+         break;
+      case PIPE_SHADER_TESS_EVAL:
+         cso_delete_tesseval_shader(st->cso_context, entry->shader);
+         break;
+      case PIPE_SHADER_COMPUTE:
+         cso_delete_compute_shader(st->cso_context, entry->shader);
+         break;
+      default:
+         unreachable("invalid shader type in free_zombie_shaders()");
+      }
+      free(entry);
+   }
+
+   assert(LIST_IS_EMPTY(&st->zombie_shaders.list.node));
+
+   mtx_unlock(&st->zombie_shaders.mutex);
+}
+
+
+/*
  * This function is called periodically to free any zombie objects
  * which are attached to this context.
  */
@@ -331,6 +413,7 @@ void
 st_context_free_zombie_objects(struct st_context *st)
 {
    free_zombie_sampler_views(st);
+   free_zombie_shaders(st);
 }
 
 
@@ -643,6 +726,8 @@ st_create_context_priv(struct gl_context *ctx, struct pipe_context *pipe,
 
    LIST_INITHEAD(&st->zombie_sampler_views.list.node);
    mtx_init(&st->zombie_sampler_views.mutex, mtx_plain);
+   LIST_INITHEAD(&st->zombie_shaders.list.node);
+   mtx_init(&st->zombie_shaders.mutex, mtx_plain);
 
    return st;
 }
@@ -847,6 +932,7 @@ st_destroy_context(struct st_context *st)
    st_context_free_zombie_objects(st);
 
    mtx_destroy(&st->zombie_sampler_views.mutex);
+   mtx_destroy(&st->zombie_shaders.mutex);
 
    /* This must be called first so that glthread has a chance to finish */
    _mesa_glthread_destroy(ctx);
diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h
index 1106bb628a3..c87ff81f973 100644
--- a/src/mesa/state_tracker/st_context.h
+++ b/src/mesa/state_tracker/st_context.h
@@ -106,6 +106,17 @@ struct st_zombie_sampler_view_node
 };
 
 
+/*
+ * Node for a linked list of dead shaders.
+ */
+struct st_zombie_shader_node
+{
+   void *shader;
+   enum pipe_shader_type type;
+   struct list_head node;
+};
+
+
 struct st_context
 {
    struct st_context_iface iface;
@@ -322,6 +333,12 @@ struct st_context
       struct st_zombie_sampler_view_node list;
       mtx_t mutex;
    } zombie_sampler_views;
+
+   struct {
+      struct st_zombie_shader_node list;
+      mtx_t mutex;
+   } zombie_shaders;
+
 };
 
 
@@ -354,6 +371,12 @@ extern void
 st_save_zombie_sampler_view(struct st_context *st,
                             struct pipe_sampler_view *view);
 
+extern void
+st_save_zombie_shader(struct st_context *st,
+                      enum pipe_shader_type type,
+                      struct pipe_shader_state *shader);
+
+
 void
 st_context_free_zombie_objects(struct st_context *st);
 
diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
index 0df800a60e0..9f6e492d6fb 100644
--- a/src/mesa/state_tracker/st_program.c
+++ b/src/mesa/state_tracker/st_program.c
@@ -229,9 +229,15 @@ delete_ir(struct pipe_shader_state *ir)
 static void
 delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv)
 {
-   if (vpv->driver_shader) 
-      cso_delete_vertex_shader(st->cso_context, vpv->driver_shader);
-      
+   if (vpv->driver_shader) {
+      if (st->has_shareable_shaders || vpv->key.st == st) {
+         cso_delete_vertex_shader(st->cso_context, vpv->driver_shader);
+      } else {
+         st_save_zombie_shader(vpv->key.st, PIPE_SHADER_VERTEX,
+                               vpv->driver_shader);
+      }
+   }
+
    if (vpv->draw_shader)
       draw_delete_vertex_shader( st->draw, vpv->draw_shader );
 
@@ -271,8 +277,15 @@ st_release_vp_variants( struct st_context *st,
 static void
 delete_fp_variant(struct st_context *st, struct st_fp_variant *fpv)
 {
-   if (fpv->driver_shader) 
-      cso_delete_fragment_shader(st->cso_context, fpv->driver_shader);
+   if (fpv->driver_shader) {
+      if (st->has_shareable_shaders || fpv->key.st == st) {
+         cso_delete_fragment_shader(st->cso_context, fpv->driver_shader);
+      } else {
+         st_save_zombie_shader(fpv->key.st, PIPE_SHADER_FRAGMENT,
+                               fpv->driver_shader);
+      }
+   }
+
    free(fpv);
 }
 
@@ -306,21 +319,45 @@ delete_basic_variant(struct st_context *st, struct st_basic_variant *v,
                      GLenum target)
 {
    if (v->driver_shader) {
-      switch (target) {
-      case GL_TESS_CONTROL_PROGRAM_NV:
-         cso_delete_tessctrl_shader(st->cso_context, v->driver_shader);
-         break;
-      case GL_TESS_EVALUATION_PROGRAM_NV:
-         cso_delete_tesseval_shader(st->cso_context, v->driver_shader);
-         break;
-      case GL_GEOMETRY_PROGRAM_NV:
-         cso_delete_geometry_shader(st->cso_context, v->driver_shader);
-         break;
-      case GL_COMPUTE_PROGRAM_NV:
-         cso_delete_compute_shader(st->cso_context, v->driver_shader);
-         break;
-      default:
-         assert(!"this shouldn't occur");
+      if (st->has_shareable_shaders || v->key.st == st) {
+         /* The shader's context matches the calling context, or we
+          * don't care.
+          */
+         switch (target) {
+         case GL_TESS_CONTROL_PROGRAM_NV:
+            cso_delete_tessctrl_shader(st->cso_context, v->driver_shader);
+            break;
+         case GL_TESS_EVALUATION_PROGRAM_NV:
+            cso_delete_tesseval_shader(st->cso_context, v->driver_shader);
+            break;
+         case GL_GEOMETRY_PROGRAM_NV:
+            cso_delete_geometry_shader(st->cso_context, v->driver_shader);
+            break;
+         case GL_COMPUTE_PROGRAM_NV:
+            cso_delete_compute_shader(st->cso_context, v->driver_shader);
+            break;
+         default:
+            unreachable("bad shader type in delete_basic_variant");
+         }
+      } else {
+         /* We can't delete a shader with a context different from the one
+          * that created it.  Add it to the creating context's zombie list.
+          */
+         enum pipe_shader_type type;
+         switch (target) {
+         case GL_TESS_CONTROL_PROGRAM_NV:
+            type = PIPE_SHADER_TESS_CTRL;
+            break;
+         case GL_TESS_EVALUATION_PROGRAM_NV:
+            type = PIPE_SHADER_TESS_EVAL;
+            break;
+         case GL_GEOMETRY_PROGRAM_NV:
+            type = PIPE_SHADER_GEOMETRY;
+            break;
+         default:
+            unreachable("");
+         }
+         st_save_zombie_shader(v->key.st, type, v->driver_shader);
       }
    }
 




More information about the mesa-commit mailing list