Mesa (master): zink: decouple renderpass from framebuffer state

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Jan 14 22:18:16 UTC 2021


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

Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date:   Thu Dec 24 09:42:24 2020 -0500

zink: decouple renderpass from framebuffer state

a framebuffer is based on the surfaces attached to it

a renderpass is based on the operations being performed

a zink_framebuffer object doesn't necessarily need to be changed
if the renderpass changes, as this might just indicate that a clear operation
is being used instead of a load, so we can cache the corresponding vk objects
into the zink_framebuffer based on the renderpass ops being used to (eventually)
reduce fb object thrashing by doing more incremental updates

Reviewed-by: Adam Jackson <ajax at redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8227>

---

 src/gallium/drivers/zink/zink_context.c     |  9 ++--
 src/gallium/drivers/zink/zink_framebuffer.c | 78 +++++++++++++++++++++++------
 src/gallium/drivers/zink/zink_framebuffer.h | 11 +++-
 3 files changed, 77 insertions(+), 21 deletions(-)

diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c
index 3f0cea6a3f1..8e5a943ea55 100644
--- a/src/gallium/drivers/zink/zink_context.c
+++ b/src/gallium/drivers/zink/zink_context.c
@@ -709,7 +709,6 @@ create_framebuffer(struct zink_context *ctx)
    struct pipe_surface *attachments[PIPE_MAX_COLOR_BUFS + 1] = {};
 
    struct zink_framebuffer_state state = {};
-   state.rp = get_render_pass(ctx);
    for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
       struct pipe_surface *psurf = ctx->fb_state.cbufs[i];
       state.attachments[i] = psurf ? zink_surface(psurf)->image_view : VK_NULL_HANDLE;
@@ -728,7 +727,9 @@ create_framebuffer(struct zink_context *ctx)
    state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1);
    state.samples = ctx->fb_state.samples;
 
-   return zink_create_framebuffer(ctx, screen, &state, attachments);
+   struct zink_framebuffer *fb = zink_create_framebuffer(ctx, &state, attachments);
+   zink_init_framebuffer(screen, fb, get_render_pass(ctx));
+   return fb;
 }
 
 static void
@@ -814,7 +815,7 @@ zink_batch_rp(struct zink_context *ctx)
    struct zink_batch *batch = zink_curr_batch(ctx);
    if (!batch->in_rp) {
       zink_begin_render_pass(ctx, batch);
-      assert(batch->fb && batch->fb->state.rp);
+      assert(batch->fb && batch->fb->rp);
    }
    return batch;
 }
@@ -847,7 +848,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx,
       zink_framebuffer_reference(screen, &fb, NULL);
    fb = create_framebuffer(ctx);
    zink_framebuffer_reference(screen, &ctx->framebuffer, fb);
-   ctx->gfx_pipeline_state.render_pass = fb->state.rp;
+   ctx->gfx_pipeline_state.render_pass = fb->rp;
 
    uint8_t rast_samples = util_framebuffer_get_num_samples(state);
    /* in vulkan, gl_SampleMask needs to be explicitly ignored for sampleCount == 1 */
diff --git a/src/gallium/drivers/zink/zink_framebuffer.c b/src/gallium/drivers/zink/zink_framebuffer.c
index 3baf8aca4e2..cbd0a5bb0ff 100644
--- a/src/gallium/drivers/zink/zink_framebuffer.c
+++ b/src/gallium/drivers/zink/zink_framebuffer.c
@@ -63,7 +63,14 @@ void
 zink_destroy_framebuffer(struct zink_screen *screen,
                          struct zink_framebuffer *fb)
 {
-   vkDestroyFramebuffer(screen->dev, fb->fb, NULL);
+   hash_table_foreach(&fb->objects, he) {
+#if defined(_WIN64) || defined(__x86_64__)
+      vkDestroyFramebuffer(screen->dev, he->data, NULL);
+#else
+      VkFramebuffer *ptr = he->data;
+      vkDestroyFramebuffer(screen->dev, *ptr, NULL);
+#endif
+   }
    for (int i = 0; i < ARRAY_SIZE(fb->surfaces); ++i)
       pipe_surface_reference(fb->surfaces + i, NULL);
 
@@ -72,11 +79,60 @@ zink_destroy_framebuffer(struct zink_screen *screen,
    ralloc_free(fb);
 }
 
+void
+zink_init_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp)
+{
+   VkFramebuffer ret;
+
+   if (fb->rp == rp)
+      return;
+
+   uint32_t hash = _mesa_hash_pointer(rp);
+
+   struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&fb->objects, hash, rp);
+   if (he) {
+#if defined(_WIN64) || defined(__x86_64__)
+      ret = (VkFramebuffer)he->data;
+#else
+      VkFramebuffer *ptr = he->data;
+      ret = *ptr;
+#endif
+      goto out;
+   }
+
+   VkFramebufferCreateInfo fci = {};
+   fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+   fci.renderPass = rp->render_pass;
+   fci.attachmentCount = fb->state.num_attachments;
+   fci.pAttachments = fb->state.attachments;
+   fci.width = fb->state.width;
+   fci.height = fb->state.height;
+   fci.layers = fb->state.layers;
+
+   if (vkCreateFramebuffer(screen->dev, &fci, NULL, &ret) != VK_SUCCESS)
+      return;
+#if defined(_WIN64) || defined(__x86_64__)
+   _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ret);
+#else
+   VkFramebuffer *ptr = ralloc(fb, VkFramebuffer);
+   if (!ptr) {
+      vkDestroyFramebuffer(screen->dev, ret, NULL);
+      return;
+   }
+   *ptr = ret;
+   _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ptr);
+#endif
+out:
+   fb->rp = rp;
+   fb->fb = ret;
+}
+
 struct zink_framebuffer *
