pan/afbc: Properly validate format/parameter combinations

AFBC has a number of superblock sizes and valid layouts, with differing
combinations allowed.

It's quite clear that 16x16 is ambivalent about whether or not
block-split mode is used. 64x4 prohibits block-split mode, and 32x8
either requires or prohibits it depending on the format.

Add proper handling so we filter out the right combinations.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40886>
This commit is contained in:
Daniel Stone 2026-04-15 10:43:17 +01:00 committed by Marge Bot
parent c5415c7aed
commit 4203b770b4
2 changed files with 113 additions and 30 deletions

View file

@ -638,21 +638,103 @@ pan_afbc_can_ytr(enum pipe_format format)
}
static inline bool
pan_afbc_can_split(unsigned arch, enum pan_afbc_mode mode, uint64_t modifier)
pan_afbc_check_params(enum pan_afbc_mode mode, uint64_t modifier)
{
unsigned block_width = pan_afbc_superblock_width(modifier);
bool is_split = modifier & AFBC_FORMAT_MOD_SPLIT;
if (arch < 6)
return false;
if (block_width == 16) {
return true;
} else if (block_width == 32) {
return (mode == PAN_AFBC_MODE_R8G8B8A8 ||
mode == PAN_AFBC_MODE_R10G10B10A2);
/* YTR is not useful on RGB formats, nor with one- or two-channel
* formats */
bool is_ytr = modifier & AFBC_FORMAT_MOD_YTR;
switch (mode) {
case PAN_AFBC_MODE_YUV420_6C8:
case PAN_AFBC_MODE_YUV420_2C8:
case PAN_AFBC_MODE_YUV420_1C8:
case PAN_AFBC_MODE_YUV420_6C10:
case PAN_AFBC_MODE_YUV420_2C10:
case PAN_AFBC_MODE_YUV420_1C10:
case PAN_AFBC_MODE_YUV422_4C8:
case PAN_AFBC_MODE_YUV422_2C8:
case PAN_AFBC_MODE_YUV422_1C8:
case PAN_AFBC_MODE_YUV422_4C10:
case PAN_AFBC_MODE_YUV422_2C10:
case PAN_AFBC_MODE_YUV422_1C10:
case PAN_AFBC_MODE_R8:
case PAN_AFBC_MODE_R8G8:
case PAN_AFBC_MODE_R16:
case PAN_AFBC_MODE_R16G16:
if (is_ytr)
return false;
break;
default:
break;
}
return false;
/* 16x16 superblocks are universally compatible */
if (block_width == 16)
return true;
/* 64x4 blocks are only usable for multi-planar YUV formats,
* and not in block-split mode. */
if (block_width == 64) {
switch (mode) {
case PAN_AFBC_MODE_YUV420_2C8:
case PAN_AFBC_MODE_YUV420_1C8:
case PAN_AFBC_MODE_YUV420_2C10:
case PAN_AFBC_MODE_YUV420_1C10:
case PAN_AFBC_MODE_YUV422_2C8:
case PAN_AFBC_MODE_YUV422_1C8:
case PAN_AFBC_MODE_YUV422_2C10:
case PAN_AFBC_MODE_YUV422_1C10:
return !is_split;
default:
return false;
}
}
assert(block_width == 32);
/* 32x8 superblocks have different requirements based on the format:
* block-split mode is required for effective bpp >16, and prohibited
* for effective bpp <= 16. */
switch (mode) {
case PAN_AFBC_MODE_R8G8B8:
case PAN_AFBC_MODE_R8G8B8A8:
case PAN_AFBC_MODE_R10G10B10A2:
case PAN_AFBC_MODE_R11G11B10:
case PAN_AFBC_MODE_R16G16:
case PAN_AFBC_MODE_R16G16B16:
case PAN_AFBC_MODE_R16G16B16A16:
return is_split;
case PAN_AFBC_MODE_R8:
case PAN_AFBC_MODE_R8G8:
case PAN_AFBC_MODE_R5G6B5:
case PAN_AFBC_MODE_R4G4B4A4:
case PAN_AFBC_MODE_R5G5B5A1:
case PAN_AFBC_MODE_R16:
case PAN_AFBC_MODE_YUV420_6C8:
case PAN_AFBC_MODE_YUV420_6C10:
case PAN_AFBC_MODE_YUV422_4C8:
case PAN_AFBC_MODE_YUV422_4C10:
return !is_split;
/* The following split luma/chroma layouts require
* AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4 to be usable, since the luma
* planes require non-split 32x8, and the chroma planes require 64x4.
*/
case PAN_AFBC_MODE_YUV420_1C8:
case PAN_AFBC_MODE_YUV420_1C10:
case PAN_AFBC_MODE_YUV422_1C8:
case PAN_AFBC_MODE_YUV422_1C10:
return !is_split;
case PAN_AFBC_MODE_YUV420_2C8:
case PAN_AFBC_MODE_YUV420_2C10:
case PAN_AFBC_MODE_YUV422_2C8:
case PAN_AFBC_MODE_YUV422_2C10:
return false;
default:
assert(!"unknown mode in pan_afbc_check_params()");
return false;
}
}
/* Only support packing for RGB formats for now. */
@ -675,6 +757,15 @@ pan_afbc_can_tile(unsigned arch)
return arch >= 7;
}
/*
* Check if a gen supports AFBC with split-block mode.
*/
static inline bool
pan_afbc_can_split(unsigned arch)
{
return arch >= 6;
}
#if PAN_ARCH >= 9
static inline enum mali_afbc_compression_mode
pan_afbc_compression_mode(enum pan_afbc_mode mode)

