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)); assert(util_format_is_yuv(format));
switch (format) { switch (format) {
#define SINGLE_RES(__in, __out) \ #define TRY_LOWERING(...) \
case PIPE_FORMAT_##__in: \ do { \
if (dev->formats[PIPE_FORMAT_##__out].bind & PAN_BIND_SAMPLER_VIEW) { \ 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){ \ return (struct panfrost_yuv_format_lowering){ \
.nres = 1, \ .nres = ARRAY_SIZE(out_fmts__), \
.res_formats[0] = PIPE_FORMAT_##__out, \ .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; break;
SINGLE_RES(AYUV, RGBA8888_UNORM) case PIPE_FORMAT_Y10X6_U10X6_V10X6_420_UNORM:
SINGLE_RES(XYUV, RGBX8888_UNORM) case PIPE_FORMAT_Y10X6_U10X6_V10X6_422_UNORM:
SINGLE_RES(YUYV, R8G8_R8B8_UNORM) case PIPE_FORMAT_Y10X6_U10X6_V10X6_444_UNORM:
SINGLE_RES(UYVY, G8R8_B8R8_UNORM) case PIPE_FORMAT_Y12X4_U12X4_V12X4_420_UNORM:
SINGLE_RES(YVYU, R8B8_R8G8_UNORM) case PIPE_FORMAT_Y12X4_U12X4_V12X4_422_UNORM:
SINGLE_RES(VYUY, B8R8_G8R8_UNORM) case PIPE_FORMAT_Y12X4_U12X4_V12X4_444_UNORM:
SINGLE_RES(NV12, R8_G8B8_420_UNORM) case PIPE_FORMAT_Y16_U16_V16_420_UNORM:
SINGLE_RES(NV21, R8_B8G8_420_UNORM) case PIPE_FORMAT_Y16_U16_V16_422_UNORM:
SINGLE_RES(NV16, R8_G8B8_422_UNORM) case PIPE_FORMAT_Y16_U16_V16_444_UNORM:
SINGLE_RES(NV15, R10_G10B10_420_UNORM) TRY_LOWERING(PIPE_FORMAT_R16_UNORM, PIPE_FORMAT_R16_UNORM,
SINGLE_RES(NV20, R10_G10B10_422_UNORM) PIPE_FORMAT_R16_UNORM);
SINGLE_RES(IYUV, R8_G8_B8_420_UNORM) break;
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)
#undef SINGLE_RES #undef TRY_LOWERING
default: default:
break; break;
} }
struct panfrost_yuv_format_lowering lowering = {0}; mesa_loge("%s is not supported\n", util_format_name(format));
unsigned nplanes = util_format_get_num_planes(format); return (struct panfrost_yuv_format_lowering){0};
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;
} }
/* We always support linear and tiled operations, both external and internal. /* 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 = yuv_lowering =
panfrost_lower_yuv_format(dev, format); 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) if (yuv_lowering.nres == 1)
format = yuv_lowering.res_formats[0]; 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); PANFROST_EMULATED_MODIFIERS(emulated_mods);
PAN_SUPPORTED_MODIFIERS(native_mods); PAN_SUPPORTED_MODIFIERS(native_mods);
unsigned count = 0; unsigned count = 0;
for (unsigned i = 0; i < ARRAY_SIZE(native_mods); ++i) { for (unsigned i = 0; i < ARRAY_SIZE(native_mods); ++i) {
if (drm_is_afbc(native_mods[i])) { uint64_t mod = native_mods[i];
if (!afbc)
continue;
if ((native_mods[i] & AFBC_FORMAT_MOD_SPLIT)) { if ((dev->debug & PAN_DBG_NO_AFBC) && drm_is_afbc(mod))
unsigned nplanes = util_format_get_num_planes(format); continue;
bool can_split = true;
for (unsigned p = 0; p < nplanes; p++) { if (!allow_afrc && drm_is_afrc(mod))
if (is_yuv && yuv_lowering.nres > 1) { continue;
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 (!can_split) /* Some single-plane subsampled YUV formats need to be lowered to two
continue; * 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);
} }
} else {
if ((native_mods[i] & AFBC_FORMAT_MOD_YTR) && !ytr) supported =
continue; pan_image_test_modifier_with_format(&dev->kmod.props, mod, format);
if ((native_mods[i] & AFBC_FORMAT_MOD_TILED) && !tiled_afbc)
continue;
} }
if (drm_is_afrc(native_mods[i]) && !afrc) if (!supported)
continue; continue;
/* If the format is still YUV after lowering, the SW emulation might if (test_modifier != DRM_FORMAT_MOD_INVALID && test_modifier != mod)
* 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])
continue; continue;
if (max > (int)count) { if (max > (int)count) {
modifiers[count] = native_mods[i]; modifiers[count] = mod;
if (external_only) if (external_only)
external_only[count] = is_yuv; 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. */ /* 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 = { struct drm_panthor_set_user_mmio_offset user_mmio_offset = {
.offset = DRM_PANTHOR_USER_MMIO_OFFSET, .offset = DRM_PANTHOR_USER_MMIO_OFFSET,
}; };