panfrost: Add the concept of render block

When dealing with AFBC render targets using wide blocks, the GPU needs to
keep rendering tiles that are a multiple of 16x16. This is described
as AFBC render block size, and adds extra constraints:

- render target buffers need to be aligned on 16 pixels in the vertical
  direction, even if the AFBC super block size is 4 or 8 pixels.
- if the effective tile size is smaller than the render block size, we
  should force a clean write and discard+ignore the CRC

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com>
Reviewed-by: Louis-Francis Ratté-Boulianne <lfrb@collabora.com>
Acked-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31948>
This commit is contained in:
Boris Brezillon 2023-10-26 21:19:14 +02:00 committed by Louis-Francis Ratté-Boulianne
parent 303acdef07
commit 762a0f4133
4 changed files with 69 additions and 12 deletions

View file

@ -762,7 +762,7 @@ panfrost_resource_create_with_modifier(struct pipe_screen *screen,
if (dev->ro && (template->bind & PIPE_BIND_SCANOUT)) {
struct winsys_handle handle;
struct pan_block_size blocksize =
panfrost_block_size(modifier, template->format);
panfrost_renderblock_size(modifier, template->format);
/* Block-based texture formats are only used for texture
* compression (not framebuffer compression!), which doesn't

View file

@ -82,11 +82,24 @@ mali_sampling_mode(const struct pan_image_view *view)
return MALI_MSAA_SINGLE;
}
static bool
renderblock_fits_in_single_pass(const struct pan_image_view *view,
unsigned tile_size)
{
uint64_t mod = view->planes[0]->layout.modifier;
if (!drm_is_afbc(mod))
return tile_size >= 16 * 16;
struct pan_block_size renderblk_sz = panfrost_afbc_renderblock_size(mod);
return tile_size >= renderblk_sz.width * renderblk_sz.height;
}
int
GENX(pan_select_crc_rt)(const struct pan_fb_info *fb, unsigned tile_size)
{
/* Disable CRC when the tile size is not 16x16. In the hardware, CRC
* tiles are the same size as the tiles of the framebuffer. However,
/* Disable CRC when the tile size is smaller than 16x16. In the hardware,
* CRC tiles are the same size as the tiles of the framebuffer. However,
* our code only handles 16x16 tiles. Therefore under the current
* implementation, we must disable CRC when 16x16 tiles are not used.
*
@ -112,6 +125,9 @@ GENX(pan_select_crc_rt)(const struct pan_fb_info *fb, unsigned tile_size)
!pan_image_view_has_crc(fb->rts[i].view))
continue;
if (!renderblock_fits_in_single_pass(fb->rts[i].view, tile_size))
continue;
bool valid = *(fb->rts[i].crc_valid);
bool full = !fb->extent.minx && !fb->extent.miny &&
fb->extent.maxx == (fb->width - 1) &&
@ -692,13 +708,13 @@ pan_force_clean_write_rt(const struct pan_image_view *rt, unsigned tile_size)
if (!drm_is_afbc(image->layout.modifier))
return false;
unsigned superblock = panfrost_afbc_superblock_width(image->layout.modifier);
struct pan_block_size renderblk_sz =
panfrost_afbc_renderblock_size(image->layout.modifier);
assert(superblock >= 16);
assert(renderblk_sz.width >= 16 && renderblk_sz.height >= 16);
assert(tile_size <= panfrost_max_effective_tile_size(PAN_ARCH));
/* Tile size and superblock differ unless they are both 16x16 */
return !(superblock == 16 && tile_size == 16 * 16);
return tile_size != renderblk_sz.width * renderblk_sz.height;
}
static bool

View file

@ -94,6 +94,26 @@ panfrost_afbc_superblock_size(uint64_t modifier)
return afbc_superblock_sizes[index];
}
/*
* Given an AFBC modifier, return the render size.
*/
struct pan_block_size
panfrost_afbc_renderblock_size(uint64_t modifier)
{
unsigned index = (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
assert(drm_is_afbc(modifier));
assert(index < ARRAY_SIZE(afbc_superblock_sizes));
struct pan_block_size blk_size = afbc_superblock_sizes[index];
/* The GPU needs to render 16x16 tiles. For wide tiles, that means we
* have to extend the render region to have a height of 16 pixels.
*/
blk_size.height = ALIGN_POT(blk_size.height, 16);
return blk_size;
}
/*
* Given an AFBC modifier, return the width of the superblock.
*/
@ -258,6 +278,19 @@ panfrost_block_size(uint64_t modifier, enum pipe_format format)
return (struct pan_block_size){1, 1};
}
/* For non-AFBC and non-wide AFBC, the render block size matches
* the block size, but for wide AFBC, the GPU wants the block height
* to be 16 pixels high.
*/
struct pan_block_size
panfrost_renderblock_size(uint64_t modifier, enum pipe_format format)
{
if (!drm_is_afbc(modifier))
return panfrost_block_size(modifier, format);
return panfrost_afbc_renderblock_size(modifier);
}
/*
* Determine the tile size used by AFBC. This tiles superblocks themselves.
* Current GPUs support either 8x8 tiling or no tiling (1x1)
@ -392,7 +425,7 @@ panfrost_get_legacy_stride(const struct pan_image_layout *layout,
{
unsigned row_stride = layout->slices[level].row_stride;
struct pan_block_size block_size =
panfrost_block_size(layout->modifier, layout->format);
panfrost_renderblock_size(layout->modifier, layout->format);
if (drm_is_afbc(layout->modifier)) {
unsigned width = u_minify(layout->width, level);
@ -415,7 +448,8 @@ unsigned
panfrost_from_legacy_stride(unsigned legacy_stride, enum pipe_format format,
uint64_t modifier)
{
struct pan_block_size block_size = panfrost_block_size(modifier, format);
struct pan_block_size block_size =
panfrost_renderblock_size(modifier, format);
if (drm_is_afbc(modifier)) {
unsigned width = legacy_stride / util_format_get_blocksize(format);
@ -492,6 +526,8 @@ pan_image_layout_init(unsigned arch, struct pan_image_layout *layout,
bool is_3d = layout->dim == MALI_TEXTURE_DIMENSION_3D;
uint64_t offset = explicit_layout ? explicit_layout->offset : 0;
struct pan_block_size renderblk_size =
panfrost_renderblock_size(layout->modifier, layout->format);
struct pan_block_size block_size =
panfrost_block_size(layout->modifier, layout->format);
@ -499,8 +535,8 @@ pan_image_layout_init(unsigned arch, struct pan_image_layout *layout,
unsigned height = layout->height;
unsigned depth = layout->depth;
unsigned align_w = block_size.width;
unsigned align_h = block_size.height;
unsigned align_w = renderblk_size.width;
unsigned align_h = renderblk_size.height;
/* For tiled AFBC, align to tiles of superblocks (this can be large) */
if (afbc) {
@ -560,7 +596,7 @@ pan_image_layout_init(unsigned arch, struct pan_image_layout *layout,
slice->afbc.nr_blocks =
slice->afbc.stride * (effective_height / block_size.height);
slice->afbc.header_size =
ALIGN_POT(slice->row_stride * (effective_height / align_h),
ALIGN_POT(slice->afbc.nr_blocks * AFBC_HEADER_BYTES_PER_TILE,
pan_afbc_body_align(arch, layout->modifier));
if (explicit_layout &&

View file

@ -271,6 +271,8 @@ unsigned panfrost_afbc_superblock_width(uint64_t modifier);
unsigned panfrost_afbc_superblock_height(uint64_t modifier);
struct pan_block_size panfrost_afbc_renderblock_size(uint64_t modifier);
bool panfrost_afbc_is_wide(uint64_t modifier);
struct pan_block_size panfrost_afbc_subblock_size(uint64_t modifier);
@ -347,6 +349,9 @@ uint32_t panfrost_afrc_get_rate(enum pipe_format format, uint64_t modifier);
struct pan_block_size panfrost_block_size(uint64_t modifier,
enum pipe_format format);
struct pan_block_size panfrost_renderblock_size(uint64_t modifier,
enum pipe_format format);
#ifdef PAN_ARCH
unsigned GENX(panfrost_estimate_texture_payload_size)(
const struct pan_image_view *iview);