}
+/*
+ * 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.
*/
}
+/*
+ * 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.
st_context_free_zombie_objects(struct st_context *st)
{
free_zombie_sampler_views(st);
+ free_zombie_shaders(st);
}
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;
}
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);
};
+/*
+ * 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;
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;
+
};
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);
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 );
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);
}
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);
}
}