summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/mesa/state_tracker/st_context.c86
-rw-r--r--src/mesa/state_tracker/st_context.h23
-rw-r--r--src/mesa/state_tracker/st_program.c77
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);
}
}