zink: implement a surface cache

this is a global cache for all surface objects, enabling some memory
optimizations as well as improved reuse of cached descriptors

loosely based on patches from Antonio Caggiano

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9541>
This commit is contained in:
Mike Blumenkrantz 2021-02-09 15:40:38 -05:00
parent 2643f9ed28
commit 38f7faa8a4
4 changed files with 125 additions and 26 deletions

View file

@ -83,6 +83,12 @@ zink_get_name(struct pipe_screen *pscreen)
return buf;
}
static bool
equals_ivci(const void *a, const void *b)
{
return memcmp(a, b, sizeof(VkImageViewCreateInfo)) == 0;
}
static VkDeviceSize
get_video_mem(struct zink_screen *screen)
{
@ -846,6 +852,14 @@ zink_destroy_screen(struct pipe_screen *pscreen)
screen->vk_DestroyDebugUtilsMessengerEXT(screen->instance, screen->debugUtilsCallbackHandle, NULL);
}
hash_table_foreach(&screen->surface_cache, entry) {
struct pipe_surface *psurf = (struct pipe_surface*)entry->data;
pipe_resource_reference(&psurf->texture, NULL);
pipe_surface_reference(&psurf, NULL);
}
simple_mtx_destroy(&screen->surface_mtx);
u_transfer_helper_destroy(pscreen->transfer_helper);
zink_screen_update_pipeline_cache(screen);
#ifdef ENABLE_SHADER_CACHE
@ -1368,6 +1382,10 @@ zink_internal_create_screen(const struct pipe_screen_config *config)
screen->total_mem = get_video_mem(screen);
simple_mtx_init(&screen->surface_mtx, mtx_plain);
_mesa_hash_table_init(&screen->surface_cache, screen, NULL, equals_ivci);
return screen;
fail:

View file

