drm/amd/display: Implement PQ curve based on output transfer function
Refactor part 5 - Regamma programming should be dependent on Output transfer function type Program sRGB gamma or PQ transfer function based on output transfer function. Signed-off-by: Anthony Koo <anthony.koo@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@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
c5ea922237
commit
e63d86dc9b
@ -791,6 +791,82 @@ static inline struct fixed31_32 calculate_oem_mapped_value(
|
||||
max_index);
|
||||
}
|
||||
|
||||
static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
|
||||
{
|
||||
/* consts for PQ gamma formula. */
|
||||
const struct fixed31_32 m1 =
|
||||
dal_fixed31_32_from_fraction(159301758, 1000000000);
|
||||
const struct fixed31_32 m2 =
|
||||
dal_fixed31_32_from_fraction(7884375, 100000);
|
||||
const struct fixed31_32 c1 =
|
||||
dal_fixed31_32_from_fraction(8359375, 10000000);
|
||||
const struct fixed31_32 c2 =
|
||||
dal_fixed31_32_from_fraction(188515625, 10000000);
|
||||
const struct fixed31_32 c3 =
|
||||
dal_fixed31_32_from_fraction(186875, 10000);
|
||||
|
||||
struct fixed31_32 l_pow_m1;
|
||||
struct fixed31_32 base;
|
||||
|
||||
if (dal_fixed31_32_lt(in_x, dal_fixed31_32_zero))
|
||||
in_x = dal_fixed31_32_zero;
|
||||
|
||||
l_pow_m1 = dal_fixed31_32_pow(in_x, m1);
|
||||
base = dal_fixed31_32_div(
|
||||
dal_fixed31_32_add(c1,
|
||||
(dal_fixed31_32_mul(c2, l_pow_m1))),
|
||||
dal_fixed31_32_add(dal_fixed31_32_one,
|
||||
(dal_fixed31_32_mul(c3, l_pow_m1))));
|
||||
*out_y = dal_fixed31_32_pow(base, m2);
|
||||
}
|
||||
|
||||
static void build_regamma_curve_pq(struct pwl_float_data_ex *rgb_regamma,
|
||||
struct pwl_float_data *rgb_oem,
|
||||
struct pixel_gamma_point *coeff128_oem,
|
||||
const struct core_gamma *ramp,
|
||||
const struct core_surface *surface,
|
||||
uint32_t hw_points_num,
|
||||
const struct hw_x_point *coordinate_x,
|
||||
const struct gamma_pixel *axis_x,
|
||||
struct dividers dividers)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
struct pwl_float_data_ex *rgb = rgb_regamma;
|
||||
const struct hw_x_point *coord_x = coordinate_x;
|
||||
struct fixed31_32 x;
|
||||
struct fixed31_32 output;
|
||||
struct fixed31_32 scaling_factor =
|
||||
dal_fixed31_32_from_fraction(8, 1000);
|
||||
|
||||
/* use coord_x to retrieve coordinates chosen base on given user curve
|
||||
* the x values are exponentially distributed and currently it is hard
|
||||
* coded, the user curve shape is ignored. Need to recalculate coord_x
|
||||
* based on input curve, translation from 256/1025 to 128 PWL points.
|
||||
*/
|
||||
for (i = 0; i <= hw_points_num; i++) {
|
||||
/* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125.
|
||||
* FP 1.0 = 80nits
|
||||
*/
|
||||
x = dal_fixed31_32_mul(coord_x->adjusted_x, scaling_factor);
|
||||
|
||||
compute_pq(x, &output);
|
||||
|
||||
/* should really not happen? */
|
||||
if (dal_fixed31_32_lt(output, dal_fixed31_32_zero))
|
||||
output = dal_fixed31_32_zero;
|
||||
else if (dal_fixed31_32_lt(dal_fixed31_32_one, output))
|
||||
output = dal_fixed31_32_one;
|
||||
|
||||
rgb->r = output;
|
||||
rgb->g = output;
|
||||
rgb->b = output;
|
||||
|
||||
++coord_x;
|
||||
++rgb;
|
||||
}
|
||||
}
|
||||
|
||||
static void build_regamma_curve(struct pwl_float_data_ex *rgb_regamma,
|
||||
struct pwl_float_data *rgb_oem,
|
||||
struct pixel_gamma_point *coeff128_oem,
|
||||
@ -1286,7 +1362,8 @@ static bool convert_to_custom_float(
|
||||
|
||||
bool calculate_regamma_params(struct pwl_params *params,
|
||||
const struct core_gamma *ramp,
|
||||
const struct core_surface *surface)
|
||||
const struct core_surface *surface,
|
||||
const struct core_stream *stream)
|
||||
{
|
||||
struct gamma_curve *arr_curve_points = params->arr_curve_points;
|
||||
struct curve_points *arr_points = params->arr_points;
|
||||
@ -1301,7 +1378,6 @@ bool calculate_regamma_params(struct pwl_params *params,
|
||||
struct pixel_gamma_point *coeff128_oem = NULL;
|
||||
struct pixel_gamma_point *coeff128 = NULL;
|
||||
|
||||
|
||||
bool ret = false;
|
||||
|
||||
coordinates_x = dm_alloc(sizeof(*coordinates_x)*(256 + 3));
|
||||
@ -1341,9 +1417,16 @@ bool calculate_regamma_params(struct pwl_params *params,
|
||||
setup_distribution_points(arr_curve_points, arr_points,
|
||||
¶ms->hw_points_num, coordinates_x);
|
||||
|
||||
build_regamma_curve(rgb_regamma, rgb_oem, coeff128_oem,
|
||||
ramp, surface, params->hw_points_num,
|
||||
coordinates_x, axix_x_256, dividers);
|
||||
if (stream->public.out_transfer_func &&
|
||||
stream->public.out_transfer_func->tf == TRANSFER_FUNCTION_PQ) {
|
||||
build_regamma_curve_pq(rgb_regamma, rgb_oem, coeff128_oem,
|
||||
ramp, surface, params->hw_points_num,
|
||||
coordinates_x, axix_x_256, dividers);
|
||||
} else {
|
||||
build_regamma_curve(rgb_regamma, rgb_oem, coeff128_oem,
|
||||
ramp, surface, params->hw_points_num,
|
||||
coordinates_x, axix_x_256, dividers);
|
||||
}
|
||||
|
||||
map_regamma_hw_to_x_user(coeff128, rgb_oem, rgb_resulted, rgb_user,
|
||||
coordinates_x, axix_x_256, &ramp->public, rgb_regamma,
|
||||
|
@ -303,7 +303,8 @@ static bool dce110_set_output_transfer_func(
|
||||
|
||||
opp->funcs->opp_power_on_regamma_lut(opp, true);
|
||||
|
||||
if (ramp && calculate_regamma_params(regamma_params, ramp, surface)) {
|
||||
if (ramp && calculate_regamma_params(
|
||||
regamma_params, ramp, surface, stream)) {
|
||||
opp->funcs->opp_program_regamma_pwl(opp, regamma_params);
|
||||
opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER);
|
||||
} else {
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
bool calculate_regamma_params(struct pwl_params *params,
|
||||
const struct core_gamma *ramp,
|
||||
const struct core_surface *surface);
|
||||
const struct core_surface *surface,
|
||||
const struct core_stream *stream);
|
||||
|
||||
#endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user