diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index 504f7a72c0c..a86da07f68f 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -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: diff --git a/src/gallium/drivers/zink/zink_screen.h b/src/gallium/drivers/zink/zink_screen.h index afbd43d930c..a7d00f00c91 100644 --- a/src/gallium/drivers/zink/zink_screen.h +++ b/src/gallium/drivers/zink/zink_screen.h @@ -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; diff --git a/src/gallium/drivers/zink/zink_surface.c b/src/gallium/drivers/zink/zink_surface.c index 08dc360ee0e..eaaa28879cc 100644 --- a/src/gallium/drivers/zink/zink_surface.c +++ b/src/gallium/drivers/zink/zink_surface.c @@ -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); diff --git a/src/gallium/drivers/zink/zink_surface.h b/src/gallium/drivers/zink/zink_surface.h index a85a4981c20..7cba720ddbd 100644 --- a/src/gallium/drivers/zink/zink_surface.h +++ b/src/gallium/drivers/zink/zink_surface.h @@ -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