From 342ed4909fe7611525b9029977463ef3291ce7ba Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Tue, 5 Oct 2021 19:20:03 -0400 Subject: [PATCH] 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 Cc: mesa-stable Part-of: --- src/panfrost/lib/pan_cs.c | 70 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) 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