[Mesa-dev] [PATCH V3 3/4] radeonsi: add support for an on-disk shader cache

Timothy Arceri tarceri at itsqueeze.com
Fri Feb 24 04:34:53 UTC 2017


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.daenzer at 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 f615aa8..9353c37 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



More information about the mesa-dev mailing list