Mesa (main): panfrost: Rework dirty tracking for Valhall

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sat Apr 16 14:33:44 UTC 2022


Module: Mesa
Branch: main
Commit: c4167e8911bdffb8d95bc00ee9eb0cc39a5fe400
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=c4167e8911bdffb8d95bc00ee9eb0cc39a5fe400

Author: Alyssa Rosenzweig <alyssa at collabora.com>
Date:   Thu Apr 14 16:12:01 2022 -0400

panfrost: Rework dirty tracking for Valhall

Midgard aggregates a large amount of state into its renderer state descriptor.
Our current dirty tracking reflects this, with a single RENDERER dirty flag.
That won't work well on Valhall, which splits out orthogonal state into
independent descriptors (a blend descriptor, a depth/stencil descriptor, and so
on). To prepare for Valhall support, this patch moves the driver to finer dirty
tracking.

Signed-off-by: Alyssa Rosenzweig <alyssa at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15956>

---

 src/gallium/drivers/panfrost/pan_cmdstream.c | 86 ++++++++++++++++------------
 src/gallium/drivers/panfrost/pan_context.c   | 34 +++++------
 src/gallium/drivers/panfrost/pan_context.h   |  7 ++-
 src/gallium/drivers/panfrost/pan_helpers.c   |  3 +-
 4 files changed, 75 insertions(+), 55 deletions(-)

diff --git a/src/gallium/drivers/panfrost/pan_cmdstream.c b/src/gallium/drivers/panfrost/pan_cmdstream.c
index 3cc8371387f..65fdfdf7427 100644
--- a/src/gallium/drivers/panfrost/pan_cmdstream.c
+++ b/src/gallium/drivers/panfrost/pan_cmdstream.c
@@ -2895,13 +2895,29 @@ panfrost_is_implicit_prim_restart(const struct pipe_draw_info *info)
         return info->primitive_restart && implicit;
 }
 
+/* On Bifrost and older, the Renderer State Descriptor aggregates many pieces of
+ * 3D state. In particular, it groups the fragment shader descriptor with
+ * depth/stencil, blend, polygon offset, and multisampling state. These pieces
+ * of state are dirty tracked independently for the benefit of newer GPUs that
+ * separate the descriptors. FRAGMENT_RSD_DIRTY_MASK contains the list of 3D
+ * dirty flags that trigger re-emits of the fragment RSD.
+ *
+ * Obscurely, occlusion queries are included. Occlusion query state is nominally
+ * specified in the draw call descriptor, but must be considered when determing
+ * early-Z state which is part of the RSD.
+ */
+#define FRAGMENT_RSD_DIRTY_MASK ( \
+        PAN_DIRTY_ZS | PAN_DIRTY_BLEND | PAN_DIRTY_MSAA | \
+        PAN_DIRTY_RASTERIZER | PAN_DIRTY_OQ)
+
 static inline void
