drm/amd/display: HLG support
Low level calculation methods. Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
1a05873f21
commit
43610a9be1
|
@ -378,6 +378,8 @@ enum dc_transfer_func_predefined {
|
||||||
TRANSFER_FUNCTION_PQ,
|
TRANSFER_FUNCTION_PQ,
|
||||||
TRANSFER_FUNCTION_LINEAR,
|
TRANSFER_FUNCTION_LINEAR,
|
||||||
TRANSFER_FUNCTION_UNITY,
|
TRANSFER_FUNCTION_UNITY,
|
||||||
|
TRANSFER_FUNCTION_HLG,
|
||||||
|
TRANSFER_FUNCTION_HLG12
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dc_transfer_func {
|
struct dc_transfer_func {
|
||||||
|
|
|
@ -131,6 +131,63 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
|
||||||
dc_fixpt_div(dc_fixpt_one, m1));
|
dc_fixpt_div(dc_fixpt_one, m1));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*de gamma, none linear to linear*/
|
||||||
|
static void compute_hlg_oetf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y)
|
||||||
|
{
|
||||||
|
struct fixed31_32 a;
|
||||||
|
struct fixed31_32 b;
|
||||||
|
struct fixed31_32 c;
|
||||||
|
struct fixed31_32 threshold;
|
||||||
|
struct fixed31_32 reference_white_level;
|
||||||
|
|
||||||
|
a = dc_fixpt_from_fraction(17883277, 100000000);
|
||||||
|
if (is_light0_12) {
|
||||||
|
/*light 0-12*/
|
||||||
|
b = dc_fixpt_from_fraction(28466892, 100000000);
|
||||||
|
c = dc_fixpt_from_fraction(55991073, 100000000);
|
||||||
|
threshold = dc_fixpt_one;
|
||||||
|
reference_white_level = dc_fixpt_half;
|
||||||
|
} else {
|
||||||
|
/*light 0-1*/
|
||||||
|
b = dc_fixpt_from_fraction(2372241, 100000000);
|
||||||
|
c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000));
|
||||||
|
threshold = dc_fixpt_from_fraction(1, 12);
|
||||||
|
reference_white_level = dc_fixpt_pow(dc_fixpt_from_fraction(3, 1), dc_fixpt_half);
|
||||||
|
}
|
||||||
|
if (dc_fixpt_lt(threshold, in_x))
|
||||||
|
*out_y = dc_fixpt_add(c, dc_fixpt_mul(a, dc_fixpt_log(dc_fixpt_sub(in_x, b))));
|
||||||
|
else
|
||||||
|
*out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_half), reference_white_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*re gamma, linear to none linear*/
|
||||||
|
static void compute_hlg_eotf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y)
|
||||||
|
{
|
||||||
|
struct fixed31_32 a;
|
||||||
|
struct fixed31_32 b;
|
||||||
|
struct fixed31_32 c;
|
||||||
|
struct fixed31_32 reference_white_level;
|
||||||
|
|
||||||
|
a = dc_fixpt_from_fraction(17883277, 100000000);
|
||||||
|
if (is_light0_12) {
|
||||||
|
/*light 0-12*/
|
||||||
|
b = dc_fixpt_from_fraction(28466892, 100000000);
|
||||||
|
c = dc_fixpt_from_fraction(55991073, 100000000);
|
||||||
|
reference_white_level = dc_fixpt_from_fraction(4, 1);
|
||||||
|
} else {
|
||||||
|
/*light 0-1*/
|
||||||
|
b = dc_fixpt_from_fraction(2372241, 100000000);
|
||||||
|
c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000));
|
||||||
|
reference_white_level = dc_fixpt_from_fraction(1, 3);
|
||||||
|
}
|
||||||
|
if (dc_fixpt_lt(dc_fixpt_half, in_x))
|
||||||
|
*out_y = dc_fixpt_add(dc_fixpt_exp(dc_fixpt_div(dc_fixpt_sub(in_x, c), a)), b);
|
||||||
|
else
|
||||||
|
*out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_from_fraction(2, 1)), reference_white_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* one-time pre-compute PQ values - only for sdr_white_level 80 */
|
/* one-time pre-compute PQ values - only for sdr_white_level 80 */
|
||||||
void precompute_pq(void)
|
void precompute_pq(void)
|
||||||
{
|
{
|
||||||
|
@ -691,6 +748,48 @@ static void build_degamma(struct pwl_float_data_ex *curve,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void build_hlg_degamma(struct pwl_float_data_ex *degamma,
|
||||||
|
uint32_t hw_points_num,
|
||||||
|
const struct hw_x_point *coordinate_x, bool is_light0_12)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
struct pwl_float_data_ex *rgb = degamma;
|
||||||
|
const struct hw_x_point *coord_x = coordinate_x;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while (i != hw_points_num + 1) {
|
||||||
|
compute_hlg_oetf(coord_x->x, is_light0_12, &rgb->r);
|
||||||
|
rgb->g = rgb->r;
|
||||||
|
rgb->b = rgb->r;
|
||||||
|
++coord_x;
|
||||||
|
++rgb;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void build_hlg_regamma(struct pwl_float_data_ex *regamma,
|
||||||
|
uint32_t hw_points_num,
|
||||||
|
const struct hw_x_point *coordinate_x, bool is_light0_12)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
struct pwl_float_data_ex *rgb = regamma;
|
||||||
|
const struct hw_x_point *coord_x = coordinate_x;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while (i != hw_points_num + 1) {
|
||||||
|
compute_hlg_eotf(coord_x->x, is_light0_12, &rgb->r);
|
||||||
|
rgb->g = rgb->r;
|
||||||
|
rgb->b = rgb->r;
|
||||||
|
++coord_x;
|
||||||
|
++rgb;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void scale_gamma(struct pwl_float_data *pwl_rgb,
|
static void scale_gamma(struct pwl_float_data *pwl_rgb,
|
||||||
const struct dc_gamma *ramp,
|
const struct dc_gamma *ramp,
|
||||||
struct dividers dividers)
|
struct dividers dividers)
|
||||||
|
@ -1614,6 +1713,25 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans,
|
||||||
}
|
}
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
|
kvfree(rgb_regamma);
|
||||||
|
} else if (trans == TRANSFER_FUNCTION_HLG ||
|
||||||
|
trans == TRANSFER_FUNCTION_HLG12) {
|
||||||
|
rgb_regamma = kvzalloc(sizeof(*rgb_regamma) *
|
||||||
|
(MAX_HW_POINTS + _EXTRA_POINTS),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!rgb_regamma)
|
||||||
|
goto rgb_regamma_alloc_fail;
|
||||||
|
|
||||||
|
build_hlg_regamma(rgb_regamma,
|
||||||
|
MAX_HW_POINTS,
|
||||||
|
coordinates_x,
|
||||||
|
trans == TRANSFER_FUNCTION_HLG12 ? true:false);
|
||||||
|
for (i = 0; i <= MAX_HW_POINTS ; i++) {
|
||||||
|
points->red[i] = rgb_regamma[i].r;
|
||||||
|
points->green[i] = rgb_regamma[i].g;
|
||||||
|
points->blue[i] = rgb_regamma[i].b;
|
||||||
|
}
|
||||||
|
ret = true;
|
||||||
kvfree(rgb_regamma);
|
kvfree(rgb_regamma);
|
||||||
}
|
}
|
||||||
rgb_regamma_alloc_fail:
|
rgb_regamma_alloc_fail:
|
||||||
|
@ -1674,6 +1792,25 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
|
||||||
}
|
}
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
|
kvfree(rgb_degamma);
|
||||||
|
} else if (trans == TRANSFER_FUNCTION_HLG ||
|
||||||
|
trans == TRANSFER_FUNCTION_HLG12) {
|
||||||
|
rgb_degamma = kvzalloc(sizeof(*rgb_degamma) *
|
||||||
|
(MAX_HW_POINTS + _EXTRA_POINTS),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!rgb_degamma)
|
||||||
|
goto rgb_degamma_alloc_fail;
|
||||||
|
|
||||||
|
build_hlg_degamma(rgb_degamma,
|
||||||
|
MAX_HW_POINTS,
|
||||||
|
coordinates_x,
|
||||||
|
trans == TRANSFER_FUNCTION_HLG12 ? true:false);
|
||||||
|
for (i = 0; i <= MAX_HW_POINTS ; i++) {
|
||||||
|
points->red[i] = rgb_degamma[i].r;
|
||||||
|
points->green[i] = rgb_degamma[i].g;
|
||||||
|
points->blue[i] = rgb_degamma[i].b;
|
||||||
|
}
|
||||||
|
ret = true;
|
||||||
kvfree(rgb_degamma);
|
kvfree(rgb_degamma);
|
||||||
}
|
}
|
||||||
points->end_exponent = 0;
|
points->end_exponent = 0;
|
||||||
|
|
Loading…
Reference in New Issue