From dfd0e55b5a82720090641b23b158f7bddca8c150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Ondra=C4=8Dka?= Date: Mon, 23 Feb 2026 14:12:36 +0100 Subject: [PATCH] r300: split large HiZ clears into multiple packets R300_PACKET3_3D_CLEAR_HIZ encodes COUNT in 14 bits (COUNT[13:0]), so a single packet can clear at most 0x3fff dwords. Large depth surfaces on R5xx can require more HiZ dwords than that. When we emitted a single packet, COUNT truncated and part of HiZ RAM remained uncleared, which could show up as HyperZ corruption. Emit CLEAR_HIZ in chunks of R300_CLEAR_HIZ_COUNT_MAX and reserve enough atom space for the worst-case packet count derived. Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/360 Fixes: 12dcbd59546 ("r300g: enable Hyper-Z by default on r500") (cherry picked from commit fddc101070b9474140828e924f97edc57abc477e) Part-of: --- .pick_status.json | 2 +- src/gallium/drivers/r300/r300_context.c | 19 +++++++++++++++++-- src/gallium/drivers/r300/r300_emit.c | 25 +++++++++++++++++-------- src/gallium/drivers/r300/r300_reg.h | 2 ++ 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index e76267f3a7c..f5e58d057ef 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -654,7 +654,7 @@ "description": "r300: split large HiZ clears into multiple packets", "nominated": true, "nomination_type": 2, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "12dcbd5954676ee32604d82cacbf9a4259967e13", "notes": null diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c index fd08cc16360..44704a6f1d8 100644 --- a/src/gallium/drivers/r300/r300_context.c +++ b/src/gallium/drivers/r300/r300_context.c @@ -146,6 +146,19 @@ do { \ return false; \ } while (0) +static unsigned r300_hiz_clear_atom_size(const struct r300_screen *screen) +{ + if (screen->caps.hiz_ram <= 0) + return 0; + + unsigned pipes = r300_hyperz_pipe_count(screen); + unsigned max_hiz_dwords = screen->caps.hiz_ram * pipes; + unsigned max_hiz_packets = + (max_hiz_dwords + R300_CLEAR_HIZ_COUNT_MAX - 1) / + R300_CLEAR_HIZ_COUNT_MAX; + return max_hiz_packets * 4; +} + static bool r300_setup_atoms(struct r300_context* r300) { bool is_rv350 = r300->screen->caps.is_rv350; @@ -203,8 +216,10 @@ static bool r300_setup_atoms(struct r300_context* r300) /* TX. */ R300_INIT_ATOM(texture_cache_inval, 2); R300_INIT_ATOM(textures_state, 0); - /* Clear commands */ - R300_INIT_ATOM(hiz_clear, r300->screen->caps.hiz_ram > 0 ? 4 : 0); + /* Clear commands. + * 3D_CLEAR_HIZ uses COUNT[13:0], so large clears are split into chunks. + * Reserve enough dwords for the worst-case per-chip HiZ RAM size. */ + R300_INIT_ATOM(hiz_clear, r300_hiz_clear_atom_size(r300->screen)); R300_INIT_ATOM(zmask_clear, r300->screen->caps.zmask_ram > 0 ? 4 : 0); R300_INIT_ATOM(cmask_clear, 4); /* ZB (unpipelined), SU. */ diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c index b981f6b5b54..2e0f633b77a 100644 --- a/src/gallium/drivers/r300/r300_emit.c +++ b/src/gallium/drivers/r300/r300_emit.c @@ -1244,17 +1244,26 @@ void r300_emit_hiz_clear(struct r300_context *r300, unsigned size, void *state) { struct pipe_framebuffer_state *fb = (struct pipe_framebuffer_state*)r300->fb_state.state; - struct r300_resource* tex; + struct r300_resource *tex = r300_resource(fb->zsbuf.texture); + unsigned remaining = tex->tex.hiz_dwords[fb->zsbuf.level]; + unsigned start = 0; CS_LOCALS(r300); - tex = r300_resource(fb->zsbuf.texture); + /* 3D_CLEAR_HIZ COUNT is 14-bit (max 0x3fff), so large surfaces must be + * split into multiple packets. */ + while (remaining) { + unsigned count = MIN2(remaining, R300_CLEAR_HIZ_COUNT_MAX); - BEGIN_CS(size); - OUT_CS_PKT3(R300_PACKET3_3D_CLEAR_HIZ, 2); - OUT_CS(0); - OUT_CS(tex->tex.hiz_dwords[fb->zsbuf.level]); - OUT_CS(r300->hiz_clear_value); - END_CS; + BEGIN_CS(4); + OUT_CS_PKT3(R300_PACKET3_3D_CLEAR_HIZ, 2); + OUT_CS(start); + OUT_CS(count); + OUT_CS(r300->hiz_clear_value); + END_CS; + + start += count; + remaining -= count; + } /* Mark the current zbuffer's hiz ram as in use. */ r300->hiz_in_use = true; diff --git a/src/gallium/drivers/r300/r300_reg.h b/src/gallium/drivers/r300/r300_reg.h index 25bbc69e232..08d45b95179 100644 --- a/src/gallium/drivers/r300/r300_reg.h +++ b/src/gallium/drivers/r300/r300_reg.h @@ -3485,6 +3485,8 @@ enum { * 2. CLEAR_VALUE: Value to write into HIZ RAM. */ #define R300_PACKET3_3D_CLEAR_HIZ 0x00003700 +/* 3D_CLEAR_HIZ COUNT field width (COUNT[13:0]). */ +#define R300_CLEAR_HIZ_COUNT_MAX 0x3fff #define R300_PACKET3_3D_CLEAR_CMASK 0x00003800 /* Draws a set of primitives using vertex buffers pointed by the state data.