r600: evergreen stencil/depth mipmap blit workaround

In certain cases, the hardware fails to properly process a mipmap level
of these special stencil and depth formats. This happens at width=16.
This change adds a software workaround.

Modifying the corresponding mipmap nblk_x, and the other related
values, could make the tests below to work. Anyway, this method
generates regressions.

This change was tested on palm and cayman and fixes the following tests:
spec/arb_framebuffer_object/framebuffer-blit-levels read stencil: fail pass
spec/arb_depth_buffer_float/fbo-clear-formats stencil/gl_depth32f_stencil8: fail pass

Cc: mesa-stable
Signed-off-by: Patrick Lerda <patrick9876@free.fr>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31957>
(cherry picked from commit ac78692be4)
This commit is contained in:
Patrick Lerda
2024-11-01 15:10:53 +01:00
committed by Dylan Baker
parent afcbe85940
commit 48e5c246c4
2 changed files with 101 additions and 1 deletions

View File

@@ -574,7 +574,7 @@
"description": "r600: evergreen stencil/depth mipmap blit workaround",
"nominated": true,
"nomination_type": 1,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": null,
"notes": null

View File

@@ -891,6 +891,64 @@ static bool do_hardware_msaa_resolve(struct pipe_context *ctx,
return true;
}
static void r600_stencil_z24unorms8_to_z24unorms8uint(struct pipe_context *ctx,
struct pipe_resource *dst, struct pipe_resource *src,
const struct pipe_box *box_dst, const struct pipe_box *box_src,
const unsigned dst_level, const unsigned src_level)
{
struct pipe_transfer *tsrc;
uint8_t *slice_src = pipe_texture_map_3d(ctx, src, src_level, PIPE_MAP_READ,
box_src->x, box_src->y, box_src->z,
box_src->width, box_src->height, box_src->depth, &tsrc);
if (slice_src) {
struct pipe_transfer *tdst;
uint8_t *slice_dst = pipe_texture_map_3d(ctx, dst, dst_level, PIPE_MAP_READ_WRITE,
box_dst->x, box_dst->y, box_dst->z,
box_src->width, box_src->height, box_src->depth, &tdst);
if (slice_dst) {
for (unsigned slice = 0; slice < box_src->depth; slice++)
for (unsigned row = 0; row < box_src->height; row++) {
for (unsigned k = 0; k < box_src->width; k++) {
slice_dst[k * 4 + 3] = slice_src[k * 4 + 3];
}
slice_src += tsrc->stride / sizeof(*slice_src);
slice_dst += tdst->stride / sizeof(*slice_dst);
}
pipe_texture_unmap(ctx, tdst);
}
pipe_texture_unmap(ctx, tsrc);
}
}
static void r600_stencil_z32floats8x24_to_z24unorms8(struct pipe_context *ctx,
struct pipe_resource *dst, struct pipe_resource *src,
const struct pipe_box *box_dst, const struct pipe_box *box_src,
const unsigned dst_level, const unsigned src_level)
{
struct pipe_transfer *tsrc;
uint8_t *slice_src = pipe_texture_map_3d(ctx, src, src_level, PIPE_MAP_READ,
box_src->x, box_src->y, box_src->z,
box_src->width, box_src->height, box_src->depth, &tsrc);
if (slice_src) {
struct pipe_transfer *tdst;
uint8_t *slice_dst = pipe_texture_map_3d(ctx, dst, dst_level, PIPE_MAP_READ_WRITE,
box_dst->x, box_dst->y, box_dst->z,
box_src->width, box_src->height, box_src->depth, &tdst);
if (slice_dst) {
for (unsigned slice = 0; slice < box_src->depth; slice++)
for (unsigned row = 0; row < box_src->height; row++) {
for (unsigned k = 0; k < box_src->width; k++) {
slice_dst[k * 4 + 3] = slice_src[k * 8 + 4];
}
slice_src += tsrc->stride / sizeof(*slice_src);
slice_dst += tdst->stride / sizeof(*slice_dst);
}
pipe_texture_unmap(ctx, tdst);
}
pipe_texture_unmap(ctx, tsrc);
}
}
static void r600_blit(struct pipe_context *ctx,
const struct pipe_blit_info *info)
{
@@ -933,6 +991,48 @@ static void r600_blit(struct pipe_context *ctx,
util_try_blit_via_copy_region(ctx, info, rctx->b.render_cond != NULL))
return;
{
const bool blit_box_same_size = info->src.box.width == info->dst.box.width &&
info->src.box.height == info->dst.box.height &&
info->src.box.depth == info->dst.box.depth;
const bool blit_stencil = (info->mask & PIPE_MASK_S) != 0;
const bool src_is_ZS = info->src.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
info->src.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT;
if (unlikely(rctx->b.gfx_level >= EVERGREEN &&
blit_stencil && blit_box_same_size && src_is_ZS &&
info->dst.format == PIPE_FORMAT_Z24_UNORM_S8_UINT &&
info->src.resource->last_level &&
!info->dst.resource->last_level &&
info->src.box.width >= 16 && info->src.box.width < 32)) {
if (info->mask & ~PIPE_MASK_S) {
struct pipe_blit_info blit;
memcpy(&blit, info, sizeof(blit));
blit.mask = info->mask & ~PIPE_MASK_S;
r600_blitter_begin(ctx, R600_BLIT |
(info->render_condition_enable ? 0 : R600_DISABLE_RENDER_COND));
util_blitter_blit(rctx->blitter, &blit, NULL);
r600_blitter_end(ctx);
}
assert(util_format_get_blocksize(PIPE_FORMAT_Z24_UNORM_S8_UINT) == 4);
assert(util_format_get_blocksize(PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) == 8);
if (info->src.format == info->dst.format)
r600_stencil_z24unorms8_to_z24unorms8uint(ctx,
info->dst.resource, info->src.resource,
&info->dst.box, &info->src.box,
info->dst.level, info->src.level);
else
r600_stencil_z32floats8x24_to_z24unorms8(ctx,
info->dst.resource, info->src.resource,
&info->dst.box, &info->src.box,
info->dst.level, info->src.level);
return;
}
}
r600_blitter_begin(ctx, R600_BLIT |
(info->render_condition_enable ? 0 : R600_DISABLE_RENDER_COND));
util_blitter_blit(rctx->blitter, info, NULL);