[Mesa-dev] [PATCH 2/8] st/mesa: implement "zombie" shaders list

Brian Paul brianp at vmware.com
Thu Mar 14 19:37:10 UTC 2019


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.
---
 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 bd919da..1e5742b 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
@@ -325,6 +358,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.
  */
@@ -332,6 +414,7 @@ void
 st_context_free_zombie_objects(struct st_context *st)
 {
    free_zombie_sampler_views(st);
+   free_zombie_shaders(st);
 }
 
 
@@ -644,6 +727,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;
 }
@@ -848,6 +933,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 1106bb6..c87ff81 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 7015e50..1e13571 100644
--- a/src/mesa/state_tracker/st_program.c
+++ b/src/mesa/state_tracker/st_program.c
@@ -213,9 +213,15 @@ st_set_prog_affected_state_flags(struct gl_program *prog)
 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 );
 
@@ -259,8 +265,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);
 }
 
@@ -297,21 +310,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);
       }
    }
 
-- 
1.8.5.6



More information about the mesa-dev mailing list