Module: Mesa
Branch: main
Commit: ee20be9b077c72662dfbd4a8758f9b803e02cd50
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=ee20be9b077c72662dfbd4a8758f9b803e02cd50

Author: Assadian, Navid <navid.assad...@amd.com>
Date:   Tue Nov 21 18:05:25 2023 -0500

amd/vpelib: Apply inverse gamut remap to background

The inverse of gamut remap is applied to background color when the tone-mapping
is enabled and the output is fp16 linear, in order to reverse the effect of 
gamut remap
on the background color to preserve the given background color.

Reviewed-by: Jesse Agate <jesse.ag...@amd.com>>
Acked-by: Alan Liu <haoping....@amd.com>
Signed-off-by: Navid Assadian <navid.assad...@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26841>

---

 src/amd/vpelib/src/core/color_bg.c           | 323 +++++++++++++++++++++------
 src/amd/vpelib/src/core/inc/color_bg.h       |   2 +-
 src/amd/vpelib/src/core/vpe_visual_confirm.c |   2 +-
 src/amd/vpelib/src/core/vpelib.c             |   6 +-
 4 files changed, 263 insertions(+), 70 deletions(-)

diff --git a/src/amd/vpelib/src/core/color_bg.c 
b/src/amd/vpelib/src/core/color_bg.c
index 7a2dafc664a..3df67cce2f7 100644
--- a/src/amd/vpelib/src/core/color_bg.c
+++ b/src/amd/vpelib/src/core/color_bg.c
@@ -16,6 +16,44 @@ struct csc_table {
     struct csc_vector blue_coef;  // BLUE coefficient
 };
 
