panfrost: Improve AFBC header block accesses

Add an AFBC header block structure pan_afbc_headerblock to improve
readability when accessing header blocks. get_superblock_size(), which
will be used for AFBC packing in the next commits, has been moved to
pan_afbc.h and renamed to pan_afbc_payload_size() so that it can be
tested. Other utility functions pan_afbc_header_subblock_size() and
pan_afbc_header_subblock_uncompressed_size() hasve been added to help
retrieve the compressed or uncompressed size of a subblock from a
header. This commit also fixes a few issues like arch handling.

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Mary Guillemard <mary.guillemard@collabora.com>
Acked-by: Eric R. Smith <eric.smith@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35001>
This commit is contained in:
Loïc Molinari 2025-05-13 16:49:07 +02:00 committed by Marge Bot
parent a0bdbcbae6
commit f750620982
2 changed files with 117 additions and 41 deletions

View file

@ -1392,62 +1392,31 @@ panfrost_load_tiled_images(struct panfrost_transfer *transfer,
#if MESA_DEBUG
static unsigned
get_superblock_size(uint32_t *hdr, unsigned uncompressed_size)
{
/* AFBC superblock layout 0 */
unsigned body_base_ptr_len = 32;
unsigned nr_subblocks = 16;
unsigned sz_len = 6; /* bits */
unsigned mask = (1 << sz_len) - 1;
unsigned size = 0;
/* Sum up all of the subblock sizes */
for (int i = 0; i < nr_subblocks; i++) {
unsigned bitoffset = body_base_ptr_len + (i * sz_len);
unsigned start = bitoffset / 32;
unsigned end = (bitoffset + (sz_len - 1)) / 32;
unsigned offset = bitoffset % 32;
unsigned subblock_size;
if (start != end)
subblock_size = (hdr[start] >> offset) | (hdr[end] << (32 - offset));
else
subblock_size = hdr[start] >> offset;
subblock_size = (subblock_size == 1) ? uncompressed_size : subblock_size;
size += subblock_size & mask;
if (i == 0 && size == 0)
return 0;
}
return size;
}
static void
dump_block(struct panfrost_resource *rsrc, uint32_t idx)
dump_headerblock(struct panfrost_resource *rsrc, uint32_t idx)
{
panfrost_bo_wait(rsrc->bo, INT64_MAX, false);
uint8_t *ptr = rsrc->bo->ptr.cpu;
uint32_t *header = (uint32_t *)(ptr + (idx * AFBC_HEADER_BYTES_PER_TILE));
uint32_t body_base_ptr = header[0];
uint32_t *body = (uint32_t *)(ptr + body_base_ptr);
struct pan_afbc_headerblock *header = (struct pan_afbc_headerblock *)
(ptr + (idx * AFBC_HEADER_BYTES_PER_TILE));
uint32_t *header_u32 = (uint32_t *)header;
uint32_t *body = (uint32_t *)(ptr + header->payload.offset);
struct pan_image_block_size block_sz =
pan_afbc_subblock_size(rsrc->modifier);
unsigned pixel_sz = util_format_get_blocksize(rsrc->base.format);
unsigned uncompressed_size = pixel_sz * block_sz.width * block_sz.height;
unsigned size = get_superblock_size(header, uncompressed_size);
uint32_t size = pan_afbc_payload_size(7, *header, uncompressed_size);
fprintf(stderr, " Header: %08x %08x %08x %08x (size: %u bytes)\n",
header[0], header[1], header[2], header[3], size);
header_u32[0], header_u32[1], header_u32[2], header_u32[3], size);
if (size > 0) {
fprintf(stderr, " Body: %08x %08x %08x %08x\n", body[0], body[1],
body[2], body[3]);
} else {
uint8_t *comp = (uint8_t *)(header + 2);
fprintf(stderr, " Color: 0x%02x%02x%02x%02x\n", comp[0], comp[1],
comp[2], comp[3]);
fprintf(stderr, " Color: 0x%02x%02x%02x%02x\n",
header->color.rgba8888.r, header->color.rgba8888.g,
header->color.rgba8888.b, header->color.rgba8888.a);
}
fprintf(stderr, "\n");
}

