panfrost: Optimize AFBC-P offsets computation

Copy block info from non-cacheable memory to cacheable memory in order
to avoid flushing the write combining buffer at each iteration for
only 4 bytes written.

This makes AFBC-P offsets computation ~13.5 times faster on Rock 5B
for a 2048x2048 RGBA8 texture, taking ~0.2 ms instead of ~2.7 ms.

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34606>
This commit is contained in:
Loïc Molinari
2025-04-17 14:35:13 +02:00
committed by Marge Bot
parent 64eed6807a
commit d3544aebd7
+33 -14
View File
@@ -1730,31 +1730,50 @@ panfrost_pack_afbc(struct panfrost_context *ctx,
struct pan_image_slice_layout *src_slice =
&prsrc->image.layout.slices[level];
struct pan_image_slice_layout *dst_slice = &slice_infos[level];
unsigned width = u_minify(prsrc->base.width0, level);
unsigned height = u_minify(prsrc->base.height0, level);
unsigned src_stride =
pan_afbc_stride_blocks(src_modifier, src_slice->row_stride);
unsigned dst_stride =
DIV_ROUND_UP(width, panfrost_afbc_superblock_width(dst_modifier));
unsigned dst_height =
DIV_ROUND_UP(height, panfrost_afbc_superblock_height(dst_modifier));
uint32_t offset = 0;
struct pan_afbc_block_info *meta =
metadata_bo->ptr.cpu + metadata_offsets[level];
for (unsigned y = 0, i = 0; y < dst_height; ++y) {
for (unsigned x = 0; x < dst_stride; ++x, ++i) {
unsigned idx = is_tiled ? get_morton_index(x, y, src_stride) : i;
uint32_t size = meta[idx].size;
meta[idx].offset = offset; /* write the start offset */
offset += size;
/* Stack allocated chunk used to copy AFBC block info from non-cacheable
* memory to cacheable memory. Each iteration of the offset computation
* loop below otherwise forces a flush of the write combining buffer
* because of the 32-bit read interleaved with the 32-bit write. A tile
* is composed of 8x8 header blocks. A chunk is made of 16 tiles so that
* at most 8 kB can be copied at each iteration (smaller values tend to
* increase latency). */
struct pan_afbc_block_info meta_chunk[64 * 16];
unsigned nr_blocks_per_chunk = ARRAY_SIZE(meta_chunk);
for (unsigned i = 0; i < src_slice->afbc.nr_blocks;
i += nr_blocks_per_chunk) {
unsigned nr_blocks = MIN2(nr_blocks_per_chunk,
src_slice->afbc.nr_blocks - i);
memcpy(meta_chunk, &meta[i],
nr_blocks * sizeof(struct pan_afbc_block_info));
for (unsigned j = 0; j < nr_blocks; j++) {
unsigned idx = j;
if (is_tiled) {
idx &= ~63;
idx += get_morton_index(j & 7, (j & 63) >> 3, src_stride);
}
meta[i + idx].offset = offset;
offset += meta_chunk[idx].size;
}
}
total_size = ALIGN_POT(total_size, pan_slice_align(dst_modifier));
{
unsigned width = u_minify(prsrc->base.width0, level);
unsigned height = u_minify(prsrc->base.height0, level);
unsigned dst_stride =
DIV_ROUND_UP(width, panfrost_afbc_superblock_width(dst_modifier));
unsigned dst_height =
DIV_ROUND_UP(height, panfrost_afbc_superblock_height(dst_modifier));
dst_slice->afbc.stride = dst_stride;
dst_slice->afbc.nr_blocks = dst_stride * dst_height;
dst_slice->afbc.header_size =