In preparation for YUV/YCbCr pixel format support in the writeback connector. The implementation is meant to mirror the existing get_conversion_matrix_to_argb_u16() as close as possible.
Signed-off-by: Robert Mader <robert.ma...@collabora.com> --- drivers/gpu/drm/vkms/vkms_formats.c | 153 ++++++++++++++++++++++++++++ drivers/gpu/drm/vkms/vkms_formats.h | 4 + 2 files changed, 157 insertions(+) diff --git a/drivers/gpu/drm/vkms/vkms_formats.c b/drivers/gpu/drm/vkms/vkms_formats.c index dfb8e13cba87..560b56fbf4fb 100644 --- a/drivers/gpu/drm/vkms/vkms_formats.c +++ b/drivers/gpu/drm/vkms/vkms_formats.c @@ -787,6 +787,20 @@ static const struct conversion_matrix yuv_bt601_full = { .y_offset = 0, }; +/* + * numpy.around(numpy.linalg.inv(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.601"], + * is_legal = False, + * bits = 8)) * 2**32).astype(int) + */ +static const struct conversion_matrix rgb_to_yuv_bt601_full = { + .matrix = { + { 1284195222, 2521145803, 489626272 }, + { -724715136, -1422768512, 2147483648 }, + { 2147483648, -1798249503, -349234145 }, + }, + .y_offset = 0, +}; + /* * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.601"], * is_legal = True, @@ -801,6 +815,20 @@ static const struct conversion_matrix yuv_bt601_limited = { .y_offset = 16, }; +/* + * numpy.around(numpy.linalg.inv(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.601"], + * is_legal = True, + * bits = 8)) * 2**32).astype(int) + */ +static const struct conversion_matrix rgb_to_yuv_bt601_limited = { + .matrix = { + { 1102897073, 2165219336, 420502563 }, + { -636612512, -1249804497, 1886417008 }, + { 1886417008, -1579638779, -306778230 }, + }, + .y_offset = 16, +}; + /* * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.709"], * is_legal = False, @@ -815,6 +843,20 @@ static const struct conversion_matrix yuv_bt709_full = { .y_offset = 0, }; +/* + * numpy.around(numpy.linalg.inv(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.709"], + * is_legal = False, + * bits = 8)) * 2**32).astype(int) + */ +static const struct conversion_matrix rgb_to_yuv_bt709_full = { + .matrix = { + { 913110047, 3071760610, 310096639 }, + { -492083449, -1655400199, 2147483648 }, + { 2147483648, -1950571889, -196911759 }, + }, + .y_offset = 0, +}; + /* * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.709"], * is_legal = True, @@ -829,6 +871,20 @@ static const struct conversion_matrix yuv_bt709_limited = { .y_offset = 16, }; +/* + * numpy.around(numpy.linalg.inv(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.709"], + * is_legal = True, + * bits = 8)) * 2**32).astype(int) + */ +static const struct conversion_matrix rgb_to_yuv_bt709_limited = { + .matrix = { + { 784200393, 2638100289, 266318290 }, + { -432261539, -1454155469, 1886417008 }, + { 1886417008, -1713443541, -172973467 }, + }, + .y_offset = 16, +}; + /* * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.2020"], * is_legal = False, @@ -843,6 +899,20 @@ static const struct conversion_matrix yuv_bt2020_full = { .y_offset = 0, }; +/* + * numpy.around(numpy.linalg.inv(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.2020"], + * is_legal = False, + * bits = 8)) * 2**32).astype(int) + */ +static const struct conversion_matrix rgb_to_yuv_bt2020_full = { + .matrix = { + { 1128287909, 2911987827, 254691561 }, + { -599706553, -1547777095, 2147483648 }, + { 2147483648, -1974764564, -172719084 }, + }, + .y_offset = 0, +}; + /* * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.2020"], * is_legal = True, @@ -857,6 +927,20 @@ static const struct conversion_matrix yuv_bt2020_limited = { .y_offset = 16, }; +/* + * numpy.around(numpy.linalg.inv(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.2020"], + * is_legal = True, + * bits = 8)) * 2**32).astype(int) + */ +static const struct conversion_matrix rgb_to_yuv_bt2020_limited = { + .matrix = { + { 969000204, 2500883663, 218735105 }, + { -526801050, -1359615958, 1886417008 }, + { 1886417008, -1734695147, -151721862 }, + }, + .y_offset = 16, +}; + /** * swap_uv_columns() - Swap u and v column of a given matrix * @@ -869,6 +953,18 @@ static void swap_uv_columns(struct conversion_matrix *matrix) swap(matrix->matrix[2][2], matrix->matrix[2][1]); } +/** + * swap_uv_columns_transposed() - Swap u and v column of a given matrix + * + * @matrix: Matrix in which column are swapped + */ +static void swap_uv_columns_transposed(struct conversion_matrix *matrix) +{ + swap(matrix->matrix[1][0], matrix->matrix[2][0]); + swap(matrix->matrix[1][1], matrix->matrix[2][1]); + swap(matrix->matrix[1][2], matrix->matrix[2][2]); +} + /** * get_conversion_matrix_to_argb_u16() - Retrieve the correct yuv to rgb conversion matrix for a * given encoding and range. @@ -935,6 +1031,63 @@ void get_conversion_matrix_to_argb_u16(u32 format, } EXPORT_SYMBOL(get_conversion_matrix_to_argb_u16); +void get_conversion_matrix_from_argb_u16(u32 format, + enum drm_color_encoding encoding, + enum drm_color_range range, + struct conversion_matrix *matrix) +{ + const struct conversion_matrix *matrix_to_copy; + bool limited_range; + + switch (range) { + case DRM_COLOR_YCBCR_LIMITED_RANGE: + limited_range = true; + break; + case DRM_COLOR_YCBCR_FULL_RANGE: + limited_range = false; + break; + case DRM_COLOR_RANGE_MAX: + limited_range = false; + WARN_ONCE(true, "The requested range is not supported."); + break; + } + + switch (encoding) { + case DRM_COLOR_YCBCR_BT601: + matrix_to_copy = limited_range ? &rgb_to_yuv_bt601_limited : + &rgb_to_yuv_bt601_full; + break; + case DRM_COLOR_YCBCR_BT709: + matrix_to_copy = limited_range ? &rgb_to_yuv_bt709_limited : + &rgb_to_yuv_bt709_full; + break; + case DRM_COLOR_YCBCR_BT2020: + matrix_to_copy = limited_range ? &rgb_to_yuv_bt2020_limited : + &rgb_to_yuv_bt2020_full; + break; + case DRM_COLOR_ENCODING_MAX: + matrix_to_copy = &no_operation; + WARN_ONCE(true, "The requested encoding is not supported."); + break; + } + + memcpy(matrix, matrix_to_copy, sizeof(*matrix_to_copy)); + + switch (format) { + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YVU444: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV61: + case DRM_FORMAT_NV42: + swap_uv_columns_transposed(matrix); + break; + default: + break; + } +} +EXPORT_SYMBOL(get_conversion_matrix_from_argb_u16); + /** * get_pixel_write_function() - Retrieve the correct write_pixel function for a specific format. * The returned pointer is NULL for unsupported pixel formats. The caller must ensure that the diff --git a/drivers/gpu/drm/vkms/vkms_formats.h b/drivers/gpu/drm/vkms/vkms_formats.h index eeb208cdd6b1..9367672b6b43 100644 --- a/drivers/gpu/drm/vkms/vkms_formats.h +++ b/drivers/gpu/drm/vkms/vkms_formats.h @@ -13,6 +13,10 @@ void get_conversion_matrix_to_argb_u16(u32 format, enum drm_color_encoding encod enum drm_color_range range, struct conversion_matrix *matrix); +void get_conversion_matrix_from_argb_u16(u32 format, enum drm_color_encoding encoding, + enum drm_color_range range, + struct conversion_matrix *matrix); + #if IS_ENABLED(CONFIG_KUNIT) struct pixel_argb_u16 argb_u16_from_yuv161616(const struct conversion_matrix *matrix, u16 y, u16 channel_1, u16 channel_2); -- 2.50.1