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 <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9540>
This commit is contained in:
Mike Blumenkrantz 2020-10-13 09:42:07 -04:00 committed by Marge Bot
parent 6205400612
commit 980a8b3fc0
4 changed files with 90 additions and 6 deletions

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -32,6 +32,7 @@
#include "compiler/nir/nir.h"
#include "util/disk_cache.h"
#include "util/log.h"
#include "util/simple_mtx.h"
#include <vulkan/vulkan.h>
@ -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;