diff --git a/.pick_status.json b/.pick_status.json index 83c4d5db389..cf683fec6d9 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -1894,7 +1894,7 @@ "description": "iris: Delete shader variants when deleting the API-facing shader", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "master_sha": null, "because_sha": "ed4ffb971585908e7bdd8ec1bfffbc6f7b06bd10" }, diff --git a/src/gallium/drivers/iris/iris_context.h b/src/gallium/drivers/iris/iris_context.h index 405de213012..1b4ceb810f0 100644 --- a/src/gallium/drivers/iris/iris_context.h +++ b/src/gallium/drivers/iris/iris_context.h @@ -410,6 +410,8 @@ struct iris_binding_table { * (iris_uncompiled_shader), due to state-based recompiles (brw_*_prog_key). */ struct iris_compiled_shader { + struct list_head link; + /** Reference to the uploaded assembly. */ struct iris_state_ref assembly; @@ -582,6 +584,9 @@ struct iris_context { struct iris_compiled_shader *prog[MESA_SHADER_STAGES]; struct brw_vue_map *last_vue_map; + /** 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; @@ -866,6 +871,8 @@ 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); 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 d1cee0df841..05a0934387c 100644 --- a/src/gallium/drivers/iris/iris_program.c +++ b/src/gallium/drivers/iris/iris_program.c @@ -1820,9 +1820,6 @@ get_vue_prog_data(struct iris_context *ice, gl_shader_stage stage) return (void *) ice->shaders.prog[stage]->prog_data; } -// XXX: iris_compiled_shaders are space-leaking :( -// XXX: do remember to unbind them if deleting them. - /** * Update the current shader variants for the given state. * @@ -2399,6 +2396,8 @@ iris_delete_shader_state(struct pipe_context *ctx, void *state, gl_shader_stage pipe_resource_reference(&ish->const_data_state.res, NULL); } + 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 62393cacf5b..5870b933472 100644 --- a/src/gallium/drivers/iris/iris_program_cache.c +++ b/src/gallium/drivers/iris/iris_program_cache.c @@ -115,6 +115,59 @@ iris_find_previous_compile(const struct iris_context *ice, return NULL; } +void +iris_delete_shader_variants(struct iris_context *ice, + struct iris_uncompiled_shader *ish) +{ + 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); + } +} + + /** * Look for an existing entry in the cache that has identical assembly code. * @@ -175,6 +228,8 @@ iris_upload_shader(struct iris_context *ice, memcpy(shader->map, assembly, prog_data->program_size); } + list_inithead(&shader->link); + shader->prog_data = prog_data; shader->streamout = streamout; shader->system_values = system_values; @@ -262,6 +317,9 @@ 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 @@ -269,6 +327,11 @@ 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); + } } hash_table_foreach(ice->shaders.cache, entry) {