v3dv: Add support for the on-disk shader cache

Quoting Jason's commit message (afa8f5892), that also applies here:

"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: Iago Toral Quiroga <itoral@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9403>
This commit is contained in:
Alejandro Piñeiro 2021-03-18 22:56:50 +01:00 committed by Marge Bot
parent cf71280d74
commit 74785346b4
3 changed files with 133 additions and 11 deletions

View File

@ -174,11 +174,22 @@ v3dv_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
return VK_SUCCESS;
}
static void
v3dv_physical_device_free_disk_cache(struct v3dv_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 void
physical_device_finish(struct v3dv_physical_device *device)
{
v3dv_wsi_finish(device);
v3dv_physical_device_free_disk_cache(device);
v3d_compiler_free(device->compiler);
close(device->render_fd);
@ -551,6 +562,8 @@ init_uuids(struct v3dv_physical_device *device)
"build-id too short. It needs to be a SHA");
}
memcpy(device->driver_build_sha1, build_id_data(note), 20);
uint32_t vendor_id = v3dv_physical_device_vendor_id(device);
uint32_t device_id = v3dv_physical_device_device_id(device);
@ -587,6 +600,20 @@ init_uuids(struct v3dv_physical_device *device)
return VK_SUCCESS;
}
static void
v3dv_physical_device_init_disk_cache(struct v3dv_physical_device *device)
{
#ifdef ENABLE_SHADER_CACHE
char timestamp[41];
_mesa_sha1_format(timestamp, device->driver_build_sha1);
assert(device->name);
device->disk_cache = disk_cache_create(device->name, timestamp, 0);
#else
device->disk_cache = NULL;
#endif
}
static VkResult
physical_device_init(struct v3dv_physical_device *device,
struct v3dv_instance *instance,
@ -671,6 +698,8 @@ physical_device_init(struct v3dv_physical_device *device,
device->devinfo.ver / 10, device->devinfo.ver % 10);
assert(len != -1);
v3dv_physical_device_init_disk_cache(device);
/* Setup available memory heaps and types */
VkPhysicalDeviceMemoryProperties *mem = &device->memory;
mem->memoryHeapCount = 1;

View File

@ -209,6 +209,19 @@ v3dv_pipeline_cache_init(struct v3dv_pipeline_cache *cache,
}
static struct v3dv_pipeline_shared_data *
v3dv_pipeline_shared_data_create_from_blob(struct v3dv_pipeline_cache *cache,
struct blob_reader *blob);
static void
pipeline_cache_upload_shared_data(struct v3dv_pipeline_cache *cache,
struct v3dv_pipeline_shared_data *shared_data,
bool from_disk_cache);
static bool
v3dv_pipeline_shared_data_write_to_blob(const struct v3dv_pipeline_shared_data *cache_entry,
struct blob *blob);
/**
* It searchs for pipeline cached data, and returns a v3dv_pipeline_shared_data with
* it, or NULL if doesn't have it cached. On the former, it will increases the
@ -261,6 +274,44 @@ v3dv_pipeline_cache_search_for_pipeline(struct v3dv_pipeline_cache *cache,
}
pthread_mutex_unlock(&cache->mutex);
#ifdef ENABLE_SHADER_CACHE
struct v3dv_device *device = cache->device;
struct disk_cache *disk_cache = device->pdevice->disk_cache;
/* Note that the on-disk-cache can be independently disabled, while keeping
* the pipeline cache working, by using the environment variable
* MESA_GLSL_CACHE_DISABLE. In that case the calls to disk_cache_put/get
* will not do anything.
*/
if (disk_cache && device->instance->pipeline_cache_enabled) {
cache_key cache_key;
disk_cache_compute_key(disk_cache, sha1_key, 20, cache_key);
size_t buffer_size;
uint8_t *buffer = disk_cache_get(disk_cache, cache_key, &buffer_size);
if (buffer) {
struct blob_reader blob;
struct v3dv_pipeline_shared_data *shared_data;
if (debug_cache)
fprintf(stderr, "\ton-disk-cache hit\n");
blob_reader_init(&blob, buffer, buffer_size);
shared_data = v3dv_pipeline_shared_data_create_from_blob(cache, &blob);
free(buffer);
if (shared_data) {
if (cache)
pipeline_cache_upload_shared_data(cache, shared_data, true);
return shared_data;
}
} else {
if (debug_cache)
fprintf(stderr, "\ton-disk-cache miss\n");
}
}
#endif
return NULL;
}
@ -338,11 +389,13 @@ v3dv_pipeline_shared_data_new(struct v3dv_pipeline_cache *cache,
return new_entry;
}
/* Uploads all the "cacheable" or shared data from the pipeline */
void
v3dv_pipeline_cache_upload_pipeline(struct v3dv_pipeline *pipeline,
struct v3dv_pipeline_cache *cache)
static void
pipeline_cache_upload_shared_data(struct v3dv_pipeline_cache *cache,
struct v3dv_pipeline_shared_data *shared_data,
bool from_disk_cache)
{
assert(shared_data);
if (!cache || !cache->cache)
return;
@ -351,28 +404,65 @@ v3dv_pipeline_cache_upload_pipeline(struct v3dv_pipeline *pipeline,
pthread_mutex_lock(&cache->mutex);
struct hash_entry *entry =
_mesa_hash_table_search(cache->cache, pipeline->shared_data->sha1_key);
_mesa_hash_table_search(cache->cache, shared_data->sha1_key);
if (entry) {
pthread_mutex_unlock(&cache->mutex);
return;
}
v3dv_pipeline_shared_data_ref(pipeline->shared_data);
_mesa_hash_table_insert(cache->cache, pipeline->shared_data->sha1_key,
pipeline->shared_data);
v3dv_pipeline_shared_data_ref(shared_data);
_mesa_hash_table_insert(cache->cache, shared_data->sha1_key, shared_data);
cache->stats.count++;
if (debug_cache) {
char sha1buf[41];
_mesa_sha1_format(sha1buf, pipeline->shared_data->sha1_key);
_mesa_sha1_format(sha1buf, shared_data->sha1_key);
fprintf(stderr, "pipeline cache %p, new cache entry with sha1 key %s:%p\n\n",
cache, sha1buf, pipeline->shared_data);
cache, sha1buf, shared_data);
if (dump_stats)
cache_dump_stats(cache);
}
pthread_mutex_unlock(&cache->mutex);
#ifdef ENABLE_SHADER_CACHE
/* If we are being called from a on-disk-cache hit, we can skip writing to
* the disk cache
*/
if (from_disk_cache)
return;
struct v3dv_device *device = cache->device;
struct disk_cache *disk_cache = device->pdevice->disk_cache;
if (disk_cache) {
struct blob binary;
blob_init(&binary);
if (v3dv_pipeline_shared_data_write_to_blob(shared_data, &binary)) {
cache_key cache_key;
disk_cache_compute_key(disk_cache, shared_data->sha1_key, 20, cache_key);
disk_cache_put(disk_cache, cache_key, binary.data, binary.size, NULL);
if (debug_cache) {
char sha1buf[41];
_mesa_sha1_format(sha1buf, shared_data->sha1_key);
fprintf(stderr, "on-disk-cache, new cache entry with sha1 key %s:%p\n\n",
sha1buf, shared_data);
}
}
blob_finish(&binary);
}
#endif
}
/* Uploads all the "cacheable" or shared data from the pipeline */
void
v3dv_pipeline_cache_upload_pipeline(struct v3dv_pipeline *pipeline,
struct v3dv_pipeline_cache *cache)
{
pipeline_cache_upload_shared_data(cache, pipeline->shared_data, false);
}
static struct serialized_nir*

View File

@ -131,10 +131,13 @@ struct v3dv_physical_device {
int32_t display_fd;
int32_t master_fd;
uint8_t driver_build_sha1[20];
uint8_t pipeline_cache_uuid[VK_UUID_SIZE];
uint8_t device_uuid[VK_UUID_SIZE];
uint8_t driver_uuid[VK_UUID_SIZE];
struct disk_cache *disk_cache;
mtx_t mutex;
struct wsi_device wsi_device;