From 7a1ef0cf8590e315d6b5e2c2e075da7153b5107d Mon Sep 17 00:00:00 2001 From: "Eric R. Smith" Date: Wed, 17 Sep 2025 14:29:35 -0300 Subject: [PATCH] panfrost: update AFBC code to handle tiling for 64bpp formats We had assumed AFBC superblocks were always tiled in an 8x8 pattern, but this is true only for 32bpp and lower formats; for larger formats the pattern is 4x4. This isn't an issue yet, but will be when we support R16G16B16A16 in AFBC. Reviewed-by: Boris Brezillon Part-of: --- src/gallium/drivers/panfrost/pan_cmdstream.c | 11 +++++----- src/gallium/drivers/panfrost/pan_resource.c | 10 +++++---- src/panfrost/lib/pan_afbc.h | 22 ++++++++++++-------- src/panfrost/lib/pan_desc.c | 6 ++++-- src/panfrost/lib/pan_mod.c | 18 +++++++++------- src/panfrost/lib/tests/test-layout.cpp | 18 ++++++++-------- 6 files changed, 48 insertions(+), 37 deletions(-) diff --git a/src/gallium/drivers/panfrost/pan_cmdstream.c b/src/gallium/drivers/panfrost/pan_cmdstream.c index 078bd7ecd01..96383eb0117 100644 --- a/src/gallium/drivers/panfrost/pan_cmdstream.c +++ b/src/gallium/drivers/panfrost/pan_cmdstream.c @@ -3618,10 +3618,11 @@ panfrost_afbc_size(struct panfrost_batch *batch, struct panfrost_resource *src, .src = src->plane.base + slice->offset_B, .layout = layout->ptr.gpu + offset, }; - unsigned stride_sb = pan_afbc_stride_blocks(src->image.props.modifier, + unsigned stride_sb = pan_afbc_stride_blocks(src->image.props.format, + src->image.props.modifier, slice->afbc.header.row_stride_B); unsigned nr_sblocks = - stride_sb * pan_afbc_height_blocks( + stride_sb * pan_afbc_height_blocks(src->image.props.format, src->image.props.modifier, u_minify(src->image.props.extent_px.height, level)); @@ -3642,12 +3643,12 @@ panfrost_afbc_pack(struct panfrost_batch *batch, struct panfrost_resource *src, struct panfrost_device *dev = pan_device(src->base.screen); struct pan_image_slice_layout *src_slice = &src->plane.layout.slices[level]; - unsigned src_stride_sb = pan_afbc_stride_blocks( + unsigned src_stride_sb = pan_afbc_stride_blocks(src->image.props.format, src->image.props.modifier, src_slice->afbc.header.row_stride_B); - unsigned dst_stride_sb = pan_afbc_stride_blocks( + unsigned dst_stride_sb = pan_afbc_stride_blocks(src->image.props.format, src->image.props.modifier, dst_slice->afbc.header.row_stride_B); unsigned nr_sblocks = - src_stride_sb * pan_afbc_height_blocks( + src_stride_sb * pan_afbc_height_blocks(src->image.props.format, src->image.props.modifier, u_minify(src->image.props.extent_px.height, level)); struct panfrost_afbc_pack_info consts = { diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c index dca5513baa5..2270fbb1fe5 100644 --- a/src/gallium/drivers/panfrost/pan_resource.c +++ b/src/gallium/drivers/panfrost/pan_resource.c @@ -2013,6 +2013,7 @@ pan_resource_afbcp_get_payload_sizes(struct panfrost_context *ctx, struct panfrost_screen *screen = pan_screen(ctx->base.screen); struct panfrost_device *dev = pan_device(ctx->base.screen); + enum pipe_format format = prsrc->base.format; uint64_t modifier = prsrc->modifier; unsigned last_level = prsrc->base.last_level; unsigned layout_size = 0; @@ -2022,9 +2023,9 @@ pan_resource_afbcp_get_payload_sizes(struct panfrost_context *ctx, &prsrc->plane.layout.slices[level]; unsigned nr_blocks = pan_afbc_stride_blocks( - modifier, slice->afbc.header.row_stride_B) * + format, modifier, slice->afbc.header.row_stride_B) * pan_afbc_height_blocks( - modifier, u_minify(prsrc->image.props.extent_px.height, level)); + format, modifier, u_minify(prsrc->image.props.extent_px.height, level)); prsrc->afbcp->layout_offsets[level] = layout_size; layout_size += nr_blocks * sizeof(struct pan_afbc_payload_extent); } @@ -2111,6 +2112,7 @@ pan_resource_afbcp_get_payload_offsets(struct panfrost_context *ctx, struct panfrost_device *dev = pan_device(ctx->base.screen); uint64_t modifier = prsrc->modifier; + enum pipe_format format = prsrc->base.format; unsigned last_level = prsrc->base.last_level; unsigned total_size = 0; @@ -2121,9 +2123,9 @@ pan_resource_afbcp_get_payload_offsets(struct panfrost_context *ctx, &prsrc->afbcp->plane.layout.slices[level]; unsigned nr_blocks_total = pan_afbc_stride_blocks( - modifier, src_slice->afbc.header.row_stride_B) * + format, modifier, src_slice->afbc.header.row_stride_B) * pan_afbc_height_blocks( - modifier, u_minify(prsrc->image.props.extent_px.height, level)); + format, modifier, u_minify(prsrc->image.props.extent_px.height, level)); uint32_t body_offset_B = pan_afbc_body_offset( dev->arch, modifier, src_slice->afbc.header.surface_size_B); struct pan_afbc_payload_extent *layout = diff --git a/src/panfrost/lib/pan_afbc.h b/src/panfrost/lib/pan_afbc.h index 5e87f35e70d..0e6a920d4f9 100644 --- a/src/panfrost/lib/pan_afbc.h +++ b/src/panfrost/lib/pan_afbc.h @@ -387,12 +387,16 @@ pan_afbc_body_offset(unsigned arch, uint64_t modifier, uint32_t header_size) /* * Determine the tile size used by AFBC. This tiles superblocks themselves. - * Current GPUs support either 8x8 tiling or no tiling (1x1) + * Current GPUs support either 8x8 tiling or no tiling (1x1) for most + * formats; but note that formats with more than 32bpp use 4x4 tiling */ static inline unsigned -pan_afbc_tile_size(uint64_t modifier) +pan_afbc_tile_size(enum pipe_format format, uint64_t modifier) { - return (modifier & AFBC_FORMAT_MOD_TILED) ? 8 : 1; + if ( !(modifier & AFBC_FORMAT_MOD_TILED) ) { + return 1; + } + return util_format_get_blocksizebits(format) <= 32 ? 8 : 4; } /* @@ -403,11 +407,11 @@ pan_afbc_tile_size(uint64_t modifier) * header blocks are in a tile together. */ static inline uint32_t -pan_afbc_row_stride(uint64_t modifier, uint32_t width) +pan_afbc_row_stride(enum pipe_format format, uint64_t modifier, uint32_t width) { unsigned block_width = pan_afbc_superblock_width(modifier); - return (width / block_width) * pan_afbc_tile_size(modifier) * + return (width / block_width) * pan_afbc_tile_size(format, modifier) * AFBC_HEADER_BYTES_PER_TILE; } @@ -418,21 +422,21 @@ pan_afbc_row_stride(uint64_t modifier, uint32_t width) * blocks, rather than a real row stride. This is required by Bifrost. */ static inline uint32_t -pan_afbc_stride_blocks(uint64_t modifier, uint32_t row_stride_bytes) +pan_afbc_stride_blocks(enum pipe_format format, uint64_t modifier, uint32_t row_stride_bytes) { return row_stride_bytes / - (AFBC_HEADER_BYTES_PER_TILE * pan_afbc_tile_size(modifier)); + (AFBC_HEADER_BYTES_PER_TILE * pan_afbc_tile_size(format, modifier)); } /* Returns a height in superblocks taking into account the tile alignment * requirement coming from the modifier. */ static inline uint32_t -pan_afbc_height_blocks(uint64_t modifier, uint32_t height_px) +pan_afbc_height_blocks(enum pipe_format format, uint64_t modifier, uint32_t height_px) { return ALIGN_POT( DIV_ROUND_UP(height_px, pan_afbc_superblock_height(modifier)), - pan_afbc_tile_size(modifier)); + pan_afbc_tile_size(format, modifier)); } static inline enum pipe_format diff --git a/src/panfrost/lib/pan_desc.c b/src/panfrost/lib/pan_desc.c index 074850f3372..e3d3915f111 100644 --- a/src/panfrost/lib/pan_desc.c +++ b/src/panfrost/lib/pan_desc.c @@ -371,7 +371,8 @@ GENX(pan_emit_afbc_zs_attachment)(const struct pan_fb_info *fb, #if PAN_ARCH >= 6 cfg.header_row_stride = - pan_afbc_stride_blocks(pref.image->props.modifier, hdr_row_stride); + pan_afbc_stride_blocks(pref.image->props.format, + pref.image->props.modifier, hdr_row_stride); #else cfg.body_size = 0x1000; cfg.chunk_size = 9; @@ -727,7 +728,8 @@ GENX(pan_emit_afbc_color_attachment)(const struct pan_fb_info *fb, #if PAN_ARCH >= 6 cfg.row_stride = - pan_afbc_stride_blocks(image->props.modifier, hdr_row_stride); + pan_afbc_stride_blocks(image->props.format, + image->props.modifier, hdr_row_stride); #else const struct pan_image_plane *plane = image->planes[pref.plane_idx]; const struct pan_image_slice_layout *slayout = diff --git a/src/panfrost/lib/pan_mod.c b/src/panfrost/lib/pan_mod.c index 845c8b8320c..2d61de70732 100644 --- a/src/panfrost/lib/pan_mod.c +++ b/src/panfrost/lib/pan_mod.c @@ -45,7 +45,8 @@ pan_mod_afbc_get_wsi_row_pitch(const struct pan_image *image, tile_extent_el.width * tile_extent_el.height * pan_format_get_plane_blocksize(props->format, plane_idx); const unsigned tile_row_payload_size_B = - pan_afbc_stride_blocks(props->modifier, header_row_stride_B) * + pan_afbc_stride_blocks(props->format, + props->modifier, header_row_stride_B) * tile_payload_size_B; return tile_row_payload_size_B / pan_afbc_superblock_height(props->modifier); @@ -95,10 +96,10 @@ pan_mod_afbc_init_slice_layout( if (props->modifier & AFBC_FORMAT_MOD_TILED) { align_px.width = ALIGN_POT(align_px.width, afbc_tile_extent_px.width * - pan_afbc_tile_size(props->modifier)); + pan_afbc_tile_size(props->format, props->modifier)); align_px.height = ALIGN_POT(align_px.height, afbc_tile_extent_px.height * - pan_afbc_tile_size(props->modifier)); + pan_afbc_tile_size(props->format, props->modifier)); } struct pan_image_extent aligned_extent_px = { @@ -134,7 +135,7 @@ pan_mod_afbc_init_slice_layout( } slayout->afbc.header.row_stride_B = - pan_afbc_row_stride(props->modifier, width_from_wsi_row_stride); + pan_afbc_row_stride(props->format, props->modifier, width_from_wsi_row_stride); if (slayout->afbc.header.row_stride_B & row_align_mask) { mesa_loge("WSI pitch not properly aligned"); return false; @@ -150,7 +151,7 @@ pan_mod_afbc_init_slice_layout( * the resource width to get the size. */ if (!layout_constraints->strict) { slayout->afbc.header.row_stride_B = ALIGN_POT( - pan_afbc_row_stride(props->modifier, aligned_extent_px.width), + pan_afbc_row_stride(props->format, props->modifier, aligned_extent_px.width), row_align_mask + 1); } } else { @@ -158,12 +159,13 @@ pan_mod_afbc_init_slice_layout( ALIGN_POT(layout_constraints ? layout_constraints->offset_B : 0, offset_align_mask + 1); slayout->afbc.header.row_stride_B = ALIGN_POT( - pan_afbc_row_stride(props->modifier, aligned_extent_px.width), + pan_afbc_row_stride(props->format, props->modifier, aligned_extent_px.width), row_align_mask + 1); } - const unsigned row_stride_sb = pan_afbc_stride_blocks( - props->modifier, slayout->afbc.header.row_stride_B); + const unsigned row_stride_sb = pan_afbc_stride_blocks(props->format, + props->modifier, + slayout->afbc.header.row_stride_B); const unsigned surface_stride_sb = row_stride_sb * (aligned_extent_px.height / afbc_tile_extent_px.height); diff --git a/src/panfrost/lib/tests/test-layout.cpp b/src/panfrost/lib/tests/test-layout.cpp index 08cc95ce605..09666fc69ec 100644 --- a/src/panfrost/lib/tests/test-layout.cpp +++ b/src/panfrost/lib/tests/test-layout.cpp @@ -173,10 +173,10 @@ TEST(BlockSize, AFBCSuperblock64x4) * stride calculations. */ static uint32_t -pan_afbc_line_stride(uint64_t modifier, uint32_t width) +pan_afbc_line_stride(enum pipe_format format, uint64_t modifier, uint32_t width) { - return pan_afbc_stride_blocks(modifier, - pan_afbc_row_stride(modifier, width)); + return pan_afbc_stride_blocks(format, modifier, + pan_afbc_row_stride(format, modifier, width)); } /* Which form of the stride we specify is hardware specific (row stride for @@ -196,17 +196,17 @@ TEST(AFBCStride, Linear) for (unsigned m = 0; m < ARRAY_SIZE(modifiers); ++m) { uint64_t modifier = modifiers[m]; - + enum pipe_format format = PIPE_FORMAT_R8G8B8A8_UNORM; uint32_t sw = pan_afbc_superblock_width(modifier); uint32_t cases[] = {1, 4, 17, 39}; for (unsigned i = 0; i < ARRAY_SIZE(cases); ++i) { uint32_t width = sw * cases[i]; - EXPECT_EQ(pan_afbc_row_stride(modifier, width), + EXPECT_EQ(pan_afbc_row_stride(format, modifier, width), 16 * DIV_ROUND_UP(width, sw)); - EXPECT_EQ(pan_afbc_line_stride(modifier, width), + EXPECT_EQ(pan_afbc_line_stride(format, modifier, width), DIV_ROUND_UP(width, sw)); } } @@ -225,17 +225,17 @@ TEST(AFBCStride, Tiled) for (unsigned m = 0; m < ARRAY_SIZE(modifiers); ++m) { uint64_t modifier = modifiers[m]; - + enum pipe_format format = PIPE_FORMAT_R8_UNORM; uint32_t sw = pan_afbc_superblock_width(modifier); uint32_t cases[] = {1, 4, 17, 39}; for (unsigned i = 0; i < ARRAY_SIZE(cases); ++i) { uint32_t width = sw * 8 * cases[i]; - EXPECT_EQ(pan_afbc_row_stride(modifier, width), + EXPECT_EQ(pan_afbc_row_stride(format, modifier, width), 16 * DIV_ROUND_UP(width, (sw * 8)) * 8 * 8); - EXPECT_EQ(pan_afbc_line_stride(modifier, width), + EXPECT_EQ(pan_afbc_line_stride(format, modifier, width), DIV_ROUND_UP(width, sw * 8) * 8); } }