-zink_create_framebuffer(struct zink_context *ctx, struct zink_screen *screen,
+zink_create_framebuffer(struct zink_context *ctx,
                         struct zink_framebuffer_state *state,
                         struct pipe_surface **attachments)
 {
+   struct zink_screen *screen = zink_screen(ctx->base.screen);
    struct zink_framebuffer *fb = rzalloc(NULL, struct zink_framebuffer);
    if (!fb)
       return NULL;
@@ -93,22 +149,14 @@ zink_create_framebuffer(struct zink_context *ctx, struct zink_screen *screen,
       }
    }
 
-   VkFramebufferCreateInfo fci = {};
-   fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
-   fci.renderPass = state->rp->render_pass;
-   fci.attachmentCount = state->num_attachments;
-   fci.pAttachments = state->attachments;
-   fci.width = state->width;
-   fci.height = state->height;
-   fci.layers = state->layers;
-
-   if (vkCreateFramebuffer(screen->dev, &fci, NULL, &fb->fb) != VK_SUCCESS) {
-      zink_destroy_framebuffer(screen, fb);
-      return NULL;
-   }
+   if (!_mesa_hash_table_init(&fb->objects, fb, _mesa_hash_pointer, _mesa_key_pointer_equal))
+      goto fail;
    memcpy(&fb->state, state, sizeof(struct zink_framebuffer_state));
 
    return fb;
+fail:
+   zink_destroy_framebuffer(screen, fb);
+   return NULL;
 }
 
 void
diff --git a/src/gallium/drivers/zink/zink_framebuffer.h b/src/gallium/drivers/zink/zink_framebuffer.h
index 1950ea23b0b..58d590e74fc 100644
--- a/src/gallium/drivers/zink/zink_framebuffer.h
+++ b/src/gallium/drivers/zink/zink_framebuffer.h
@@ -27,6 +27,7 @@
 #include "pipe/p_state.h"
 #include <vulkan/vulkan.h>
 
+#include "util/hash_table.h"
 #include "util/u_inlines.h"
 
 struct zink_context;
@@ -34,7 +35,6 @@ struct zink_screen;
 struct zink_render_pass;
 
 struct zink_framebuffer_state {
-   struct zink_render_pass *rp;
    uint32_t width;
    uint16_t height, layers;
    uint8_t samples;
@@ -44,18 +44,25 @@ struct zink_framebuffer_state {
 
 struct zink_framebuffer {
    struct pipe_reference reference;
+
+   /* current objects */
    VkFramebuffer fb;
+   struct zink_render_pass *rp;
 
    struct pipe_surface *surfaces[PIPE_MAX_COLOR_BUFS + 1];
    struct pipe_surface *null_surface; /* for use with unbound attachments */
    struct zink_framebuffer_state state;
+   struct hash_table objects;
 };
 
 struct zink_framebuffer *
-zink_create_framebuffer(struct zink_context *ctx, struct zink_screen *screen,
+zink_create_framebuffer(struct zink_context *ctx,
                         struct zink_framebuffer_state *fb,
                         struct pipe_surface **attachments);
 
+void
+zink_init_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp);
+
 void
 zink_destroy_framebuffer(struct zink_screen *screen,
                          struct zink_framebuffer *fbuf);



More information about the mesa-commit mailing list