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: 12dcbd5954 ("r300g: enable Hyper-Z by default on r500")
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40040>
This commit is contained in:
Pavel Ondračka 2026-02-23 14:12:36 +01:00 committed by Marge Bot
parent e97ac38ff3
commit fddc101070
3 changed files with 36 additions and 10 deletions

View file

@ -147,6 +147,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;
@ -204,8 +217,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. */

View file

@ -1300,17 +1300,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;

View file

@ -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.