From 41c4c49463f65cd6c564b2a66634ba6572a824fb Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 12 Mar 2019 16:01:56 -0600 Subject: [PATCH] st/mesa: implement "zombie" shaders list MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Neha Bhende Reviewed-by: Mathias Fröhlich Reviewed-By: Jose Fonseca --- 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 @@ -293,6 +293,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. */ @@ -323,6 +356,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); } } -- 2.30.2