panfrost: Use pan_image_test_modifier_with_format() to do our modifier check

Now that we have pan_image_test_modifier_with_format(), use it do our
native modifier check. This involves fully describing the YUV lowering
even for formats that don't have a native YUV-as-RGB fallback.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com>
Reviewed-by: Eric R. Smith <eric.smith@collabora.com>
Acked-by: Daniel Stone <daniels@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35761>
This commit is contained in:
Boris Brezillon 2025-06-26 08:54:04 +02:00 committed by Marge Bot
parent 6c0e72ba5a
commit 590ad83b98
2 changed files with 135 additions and 95 deletions

View file

@ -257,54 +257,116 @@ panfrost_lower_yuv_format(struct panfrost_device *dev,
assert(util_format_is_yuv(format));
switch (format) {
#define SINGLE_RES(__in, __out) \
case PIPE_FORMAT_##__in: \
if (dev->formats[PIPE_FORMAT_##__out].bind & PAN_BIND_SAMPLER_VIEW) { \
#define TRY_LOWERING(...) \
do { \
const enum pipe_format out_fmts__[] = {__VA_ARGS__}; \
bool supported__ = true; \
for (unsigned r__ = 0; r__ < ARRAY_SIZE(out_fmts__); r__++) { \
supported__ &= \
!!(dev->formats[out_fmts__[r__]].bind & PAN_BIND_SAMPLER_VIEW); \
} \
if (supported__) { \
return (struct panfrost_yuv_format_lowering){ \
.nres = 1, \
.res_formats[0] = PIPE_FORMAT_##__out, \
.nres = ARRAY_SIZE(out_fmts__), \
.res_formats = {__VA_ARGS__}, \
}; \
} \
} while (0)
case PIPE_FORMAT_AYUV:
TRY_LOWERING(PIPE_FORMAT_RGBA8888_UNORM);
break;
case PIPE_FORMAT_XYUV:
TRY_LOWERING(PIPE_FORMAT_RGBX8888_UNORM);
break;
case PIPE_FORMAT_Y410:
TRY_LOWERING(PIPE_FORMAT_R10G10B10A2_UNORM);
break;
case PIPE_FORMAT_Y412:
case PIPE_FORMAT_Y416:
TRY_LOWERING(PIPE_FORMAT_R16G16B16A16_UNORM);
break;
case PIPE_FORMAT_YUYV:
TRY_LOWERING(PIPE_FORMAT_R8G8_R8B8_UNORM);
TRY_LOWERING(PIPE_FORMAT_RG88_UNORM, PIPE_FORMAT_BGRA8888_UNORM);
break;
case PIPE_FORMAT_UYVY:
TRY_LOWERING(PIPE_FORMAT_G8R8_B8R8_UNORM);
TRY_LOWERING(PIPE_FORMAT_RG88_UNORM, PIPE_FORMAT_RGBA8888_UNORM);
break;
case PIPE_FORMAT_YVYU:
TRY_LOWERING(PIPE_FORMAT_R8B8_R8G8_UNORM);
TRY_LOWERING(PIPE_FORMAT_RG88_UNORM, PIPE_FORMAT_BGRA8888_UNORM);
break;
case PIPE_FORMAT_VYUY:
TRY_LOWERING(PIPE_FORMAT_B8R8_G8R8_UNORM);
TRY_LOWERING(PIPE_FORMAT_RG88_UNORM, PIPE_FORMAT_RGBA8888_UNORM);
break;
case PIPE_FORMAT_NV12:
TRY_LOWERING(PIPE_FORMAT_R8_G8B8_420_UNORM);
TRY_LOWERING(PIPE_FORMAT_R8_UNORM, PIPE_FORMAT_RG88_UNORM);
break;
case PIPE_FORMAT_NV21:
TRY_LOWERING(PIPE_FORMAT_R8_B8G8_420_UNORM);
TRY_LOWERING(PIPE_FORMAT_R8_UNORM, PIPE_FORMAT_RG88_UNORM);
break;
case PIPE_FORMAT_NV16:
TRY_LOWERING(PIPE_FORMAT_R8_G8B8_422_UNORM);
TRY_LOWERING(PIPE_FORMAT_R8_UNORM, PIPE_FORMAT_RG88_UNORM);
break;
case PIPE_FORMAT_NV15:
TRY_LOWERING(PIPE_FORMAT_R10_G10B10_420_UNORM);
break;
case PIPE_FORMAT_NV20:
TRY_LOWERING(PIPE_FORMAT_R10_G10B10_422_UNORM);
break;
case PIPE_FORMAT_IYUV:
TRY_LOWERING(PIPE_FORMAT_R8_G8_B8_420_UNORM);
TRY_LOWERING(PIPE_FORMAT_R8_UNORM, PIPE_FORMAT_R8_UNORM, PIPE_FORMAT_R8_UNORM);
break;
case PIPE_FORMAT_YV12:
TRY_LOWERING(PIPE_FORMAT_R8_B8_G8_420_UNORM);
TRY_LOWERING(PIPE_FORMAT_R8_UNORM, PIPE_FORMAT_R8_UNORM, PIPE_FORMAT_R8_UNORM);
break;
case PIPE_FORMAT_Y8U8V8_420_UNORM_PACKED:
TRY_LOWERING(PIPE_FORMAT_R8G8B8_420_UNORM_PACKED);
break;
case PIPE_FORMAT_Y10U10V10_420_UNORM_PACKED:
TRY_LOWERING(PIPE_FORMAT_R10G10B10_420_UNORM_PACKED);
break;
case PIPE_FORMAT_Y210:
case PIPE_FORMAT_Y212:
case PIPE_FORMAT_Y216:
TRY_LOWERING(PIPE_FORMAT_RG1616_UNORM, PIPE_FORMAT_R16G16B16A16_UNORM);
break;
case PIPE_FORMAT_P010:
case PIPE_FORMAT_P012:
case PIPE_FORMAT_P016:
case PIPE_FORMAT_P030:
TRY_LOWERING(PIPE_FORMAT_R16_UNORM, PIPE_FORMAT_RG1616_UNORM);
break;
SINGLE_RES(AYUV, RGBA8888_UNORM)
SINGLE_RES(XYUV, RGBX8888_UNORM)
SINGLE_RES(YUYV, R8G8_R8B8_UNORM)
SINGLE_RES(UYVY, G8R8_B8R8_UNORM)
SINGLE_RES(YVYU, R8B8_R8G8_UNORM)
SINGLE_RES(VYUY, B8R8_G8R8_UNORM)
SINGLE_RES(NV12, R8_G8B8_420_UNORM)
SINGLE_RES(NV21, R8_B8G8_420_UNORM)
SINGLE_RES(NV16, R8_G8B8_422_UNORM)
SINGLE_RES(NV15, R10_G10B10_420_UNORM)
SINGLE_RES(NV20, R10_G10B10_422_UNORM)
SINGLE_RES(IYUV, R8_G8_B8_420_UNORM)
SINGLE_RES(YV12, R8_B8_G8_420_UNORM)
SINGLE_RES(Y8U8V8_420_UNORM_PACKED, R8G8B8_420_UNORM_PACKED)
SINGLE_RES(Y10U10V10_420_UNORM_PACKED, R10G10B10_420_UNORM_PACKED)
case PIPE_FORMAT_Y10X6_U10X6_V10X6_420_UNORM:
case PIPE_FORMAT_Y10X6_U10X6_V10X6_422_UNORM:
case PIPE_FORMAT_Y10X6_U10X6_V10X6_444_UNORM:
case PIPE_FORMAT_Y12X4_U12X4_V12X4_420_UNORM:
case PIPE_FORMAT_Y12X4_U12X4_V12X4_422_UNORM:
case PIPE_FORMAT_Y12X4_U12X4_V12X4_444_UNORM:
case PIPE_FORMAT_Y16_U16_V16_420_UNORM:
case PIPE_FORMAT_Y16_U16_V16_422_UNORM:
case PIPE_FORMAT_Y16_U16_V16_444_UNORM:
TRY_LOWERING(PIPE_FORMAT_R16_UNORM, PIPE_FORMAT_R16_UNORM,
PIPE_FORMAT_R16_UNORM);
break;
#undef SINGLE_RES
#undef TRY_LOWERING
default:
break;
}
struct panfrost_yuv_format_lowering lowering = {0};
unsigned nplanes = util_format_get_num_planes(format);
for (unsigned i = 0; i < nplanes; i++) {
lowering.res_formats[lowering.nres++] =
util_format_get_plane_format(format, i);
/* If there's no YUV-as-RGB lowering available, the original YUV format
* will be returned, and only LINEAR will be allowed. */
if (i == 0 && lowering.res_formats[i] == format)
return lowering;
/* If plane0 got lowered, so should planeX. */
assert(lowering.res_formats[i] != format);
}
return lowering;
mesa_loge("%s is not supported\n", util_format_name(format));
return (struct panfrost_yuv_format_lowering){0};
}
/* We always support linear and tiled operations, both external and internal.
@ -325,83 +387,61 @@ panfrost_walk_dmabuf_modifiers(struct pipe_screen *screen,
yuv_lowering =
panfrost_lower_yuv_format(dev, format);
/* If we get there, format support must have been validated beforehand,
* and the lowering can't return 0 resouces. Similarly, it can't be a YUV
* format either. */
assert(yuv_lowering.nres >= 1);
for (unsigned i = 0; i < yuv_lowering.nres; i++)
assert(!util_format_is_yuv(yuv_lowering.res_formats[i]));
if (yuv_lowering.nres == 1)
format = yuv_lowering.res_formats[0];
}
/* Query AFBC status */
bool afbc = dev->has_afbc;
bool ytr = afbc && !is_yuv;
bool tiled_afbc = pan_afbc_can_tile(dev->arch);
bool afrc = allow_afrc && dev->has_afrc;
if (is_yuv && yuv_lowering.nres > 1) {
for (unsigned i = 0; i < yuv_lowering.nres; i++) {
enum pipe_format plane_format = yuv_lowering.res_formats[i];
afbc &= pan_afbc_supports_format(dev->arch, plane_format);
}
} else {
afbc &= pan_afbc_supports_format(dev->arch, format);
ytr &= pan_afbc_can_ytr(format);
afrc &= !is_yuv && pan_afrc_supports_format(format);
}
PANFROST_EMULATED_MODIFIERS(emulated_mods);
PAN_SUPPORTED_MODIFIERS(native_mods);
unsigned count = 0;
for (unsigned i = 0; i < ARRAY_SIZE(native_mods); ++i) {
if (drm_is_afbc(native_mods[i])) {
if (!afbc)
continue;
uint64_t mod = native_mods[i];
if ((native_mods[i] & AFBC_FORMAT_MOD_SPLIT)) {
unsigned nplanes = util_format_get_num_planes(format);
bool can_split = true;
if ((dev->debug & PAN_DBG_NO_AFBC) && drm_is_afbc(mod))
continue;
for (unsigned p = 0; p < nplanes; p++) {
if (is_yuv && yuv_lowering.nres > 1) {
can_split &= pan_afbc_can_split(
dev->arch, yuv_lowering.res_formats[p], native_mods[i], 0);
} else {
can_split &=
pan_afbc_can_split(dev->arch, format, native_mods[i], p);
}
}
if (!allow_afrc && drm_is_afrc(mod))
continue;
if (!can_split)
continue;
/* Some single-plane subsampled YUV formats need to be lowered to two
* resources pointing to the same image. Such aliasing only works with
* linear images, so bail out early if that's the case and the modifier is
* not linear. */
if (yuv_lowering.nres > util_format_get_num_planes(format) &&
mod != DRM_FORMAT_MOD_LINEAR)
continue;
/* Defer the <modifier,format> test to the mod handler. */
bool supported;
if (is_yuv && yuv_lowering.nres > 1) {
supported = true;
for (unsigned r = 0; r < yuv_lowering.nres; r++) {
enum pipe_format res_format = yuv_lowering.res_formats[r];
supported &= pan_image_test_modifier_with_format(&dev->kmod.props,
mod, res_format);
}
if ((native_mods[i] & AFBC_FORMAT_MOD_YTR) && !ytr)
continue;
if ((native_mods[i] & AFBC_FORMAT_MOD_TILED) && !tiled_afbc)
continue;
} else {
supported =
pan_image_test_modifier_with_format(&dev->kmod.props, mod, format);
}
if (drm_is_afrc(native_mods[i]) && !afrc)
if (!supported)
continue;
/* If the format is still YUV after lowering, the SW emulation might
* involve plane aliasing which we can't do with U_TILED. */
if (util_format_is_yuv(format) &&
native_mods[i] == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED)
continue;
/* Some formats only work with AFBC. */
if ((native_mods[i] == DRM_FORMAT_MOD_LINEAR ||
native_mods[i] == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) &&
!pan_u_tiled_or_linear_supports_format(format))
continue;
if (test_modifier != DRM_FORMAT_MOD_INVALID &&
test_modifier != native_mods[i])
if (test_modifier != DRM_FORMAT_MOD_INVALID && test_modifier != mod)
continue;
if (max > (int)count) {
modifiers[count] = native_mods[i];
modifiers[count] = mod;
if (external_only)
external_only[count] = is_yuv;

View file

@ -153,7 +153,7 @@ panthor_kmod_dev_create(int fd, uint32_t flags, drmVersionPtr version,
}
/* Map the LATEST_FLUSH_ID register at device creation time. */
if (version->version_major > 1 || version->version_minor >= 5) {
if (version->version_major > 1 || version->version_minor >= 10) {
struct drm_panthor_set_user_mmio_offset user_mmio_offset = {
.offset = DRM_PANTHOR_USER_MMIO_OFFSET,
};