zink: improve granularity of renderpass switching
authorMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Fri, 15 Jul 2022 20:53:33 +0000 (16:53 -0400)
committerMarge Bot <emma+marge@anholt.net>
Wed, 20 Jul 2022 17:30:19 +0000 (17:30 +0000)
this should ensure that (future) renderpass recalcs will never split
a renderpass unnecessarily

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17640>

src/gallium/drivers/zink/zink_pipeline.h
src/gallium/drivers/zink/zink_render_pass.c

index 29f5243..a4c31f5 100644 (file)
@@ -92,6 +92,7 @@ struct zink_gfx_pipeline_state {
    } shader_keys;
    struct zink_blend_state *blend_state;
    struct zink_render_pass *render_pass;
+   struct zink_render_pass *next_render_pass; //will be used next time rp is begun
    VkFormat rendering_formats[PIPE_MAX_COLOR_BUFS];
    VkPipelineRenderingCreateInfo rendering_info;
    VkPipeline pipeline;
index 4a6a248..f796f73 100644 (file)
@@ -449,6 +449,37 @@ get_render_pass(struct zink_context *ctx)
    return rp;
 }
 
+/* check whether the active rp needs to be split to replace it with rp2 */
+static bool
+rp_must_change(const struct zink_render_pass *rp, const struct zink_render_pass *rp2, bool in_rp)
+{
+   if (rp == rp2)
+      return false;
+   unsigned num_cbufs = rp->state.num_cbufs;
+   if (rp->pipeline_state != rp2->pipeline_state) {
+      /* if any core attrib bits are different, must split */
+      if (rp->state.val != rp2->state.val)
+         return true;
+      for (unsigned i = 0; i < num_cbufs; i++) {
+         const struct zink_rt_attrib *rt = &rp->state.rts[i];
+         const struct zink_rt_attrib *rt2 = &rp2->state.rts[i];
+         /* if layout changed, must split */
+         if (get_color_rt_layout(rt) != get_color_rt_layout(rt2))
+            return true;
+      }
+   }
+   if (rp->state.have_zsbuf) {
+      const struct zink_rt_attrib *rt = &rp->state.rts[num_cbufs];
+      const struct zink_rt_attrib *rt2 = &rp2->state.rts[num_cbufs];
+      /* if zs layout has gone from read-only to read-write, split renderpass */
+      if (get_zs_rt_layout(rt) == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL &&
+          get_zs_rt_layout(rt2) == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
+         return true;
+   }
+   /* any other change doesn't require splitting a renderpass */
+   return !in_rp;
+}
+
 static void
 setup_framebuffer(struct zink_context *ctx)
 {
@@ -457,15 +488,36 @@ setup_framebuffer(struct zink_context *ctx)
 
    zink_update_vk_sample_locations(ctx);
 
-   if (ctx->rp_changed || ctx->rp_layout_changed)
+   if (ctx->rp_changed || ctx->rp_layout_changed || ctx->rp_loadop_changed) {
+      /* 0. ensure no stale pointers are set */
+      ctx->gfx_pipeline_state.next_render_pass = NULL;
+      /* 1. calc new rp */
       rp = get_render_pass(ctx);
-
-   ctx->fb_changed |= rp != ctx->gfx_pipeline_state.render_pass;
+      /* 2. evaluate whether to use new rp */
+      if (ctx->gfx_pipeline_state.render_pass) {
+         /* 2a. if previous rp exists, check whether new rp MUST be used */
+         bool must_change = rp_must_change(ctx->gfx_pipeline_state.render_pass, rp, ctx->batch.in_rp);
+         ctx->fb_changed |= must_change;
+         if (!must_change)
+            /* 2b. if non-essential attribs have changed, store for later use and continue on */
+            ctx->gfx_pipeline_state.next_render_pass = rp;
+      } else {
+         /* 2c. no previous rp in use, use this one */
+         ctx->fb_changed = true;
+      }
+   } else if (ctx->gfx_pipeline_state.next_render_pass) {
+      /* previous rp was calculated but deferred: use it */
+      assert(!ctx->batch.in_rp);
+      rp = ctx->gfx_pipeline_state.next_render_pass;
+      ctx->gfx_pipeline_state.next_render_pass = NULL;
+      ctx->fb_changed = true;
+   }
    if (rp->pipeline_state != ctx->gfx_pipeline_state.rp_state) {
       ctx->gfx_pipeline_state.rp_state = rp->pipeline_state;
       ctx->gfx_pipeline_state.dirty = true;
    }
 
+   ctx->rp_loadop_changed = false;
    ctx->rp_layout_changed = false;
    ctx->rp_changed = false;
    zink_render_update_swapchain(ctx);