-panfrost_update_state_tex(struct panfrost_batch *batch,
-                          enum pipe_shader_type st)
+panfrost_update_shader_state(struct panfrost_batch *batch,
+                             enum pipe_shader_type st)
 {
         struct panfrost_context *ctx = batch->ctx;
         struct panfrost_shader_state *ss = panfrost_get_shader_state(ctx, st);
 
+        bool frag = (st == PIPE_SHADER_FRAGMENT);
         unsigned dirty_3d = ctx->dirty;
         unsigned dirty = ctx->dirty_shader[st];
 
@@ -2915,48 +2931,46 @@ panfrost_update_state_tex(struct panfrost_batch *batch,
                         panfrost_emit_sampler_descriptors(batch, st);
         }
 
+        /* On Bifrost and older, the fragment shader descriptor is fused
+         * together with the renderer state; the combined renderer state
+         * descriptor is emitted below. Otherwise, the shader descriptor is
+         * standalone and is emitted here.
+         */
+        if ((dirty & PAN_DIRTY_STAGE_SHADER) && !((PAN_ARCH <= 7) && frag)) {
+                batch->rsd[st] = panfrost_emit_compute_shader_meta(batch, st);
+        }
+
         if ((dirty & ss->dirty_shader) || (dirty_3d & ss->dirty_3d)) {
                 batch->uniform_buffers[st] = panfrost_emit_const_buf(batch, st,
                                 &batch->push_uniforms[st]);
         }
-}
-
-static inline void
-panfrost_update_state_3d(struct panfrost_batch *batch)
-{
-        unsigned dirty = batch->ctx->dirty;
-
-        if (dirty & PAN_DIRTY_TLS_SIZE)
-                panfrost_batch_adjust_stack_size(batch);
-}
-
-static void
-panfrost_update_state_vs(struct panfrost_batch *batch)
-{
-        enum pipe_shader_type st = PIPE_SHADER_VERTEX;
-        unsigned dirty = batch->ctx->dirty_shader[st];
 
-        if (dirty & PAN_DIRTY_STAGE_RENDERER)
-                batch->rsd[st] = panfrost_emit_compute_shader_meta(batch, st);
-
-        panfrost_update_state_tex(batch, st);
-}
-
-static void
-panfrost_update_state_fs(struct panfrost_batch *batch)
-{
-        enum pipe_shader_type st = PIPE_SHADER_FRAGMENT;
-        unsigned dirty = batch->ctx->dirty_shader[st];
+#if PAN_ARCH <= 7
+        /* On Bifrost and older, if the fragment shader changes OR any renderer
+         * state specified with the fragment shader, the whole renderer state
+         * descriptor is dirtied and must be reemited.
+         */
+        if (frag && ((dirty & PAN_DIRTY_STAGE_SHADER) ||
+                     (dirty_3d & FRAGMENT_RSD_DIRTY_MASK))) {
 
-        if (dirty & PAN_DIRTY_STAGE_RENDERER)
                 batch->rsd[st] = panfrost_emit_frag_shader_meta(batch);
+        }
 
-        if (dirty & PAN_DIRTY_STAGE_IMAGE) {
+        if (frag && (dirty & PAN_DIRTY_STAGE_IMAGE)) {
                 batch->attribs[st] = panfrost_emit_image_attribs(batch,
                                 &batch->attrib_bufs[st], st);
         }
+#endif
+}
 
-        panfrost_update_state_tex(batch, st);
+static inline void
+panfrost_update_state_3d(struct panfrost_batch *batch)
+{
+        struct panfrost_context *ctx = batch->ctx;
+        unsigned dirty = ctx->dirty;
+
+        if (dirty & PAN_DIRTY_TLS_SIZE)
+                panfrost_batch_adjust_stack_size(batch);
 }
 
 #if PAN_ARCH >= 6
@@ -3207,8 +3221,8 @@ panfrost_direct_draw(struct panfrost_batch *batch,
         attribs = panfrost_emit_vertex_data(batch, &attrib_bufs);
 
         panfrost_update_state_3d(batch);
-        panfrost_update_state_vs(batch);
-        panfrost_update_state_fs(batch);
+        panfrost_update_shader_state(batch, PIPE_SHADER_VERTEX);
+        panfrost_update_shader_state(batch, PIPE_SHADER_FRAGMENT);
         panfrost_clean_state_3d(ctx);
 
         /* Fire off the draw itself */
@@ -3303,8 +3317,8 @@ panfrost_indirect_draw(struct panfrost_batch *batch,
         ctx->base_instance_sysval_ptr = 0;
 
         panfrost_update_state_3d(batch);
-        panfrost_update_state_vs(batch);
-        panfrost_update_state_fs(batch);
+        panfrost_update_shader_state(batch, PIPE_SHADER_VERTEX);
+        panfrost_update_shader_state(batch, PIPE_SHADER_FRAGMENT);
         panfrost_clean_state_3d(ctx);
 
         bool point_coord_replace = (info->mode == PIPE_PRIM_POINTS);
diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c
index 7d3c050306b..9bdb220429a 100644
--- a/src/gallium/drivers/panfrost/pan_context.c
+++ b/src/gallium/drivers/panfrost/pan_context.c
@@ -136,7 +136,7 @@ panfrost_bind_blend_state(struct pipe_context *pipe, void *cso)
 {
         struct panfrost_context *ctx = pan_context(pipe);
         ctx->blend = cso;
-        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+        ctx->dirty |= PAN_DIRTY_BLEND;
 }
 
 static void
@@ -144,7 +144,7 @@ panfrost_set_blend_color(struct pipe_context *pipe,
                          const struct pipe_blend_color *blend_color)
 {
         struct panfrost_context *ctx = pan_context(pipe);
-        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+        ctx->dirty |= PAN_DIRTY_BLEND;
 
         if (blend_color)
                 ctx->blend_color = *blend_color;
@@ -223,12 +223,11 @@ panfrost_bind_rasterizer_state(
         struct panfrost_context *ctx = pan_context(pctx);
         ctx->rasterizer = hwcso;
 
-        /* We can assume the renderer state descriptor is always dirty, the
-         * dependencies are too intricate to bother tracking in detail. However
-         * we could probably diff the renderers for viewport dirty tracking,
-         * that just cares about the scissor enable and the depth clips. */
-        ctx->dirty |= PAN_DIRTY_SCISSOR;
-        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+        /* We can assume rasterizer is always dirty, the dependencies are
+         * too intricate to bother tracking in detail. However we could
+         * probably diff the renderers for viewport dirty tracking, that
+         * just cares about the scissor enable and the depth clips. */
+        ctx->dirty |= PAN_DIRTY_SCISSOR | PAN_DIRTY_RASTERIZER;
 }
 
 static void
@@ -287,6 +286,7 @@ panfrost_bind_vertex_elements_state(
 {
         struct panfrost_context *ctx = pan_context(pctx);
         ctx->vertex = hwcso;
+        ctx->dirty |= PAN_DIRTY_VERTEX;
 }
 
 static void *
@@ -448,7 +448,7 @@ panfrost_bind_shader_state(
         ctx->shader[type] = hwcso;
 
         ctx->dirty |= PAN_DIRTY_TLS_SIZE;
-        ctx->dirty_shader[type] |= PAN_DIRTY_STAGE_RENDERER;
+        ctx->dirty_shader[type] |= PAN_DIRTY_STAGE_SHADER;
 
         if (!hwcso) return;
 
@@ -581,6 +581,8 @@ panfrost_set_vertex_buffers(
         util_set_vertex_buffers_mask(ctx->vertex_buffers, &ctx->vb_mask, buffers,
                                      start_slot, num_buffers, unbind_num_trailing_slots,
                                      take_ownership);
+
+        ctx->dirty |= PAN_DIRTY_VERTEX;
 }
 
 static void
@@ -612,7 +614,7 @@ panfrost_set_stencil_ref(
 {
         struct panfrost_context *ctx = pan_context(pctx);
         ctx->stencil_ref = ref;
-        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+        ctx->dirty |= PAN_DIRTY_ZS;
 }
 
 static void
@@ -717,7 +719,7 @@ panfrost_bind_depth_stencil_state(struct pipe_context *pipe,
 {
         struct panfrost_context *ctx = pan_context(pipe);
         ctx->depth_stencil = cso;
-        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+        ctx->dirty |= PAN_DIRTY_ZS;
 }
 
 static void
@@ -726,7 +728,7 @@ panfrost_set_sample_mask(struct pipe_context *pipe,
 {
         struct panfrost_context *ctx = pan_context(pipe);
         ctx->sample_mask = sample_mask;
-        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+        ctx->dirty |= PAN_DIRTY_MSAA;
 }
 
 static void
@@ -735,7 +737,7 @@ panfrost_set_min_samples(struct pipe_context *pipe,
 {
         struct panfrost_context *ctx = pan_context(pipe);
         ctx->min_samples = min_samples;
-        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+        ctx->dirty |= PAN_DIRTY_MSAA;
 }
 
 static void
@@ -788,7 +790,7 @@ panfrost_set_active_query_state(struct pipe_context *pipe,
 {
         struct panfrost_context *ctx = pan_context(pipe);
         ctx->active_queries = enable;
-        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+        ctx->dirty |= PAN_DIRTY_OQ;
 }
 
 static void
@@ -873,7 +875,7 @@ panfrost_begin_query(struct pipe_context *pipe, struct pipe_query *q)
 
                 query->msaa = (ctx->pipe_framebuffer.samples > 1);
                 ctx->occlusion_query = query;
-                ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+                ctx->dirty |= PAN_DIRTY_OQ;
                 break;
         }
 
@@ -906,7 +908,7 @@ panfrost_end_query(struct pipe_context *pipe, struct pipe_query *q)
         case PIPE_QUERY_OCCLUSION_PREDICATE:
         case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
                 ctx->occlusion_query = NULL;
-                ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
+                ctx->dirty |= PAN_DIRTY_OQ;
                 break;
         case PIPE_QUERY_PRIMITIVES_GENERATED:
                 query->end = ctx->prims_generated;
diff --git a/src/gallium/drivers/panfrost/pan_context.h b/src/gallium/drivers/panfrost/pan_context.h
index ac28f53da45..12644ab0cb9 100644
--- a/src/gallium/drivers/panfrost/pan_context.h
+++ b/src/gallium/drivers/panfrost/pan_context.h
@@ -68,10 +68,15 @@ enum pan_dirty_3d {
         PAN_DIRTY_PARAMS         = BITFIELD_BIT(3),
         PAN_DIRTY_DRAWID         = BITFIELD_BIT(4),
         PAN_DIRTY_TLS_SIZE       = BITFIELD_BIT(5),
+        PAN_DIRTY_ZS             = BITFIELD_BIT(6),
+        PAN_DIRTY_BLEND          = BITFIELD_BIT(7),
+        PAN_DIRTY_MSAA           = BITFIELD_BIT(8),
+        PAN_DIRTY_OQ             = BITFIELD_BIT(9),
+        PAN_DIRTY_RASTERIZER     = BITFIELD_BIT(10),
 };
 
 enum pan_dirty_shader {
-        PAN_DIRTY_STAGE_RENDERER = BITFIELD_BIT(0),
+        PAN_DIRTY_STAGE_SHADER   = BITFIELD_BIT(0),
         PAN_DIRTY_STAGE_TEXTURE  = BITFIELD_BIT(1),
         PAN_DIRTY_STAGE_SAMPLER  = BITFIELD_BIT(2),
         PAN_DIRTY_STAGE_IMAGE    = BITFIELD_BIT(3),
diff --git a/src/gallium/drivers/panfrost/pan_helpers.c b/src/gallium/drivers/panfrost/pan_helpers.c
index b492e0fe76c..e9a02125109 100644
--- a/src/gallium/drivers/panfrost/pan_helpers.c
+++ b/src/gallium/drivers/panfrost/pan_helpers.c
@@ -28,8 +28,7 @@ void
 panfrost_analyze_sysvals(struct panfrost_shader_state *ss)
 {
         unsigned dirty = 0;
-        unsigned dirty_shader =
-                PAN_DIRTY_STAGE_RENDERER | PAN_DIRTY_STAGE_CONST;
+        unsigned dirty_shader = PAN_DIRTY_STAGE_SHADER | PAN_DIRTY_STAGE_CONST;
 
         for (unsigned i = 0; i < ss->info.sysvals.sysval_count; ++i) {
                 switch (PAN_SYSVAL_TYPE(ss->info.sysvals.sysvals[i])) {



More information about the mesa-commit mailing list