From ac78692be4963ef491343182cd4c2793d91734d7 Mon Sep 17 00:00:00 2001 From: Patrick Lerda Date: Fri, 1 Nov 2024 15:10:53 +0100 Subject: [PATCH] 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 Part-of: --- src/gallium/drivers/r600/r600_blit.c | 100 +++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/gallium/drivers/r600/r600_blit.c b/src/gallium/drivers/r600/r600_blit.c index 64adfd9b428..3694f608b1a 100644 --- a/src/gallium/drivers/r600/r600_blit.c +++ b/src/gallium/drivers/r600/r600_blit.c @@ -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);