V2: - when loading from disk cache also binary insert into memory cache. - check that the binary loaded from disk is the correct size. If not delete the cache item and skip loading from cache.
V3: - remove unrequired variable Tested-by: Michel Dänzer <michel.daen...@amd.com> --- src/gallium/drivers/radeonsi/si_state_shaders.c | 67 ++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c index 750cdd6..a82e38e 100644 --- a/src/gallium/drivers/radeonsi/si_state_shaders.c +++ b/src/gallium/drivers/radeonsi/si_state_shaders.c @@ -29,20 +29,23 @@ #include "sid.h" #include "radeon/r600_cs.h" #include "tgsi/tgsi_parse.h" #include "tgsi/tgsi_ureg.h" #include "util/hash_table.h" #include "util/crc32.h" #include "util/u_memory.h" #include "util/u_prim.h" +#include "util/disk_cache.h" +#include "util/mesa-sha1.h" + /* SHADER_CACHE */ /** * Return the TGSI binary in a buffer. The first 4 bytes contain its size as * integer. */ static void *si_get_tgsi_binary(struct si_shader_selector *sel) { unsigned tgsi_size = tgsi_num_tokens(sel->tokens) * sizeof(struct tgsi_token); @@ -175,54 +178,104 @@ static bool si_load_shader_binary(struct si_shader *shader, void *binary) } /** * Insert a shader into the cache. It's assumed the shader is not in the cache. * Use si_shader_cache_load_shader before calling this. * * Returns false on failure, in which case the tgsi_binary should be freed. */ static bool si_shader_cache_insert_shader(struct si_screen *sscreen, void *tgsi_binary, - struct si_shader *shader) + struct si_shader *shader, + bool insert_into_disk_cache) { void *hw_binary; struct hash_entry *entry; + uint8_t key[CACHE_KEY_SIZE]; entry = _mesa_hash_table_search(sscreen->shader_cache, tgsi_binary); if (entry) return false; /* already added */ hw_binary = si_get_shader_binary(shader); if (!hw_binary) return false; if (_mesa_hash_table_insert(sscreen->shader_cache, tgsi_binary, hw_binary) == NULL) { FREE(hw_binary); return false; } + if (sscreen->b.disk_shader_cache && insert_into_disk_cache) { + _mesa_sha1_compute(tgsi_binary, *((uint32_t *)tgsi_binary), key); + disk_cache_put(sscreen->b.disk_shader_cache, key, hw_binary, + *((uint32_t *) hw_binary)); + } + return true; } static bool si_shader_cache_load_shader(struct si_screen *sscreen, void *tgsi_binary, struct si_shader *shader) { struct hash_entry *entry = _mesa_hash_table_search(sscreen->shader_cache, tgsi_binary); - if (!entry) - return false; + if (!entry) { + if (sscreen->b.disk_shader_cache) { + unsigned char sha1[CACHE_KEY_SIZE]; + size_t tg_size = *((uint32_t *) tgsi_binary); + + _mesa_sha1_compute(tgsi_binary, tg_size, sha1); + + size_t binary_size; + uint8_t *buffer = + disk_cache_get(sscreen->b.disk_shader_cache, + sha1, &binary_size); + if (!buffer) + return false; - if (!si_load_shader_binary(shader, entry->data)) - return false; + if (binary_size < sizeof(uint32_t) || + *((uint32_t*)buffer) != binary_size) { + /* Something has gone wrong discard the item + * from the cache and rebuild/link from + * source. + */ + assert(!"Invalid radeonsi shader disk cache " + "item!"); + + disk_cache_remove(sscreen->b.disk_shader_cache, + sha1); + free(buffer); + + return false; + } + + if (!si_load_shader_binary(shader, buffer)) { + free(buffer); + return false; + } + free(buffer); + if (!si_shader_cache_insert_shader(sscreen, tgsi_binary, + shader, false)) + FREE(tgsi_binary); + } else { + return false; + } + } else { + if (si_load_shader_binary(shader, entry->data)) + FREE(tgsi_binary); + else + return false; + } p_atomic_inc(&sscreen->b.num_shader_cache_hits); return true; } static uint32_t si_shader_cache_key_hash(const void *key) { /* The first dword is the key size. */ return util_hash_crc32(key, *(uint32_t*)key); } @@ -244,20 +297,21 @@ static void si_destroy_shader_cache_entry(struct hash_entry *entry) FREE(entry->data); } bool si_init_shader_cache(struct si_screen *sscreen) { pipe_mutex_init(sscreen->shader_cache_mutex); sscreen->shader_cache = _mesa_hash_table_create(NULL, si_shader_cache_key_hash, si_shader_cache_key_equals); + return sscreen->shader_cache != NULL; } void si_destroy_shader_cache(struct si_screen *sscreen) { if (sscreen->shader_cache) _mesa_hash_table_destroy(sscreen->shader_cache, si_destroy_shader_cache_entry); pipe_mutex_destroy(sscreen->shader_cache_mutex); } @@ -1400,37 +1454,36 @@ void si_init_shader_selector_async(void *job, int thread_index) shader->selector = sel; si_parse_next_shader_property(&sel->info, &shader->key); tgsi_binary = si_get_tgsi_binary(sel); /* Try to load the shader from the shader cache. */ pipe_mutex_lock(sscreen->shader_cache_mutex); if (tgsi_binary && si_shader_cache_load_shader(sscreen, tgsi_binary, shader)) { - FREE(tgsi_binary); pipe_mutex_unlock(sscreen->shader_cache_mutex); } else { pipe_mutex_unlock(sscreen->shader_cache_mutex); /* Compile the shader if it hasn't been loaded from the cache. */ if (si_compile_tgsi_shader(sscreen, tm, shader, false, debug) != 0) { FREE(shader); FREE(tgsi_binary); fprintf(stderr, "radeonsi: can't compile a main shader part\n"); return; } if (tgsi_binary) { pipe_mutex_lock(sscreen->shader_cache_mutex); - if (!si_shader_cache_insert_shader(sscreen, tgsi_binary, shader)) + if (!si_shader_cache_insert_shader(sscreen, tgsi_binary, shader, true)) FREE(tgsi_binary); pipe_mutex_unlock(sscreen->shader_cache_mutex); } } *si_get_main_shader_part(sel, &shader->key) = shader; /* Unset "outputs_written" flags for outputs converted to * DEFAULT_VAL, so that later inter-shader optimizations don't * try to eliminate outputs that don't exist in the final -- 2.9.3 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev