diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/modules/color/color_gamma.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/modules/color/color_gamma.c | 124 |
1 files changed, 100 insertions, 24 deletions
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index b8695660b480..eced40a2fce4 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -151,7 +151,7 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) div = dc_fixpt_sub(c2, dc_fixpt_mul(c3, l_pow_m1)); base2 = dc_fixpt_div(base, div); - //avoid complex numbers + // avoid complex numbers if (dc_fixpt_lt(base2, dc_fixpt_zero)) base2 = dc_fixpt_sub(dc_fixpt_zero, base2); @@ -161,7 +161,7 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) } -/*de gamma, none linear to linear*/ +/* de gamma, non-linear to linear */ static void compute_hlg_eotf(struct fixed31_32 in_x, struct fixed31_32 *out_y, uint32_t sdr_white_level, uint32_t max_luminance_nits) @@ -193,7 +193,7 @@ static void compute_hlg_eotf(struct fixed31_32 in_x, } -/*re gamma, linear to none linear*/ +/* re gamma, linear to non-linear */ static void compute_hlg_oetf(struct fixed31_32 in_x, struct fixed31_32 *out_y, uint32_t sdr_white_level, uint32_t max_luminance_nits) { @@ -830,7 +830,7 @@ static bool build_regamma(struct pwl_float_data_ex *rgb_regamma, i = 0; while (i <= hw_points_num) { - /*TODO use y vs r,g,b*/ + /* TODO use y vs r,g,b */ rgb->r = translate_from_linear_space_ex( coord_x->x, coeff, 0, cal_buffer); rgb->g = rgb->r; @@ -937,6 +937,7 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, uint32_t i; struct pwl_float_data_ex *rgb = rgb_regamma; const struct hw_x_point *coord_x = coordinate_x; + const struct hw_x_point *prv_coord_x = coord_x; struct fixed31_32 scaledX = dc_fixpt_zero; struct fixed31_32 scaledX1 = dc_fixpt_zero; struct fixed31_32 max_display; @@ -947,6 +948,9 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, bool use_eetf = false; bool is_clipped = false; struct fixed31_32 sdr_white_level; + struct fixed31_32 coordX_diff; + struct fixed31_32 out_dist_max; + struct fixed31_32 bright_norm; if (fs_params->max_content == 0 || fs_params->max_display == 0) @@ -975,7 +979,7 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, for (i = 32; i <= hw_points_num; i++) { if (!is_clipped) { if (use_eetf) { - /*max content is equal 1 */ + /* max content is equal 1 */ scaledX1 = dc_fixpt_div(coord_x->x, dc_fixpt_div(max_content, sdr_white_level)); hermite_spline_eetf(scaledX1, max_display, min_display, @@ -990,21 +994,65 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, else output = calculate_gamma22(scaledX, use_eetf, cal_buffer); + // Ensure output respects reasonable boundaries + output = dc_fixpt_clamp(output, dc_fixpt_zero, dc_fixpt_one); + rgb->r = output; rgb->g = output; rgb->b = output; } else { + /* Here clipping happens for the first time */ is_clipped = true; - rgb->r = clip; - rgb->g = clip; - rgb->b = clip; + + /* The next few lines implement the equation + * output = prev_out + + * (coord_x->x - prev_coord_x->x) * + * (1.0 - prev_out) / + * (maxDisp/sdr_white_level - prevCoordX) + * + * This equation interpolates the first point + * after max_display/80 so that the slope from + * hw_x_before_max and hw_x_after_max is such + * that we hit Y=1.0 at max_display/80. + */ + + coordX_diff = dc_fixpt_sub(coord_x->x, prv_coord_x->x); + out_dist_max = dc_fixpt_sub(dc_fixpt_one, output); + bright_norm = dc_fixpt_div(max_display, sdr_white_level); + + output = dc_fixpt_add( + output, dc_fixpt_mul( + coordX_diff, dc_fixpt_div( + out_dist_max, + dc_fixpt_sub(bright_norm, prv_coord_x->x) + ) + ) + ); + + /* Relaxing the maximum boundary to 1.07 (instead of 1.0) + * because the last point in the curve must be such that + * the maximum display pixel brightness interpolates to + * exactly 1.0. The worst case scenario was calculated + * around 1.057, so the limit of 1.07 leaves some safety + * margin. + */ + output = dc_fixpt_clamp(output, dc_fixpt_zero, + dc_fixpt_from_fraction(107, 100)); + + rgb->r = output; + rgb->g = output; + rgb->b = output; } } else { + /* Every other clipping after the first + * one is dealt with here + */ rgb->r = clip; rgb->g = clip; rgb->b = clip; } + prv_coord_x = coord_x; ++coord_x; ++rgb; } @@ -1073,7 +1121,7 @@ static void build_hlg_degamma(struct pwl_float_data_ex *degamma, const struct hw_x_point *coord_x = coordinate_x; i = 0; - //check when i == 434 + // check when i == 434 while (i != hw_points_num + 1) { compute_hlg_eotf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); rgb->g = rgb->r; @@ -1097,7 +1145,7 @@ static void build_hlg_regamma(struct pwl_float_data_ex *regamma, i = 0; - //when i == 471 + // when i == 471 while (i != hw_points_num + 1) { compute_hlg_oetf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); rgb->g = rgb->r; @@ -1331,6 +1379,8 @@ static void apply_lut_1d( struct fixed31_32 lut1; struct fixed31_32 lut2; const int max_lut_index = 4095; + const struct fixed31_32 penult_lut_index_f = + dc_fixpt_from_int(max_lut_index-1); const struct fixed31_32 max_lut_index_f = dc_fixpt_from_int(max_lut_index); int32_t index = 0, index_next = 0; @@ -1355,10 +1405,21 @@ static void apply_lut_1d( index = dc_fixpt_floor(norm_y); index_f = dc_fixpt_from_int(index); - if (index < 0 || index > max_lut_index) + if (index < 0) continue; - index_next = (index == max_lut_index) ? index : index+1; + if (index <= max_lut_index) + index_next = (index == max_lut_index) ? index : index+1; + else { + /* Here we are dealing with the last point in the curve, + * which in some cases might exceed the range given by + * max_lut_index. So we interpolate the value using + * max_lut_index and max_lut_index - 1. + */ + index = max_lut_index - 1; + index_next = max_lut_index; + index_f = penult_lut_index_f; + } if (color == 0) { lut1 = ramp->entries.red[index]; @@ -1586,9 +1647,7 @@ static void build_new_custom_resulted_curve( uint32_t hw_points_num, struct dc_transfer_func_distributed_points *tf_pts) { - uint32_t i; - - i = 0; + uint32_t i = 0; while (i != hw_points_num + 1) { tf_pts->red[i] = dc_fixpt_clamp( @@ -1614,7 +1673,7 @@ static void apply_degamma_for_user_regamma(struct pwl_float_data_ex *rgb_regamma struct pwl_float_data_ex *rgb = rgb_regamma; const struct hw_x_point *coord_x = coordinates_x; - build_coefficients(&coeff, true); + build_coefficients(&coeff, TRANSFER_FUNCTION_SRGB); i = 0; while (i != hw_points_num + 1) { @@ -1637,7 +1696,8 @@ static bool map_regamma_hw_to_x_user( const struct pwl_float_data_ex *rgb_regamma, uint32_t hw_points_num, struct dc_transfer_func_distributed_points *tf_pts, - bool mapUserRamp) + bool mapUserRamp, + bool doClamping) { /* setup to spare calculated ideal regamma values */ @@ -1665,8 +1725,10 @@ static bool map_regamma_hw_to_x_user( } } - /* this should be named differently, all it does is clamp to 0-1 */ - build_new_custom_resulted_curve(hw_points_num, tf_pts); + if (doClamping) { + /* this should be named differently, all it does is clamp to 0-1 */ + build_new_custom_resulted_curve(hw_points_num, tf_pts); + } return true; } @@ -1675,7 +1737,8 @@ static bool map_regamma_hw_to_x_user( bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer) + struct calculate_buffer *cal_buffer, + const struct dc_gamma *ramp) { struct gamma_coefficients coeff; const struct hw_x_point *coord_x = coordinates_x; @@ -1716,6 +1779,9 @@ bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, ++i; } + if (ramp && ramp->type == GAMMA_CS_TFM_1D) + apply_lut_1d(ramp, MAX_HW_POINTS, &output_tf->tf_pts); + // this function just clamps output to 0-1 build_new_custom_resulted_curve(MAX_HW_POINTS, &output_tf->tf_pts); output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; @@ -1725,7 +1791,8 @@ bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf, const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer) + struct calculate_buffer *cal_buffer, + const struct dc_gamma *ramp) { struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; struct dividers dividers; @@ -1772,6 +1839,9 @@ bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf, tf_pts->x_point_at_y1_green = 1; tf_pts->x_point_at_y1_blue = 1; + if (ramp && ramp->type == GAMMA_CS_TFM_1D) + apply_lut_1d(ramp, MAX_HW_POINTS, &output_tf->tf_pts); + // this function just clamps output to 0-1 build_new_custom_resulted_curve(MAX_HW_POINTS, tf_pts); @@ -1914,11 +1984,12 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps, ++i; } } else { - //clamps to 0-1 + // clamps to 0-1 map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axis_x, curve, MAX_HW_POINTS, tf_pts, - mapUserRamp && ramp && ramp->type == GAMMA_RGB_256); + mapUserRamp && ramp && ramp->type == GAMMA_RGB_256, + true); } @@ -2034,6 +2105,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, struct gamma_pixel *axis_x = NULL; struct pixel_gamma_point *coeff = NULL; enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; + bool doClamping = true; bool ret = false; if (output_tf->type == TF_TYPE_BYPASS) @@ -2100,11 +2172,15 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, cal_buffer); if (ret) { + doClamping = !(output_tf->tf == TRANSFER_FUNCTION_GAMMA22 && + fs_params != NULL && fs_params->skip_tm == 0); + map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axis_x, rgb_regamma, MAX_HW_POINTS, tf_pts, (mapUserRamp || (ramp && ramp->type != GAMMA_RGB_256)) && - (ramp && ramp->type != GAMMA_CS_TFM_1D)); + (ramp && ramp->type != GAMMA_CS_TFM_1D), + doClamping); if (ramp && ramp->type == GAMMA_CS_TFM_1D) apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); |