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

Reply via email to