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 <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35771>
This commit is contained in:
Eric R. Smith 2025-09-17 14:29:35 -03:00 committed by Marge Bot
parent 3303a04d4f
commit 7a1ef0cf85
6 changed files with 48 additions and 37 deletions

View file

@ -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 = {

View file

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

View file

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

View file

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

View file

@ -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);

View file

@ -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);
}
}