View file

@ -190,28 +190,20 @@ pan_mod_afbc_test_props(const struct pan_kmod_dev_props *dprops,
if ((iprops->modifier & AFBC_FORMAT_MOD_TILED) && !pan_afbc_can_tile(PAN_ARCH))
return PAN_MOD_NOT_SUPPORTED;
unsigned plane_count = util_format_get_num_planes(iprops->format);
const struct util_format_description *fdesc =
util_format_description(iprops->format);
/* Check if the format supports AFBC */
enum pan_afbc_mode plane_modes[3];
for (unsigned p = 0; p < plane_count; p++) {
plane_modes[p] = pan_afbc_format(PAN_ARCH, iprops->format, p);
if (plane_modes[p] == PAN_AFBC_MODE_INVALID)
return PAN_MOD_NOT_SUPPORTED;
if ((iprops->modifier & AFBC_FORMAT_MOD_SPLIT) &&
!pan_afbc_can_split(PAN_ARCH, plane_modes[p], iprops->modifier)) {
return PAN_MOD_NOT_SUPPORTED;
}
}
/* YTR is only useful on RGB formats. */
if ((iprops->modifier & AFBC_FORMAT_MOD_YTR) &&
(pan_format_is_yuv(iprops->format) || fdesc->nr_channels < 3))
/* ... or split mode */
if ((iprops->modifier & AFBC_FORMAT_MOD_SPLIT) && !pan_afbc_can_split(PAN_ARCH))
return PAN_MOD_NOT_SUPPORTED;
/* Check compatibility between formats and parameters */
unsigned plane_count = util_format_get_num_planes(iprops->format);
for (unsigned p = 0; p < plane_count; p++) {
enum pan_afbc_mode mode = pan_afbc_format(PAN_ARCH, iprops->format, p);
if (mode == PAN_AFBC_MODE_INVALID)
return PAN_MOD_NOT_SUPPORTED;
if (!pan_afbc_check_params(mode, iprops->modifier))
return PAN_MOD_NOT_SUPPORTED;
}
/* AFBC can't do multisampling. */
if (iprops->nr_samples > 1)
return PAN_MOD_NOT_SUPPORTED;