+
+const double bt_709_rgb_xyz_matrix[] = {
+    0.135676572958501,   0.117645247657296,   0.059378179384203,
+    0.069958232931727,   0.235290495314592,   0.023751271753681,
+    0.006359839357430,   0.039215082552432,   0.312725078090138
+};
+
+const double bt_601_rgb_xyz_matrix[] = {
+    0.129468377303939,   0.120169907240092,   0.063061715455969,
+    0.069871822671967,   0.230648692928563,   0.028479484399470,
+    0.006165160823997,   0.036826261896157,   0.315308577279846
+};
+
+const double bt_2020_rgb_xyz_matrix[] = {
+    0.209559197891125,   0.047578961279863,   0.055561840829013,
+    0.086428369751707,   0.223061365529709,   0.019510264718585,
+    0.000000000000000,   0.009235916013150,   0.349064083986850
+};
+
+const double bt_709_xyz_rgb_matrix[] = {
+    9.850972467794900,    -4.672897196261683,    -1.515534225814599,
+   -2.946029289607537,     5.702028879962675,     0.126307165371354,
+    0.169088388136759,    -0.619990756501448,     3.212679374598414
+};
+
+const double bt_601_xyz_rgb_matrix[] = {
+    10.656544932293809,   -5.288117709127149,    -1.653672548215019,
+   -3.249384680406732,     6.011485965740993,     0.106904010143450,
+    0.171144655726832,    -0.598710197023623,     3.191344462670923
+};
+
+const double bt_2020_xyz_rgb_matrix[] = {
+    5.217784765870115,    -1.081066212086299,    -0.770110277731489,
+   -2.026396206177778,     4.913316828677627,     0.047928710680581,
+    0.053616587979668,    -0.130001864005497,     2.863535322904176
+};
+
+
 static struct csc_table bgcolor_to_rgbfull_table[COLOR_SPACE_MAX] = {
     [COLOR_SPACE_YCBCR601] =
         {
@@ -93,6 +131,80 @@ static float clip_float(float x)
         return x;
 }
 
+static void color_multiply_matrices_double(double *mResult, double *M1,
+    double *M2, unsigned int Rows1, unsigned int Cols1, unsigned int Cols2)
+{
+    unsigned int i, j, k;
+
+    for (i = 0; i < Rows1; i++) {
+        for (j = 0; j < Cols2; j++) {
+            mResult[(i * Cols2) + j] = 0.0;
+            for (k = 0; k < Cols1; k++)
+                mResult[(i * Cols2) + j] = mResult[(i * Cols2) + j] +
+                    M1[(i * Cols1) + k] * M2[(k * Cols2) + j];
+        }
+    }
+}
+
+static void set_gamut_remap_matrix(double* res, enum color_space src_cs, enum 
color_space dst_cs) {
+
+    double rgb_to_xyz[9] = { 0.0 };
+    double xyz_to_rgb[9] = { 0.0 };
+
+    switch (src_cs)
+    {
+    case COLOR_SPACE_SRGB:
+    case COLOR_SPACE_SRGB_LIMITED:
+    case COLOR_SPACE_MSREF_SCRGB:
+    case COLOR_SPACE_YCBCR709_LIMITED:
+    case COLOR_SPACE_YCBCR709:
+    case COLOR_SPACE_JFIF:
+        memcpy(rgb_to_xyz, bt_709_rgb_xyz_matrix, 9 * sizeof(double));
+        break;
+    case COLOR_SPACE_YCBCR601:
+    case COLOR_SPACE_YCBCR601_LIMITED:
+        memcpy(rgb_to_xyz, bt_601_rgb_xyz_matrix, 9 * sizeof(double));
+        break;
+    case COLOR_SPACE_2020_RGB_FULLRANGE:
+    case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
+    case COLOR_SPACE_2020_YCBCR:
+    case COLOR_SPACE_2020_YCBCR_LIMITED:
+        memcpy(rgb_to_xyz, bt_2020_rgb_xyz_matrix, 9 * sizeof(double));
+        break;
+    default:
+        VPE_ASSERT(0);
+        break;
+    }
+
+    switch (dst_cs)
+    {
+    case COLOR_SPACE_SRGB:
+    case COLOR_SPACE_SRGB_LIMITED:
+    case COLOR_SPACE_MSREF_SCRGB:
+    case COLOR_SPACE_YCBCR709_LIMITED:
+    case COLOR_SPACE_YCBCR709:
+    case COLOR_SPACE_JFIF:
+        memcpy(xyz_to_rgb, bt_709_xyz_rgb_matrix, 9 * sizeof(double));
+        break;
+    case COLOR_SPACE_YCBCR601:
+    case COLOR_SPACE_YCBCR601_LIMITED:
+        memcpy(xyz_to_rgb, bt_601_xyz_rgb_matrix, 9 * sizeof(double));
+        break;
+    case COLOR_SPACE_2020_RGB_FULLRANGE:
+    case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
+    case COLOR_SPACE_2020_YCBCR:
+    case COLOR_SPACE_2020_YCBCR_LIMITED:
+        memcpy(xyz_to_rgb, bt_2020_xyz_rgb_matrix, 9 * sizeof(double));
+        break;
+    default:
+        VPE_ASSERT(0);
+        break;
+    }
+
+    color_multiply_matrices_double(res, xyz_to_rgb, rgb_to_xyz, 3, 3, 3);
+
+}
+
 static bool bg_csc(struct vpe_color *bg_color, enum color_space cs)
 {
     struct csc_table *entry             = &bgcolor_to_rgbfull_table[cs];
@@ -282,92 +394,169 @@ static void compute_depq(double inY, double *outX, bool 
clip)
     *outX = ret;
 }
 
-static bool is_rgb_limited(enum color_space cs)
+static bool is_limited_cs(enum color_space cs)
 {
-    return (cs == COLOR_SPACE_SRGB_LIMITED || cs == 
COLOR_SPACE_2020_RGB_LIMITEDRANGE);
+    bool is_limited = false;
+
+    switch (cs)
+    {
+    case COLOR_SPACE_SRGB:
+    case COLOR_SPACE_2020_RGB_FULLRANGE:
+    case COLOR_SPACE_MSREF_SCRGB:
+    case COLOR_SPACE_YCBCR601:
+    case COLOR_SPACE_YCBCR709:
+    case COLOR_SPACE_JFIF:
+    case COLOR_SPACE_2020_YCBCR:
+        is_limited = false;
+        break;
+    case COLOR_SPACE_SRGB_LIMITED:
+    case COLOR_SPACE_YCBCR601_LIMITED:
+    case COLOR_SPACE_YCBCR709_LIMITED:
+    case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
+    case COLOR_SPACE_2020_YCBCR_LIMITED:
+        is_limited = true;
+        break;
+    default:
+        VPE_ASSERT(0);
+        is_limited = false;
+        break;
+    }
+    return is_limited;
 }
 
-// To understand the logic for background color conversion,
-// please refer to vpe_update_output_gamma_sequence in color.c
-void vpe_bg_color_convert(
-    enum color_space output_cs, struct transfer_func *output_tf, struct 
vpe_color *bg_color)
-{
-    enum color_space bgcolor_cs;
-
-    if (bg_color->is_ycbcr) {
-        // Need YUV to RGB csc as internal pipe is using RGB full range
-        // For range conversion, if output is limited, we assume bg color
-        // is limited range too
-        switch (output_cs) {
-            // output is ycbr cs, follow output's setting
-        case COLOR_SPACE_YCBCR601:
-        case COLOR_SPACE_YCBCR709:
-        case COLOR_SPACE_YCBCR601_LIMITED:
-        case COLOR_SPACE_YCBCR709_LIMITED:
-        case COLOR_SPACE_2020_YCBCR:
-        case COLOR_SPACE_2020_YCBCR_LIMITED:
-            bgcolor_cs = output_cs;
-            break;
-            // output is RGB cs, follow output's range
-            // but need yuv to rgb csc
-        case COLOR_SPACE_SRGB_LIMITED:
-            bgcolor_cs = COLOR_SPACE_YCBCR709_LIMITED;
-            break;
-        case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
-            bgcolor_cs = COLOR_SPACE_2020_YCBCR_LIMITED;
-            break;
-        case COLOR_SPACE_SRGB:
-        case COLOR_SPACE_MSREF_SCRGB:
-            bgcolor_cs = COLOR_SPACE_YCBCR709;
-            break;
-        case COLOR_SPACE_2020_RGB_FULLRANGE:
-            bgcolor_cs = COLOR_SPACE_2020_YCBCR;
-            break;
-        default:
-            // should revise the newly added CS
-            // and set corresponding bgcolor_cs accordingly
-            VPE_ASSERT(0);
-            bgcolor_cs = COLOR_SPACE_YCBCR709;
-            break;
-        }
-    } else {
-        // RGB BG color, use output's cs for range check
-        bgcolor_cs = output_cs;
+static void vpe_bg_degam(
+    struct transfer_func *output_tf, struct vpe_color *bg_color) {
+
+    double degam_r = (double)bg_color->rgba.r;
+    double degam_g = (double)bg_color->rgba.g;
+    double degam_b = (double)bg_color->rgba.b;
+
+    // de-gam
+    switch (output_tf->tf) {
+
+    case TRANSFER_FUNC_PQ2084:
+        compute_depq((double)bg_color->rgba.r, &degam_r, true);
+        compute_depq((double)bg_color->rgba.g, &degam_g, true);
+        compute_depq((double)bg_color->rgba.b, &degam_b, true);
+        break;
+    case TRANSFER_FUNC_SRGB:
+    case TRANSFER_FUNC_BT709:
+    case TRANSFER_FUNC_BT1886:
+        compute_degam(output_tf->tf, (double)bg_color->rgba.r, &degam_r, true);
+        compute_degam(output_tf->tf, (double)bg_color->rgba.g, &degam_g, true);
+        compute_degam(output_tf->tf, (double)bg_color->rgba.b, &degam_b, true);
+        break;
+    case TRANSFER_FUNC_LINEAR_0_125:
+    case TRANSFER_FUNC_LINEAR_0_1:
+        break;
+    default:
+        VPE_ASSERT(0);
+        break;
     }
+    bg_color->rgba.r = (float)degam_r;
+    bg_color->rgba.g = (float)degam_g;
+    bg_color->rgba.b = (float)degam_b;
 
-    // input is [0-0xffff]
-    // convert bg color to RGB full range for use inside pipe
-    if (bg_color->is_ycbcr)
-        bg_csc(bg_color, bgcolor_cs);
+}
+
+static void vpe_bg_inverse_gamut_remap(enum color_space output_cs,
+    struct transfer_func *output_tf, struct vpe_color *bg_color)
+{
 
-    if (output_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
-        double degam_r = 0;
-        double degam_g = 0;
-        double degam_b = 0;
+        double bg_rgb[3] = { 0.0 };
+        double final_bg_rgb[3] = { 0.0 };
+        double matrix[9] = { 0.0 };
+        bg_rgb[0] = (double)bg_color->rgba.r;
+        bg_rgb[1] = (double)bg_color->rgba.g;
+        bg_rgb[2] = (double)bg_color->rgba.b;
 
-        // de-gam
         switch (output_tf->tf) {
-      
-        case TRANSFER_FUNC_PQ2084:
-            compute_depq((double)bg_color->rgba.r, &degam_r, true);
-            compute_depq((double)bg_color->rgba.g, &degam_g, true);
-            compute_depq((double)bg_color->rgba.b, &degam_b, true);
-            bg_color->rgba.r = (float)degam_r;
-            bg_color->rgba.g = (float)degam_g;
-            bg_color->rgba.b = (float)degam_b;
+        case TRANSFER_FUNC_LINEAR_0_1:
+        case TRANSFER_FUNC_LINEAR_0_125:
+            /* Since linear output uses Bt709, and this conversion is only 
needed
+             * when the tone mapping is enabled on (Bt2020) input, it is 
needed to
+             * apply the reverse of Bt2020 -> Bt709 on the background color to
+             * cancel out the effect of Bt2020 -> Bt709 on the background 
color.
+             */
+            set_gamut_remap_matrix(matrix, COLOR_SPACE_SRGB, 
COLOR_SPACE_2020_RGB_FULLRANGE);
+            color_multiply_matrices_double(final_bg_rgb, matrix, bg_rgb, 3, 3, 
1);
+
+            bg_color->rgba.r = (float)clip_double(final_bg_rgb[0]);
+            bg_color->rgba.g = (float)clip_double(final_bg_rgb[1]);
+            bg_color->rgba.b = (float)clip_double(final_bg_rgb[2]);
+
             break;
+        case TRANSFER_FUNC_PQ2084:
         case TRANSFER_FUNC_SRGB:
         case TRANSFER_FUNC_BT709:
         case TRANSFER_FUNC_BT1886:
-        case TRANSFER_FUNC_LINEAR_0_125:
-        case TRANSFER_FUNC_LINEAR_0_1:
             break;
         default:
             VPE_ASSERT(0);
             break;
         }
+
+}
+
+static void inverse_output_csc(enum color_space output_cs, struct vpe_color* 
bg_color)
+{
+    enum color_space bgcolor_cs = COLOR_SPACE_YCBCR709;
+
+    switch (output_cs) {
+        // output is ycbr cs, follow output's setting
+    case COLOR_SPACE_YCBCR601:
+    case COLOR_SPACE_YCBCR709:
+    case COLOR_SPACE_YCBCR601_LIMITED:
+    case COLOR_SPACE_YCBCR709_LIMITED:
+    case COLOR_SPACE_2020_YCBCR:
+    case COLOR_SPACE_2020_YCBCR_LIMITED:
+        bgcolor_cs = output_cs;
+        break;
+        // output is RGB cs, follow output's range
+        // but need yuv to rgb csc
+    case COLOR_SPACE_SRGB_LIMITED:
+        bgcolor_cs = COLOR_SPACE_YCBCR709_LIMITED;
+        break;
+    case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
+        bgcolor_cs = COLOR_SPACE_2020_YCBCR_LIMITED;
+        break;
+    case COLOR_SPACE_SRGB:
+    case COLOR_SPACE_MSREF_SCRGB:
+        bgcolor_cs = COLOR_SPACE_YCBCR709;
+        break;
+    case COLOR_SPACE_2020_RGB_FULLRANGE:
+        bgcolor_cs = COLOR_SPACE_2020_YCBCR;
+        break;
+    default:
+        // should revise the newly added CS
+        // and set corresponding bgcolor_cs accordingly
+        VPE_ASSERT(0);
+        bgcolor_cs = COLOR_SPACE_YCBCR709;
+        break;
     }
 
+    // input is [0-0xffff]
+    // convert bg color to RGB full range for use inside pipe
+    bg_csc(bg_color, bgcolor_cs);
+}
+
+// To understand the logic for background color conversion,
+// please refer to vpe_update_output_gamma_sequence in color.c
+void vpe_bg_color_convert(
+    enum color_space output_cs, struct transfer_func *output_tf, struct 
vpe_color *bg_color, bool enable_3dlut)
+{
+    // inverse OCSC
+    if (bg_color->is_ycbcr)
+        inverse_output_csc(output_cs, bg_color);
+
+    if (output_tf->type != TF_TYPE_BYPASS) {
+        // inverse degam
+        if (output_tf->tf == TRANSFER_FUNC_PQ2084 && !is_limited_cs(output_cs))
+            vpe_bg_degam(output_tf, bg_color);
+        // inverse gamut remap
+        if (enable_3dlut)
+            vpe_bg_inverse_gamut_remap(output_cs, output_tf, bg_color);
+    }
     // for TF_TYPE_BYPASS, bg color should be programmed to mpc as linear
 }
 
diff --git a/src/amd/vpelib/src/core/inc/color_bg.h 
b/src/amd/vpelib/src/core/inc/color_bg.h
index fbc47695a35..bc7ee8834d9 100644
--- a/src/amd/vpelib/src/core/inc/color_bg.h
+++ b/src/amd/vpelib/src/core/inc/color_bg.h
@@ -27,7 +27,7 @@
 #include "color.h"
 
 void vpe_bg_color_convert(
-    enum color_space cs, struct transfer_func *output_tf, struct vpe_color 
*bg_color);
+    enum color_space cs, struct transfer_func *output_tf, struct vpe_color 
*bg_color, bool enable_3dlut);
 
 enum vpe_status vpe_bg_color_outside_cs_gamut(
     const struct vpe_priv *vpe_priv, struct vpe_color *bg_color);
diff --git a/src/amd/vpelib/src/core/vpe_visual_confirm.c 
b/src/amd/vpelib/src/core/vpe_visual_confirm.c
index 0283ee596d3..a29919cec4d 100644
--- a/src/amd/vpelib/src/core/vpe_visual_confirm.c
+++ b/src/amd/vpelib/src/core/vpe_visual_confirm.c
@@ -145,7 +145,7 @@ struct vpe_color vpe_get_visual_confirm_color(enum 
vpe_surface_pixel_format form
     }
 
     // Due to there will be regamma (ogam), need convert the bg color for 
visual confirm
-    vpe_bg_color_convert(output_cs, output_tf, &visual_confirm_color);
+    vpe_bg_color_convert(output_cs, output_tf, &visual_confirm_color, 
enable_3dlut);
 
     // Experimental: To make FP16 Linear color looks more visually ok
     if (output_tf->tf == TRANSFER_FUNC_LINEAR_0_125) {
diff --git a/src/amd/vpelib/src/core/vpelib.c b/src/amd/vpelib/src/core/vpelib.c
index 224d4c1abd2..fe85fb7f5d1 100644
--- a/src/amd/vpelib/src/core/vpelib.c
+++ b/src/amd/vpelib/src/core/vpelib.c
@@ -602,8 +602,12 @@ enum vpe_status vpe_build_commands(
     }
 
     if (status == VPE_STATUS_OK) {
+        /* since the background is generated by the first stream,
+         * the 3dlut enablement for the background color conversion
+         * is used based on the information of the first stream.
+         */
         vpe_bg_color_convert(vpe_priv->output_ctx.cs, 
vpe_priv->output_ctx.output_tf,
-            &vpe_priv->output_ctx.bg_color);
+            &vpe_priv->output_ctx.bg_color, 
vpe_priv->stream_ctx[0].enable_3dlut);
 
         for (cmd_idx = 0; cmd_idx < vpe_priv->num_vpe_cmds; cmd_idx++) {
 

Reply via email to