@ -54,6 +54,9 @@ struct zink_screen {
struct sw_winsys *winsys;
struct hash_table surface_cache;
simple_mtx_t surface_mtx;
struct slab_parent_pool transfer_pool;
VkPipelineCache pipeline_cache;
size_t pipeline_cache_size;

View file

@ -30,36 +30,16 @@
#include "util/u_inlines.h"
#include "util/u_memory.h"
static struct pipe_surface *
zink_create_surface(struct pipe_context *pctx,
struct pipe_resource *pres,
const struct pipe_surface *templ)
VkImageViewCreateInfo
create_ivci(struct zink_screen *screen,
struct zink_resource *res,
const struct pipe_surface *templ)
{
struct zink_screen *screen = zink_screen(pctx->screen);
unsigned int level = templ->u.tex.level;
struct zink_surface *surface = CALLOC_STRUCT(zink_surface);
if (!surface)
return NULL;
pipe_resource_reference(&surface->base.texture, pres);
pipe_reference_init(&surface->base.reference, 1);
surface->base.context = pctx;
surface->base.format = templ->format;
surface->base.width = u_minify(pres->width0, level);
surface->base.height = u_minify(pres->height0, level);
surface->base.nr_samples = templ->nr_samples;
surface->base.u.tex.level = level;
surface->base.u.tex.first_layer = templ->u.tex.first_layer;
surface->base.u.tex.last_layer = templ->u.tex.last_layer;
struct zink_resource *res = zink_resource(pres);
VkImageViewCreateInfo ivci = {};
ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
ivci.image = res->image;
switch (pres->target) {
switch (res->base.target) {
case PIPE_TEXTURE_1D:
ivci.viewType = VK_IMAGE_VIEW_TYPE_1D;
break;
@ -118,21 +98,105 @@ zink_create_surface(struct pipe_context *pctx,
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
}
if (vkCreateImageView(screen->dev, &ivci, NULL,
return ivci;
}
static struct zink_surface *
create_surface(struct pipe_context *pctx,
struct pipe_resource *pres,
const struct pipe_surface *templ,
VkImageViewCreateInfo *ivci)
{
struct zink_screen *screen = zink_screen(pctx->screen);
unsigned int level = templ->u.tex.level;
struct zink_surface *surface = CALLOC_STRUCT(zink_surface);
if (!surface)
return NULL;
pipe_resource_reference(&surface->base.texture, pres);
pipe_reference_init(&surface->base.reference, 1);
surface->base.context = pctx;
surface->base.format = templ->format;
surface->base.width = u_minify(pres->width0, level);
surface->base.height = u_minify(pres->height0, level);
surface->base.nr_samples = templ->nr_samples;
surface->base.u.tex.level = level;
surface->base.u.tex.first_layer = templ->u.tex.first_layer;
surface->base.u.tex.last_layer = templ->u.tex.last_layer;
if (vkCreateImageView(screen->dev, ivci, NULL,
&surface->image_view) != VK_SUCCESS) {
FREE(surface);
return NULL;
}
return surface;
}
static uint32_t
hash_ivci(const void *key)
{
return _mesa_hash_data((char*)key + offsetof(VkImageViewCreateInfo, flags), sizeof(VkImageViewCreateInfo) - offsetof(VkImageViewCreateInfo, flags));
}
struct pipe_surface *
zink_get_surface(struct zink_context *ctx,
struct pipe_resource *pres,
const struct pipe_surface *templ,
VkImageViewCreateInfo *ivci)
{
struct zink_screen *screen = zink_screen(ctx->base.screen);
struct zink_surface *surface = NULL;
uint32_t hash = hash_ivci(ivci);
simple_mtx_lock(&screen->surface_mtx);
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, hash, ivci);
if (!entry) {
/* create a new surface */
surface = create_surface(&ctx->base, pres, templ, ivci);
surface->hash = hash;
surface->ivci = *ivci;
entry = _mesa_hash_table_insert_pre_hashed(&screen->surface_cache, hash, &surface->ivci, surface);
if (!entry) {
simple_mtx_unlock(&screen->surface_mtx);
return NULL;
}
surface = entry->data;
} else {
surface = entry->data;
p_atomic_inc(&surface->base.reference.count);
}
simple_mtx_unlock(&screen->surface_mtx);
return &surface->base;
}
static struct pipe_surface *
zink_create_surface(struct pipe_context *pctx,
struct pipe_resource *pres,
const struct pipe_surface *templ)
{
VkImageViewCreateInfo ivci = create_ivci(zink_screen(pctx->screen),
zink_resource(pres), templ);
return zink_get_surface(zink_context(pctx), pres, templ, &ivci);
}
static void
zink_surface_destroy(struct pipe_context *pctx,
struct pipe_surface *psurface)
{
struct zink_screen *screen = zink_screen(pctx->screen);
struct zink_surface *surface = zink_surface(psurface);
simple_mtx_lock(&screen->surface_mtx);
struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);
assert(he);
_mesa_hash_table_remove(&screen->surface_cache, he);
simple_mtx_unlock(&screen->surface_mtx);
pipe_resource_reference(&psurface->texture, NULL);
vkDestroyImageView(screen->dev, surface->image_view, NULL);
FREE(surface);

View file

@ -32,7 +32,9 @@ struct pipe_context;
struct zink_surface {
struct pipe_surface base;
VkImageViewCreateInfo ivci;
VkImageView image_view;
uint32_t hash;
};
static inline struct zink_surface *
@ -44,4 +46,16 @@ zink_surface(struct pipe_surface *pipe)
void
zink_context_surface_init(struct pipe_context *context);
VkImageViewCreateInfo
create_ivci(struct zink_screen *screen,
struct zink_resource *res,
const struct pipe_surface *templ);
struct pipe_surface *
zink_get_surface(struct zink_context *ctx,
struct pipe_resource *pres,
const struct pipe_surface *templ,
VkImageViewCreateInfo *ivci);
#endif