util/format: make subsampling explicit

Instead of parsing the format name, let's make the subsampling explicit
in the format table.

This fixes the reported subsampling for Y8U8V8_420_UNORM_PACKED and
Y10U10V10_420_UNORM_PACKED, which didn't match because of the _PACKED
suffix.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Eric R. Smith <eric.smith@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41151>
This commit is contained in:
Erik Faye-Lund 2026-04-22 09:45:43 +02:00 committed by Marge Bot
parent 36fc68ffa1
commit 22cf4f6742
5 changed files with 94 additions and 28 deletions

View file

@ -141,6 +141,16 @@ struct util_format_channel_description
};
enum pipe_video_chroma_format {
PIPE_VIDEO_CHROMA_FORMAT_NONE = 0,
PIPE_VIDEO_CHROMA_FORMAT_400 = 1,
PIPE_VIDEO_CHROMA_FORMAT_420 = 2,
PIPE_VIDEO_CHROMA_FORMAT_422 = 3,
PIPE_VIDEO_CHROMA_FORMAT_440 = 4,
PIPE_VIDEO_CHROMA_FORMAT_444 = 5,
};
struct util_format_description
{
enum pipe_format format;
@ -238,6 +248,11 @@ struct util_format_description
*/
enum util_format_colorspace colorspace;
/**
* subsampling.
*/
enum pipe_video_chroma_format subsampling;
/**
* For sRGB formats, equivalent linear format; for linear formats,
* equivalent sRGB format
@ -1578,6 +1593,12 @@ util_format_rgb_to_bgr(enum pipe_format format);
enum pipe_format
util_format_rgbx_to_rgba(enum pipe_format format);
static inline enum pipe_video_chroma_format
pipe_format_to_chroma_format(enum pipe_format format)
{
return util_format_description(format)->subsampling;
}
/* Returns the pipe format for the given array type, bitsize and component count. */
enum pipe_format
util_format_get_array(const enum util_format_type type, const unsigned bits,

View file

@ -31,6 +31,7 @@
# - number of bits
# - channel swizzle
# - color space: rgb, srgb, yuv, zs
# - subsampling: 400, 420, 422, 440 or 444
#
# The channel encoding and swizzle may be defined separately for little-endian
# and big-endian hosts when using a packed (non-array/bitmask) format.
@ -695,6 +696,7 @@
alias: UYVY
layout: subsampled
colorspace: YUV
subsampling: 422
block: {width: 2, height: 1, depth: 1}
channels: [UN8, UN8, UN8, UN8]
swizzles: [X, Y, Z, 1]
@ -702,6 +704,7 @@
alias: VYUY
layout: subsampled
colorspace: YUV
subsampling: 422
block: {width: 2, height: 1, depth: 1}
channels: [UN8, UN8, UN8, UN8]
swizzles: [X, Y, Z, 1]
@ -710,6 +713,7 @@
alias: YUYV
layout: subsampled
colorspace: YUV
subsampling: 422
block: {width: 2, height: 1, depth: 1}
channels: [UN8, UN8, UN8, UN8]
swizzles: [X, Y, Z, 1]
@ -717,6 +721,7 @@
alias: YVYU
layout: subsampled
colorspace: YUV
subsampling: 422
block: {width: 2, height: 1, depth: 1}
channels: [UN8, UN8, UN8, UN8]
swizzles: [X, Y, Z, 1]
@ -725,6 +730,7 @@
alias: AYUV
layout: other
colorspace: YUV
subsampling: 444
block: {width: 4, height: 4, depth: 1}
channels: [UN8]
swizzles: [X, Y, Z, W]
@ -732,6 +738,7 @@
alias: XYUV
layout: other
colorspace: YUV
subsampling: 444
block: {width: 4, height: 4, depth: 1}
channels: [UN8]
swizzles: [X, Y, Z, 1]
@ -2001,6 +2008,7 @@
alias: YV12
layout: planar3
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2008,6 +2016,7 @@
alias: YV16
layout: planar3
colorspace: YUV
subsampling: 422
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2015,6 +2024,7 @@
alias: IYUV
layout: planar3
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2022,6 +2032,7 @@
alias: NV12
layout: planar2
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2030,12 +2041,14 @@
layout: planar2
colorspace: YUV
block: {width: 1, height: 1, depth: 1}
subsampling: 420
channels: []
swizzles: [X, Y, Z, W]
- name: Y8_400_UNORM
alias: Y8_UNORM
layout: other
colorspace: YUV
subsampling: 400
block: {width: 1, height: 1, depth: 1}
channels: [UN8]
swizzles: [X, 0, 0, 1]
@ -2043,6 +2056,7 @@
alias: NV15
layout: planar2
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2050,6 +2064,7 @@
alias: NV20
layout: planar2
colorspace: YUV
subsampling: 422
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2164,6 +2179,7 @@
- name: Y16_U16V16_444_UNORM
layout: planar2
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2225,6 +2241,7 @@
- name: Y8_U8_V8_422_UNORM
layout: planar3
colorspace: YUV
subsampling: 422
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2233,12 +2250,14 @@
layout: planar2
colorspace: YUV
block: {width: 1, height: 1, depth: 1}
subsampling: 422
channels: []
swizzles: [X, Y, Z, W]
- name: Y8_V8U8_422_UNORM
alias: NV61
layout: planar2
colorspace: YUV
subsampling: 422
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2246,6 +2265,7 @@
alias: NV24
layout: planar2
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2253,18 +2273,21 @@
alias: NV42
layout: planar2
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y8_U8_V8_444_UNORM
layout: planar3
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y8_U8_V8_440_UNORM
layout: planar3
colorspace: YUV
subsampling: 440
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2273,60 +2296,70 @@
- name: Y10X6_U10X6_V10X6_420_UNORM
layout: planar3
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y12X4_U12X4_V12X4_420_UNORM
layout: planar3
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y16_U16_V16_420_UNORM
layout: planar3
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y10X6_U10X6_V10X6_422_UNORM
layout: planar3
colorspace: YUV
subsampling: 422
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y12X4_U12X4_V12X4_422_UNORM
layout: planar3
colorspace: YUV
subsampling: 422
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y16_U16_V16_422_UNORM
layout: planar3
colorspace: YUV
subsampling: 422
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y10X6_U10X6_V10X6_444_UNORM
layout: planar3
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y12X4_U12X4_V12X4_444_UNORM
layout: planar3
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y16_U16_V16_444_UNORM
layout: planar3
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y16_U16V16_422_UNORM
layout: planar2
colorspace: YUV
subsampling: 422
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2336,6 +2369,7 @@
alias: P010
layout: planar2
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2343,6 +2377,7 @@
alias: P012
layout: planar2
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2350,6 +2385,7 @@
alias: P016
layout: planar2
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2357,6 +2393,7 @@
alias: P030
layout: planar2
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
@ -2366,6 +2403,7 @@
alias: Y210
layout: subsampled
colorspace: YUV
subsampling: 422
block: {width: 2, height: 1, depth: 1}
channels: [X64]
swizzles: [X, Y, Z, 1]
@ -2373,6 +2411,7 @@
alias: Y212
layout: subsampled
colorspace: YUV
subsampling: 422
block: {width: 2, height: 1, depth: 1}
channels: [X64]
swizzles: [X, Y, Z, 1]
@ -2380,6 +2419,7 @@
alias: Y216
layout: subsampled
colorspace: YUV
subsampling: 422
block: {width: 2, height: 1, depth: 1}
channels: [X64]
swizzles: [X, Y, Z, 1]
@ -2389,6 +2429,7 @@
alias: Y410
layout: other
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: [UN10, UN10, UN10, UN2]
swizzles: [Y, Z, X, W]
@ -2396,6 +2437,7 @@
alias: Y412
layout: other
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: [UN16, UN16, UN16, UN16]
swizzles: [Y, Z, X, W]
@ -2403,6 +2445,7 @@
alias: Y416
layout: other
colorspace: YUV
subsampling: 444
block: {width: 1, height: 1, depth: 1}
channels: [UN16, UN16, UN16, UN16]
swizzles: [Y, Z, X, W]
@ -2412,12 +2455,14 @@
- name: Y8U8V8_420_UNORM_PACKED
layout: subsampled
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]
- name: Y10U10V10_420_UNORM_PACKED
layout: subsampled
colorspace: YUV
subsampling: 420
block: {width: 1, height: 1, depth: 1}
channels: []
swizzles: [X, Y, Z, W]

View file

@ -234,6 +234,10 @@ class Format:
self.block_depth = consume_int(self, source, 'block', 'depth')
consumed(self, source, 'block')
self.colorspace = consume_str(self, source, 'colorspace')
if 'subsampling' in source:
self.subsampling = consume_int(self, source, 'subsampling')
else:
self.subsampling = None
self.srgb_equivalent = None
self.linear_equivalent = None

View file

@ -41,6 +41,9 @@ def layout_map(layout):
def colorspace_map(colorspace):
return 'UTIL_FORMAT_COLORSPACE_' + str(colorspace).upper()
def subsampling_map(subsampling):
return 'PIPE_VIDEO_CHROMA_FORMAT_' + str(subsampling).upper()
colorspace_channels_map = {
'RGB': ['r', 'g', 'b', 'a'],
'SRGB': ['sr', 'sg', 'sb', 'a'],
@ -304,32 +307,6 @@ def write_format_aliases(formats):
CHROMA_SUBSAMP = ['400', '420', '422', '444', '440']
def write_to_chroma_format(formats):
print('enum pipe_video_chroma_format {', file=sys.stdout3)
for subsamp in CHROMA_SUBSAMP:
print(' PIPE_VIDEO_CHROMA_FORMAT_%s,' % subsamp, file=sys.stdout3)
print(' PIPE_VIDEO_CHROMA_FORMAT_NONE,', file=sys.stdout3)
print('};', file=sys.stdout3)
print(file=sys.stdout3)
print('static inline enum pipe_video_chroma_format', file=sys.stdout3)
print('pipe_format_to_chroma_format(enum pipe_format format)', file=sys.stdout3)
print('{', file=sys.stdout3)
print(' switch(format) {', file=sys.stdout3)
for subsamp in CHROMA_SUBSAMP:
format_count = 0
for f in formats:
if f.colorspace == 'YUV':
yuv_split_name = f.name.split('_')
if yuv_split_name[-2] == subsamp:
print(' case %s:' % f.name, file=sys.stdout3)
format_count += 1
if format_count > 0:
print(' return PIPE_VIDEO_CHROMA_FORMAT_%s;' % subsamp, file=sys.stdout3)
print(' default:', file=sys.stdout3)
print(' return PIPE_VIDEO_CHROMA_FORMAT_NONE;', file=sys.stdout3)
print(' }', file=sys.stdout3)
print('}', file=sys.stdout3)
def chroma_horizontal_subsample_factor(subsample_name):
assert(subsample_name in CHROMA_SUBSAMP)
if subsample_name in ['420', '422']:
@ -530,8 +507,6 @@ def write_type_conv_helpers(formats):
print(file=sys.stdout3)
def write_format_inline_helpers(formats):
write_to_chroma_format(formats)
print(file=sys.stdout3)
write_get_plane_format(formats)
print(file=sys.stdout3)
write_get_plane_width_height(formats)
@ -656,6 +631,7 @@ def write_format_table(formats):
u_format_pack.print_channels(format, do_channel_array)
u_format_pack.print_channels(format, do_swizzle_array)
print(" .colorspace = %s," % (colorspace_map(format.colorspace),))
print(" .subsampling = %s," % (subsampling_map(format.subsampling),))
if format.srgb_equivalent:
print(" .srgb_equivalent = %s,\t/* srgb_equivalent */" % format.srgb_equivalent.name)
elif format.linear_equivalent:

View file

@ -731,6 +731,25 @@ test_format_norm_flags(const struct util_format_description *format_desc)
return success;
}
/* Test that subsampling is set up correctly */
static bool
test_format_subsampling(const struct util_format_description *format_desc)
{
if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_YUV ||
(format_desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED &&
format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB)) {
/* subsampled non-RGB and YUV formats must specify a subsampling format */
if (format_desc->subsampling == PIPE_VIDEO_CHROMA_FORMAT_NONE) {
fprintf(stderr, "%s is not subsampled, as it should be.\n",
format_desc->name);
return false;
}
}
return true;
}
typedef bool
(*test_func_t)(const struct util_format_description *format_desc,
const struct util_format_test_case *test);
@ -856,6 +875,7 @@ test_all(void)
TEST_ONE_PACK_FUNC(pack_s_8uint);
TEST_FORMAT_METADATA(norm_flags);
TEST_FORMAT_METADATA(subsampling);
# undef TEST_ONE_FUNC
# undef TEST_ONE_FORMAT