diff --git a/src/gallium/drivers/iris/iris_context.h b/src/gallium/drivers/iris/iris_context.h index ffdd96ec922..5fd4cdb5e11 100644 --- a/src/gallium/drivers/iris/iris_context.h +++ b/src/gallium/drivers/iris/iris_context.h @@ -429,7 +429,7 @@ struct iris_binding_table { * (iris_uncompiled_shader), due to state-based recompiles (brw_*_prog_key). */ struct iris_compiled_shader { - struct list_head link; + struct pipe_reference ref; /** Reference to the uploaded assembly. */ struct iris_state_ref assembly; @@ -615,9 +615,6 @@ struct iris_context { bool constrained; } urb; - /** List of shader variants whose deletion has been deferred for now */ - struct list_head deleted_variants[MESA_SHADER_STAGES]; - struct u_upload_mgr *uploader; struct hash_table *cache; @@ -911,8 +908,20 @@ struct iris_compiled_shader *iris_upload_shader(struct iris_context *ice, const void *iris_find_previous_compile(const struct iris_context *ice, enum iris_program_cache_id cache_id, unsigned program_string_id); -void iris_delete_shader_variants(struct iris_context *ice, - struct iris_uncompiled_shader *ish); +void iris_delete_shader_variant(struct iris_compiled_shader *shader); + +static inline void +iris_shader_variant_reference(struct iris_compiled_shader **dst, + struct iris_compiled_shader *src) +{ + struct iris_compiled_shader *old_dst = *dst; + + if (pipe_reference(old_dst ? &old_dst->ref: NULL, src ? &src->ref : NULL)) + iris_delete_shader_variant(old_dst); + + *dst = src; +} + bool iris_blorp_lookup_shader(struct blorp_batch *blorp_batch, const void *key, uint32_t key_size, diff --git a/src/gallium/drivers/iris/iris_program.c b/src/gallium/drivers/iris/iris_program.c index acf4a8e3874..c53b808b600 100644 --- a/src/gallium/drivers/iris/iris_program.c +++ b/src/gallium/drivers/iris/iris_program.c @@ -1213,7 +1213,8 @@ iris_update_compiled_vs(struct iris_context *ice) shader = iris_compile_vs(ice, ish, &key); if (old != shader) { - ice->shaders.prog[IRIS_CACHE_VS] = shader; + iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_VERTEX], + shader); ice->state.dirty |= IRIS_DIRTY_VF_SGVS; ice->state.stage_dirty |= IRIS_STAGE_DIRTY_VS | IRIS_STAGE_DIRTY_BINDINGS_VS | @@ -1411,7 +1412,8 @@ iris_update_compiled_tcs(struct iris_context *ice) shader = iris_compile_tcs(ice, tcs, &key); if (old != shader) { - ice->shaders.prog[IRIS_CACHE_TCS] = shader; + iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_TESS_CTRL], + shader); ice->state.stage_dirty |= IRIS_STAGE_DIRTY_TCS | IRIS_STAGE_DIRTY_BINDINGS_TCS | IRIS_STAGE_DIRTY_CONSTANTS_TCS; @@ -1525,7 +1527,8 @@ iris_update_compiled_tes(struct iris_context *ice) shader = iris_compile_tes(ice, ish, &key); if (old != shader) { - ice->shaders.prog[IRIS_CACHE_TES] = shader; + iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_TESS_EVAL], + shader); ice->state.stage_dirty |= IRIS_STAGE_DIRTY_TES | IRIS_STAGE_DIRTY_BINDINGS_TES | IRIS_STAGE_DIRTY_CONSTANTS_TES; @@ -1647,7 +1650,8 @@ iris_update_compiled_gs(struct iris_context *ice) } if (old != shader) { - ice->shaders.prog[IRIS_CACHE_GS] = shader; + iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_GEOMETRY], + shader); ice->state.stage_dirty |= IRIS_STAGE_DIRTY_GS | IRIS_STAGE_DIRTY_BINDINGS_GS | IRIS_STAGE_DIRTY_CONSTANTS_GS; @@ -1763,7 +1767,8 @@ iris_update_compiled_fs(struct iris_context *ice) if (old != shader) { // XXX: only need to flag CLIP if barycentric has NONPERSPECTIVE // toggles. might be able to avoid flagging SBE too. - ice->shaders.prog[IRIS_CACHE_FS] = shader; + iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_FRAGMENT], + shader); ice->state.dirty |= IRIS_DIRTY_WM | IRIS_DIRTY_CLIP | IRIS_DIRTY_SBE; @@ -1858,8 +1863,8 @@ iris_update_compiled_shaders(struct iris_context *ice) iris_update_compiled_tcs(ice); iris_update_compiled_tes(ice); } else { - ice->shaders.prog[IRIS_CACHE_TCS] = NULL; - ice->shaders.prog[IRIS_CACHE_TES] = NULL; + iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_TESS_CTRL], NULL); + iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_TESS_EVAL], NULL); ice->state.stage_dirty |= IRIS_STAGE_DIRTY_TCS | IRIS_STAGE_DIRTY_TES | IRIS_STAGE_DIRTY_BINDINGS_TCS | IRIS_STAGE_DIRTY_BINDINGS_TES | @@ -2005,7 +2010,8 @@ iris_update_compiled_cs(struct iris_context *ice) shader = iris_compile_cs(ice, ish, &key); if (old != shader) { - ice->shaders.prog[IRIS_CACHE_CS] = shader; + iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_COMPUTE], + shader); ice->state.stage_dirty |= IRIS_STAGE_DIRTY_CS | IRIS_STAGE_DIRTY_BINDINGS_CS | IRIS_STAGE_DIRTY_CONSTANTS_CS; @@ -2409,8 +2415,6 @@ iris_delete_shader_state(struct pipe_context *ctx, void *state, gl_shader_stage ice->state.stage_dirty |= IRIS_STAGE_DIRTY_UNCOMPILED_VS << stage; } - iris_delete_shader_variants(ice, ish); - ralloc_free(ish->nir); free(ish); } diff --git a/src/gallium/drivers/iris/iris_program_cache.c b/src/gallium/drivers/iris/iris_program_cache.c index 357c9eec1d3..15f524ff628 100644 --- a/src/gallium/drivers/iris/iris_program_cache.c +++ b/src/gallium/drivers/iris/iris_program_cache.c @@ -117,58 +117,12 @@ iris_find_previous_compile(const struct iris_context *ice, } void -iris_delete_shader_variants(struct iris_context *ice, - struct iris_uncompiled_shader *ish) +iris_delete_shader_variant(struct iris_compiled_shader *shader) { - struct hash_table *cache = ice->shaders.cache; - gl_shader_stage stage = ish->nir->info.stage; - enum iris_program_cache_id cache_id = stage; - - hash_table_foreach(cache, entry) { - const struct keybox *keybox = entry->key; - const struct brw_base_prog_key *key = (const void *)keybox->data; - - if (keybox->cache_id == cache_id && - key->program_string_id == ish->program_id) { - struct iris_compiled_shader *shader = entry->data; - - _mesa_hash_table_remove(cache, entry); - - /* Shader variants may still be bound in the context even after - * the API-facing shader has been deleted. In particular, a draw - * may not have triggered iris_update_compiled_shaders() yet. In - * that case, we may be referring to that shader's VUE map, stream - * output settings, and so on. We also like to compare the old and - * new shader programs when swapping them out to flag dirty state. - * - * So, it's hazardous to delete a bound shader variant. We avoid - * doing so, choosing to instead move "deleted" shader variants to - * a list, deferring the actual deletion until they're not bound. - * - * For simplicity, we always move deleted variants to the list, - * even if we could delete them immediately. We'll then process - * the list, catching both these variants and any others. - */ - list_addtail(&shader->link, &ice->shaders.deleted_variants[stage]); - } - } - - /* Process any pending deferred variant deletions. */ - list_for_each_entry_safe(struct iris_compiled_shader, shader, - &ice->shaders.deleted_variants[stage], link) { - /* If the shader is still bound, defer deletion. */ - if (ice->shaders.prog[stage] == shader) - continue; - - list_del(&shader->link); - - /* Actually delete the variant. */ - pipe_resource_reference(&shader->assembly.res, NULL); - ralloc_free(shader); - } + pipe_resource_reference(&shader->assembly.res, NULL); + ralloc_free(shader); } - struct iris_compiled_shader * iris_upload_shader(struct iris_context *ice, enum iris_program_cache_id cache_id, @@ -189,6 +143,8 @@ iris_upload_shader(struct iris_context *ice, rzalloc_size(cache, sizeof(struct iris_compiled_shader) + screen->vtbl.derived_program_state_size(cache_id)); + pipe_reference_init(&shader->ref, 1); + shader->assembly.res = NULL; u_upload_alloc(ice->shaders.uploader, 0, prog_data->program_size, 64, &shader->assembly.offset, &shader->assembly.res, @@ -213,8 +169,6 @@ iris_upload_shader(struct iris_context *ice, brw_write_shader_relocs(&screen->devinfo, shader->map, prog_data, reloc_values, ARRAY_SIZE(reloc_values)); - list_inithead(&shader->link); - shader->prog_data = prog_data; shader->streamout = streamout; shader->system_values = system_values; @@ -304,26 +258,18 @@ iris_init_program_cache(struct iris_context *ice) ice->shaders.uploader = u_upload_create(&ice->ctx, 16384, PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, IRIS_RESOURCE_FLAG_SHADER_MEMZONE); - - for (int i = 0; i < MESA_SHADER_STAGES; i++) - list_inithead(&ice->shaders.deleted_variants[i]); } void iris_destroy_program_cache(struct iris_context *ice) { for (int i = 0; i < MESA_SHADER_STAGES; i++) { - ice->shaders.prog[i] = NULL; - - list_for_each_entry_safe(struct iris_compiled_shader, shader, - &ice->shaders.deleted_variants[i], link) { - pipe_resource_reference(&shader->assembly.res, NULL); - } + iris_shader_variant_reference(&ice->shaders.prog[i], NULL); } hash_table_foreach(ice->shaders.cache, entry) { struct iris_compiled_shader *shader = entry->data; - pipe_resource_reference(&shader->assembly.res, NULL); + iris_delete_shader_variant(shader); } u_upload_destroy(ice->shaders.uploader);