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.Agate@amd.com>>
Acked-by: Alan Liu <haoping.liu@amd.com>
Signed-off-by: Navid Assadian <navid.assadian@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26841>
This commit is contained in:
Assadian, Navid
2023-11-21 18:05:25 -05:00
committed by Marge Bot
parent 73713f837b
commit ee20be9b07
4 changed files with 272 additions and 79 deletions

View File

@@ -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;
}
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;
}
static void vpe_bg_inverse_gamut_remap(enum color_space output_cs,
struct transfer_func *output_tf, struct vpe_color *bg_color)
{
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;
switch (output_tf->tf) {
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:
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)
enum color_space output_cs, struct transfer_func *output_tf, struct vpe_color *bg_color, bool enable_3dlut)
{
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;
}
// input is [0-0xffff]
// convert bg color to RGB full range for use inside pipe
// inverse OCSC
if (bg_color->is_ycbcr)
bg_csc(bg_color, bgcolor_cs);
inverse_output_csc(output_cs, bg_color);
if (output_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
double degam_r = 0;
double degam_g = 0;
double degam_b = 0;
// 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;
break;
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;
}
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
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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++) {