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;