Mesa (staging/21.3): panfrost: Workaround ISSUE_TSIX_2033

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sun Oct 24 15:00:10 UTC 2021


Module: Mesa
Branch: staging/21.3
Commit: 1bd3d6309aa47e98c2609f35fa8b0d12d802301d
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=1bd3d6309aa47e98c2609f35fa8b0d12d802301d

Author: Alyssa Rosenzweig <alyssa at collabora.com>
Date:   Tue Oct  5 19:20:03 2021 -0400

panfrost: Workaround ISSUE_TSIX_2033

According to mali_kbase, all Bifrost and Valhall GPUs are affected by
issue TSIX_2033. This hardware bug breaks the INTERSECT frame shader
mode when forcing clean_tile_writes. What does that mean?

The hardware considers a tile "clean" if it has been cleared but not
drawn to. Setting clean_tile_write forces the hardware to write back
such "clean" tiles to main memory.

Bifrost hardware supports frame shaders, which insert a rectangle into
every tile according to a configured rule. Frame shaders are used in
Panfrost to implement tile reloads (i.e. LOAD_OP_LOAD). Two modes are
relevant to the current discussion: ALWAYS, which always inserts a frame
shader, and INTERSECT, which tries to only insert where there is
geometry. Normally, we use INTERSECT for tile reloads as it is more
efficient than ALWAYS-- it allows us to skip reloads of tiles that are
discarded and never written back to memory.

>From a software perspective, Panfrost's current logic is correct: if we
clear, we set clean_tile_writes, else we use an INTERSECT frame shader.
There is no software interaction between the two.

Unfortunately, there is a hardware interaction. The hardware forces
clean_tile_writes in certain circumstances when AFBC is used.
Ordinarily, this is a hardware implementation detail and invisible to
software. Unfortunately, this implicit clean tile write is enough to
trigger the hardware bug when using INTERSECT. As such, we need to
detect this case and use ALWAYS instead of INTERSECT for correct
results.

Signed-off-by: Alyssa Rosenzweig <alyssa at collabora.com>
Cc: mesa-stable
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13205>
(cherry picked from commit 342ed4909fe7611525b9029977463ef3291ce7ba)

---

 .pick_status.json         |  2 +-
 src/panfrost/lib/pan_cs.c | 70 +++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/.pick_status.json b/.pick_status.json
index c3318ae39e8..3de443ca88a 100644
--- a/.pick_status.json
+++ b/.pick_status.json
@@ -49,7 +49,7 @@
         "description": "panfrost: Workaround ISSUE_TSIX_2033",
         "nominated": true,
         "nomination_type": 0,
-        "resolution": 0,
+        "resolution": 1,
         "main_sha": null,
         "because_sha": null
     },
diff --git a/src/panfrost/lib/pan_cs.c b/src/panfrost/lib/pan_cs.c
index c5ae5460025..b4375a19db6 100644
--- a/src/panfrost/lib/pan_cs.c
+++ b/src/panfrost/lib/pan_cs.c
@@ -551,6 +551,68 @@ pan_emit_rt(const struct pan_fb_info *fb,
         }
 }
 
+#if PAN_ARCH >= 6
+/* All Bifrost and Valhall GPUs are affected by issue TSIX-2033:
+ *
+ *      Forcing clean_tile_writes breaks INTERSECT readbacks
+ *
+ * To workaround, use the frame shader mode ALWAYS instead of INTERSECT if
+ * clean tile writes is forced. Since INTERSECT is a hint that the hardware may
+ * ignore, this cannot affect correctness, only performance */
+
+static enum mali_pre_post_frame_shader_mode
+pan_fix_frame_shader_mode(enum mali_pre_post_frame_shader_mode mode, bool force_clean_tile)
+{
+        if (force_clean_tile && mode == MALI_PRE_POST_FRAME_SHADER_MODE_INTERSECT)
+                return MALI_PRE_POST_FRAME_SHADER_MODE_ALWAYS;
+        else
+                return mode;
+}
+
+/* Regardless of clean_tile_write_enable, the hardware writes clean tiles if
+ * the effective tile size differs from the superblock size of any enabled AFBC
+ * render target. Check this condition. */
+
+static bool
+pan_force_clean_write_rt(const struct pan_image_view *rt, unsigned tile_size)
+{
+        if (!drm_is_afbc(rt->image->layout.modifier))
+                return false;
+
+        unsigned superblock = panfrost_block_dim(rt->image->layout.modifier, true, 0);
+
+        assert(superblock >= 16);
+        assert(tile_size <= 16*16);
+
+        /* Tile size and superblock differ unless they are both 16x16 */
+        return !(superblock == 16 && tile_size == 16*16);
+}
+
+static bool
+pan_force_clean_write(const struct pan_fb_info *fb, unsigned tile_size)
+{
+        /* Maximum tile size */
+        assert(tile_size <= 16*16);
+
+        for (unsigned i = 0; i < fb->rt_count; ++i) {
+                if (fb->rts[i].view && !fb->rts[i].discard &&
+                    pan_force_clean_write_rt(fb->rts[i].view, tile_size))
+                        return true;
+        }
+
+        if (fb->zs.view.zs && !fb->zs.discard.z &&
+            pan_force_clean_write_rt(fb->zs.view.zs, tile_size))
+                return true;
+
+        if (fb->zs.view.s && !fb->zs.discard.s &&
+            pan_force_clean_write_rt(fb->zs.view.s, tile_size))
+                return true;
+
+        return false;
+}
+
+#endif
+
 static unsigned
 pan_emit_mfbd(const struct panfrost_device *dev,
               const struct pan_fb_info *fb,
@@ -574,11 +636,13 @@ pan_emit_mfbd(const struct panfrost_device *dev,
 
         pan_section_pack(fbd, FRAMEBUFFER, PARAMETERS, cfg) {
 #if PAN_ARCH >= 6
+                bool force_clean_write = pan_force_clean_write(fb, tile_size);
+
                 cfg.sample_locations =
                         panfrost_sample_positions(dev, pan_sample_pattern(fb->nr_samples));
-                cfg.pre_frame_0 = fb->bifrost.pre_post.modes[0];
-                cfg.pre_frame_1 = fb->bifrost.pre_post.modes[1];
-                cfg.post_frame = fb->bifrost.pre_post.modes[2];
+                cfg.pre_frame_0 = pan_fix_frame_shader_mode(fb->bifrost.pre_post.modes[0], force_clean_write);
+                cfg.pre_frame_1 = pan_fix_frame_shader_mode(fb->bifrost.pre_post.modes[1], force_clean_write);
+                cfg.post_frame  = pan_fix_frame_shader_mode(fb->bifrost.pre_post.modes[2], force_clean_write);
                 cfg.frame_shader_dcds = fb->bifrost.pre_post.dcds.gpu;
                 cfg.tiler = tiler_ctx->bifrost;
 #endif



More information about the mesa-commit mailing list