From 980a8b3fc0ed60f60b335358f4232fd99bd685d5 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Tue, 13 Oct 2020 09:42:07 -0400 Subject: [PATCH] zink: implement an extremely dumb resource memory cache this stores a number (currently 5) of backing allocations for resources for later reuse when creating matching resources because this is on the screen object it requires locking, but this is still far faster than allocating new memory each time Reviewed-by: Dave Airlie Part-of: --- src/gallium/drivers/zink/zink_resource.c | 63 ++++++++++++++++++++++-- src/gallium/drivers/zink/zink_resource.h | 9 +++- src/gallium/drivers/zink/zink_screen.c | 19 ++++++- src/gallium/drivers/zink/zink_screen.h | 5 ++ 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c index 32d6f331ce2..1b5f71338b2 100644 --- a/src/gallium/drivers/zink/zink_resource.c +++ b/src/gallium/drivers/zink/zink_resource.c @@ -67,6 +67,42 @@ resource_sync_writes_from_batch_id(struct zink_context *ctx, uint32_t batch_uses } } +static uint32_t +mem_hash(const void *key) +{ + return _mesa_hash_data(key, sizeof(struct mem_key)); +} + +static bool +mem_equals(const void *a, const void *b) +{ + return !memcmp(a, b, sizeof(struct mem_key)); +} + +static void +cache_or_free_mem(struct zink_screen *screen, struct zink_resource *res) +{ + if (res->mkey.flags) { + simple_mtx_lock(&screen->mem_cache_mtx); + struct hash_entry *he = _mesa_hash_table_search_pre_hashed(screen->resource_mem_cache, res->mem_hash, &res->mkey); + struct util_dynarray *array = he ? (void*)he->data : NULL; + if (!array) { + struct mem_key *mkey = rzalloc(screen->resource_mem_cache, struct mem_key); + memcpy(mkey, &res->mkey, sizeof(struct mem_key)); + array = rzalloc(screen->resource_mem_cache, struct util_dynarray); + util_dynarray_init(array, screen->resource_mem_cache); + _mesa_hash_table_insert_pre_hashed(screen->resource_mem_cache, res->mem_hash, mkey, array); + } + if (util_dynarray_num_elements(array, VkDeviceMemory) < 5) { + util_dynarray_append(array, VkDeviceMemory, res->mem); + simple_mtx_unlock(&screen->mem_cache_mtx); + return; + } + simple_mtx_unlock(&screen->mem_cache_mtx); + } + vkFreeMemory(screen->dev, res->mem, NULL); +} + static void zink_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pres) @@ -81,7 +117,8 @@ zink_resource_destroy(struct pipe_screen *pscreen, zink_descriptor_set_refs_clear(&res->desc_set_refs, res); - vkFreeMemory(screen->dev, res->mem, NULL); + cache_or_free_mem(screen, res); + FREE(res); } @@ -369,7 +406,21 @@ resource_create(struct pipe_screen *pscreen, mai.pNext = &memory_wsi_info; } - if (vkAllocateMemory(screen->dev, &mai, NULL, &res->mem) != VK_SUCCESS) { + if (!mai.pNext && !(templ->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT)) { + res->mkey.reqs = reqs; + res->mkey.flags = flags; + res->mem_hash = mem_hash(&res->mkey); + simple_mtx_lock(&screen->mem_cache_mtx); + + struct hash_entry *he = _mesa_hash_table_search_pre_hashed(screen->resource_mem_cache, res->mem_hash, &res->mkey); + struct util_dynarray *array = he ? (void*)he->data : NULL; + if (array && util_dynarray_num_elements(array, VkDeviceMemory)) { + res->mem = util_dynarray_pop(array, VkDeviceMemory); + } + simple_mtx_unlock(&screen->mem_cache_mtx); + } + + if (!res->mem && vkAllocateMemory(screen->dev, &mai, NULL, &res->mem) != VK_SUCCESS) { debug_printf("vkAllocateMemory failed\n"); goto fail; } @@ -877,17 +928,21 @@ static const struct u_transfer_vtbl transfer_vtbl = { .get_stencil = zink_resource_get_separate_stencil, }; -void +bool zink_screen_resource_init(struct pipe_screen *pscreen) { + struct zink_screen *screen = zink_screen(pscreen); pscreen->resource_create = zink_resource_create; pscreen->resource_destroy = zink_resource_destroy; pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, true, true, false, false); - if (zink_screen(pscreen)->info.have_KHR_external_memory_fd) { + if (screen->info.have_KHR_external_memory_fd) { pscreen->resource_get_handle = zink_resource_get_handle; pscreen->resource_from_handle = zink_resource_from_handle; } + simple_mtx_init(&screen->mem_cache_mtx, mtx_plain); + screen->resource_mem_cache = _mesa_hash_table_create(NULL, mem_hash, mem_equals); + return !!screen->resource_mem_cache; } void diff --git a/src/gallium/drivers/zink/zink_resource.h b/src/gallium/drivers/zink/zink_resource.h index e252dda3a35..9f2d02306c1 100644 --- a/src/gallium/drivers/zink/zink_resource.h +++ b/src/gallium/drivers/zink/zink_resource.h @@ -40,6 +40,11 @@ struct zink_context; #define ZINK_RESOURCE_ACCESS_READ 1 #define ZINK_RESOURCE_ACCESS_WRITE 32 +struct mem_key { + VkMemoryRequirements reqs; + VkMemoryPropertyFlags flags; +}; + struct zink_resource { struct pipe_resource base; @@ -62,6 +67,8 @@ struct zink_resource { }; }; VkDeviceMemory mem; + uint32_t mem_hash; + struct mem_key mkey; VkDeviceSize offset, size; struct sw_displaytarget *dt; @@ -85,7 +92,7 @@ zink_resource(struct pipe_resource *r) return (struct zink_resource *)r; } -void +bool zink_screen_resource_init(struct pipe_screen *pscreen); void diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index 6c8dd8242d7..55a677ce983 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -35,6 +35,7 @@ #include "os/os_process.h" #include "util/u_debug.h" #include "util/format/u_format.h" +#include "util/hash_table.h" #include "util/u_math.h" #include "util/u_memory.h" #include "util/u_screen.h" @@ -827,6 +828,15 @@ zink_is_format_supported(struct pipe_screen *pscreen, return true; } +static void +resource_cache_entry_destroy(struct zink_screen *screen, struct hash_entry *he) +{ + struct util_dynarray *array = (void*)he->data; + util_dynarray_foreach(array, VkDeviceMemory, mem) + vkFreeMemory(screen->dev, *mem, NULL); + util_dynarray_fini(array); +} + static void zink_destroy_screen(struct pipe_screen *pscreen) { @@ -843,6 +853,12 @@ zink_destroy_screen(struct pipe_screen *pscreen) disk_cache_wait_for_idle(screen->disk_cache); #endif disk_cache_destroy(screen->disk_cache); + simple_mtx_lock(&screen->mem_cache_mtx); + hash_table_foreach(screen->resource_mem_cache, he) + resource_cache_entry_destroy(screen, he); + _mesa_hash_table_destroy(screen->resource_mem_cache, NULL); + simple_mtx_unlock(&screen->mem_cache_mtx); + simple_mtx_destroy(&screen->mem_cache_mtx); vkDestroyPipelineCache(screen->dev, screen->pipeline_cache, NULL); vkDestroyDevice(screen->dev, NULL); @@ -1320,7 +1336,8 @@ zink_internal_create_screen(const struct pipe_screen_config *config) screen->base.flush_frontbuffer = zink_flush_frontbuffer; screen->base.destroy = zink_destroy_screen; - zink_screen_resource_init(&screen->base); + if (!zink_screen_resource_init(&screen->base)) + goto fail; zink_screen_fence_init(&screen->base); zink_screen_init_compiler(screen); diff --git a/src/gallium/drivers/zink/zink_screen.h b/src/gallium/drivers/zink/zink_screen.h index c7f95c473e1..afbd43d930c 100644 --- a/src/gallium/drivers/zink/zink_screen.h +++ b/src/gallium/drivers/zink/zink_screen.h @@ -32,6 +32,7 @@ #include "compiler/nir/nir.h" #include "util/disk_cache.h" #include "util/log.h" +#include "util/simple_mtx.h" #include @@ -41,6 +42,7 @@ #endif extern uint32_t zink_debug; +struct hash_table; #define ZINK_DEBUG_NIR 0x1 #define ZINK_DEBUG_SPIRV 0x2 @@ -58,6 +60,9 @@ struct zink_screen { struct disk_cache *disk_cache; cache_key disk_cache_key; + simple_mtx_t mem_cache_mtx; + struct hash_table *resource_mem_cache; + unsigned shader_id; uint64_t total_mem;