From f750620982321f0a9586f6cd8b6e86bef08e3eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Molinari?= Date: Tue, 13 May 2025 16:49:07 +0200 Subject: [PATCH] panfrost: Improve AFBC header block accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Boris Brezillon Reviewed-by: Mary Guillemard Acked-by: Eric R. Smith Part-of: --- src/gallium/drivers/panfrost/pan_resource.c | 51 ++-------- src/panfrost/lib/pan_afbc.h | 107 ++++++++++++++++++++ 2 files changed, 117 insertions(+), 41 deletions(-) diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c index e3b69d1f031..4a19a2637a0 100644 --- a/src/gallium/drivers/panfrost/pan_resource.c +++ b/src/gallium/drivers/panfrost/pan_resource.c @@ -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"); } diff --git a/src/panfrost/lib/pan_afbc.h b/src/panfrost/lib/pan_afbc.h index 26cbbd26950..59e989e62d3 100644 --- a/src/panfrost/lib/pan_afbc.h +++ b/src/panfrost/lib/pan_afbc.h @@ -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)