From afa8f589219440890d3afc42df6a055a15eb676f Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 29 Jun 2018 17:08:30 -0700 Subject: [PATCH] anv: Add support for the on-disk shader cache The Vulkan API provides a mechanism for applications to cache their own shaders and manage on-disk pipeline caching themselves. Generally, this is what I would recommend to application developers and I've resisted implementing driver-side transparent caching in the Vulkan driver for a long time. However, not all applications do this and, for some use-cases, it's just not practical. Reviewed-by: Timothy Arceri --- src/intel/vulkan/anv_device.c | 36 ++++++++++ src/intel/vulkan/anv_pipeline_cache.c | 98 ++++++++++++++++++++++++--- src/intel/vulkan/anv_private.h | 3 + 3 files changed, 126 insertions(+), 11 deletions(-) diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c index 2d0b23dfdae..7b3ddbb9501 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -35,6 +35,7 @@ #include "util/strtod.h" #include "util/debug.h" #include "util/build_id.h" +#include "util/disk_cache.h" #include "util/mesa-sha1.h" #include "vk_util.h" #include "common/gen_defines.h" @@ -233,6 +234,8 @@ anv_physical_device_init_uuids(struct anv_physical_device *device) "build-id too short. It needs to be a SHA"); } + memcpy(device->driver_build_sha1, build_id_data(note), 20); + struct mesa_sha1 sha1_ctx; uint8_t sha1[20]; STATIC_ASSERT(VK_UUID_SIZE <= sizeof(sha1)); @@ -271,6 +274,35 @@ anv_physical_device_init_uuids(struct anv_physical_device *device) return VK_SUCCESS; } +static void +anv_physical_device_init_disk_cache(struct anv_physical_device *device) +{ +#ifdef ENABLE_SHADER_CACHE + char renderer[9]; + MAYBE_UNUSED int len = snprintf(renderer, sizeof(renderer), "anv_%04x", + device->chipset_id); + assert(len == sizeof(renderer) - 1); + + char timestamp[41]; + _mesa_sha1_format(timestamp, device->driver_build_sha1); + + device->disk_cache = disk_cache_create(renderer, timestamp, 0); +#else + device->disk_cache = NULL; +#endif +} + +static void +anv_physical_device_free_disk_cache(struct anv_physical_device *device) +{ +#ifdef ENABLE_SHADER_CACHE + if (device->disk_cache) + disk_cache_destroy(device->disk_cache); +#else + assert(device->disk_cache == NULL); +#endif +} + static VkResult anv_physical_device_init(struct anv_physical_device *device, struct anv_instance *instance, @@ -442,6 +474,8 @@ anv_physical_device_init(struct anv_physical_device *device, if (result != VK_SUCCESS) goto fail; + anv_physical_device_init_disk_cache(device); + if (instance->enabled_extensions.KHR_display) { master_fd = open(primary_path, O_RDWR | O_CLOEXEC); if (master_fd >= 0) { @@ -459,6 +493,7 @@ anv_physical_device_init(struct anv_physical_device *device, result = anv_init_wsi(device); if (result != VK_SUCCESS) { ralloc_free(device->compiler); + anv_physical_device_free_disk_cache(device); goto fail; } @@ -481,6 +516,7 @@ static void anv_physical_device_finish(struct anv_physical_device *device) { anv_finish_wsi(device); + anv_physical_device_free_disk_cache(device); ralloc_free(device->compiler); close(device->local_fd); if (device->master_fd >= 0) diff --git a/src/intel/vulkan/anv_pipeline_cache.c b/src/intel/vulkan/anv_pipeline_cache.c index e57cd1c75c6..d4c7262dc05 100644 --- a/src/intel/vulkan/anv_pipeline_cache.c +++ b/src/intel/vulkan/anv_pipeline_cache.c @@ -24,6 +24,8 @@ #include "compiler/blob.h" #include "util/hash_table.h" #include "util/debug.h" +#include "util/disk_cache.h" +#include "util/mesa-sha1.h" #include "anv_private.h" struct anv_shader_bin * @@ -280,6 +282,25 @@ anv_pipeline_cache_search(struct anv_pipeline_cache *cache, return shader; } +static void +anv_pipeline_cache_add_shader_bin(struct anv_pipeline_cache *cache, + struct anv_shader_bin *bin) +{ + if (!cache->cache) + return; + + pthread_mutex_lock(&cache->mutex); + + struct hash_entry *entry = _mesa_hash_table_search(cache->cache, bin->key); + if (entry == NULL) { + /* Take a reference for the cache */ + anv_shader_bin_ref(bin); + _mesa_hash_table_insert(cache->cache, bin->key, bin); + } + + pthread_mutex_unlock(&cache->mutex); +} + static struct anv_shader_bin * anv_pipeline_cache_add_shader_locked(struct anv_pipeline_cache *cache, const void *key_data, uint32_t key_size, @@ -540,7 +561,38 @@ anv_device_search_for_kernel(struct anv_device *device, struct anv_pipeline_cache *cache, const void *key_data, uint32_t key_size) { - return cache ? anv_pipeline_cache_search(cache, key_data, key_size) : NULL; + struct anv_shader_bin *bin; + + if (cache) { + bin = anv_pipeline_cache_search(cache, key_data, key_size); + if (bin) + return bin; + } + +#ifdef ENABLE_SHADER_CACHE + struct disk_cache *disk_cache = device->instance->physicalDevice.disk_cache; + if (disk_cache) { + cache_key cache_key; + disk_cache_compute_key(disk_cache, key_data, key_size, cache_key); + + size_t buffer_size; + uint8_t *buffer = disk_cache_get(disk_cache, cache_key, &buffer_size); + if (buffer) { + struct blob_reader blob; + blob_reader_init(&blob, buffer, buffer_size); + bin = anv_shader_bin_create_from_blob(device, &blob); + free(buffer); + + if (bin) { + if (cache) + anv_pipeline_cache_add_shader_bin(cache, bin); + return bin; + } + } + } +#endif + + return NULL; } struct anv_shader_bin * @@ -554,17 +606,41 @@ anv_device_upload_kernel(struct anv_device *device, uint32_t prog_data_size, const struct anv_pipeline_bind_map *bind_map) { + struct anv_shader_bin *bin; if (cache) { - return anv_pipeline_cache_upload_kernel(cache, key_data, key_size, - kernel_data, kernel_size, - constant_data, constant_data_size, - prog_data, prog_data_size, - bind_map); + bin = anv_pipeline_cache_upload_kernel(cache, key_data, key_size, + kernel_data, kernel_size, + constant_data, constant_data_size, + prog_data, prog_data_size, + bind_map); } else { - return anv_shader_bin_create(device, key_data, key_size, - kernel_data, kernel_size, - constant_data, constant_data_size, - prog_data, prog_data_size, - prog_data->param, bind_map); + bin = anv_shader_bin_create(device, key_data, key_size, + kernel_data, kernel_size, + constant_data, constant_data_size, + prog_data, prog_data_size, + prog_data->param, bind_map); } + + if (bin == NULL) + return NULL; + +#ifdef ENABLE_SHADER_CACHE + struct disk_cache *disk_cache = device->instance->physicalDevice.disk_cache; + if (disk_cache) { + struct blob binary; + blob_init(&binary); + anv_shader_bin_write_to_blob(bin, &binary); + + if (!binary.out_of_memory) { + cache_key cache_key; + disk_cache_compute_key(disk_cache, key_data, key_size, cache_key); + + disk_cache_put(disk_cache, cache_key, binary.data, binary.size, NULL); + } + + blob_finish(&binary); + } +#endif + + return bin; } diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 1f1f9795cf3..4a26b1d3096 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -870,10 +870,13 @@ struct anv_physical_device { struct anv_memory_heap heaps[VK_MAX_MEMORY_HEAPS]; } memory; + uint8_t driver_build_sha1[20]; uint8_t pipeline_cache_uuid[VK_UUID_SIZE]; uint8_t driver_uuid[VK_UUID_SIZE]; uint8_t device_uuid[VK_UUID_SIZE]; + struct disk_cache * disk_cache; + struct wsi_device wsi_device; int local_fd; int master_fd; -- 2.30.2