Mesa (master): zink: implement a surface cache

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Mar 15 14:09:55 UTC 2021


Module: Mesa
Branch: master
Commit: 38f7faa8a49f4d8b70d7a477a2bc3255b0995e64
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=38f7faa8a49f4d8b70d7a477a2bc3255b0995e64

Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date:   Tue Feb  9 15:40:38 2021 -0500

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 at redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9541>

---

 src/gallium/drivers/zink/zink_screen.c  |  18 +++++
 src/gallium/drivers/zink/zink_screen.h  |   3 +
 src/gallium/drivers/zink/zink_surface.c | 116 +++++++++++++++++++++++++-------
 src/gallium/drivers/zink/zink_surface.h |  14 ++++
 4 files changed, 125 insertions(+), 26 deletions(-)

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



More information about the mesa-commit mailing list