View file

@ -100,6 +100,42 @@ enum pan_afbc_mode {
PAN_AFBC_MODE_INVALID
};
/*
* An AFBC header block provides access to an associated superblock payload of
* 4x4 subblocks or to an embedded solid color.
*/
struct pan_afbc_headerblock {
union {
/* Superblock payload. */
struct {
/* Offset in bytes from the start of the AFBC buffer (1st header
* block) to the start of the superblock payload data. */
uint32_t offset;
/* Sizes in bytes of the 4x4 6-bit subblocks. */
uint8_t subblock_sizes[12];
} payload;
/* Solid color. */
struct {
uint64_t reserved;
/* RGBA 8-8-8-8 color format. */
/* XXX: Add other formats. */
struct {
uint8_t r, g, b, a;
uint32_t reserved;
} rgba8888;
} color;
/* Random access. */
uint8_t u8[16];
uint16_t u16[8];
uint32_t u32[4];
uint64_t u64[2];
};
};
/*
* Given an AFBC modifier, return the superblock size.
*
@ -215,6 +251,77 @@ pan_afbc_subblock_size(uint64_t modifier)
return (struct pan_image_block_size){4, 4};
}
/*
* Given an AFBC header block, return the size of the subblock at the given
* index in the range [0, 15].
*/
static inline unsigned
pan_afbc_header_subblock_size(struct pan_afbc_headerblock header,
uint32_t index)
{
uint64_t mask = BITFIELD_MASK(6);
switch (index) {
case 0: return (header.u64[0] >> 32) & mask; break;
case 1: return (header.u64[0] >> 38) & mask; break;
case 2: return (header.u64[0] >> 44) & mask; break;
case 3: return (header.u64[0] >> 50) & mask; break;
case 4: return (header.u64[0] >> 56) & mask; break;
case 5: return ((header.u64[0] >> 62) |
(header.u64[1] << 2)) & mask; break;
case 6: return (header.u64[1] >> 4) & mask; break;
case 7: return (header.u64[1] >> 10) & mask; break;
case 8: return (header.u64[1] >> 16) & mask; break;
case 9: return (header.u64[1] >> 22) & mask; break;
case 10: return (header.u64[1] >> 28) & mask; break;
case 11: return (header.u64[1] >> 34) & mask; break;
case 12: return (header.u64[1] >> 40) & mask; break;
case 13: return (header.u64[1] >> 46) & mask; break;
case 14: return (header.u64[1] >> 52) & mask; break;
case 15: return (header.u64[1] >> 58) & mask; break;
default: unreachable("invalid index"); return 0;
}
}
/*
* Given an AFBC header block, return the size in bytes of the associated
* superblock payload data (for the superblock layouts 0, 3, 4 and 7).
*/
static inline uint32_t
pan_afbc_payload_size(unsigned arch,
struct pan_afbc_headerblock header,
uint32_t uncompressed_size)
{
/* Skip sum if the 1st subblock is 0 (solid color encoding). */
if (arch >= 7 && pan_afbc_header_subblock_size(header, 0) == 0)
return 0;
uint64_t size = 0;
for (unsigned i = 0; i < 16; i++) {
unsigned sub_size = pan_afbc_header_subblock_size(header, i);
size += sub_size != 1 ? sub_size : uncompressed_size;
}
return ALIGN_POT(size, 16);
}
/*
* Given a format and a modifier, return the size in bytes of an uncompressed
* superblock payload.
*/
static inline uint32_t
pan_afbc_payload_uncompressed_size(enum pipe_format format, uint64_t modifier)
{
struct pan_image_block_size size_px = pan_afbc_subblock_size(modifier);
uint32_t size_B = util_format_get_blocksizebits(format) / 8;
size_B *= size_px.width * size_px.height;
assert(size_B == ALIGN_POT(size_B, 16));
return size_B;
}
static inline uint32_t
pan_afbc_header_row_stride_align(unsigned arch, enum pipe_format format,
uint64_t modifier)