From de801062bf2c4216c1884d3707ff3f1f3533c4d9 Mon Sep 17 00:00:00 2001 From: Harmanprit Tatla Date: Mon, 24 Sep 2018 16:46:38 -0400 Subject: drm/amd/display: Freesync does not engage on some displays [Why] Current render margin time is not sufficient to compute exit frame time for most monitors. [How] Declared render margin in FPS to compute a exit frame rate that is 4 FPS above the minimum FPS required to engage FreeSync. Also did code clean-up to remove redundancies. Signed-off-by: Harmanprit Tatla Reviewed-by: Anthony Koo Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- .../drm/amd/display/modules/freesync/freesync.c | 37 ++++++---------------- 1 file changed, 9 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm/amd/display/modules') diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index 4018c7180d00..620a171620ee 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -37,6 +37,8 @@ #define RENDER_TIMES_MAX_COUNT 10 /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ #define BTR_EXIT_MARGIN 2000 +/*Threshold to exit fixed refresh rate*/ +#define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 4 /* Number of consecutive frames to check before entering/exiting fixed refresh*/ #define FIXED_REFRESH_ENTER_FRAME_COUNT 5 #define FIXED_REFRESH_EXIT_FRAME_COUNT 5 @@ -257,40 +259,14 @@ static void apply_below_the_range(struct core_freesync *core_freesync, if (in_out_vrr->btr.btr_active) { in_out_vrr->btr.frame_counter = 0; in_out_vrr->btr.btr_active = false; - - /* Exit Fixed Refresh mode */ - } else if (in_out_vrr->fixed.fixed_active) { - - in_out_vrr->fixed.frame_counter++; - - if (in_out_vrr->fixed.frame_counter > - FIXED_REFRESH_EXIT_FRAME_COUNT) { - in_out_vrr->fixed.frame_counter = 0; - in_out_vrr->fixed.fixed_active = false; - } } } else if (last_render_time_in_us > max_render_time_in_us) { /* Enter Below the Range */ - if (!in_out_vrr->btr.btr_active && - in_out_vrr->btr.btr_enabled) { - in_out_vrr->btr.btr_active = true; - - /* Enter Fixed Refresh mode */ - } else if (!in_out_vrr->fixed.fixed_active && - !in_out_vrr->btr.btr_enabled) { - in_out_vrr->fixed.frame_counter++; - - if (in_out_vrr->fixed.frame_counter > - FIXED_REFRESH_ENTER_FRAME_COUNT) { - in_out_vrr->fixed.frame_counter = 0; - in_out_vrr->fixed.fixed_active = true; - } - } + in_out_vrr->btr.btr_active = true; } /* BTR set to "not active" so disengage */ if (!in_out_vrr->btr.btr_active) { - in_out_vrr->btr.btr_active = false; in_out_vrr->btr.inserted_duration_in_us = 0; in_out_vrr->btr.frames_to_insert = 0; in_out_vrr->btr.frame_counter = 0; @@ -375,7 +351,12 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync, bool update = false; unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us; - if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) { + //Compute the exit refresh rate and exit frame duration + unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us) + + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ)); + unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz; + + if (last_render_time_in_us < exit_frame_duration_in_us) { /* Exit Fixed Refresh mode */ if (in_out_vrr->fixed.fixed_active) { in_out_vrr->fixed.frame_counter++; -- cgit From e1e8a020c6b88931d541ccd44043285ab93324d3 Mon Sep 17 00:00:00 2001 From: SivapiriyanKumarasamy Date: Tue, 11 Sep 2018 17:48:07 -0400 Subject: drm/amd/display: Add support for Freesync 2 HDR and Content to Display Mapping [Why] Freesync 2 HDR and support for HDR content outside the range of the HDR display require implementation on Dal 3 to better match Dal2. [How] Add support for Freesync HDR and mapping of source content to display ranges for better representation of HDR content. Signed-off-by: SivapiriyanKumarasamy Reviewed-by: Anthony Koo Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- .../drm/amd/display/modules/color/color_gamma.c | 175 ++++++++++++++++++++- .../drm/amd/display/modules/color/color_gamma.h | 11 +- 2 files changed, 184 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/display/modules') 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 cdcefd087487..2e215c9e5445 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -306,6 +306,18 @@ static struct fixed31_32 translate_from_linear_space( a1); } +static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg) +{ + struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10); + + return translate_from_linear_space(arg, + dc_fixpt_zero, + dc_fixpt_zero, + dc_fixpt_zero, + dc_fixpt_zero, + gamma); +} + static struct fixed31_32 translate_to_linear_space( struct fixed31_32 arg, struct fixed31_32 a0, @@ -709,6 +721,160 @@ static void build_regamma(struct pwl_float_data_ex *rgb_regamma, } } +static void hermite_spline_eetf(struct fixed31_32 input_x, + struct fixed31_32 max_display, + struct fixed31_32 min_display, + struct fixed31_32 max_content, + struct fixed31_32 *out_x) +{ + struct fixed31_32 min_lum_pq; + struct fixed31_32 max_lum_pq; + struct fixed31_32 max_content_pq; + struct fixed31_32 ks; + struct fixed31_32 E1; + struct fixed31_32 E2; + struct fixed31_32 E3; + struct fixed31_32 t; + struct fixed31_32 t2; + struct fixed31_32 t3; + struct fixed31_32 two; + struct fixed31_32 three; + struct fixed31_32 temp1; + struct fixed31_32 temp2; + struct fixed31_32 a = dc_fixpt_from_fraction(15, 10); + struct fixed31_32 b = dc_fixpt_from_fraction(5, 10); + struct fixed31_32 epsilon = dc_fixpt_from_fraction(1, 1000000); // dc_fixpt_epsilon is a bit too small + + if (dc_fixpt_eq(max_content, dc_fixpt_zero)) { + *out_x = dc_fixpt_zero; + return; + } + + compute_pq(input_x, &E1); + compute_pq(dc_fixpt_div(min_display, max_content), &min_lum_pq); + compute_pq(dc_fixpt_div(max_display, max_content), &max_lum_pq); + compute_pq(dc_fixpt_one, &max_content_pq); // always 1? DAL2 code is weird + a = dc_fixpt_div(dc_fixpt_add(dc_fixpt_one, b), max_content_pq); // (1+b)/maxContent + ks = dc_fixpt_sub(dc_fixpt_mul(a, max_lum_pq), b); // a * max_lum_pq - b + + if (dc_fixpt_lt(E1, ks)) + E2 = E1; + else if (dc_fixpt_le(ks, E1) && dc_fixpt_le(E1, dc_fixpt_one)) { + if (dc_fixpt_lt(epsilon, dc_fixpt_sub(dc_fixpt_one, ks))) + // t = (E1 - ks) / (1 - ks) + t = dc_fixpt_div(dc_fixpt_sub(E1, ks), + dc_fixpt_sub(dc_fixpt_one, ks)); + else + t = dc_fixpt_zero; + + two = dc_fixpt_from_int(2); + three = dc_fixpt_from_int(3); + + t2 = dc_fixpt_mul(t, t); + t3 = dc_fixpt_mul(t2, t); + temp1 = dc_fixpt_mul(two, t3); + temp2 = dc_fixpt_mul(three, t2); + + // (2t^3 - 3t^2 + 1) * ks + E2 = dc_fixpt_mul(ks, dc_fixpt_add(dc_fixpt_one, + dc_fixpt_sub(temp1, temp2))); + + // (-2t^3 + 3t^2) * max_lum_pq + E2 = dc_fixpt_add(E2, dc_fixpt_mul(max_lum_pq, + dc_fixpt_sub(temp2, temp1))); + + temp1 = dc_fixpt_mul(two, t2); + temp2 = dc_fixpt_sub(dc_fixpt_one, ks); + + // (t^3 - 2t^2 + t) * (1-ks) + E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2, + dc_fixpt_add(t, dc_fixpt_sub(t3, temp1)))); + } + + temp1 = dc_fixpt_sub(dc_fixpt_one, E2); + temp2 = dc_fixpt_mul(temp1, temp1); + temp2 = dc_fixpt_mul(temp2, temp2); + // temp2 = (1-E2)^4 + + E3 = dc_fixpt_add(E2, dc_fixpt_mul(min_lum_pq, temp2)); + compute_de_pq(E3, out_x); + + *out_x = dc_fixpt_div(*out_x, dc_fixpt_div(max_display, max_content)); +} + +static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, + uint32_t hw_points_num, + const struct hw_x_point *coordinate_x, + const struct freesync_hdr_tf_params *fs_params) +{ + uint32_t i; + struct pwl_float_data_ex *rgb = rgb_regamma; + const struct hw_x_point *coord_x = coordinate_x; + struct fixed31_32 scaledX = dc_fixpt_zero; + struct fixed31_32 scaledX1 = dc_fixpt_zero; + struct fixed31_32 max_display = dc_fixpt_from_int(fs_params->max_display); + struct fixed31_32 min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000); + struct fixed31_32 max_content = dc_fixpt_from_int(fs_params->max_content); + struct fixed31_32 min_content = dc_fixpt_from_fraction(fs_params->min_content, 10000); + struct fixed31_32 clip = dc_fixpt_one; + struct fixed31_32 output; + bool use_eetf = false; + struct fixed31_32 sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level); + + if (fs_params == NULL || fs_params->max_content == 0 || + fs_params->max_display == 0) + return false; + + if (fs_params->min_display > 1000) // cap at 0.1 at the bottom + min_display = dc_fixpt_from_fraction(1, 10); + if (fs_params->max_display < 100) // cap at 100 at the top + max_display = dc_fixpt_from_int(100); + + if (fs_params->min_content < fs_params->min_display) + use_eetf = true; + else + min_content = min_display; + + if (fs_params->max_content > fs_params->max_display) + use_eetf = true; + else + max_content = max_display; + + rgb += 32; // first 32 points have problems with fixed point, too small + coord_x += 32; + for (i = 32; i <= hw_points_num; i++) { + if (use_eetf) { + /*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, + max_content, &scaledX); + } else + scaledX = dc_fixpt_div(coord_x->x, + dc_fixpt_div(max_display, sdr_white_level)); + + if (dc_fixpt_lt(scaledX, clip)) { + if (dc_fixpt_lt(scaledX, dc_fixpt_zero)) + output = dc_fixpt_zero; + else + output = calculate_gamma22(scaledX); + + rgb->r = output; + rgb->g = output; + rgb->b = output; + } else { + rgb->r = clip; + rgb->g = clip; + rgb->b = clip; + } + + ++coord_x; + ++rgb; + } + + return true; +} + static void build_degamma(struct pwl_float_data_ex *curve, uint32_t hw_points_num, const struct hw_x_point *coordinate_x, bool is_2_4) @@ -1356,7 +1522,8 @@ static bool map_regamma_hw_to_x_user( #define _EXTRA_POINTS 3 bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, - const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed) + const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed, + const struct freesync_hdr_tf_params *fs_params) { struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; struct dividers dividers; @@ -1424,6 +1591,12 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, MAX_HW_POINTS, coordinates_x, output_tf->sdr_ref_white_level); + } else if (tf == TRANSFER_FUNCTION_GAMMA22 && + fs_params != NULL) { + build_freesync_hdr(rgb_regamma, + MAX_HW_POINTS, + coordinates_x, + fs_params); } else { tf_pts->end_exponent = 0; tf_pts->x_point_at_y1_red = 1; diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h index 63ccb9c91224..a6e164df090a 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h @@ -73,12 +73,21 @@ struct regamma_lut { }; }; +struct freesync_hdr_tf_params { + unsigned int sdr_white_level; + unsigned int min_content; // luminance in 1/10000 nits + unsigned int max_content; // luminance in nits + unsigned int min_display; // luminance in 1/10000 nits + unsigned int max_display; // luminance in nits +}; + void setup_x_points_distribution(void); void precompute_pq(void); void precompute_de_pq(void); bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, - const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed); + const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed, + const struct freesync_hdr_tf_params *fs_params); bool mod_color_calculate_degamma_params(struct dc_transfer_func *output_tf, const struct dc_gamma *ramp, bool mapUserRamp); -- cgit From d76e393f4cef8151c0a2178b6abeacecb9da4875 Mon Sep 17 00:00:00 2001 From: SivapiriyanKumarasamy Date: Tue, 2 Oct 2018 08:44:04 -0400 Subject: drm/amd/display: Fix incorrect end slope of EETF Force the E2 to dc_fixpt_one when E1 exceeds that value. This is the correct thing to do to avoid corruption. Signed-off-by: SivapiriyanKumarasamy Reviewed-by: Krunoslav Kovac Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/modules/color/color_gamma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display/modules') 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 2e215c9e5445..bba518684243 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -789,7 +789,8 @@ static void hermite_spline_eetf(struct fixed31_32 input_x, // (t^3 - 2t^2 + t) * (1-ks) E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2, dc_fixpt_add(t, dc_fixpt_sub(t3, temp1)))); - } + } else + E2 = dc_fixpt_one; temp1 = dc_fixpt_sub(dc_fixpt_one, E2); temp2 = dc_fixpt_mul(temp1, temp1); -- cgit From 097578091327ec9b9707d4efa934c55b4e761030 Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac Date: Mon, 24 Sep 2018 16:30:20 -0400 Subject: drm/amd/display: Set gamma not working on MPO planes [Why] Set gamma not working on certain planes in MPO configuration Root cause is that video format (YUV-420) isn't allowed for IGAM where gamma is applied. Fix is not easy though: 1. allowing will not work because IGAM is before ICSC so RGB gamma would be applied on YUV pixels. 2. Moving OS gamma to DGAM or RGAM resulted in weird artifacts. Ultimately the root cause for these artifacts was due to handling end points and the fact that YUV->RGB conversion will frequently "overshoot" FP 1.0 value. DCE has a single end point and slope, so we would take max. In nightlight mode, blue channel is reduced, sometimes to flat 0 line, but red is virtually unchanged. Any "overshot" in blue will be clipped to 1 (max R,G,B) instead of max blue value. [How] Fortunately, this can be fixed on DCN where we have end point and slope for all three color channels. We cannot fix this problem on DCE. Other things fixed: - switch (back) to using RGAM for OS gamma instead of IGAM - add coeffs for 709 YUV->RGB (we used RGB->YUV for both conversions) - switch color temperature method to scaled bradford - otherwise we would have clipping problems that caused us to switch to IGAM for OS gamma in the first place. - comments and some minor improvements - there are some more issues but they will be addressed in separate commits. Signed-off-by: Krunoslav Kovac Reviewed-by: Aric Cyr Acked-by: Leo Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/modules/color/color_gamma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display/modules') 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 bba518684243..81b842270db9 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1542,7 +1542,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, /* we can use hardcoded curve for plain SRGB TF */ if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true && output_tf->tf == TRANSFER_FUNCTION_SRGB && - (!mapUserRamp && ramp->type == GAMMA_RGB_256)) + (ramp->is_identity || (!mapUserRamp && ramp->type == GAMMA_RGB_256))) return true; output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; -- cgit From b76dfbef061acc29b74cc61e9fbbb60537edcc55 Mon Sep 17 00:00:00 2001 From: SivapiriyanKumarasamy Date: Tue, 9 Oct 2018 12:59:46 -0400 Subject: drm/amd/display: Clip all remaining regamma points after first clipped point [Why] All values computed in the gamma curve after the first upperbound clipped point will need to be clipped anyways. We can avoid unnecessary computations and potential fixed point overflow by instead clipping these values to 1 automatically. [How] Track if upper-bound clipping has been done, and clip all values after this threshold is reached without computing the output gamma point. Signed-off-by: SivapiriyanKumarasamy Reviewed-by: Krunoslav Kovac Acked-by: Leo Li Signed-off-by: Alex Deucher --- .../drm/amd/display/modules/color/color_gamma.c | 44 +++++++++++++--------- 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/amd/display/modules') 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 81b842270db9..7480f072c375 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -820,6 +820,7 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, struct fixed31_32 clip = dc_fixpt_one; struct fixed31_32 output; bool use_eetf = false; + bool is_clipped = false; struct fixed31_32 sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level); if (fs_params == NULL || fs_params->max_content == 0 || @@ -844,25 +845,32 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, rgb += 32; // first 32 points have problems with fixed point, too small coord_x += 32; for (i = 32; i <= hw_points_num; i++) { - if (use_eetf) { - /*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, - max_content, &scaledX); - } else - scaledX = dc_fixpt_div(coord_x->x, - dc_fixpt_div(max_display, sdr_white_level)); - - if (dc_fixpt_lt(scaledX, clip)) { - if (dc_fixpt_lt(scaledX, dc_fixpt_zero)) - output = dc_fixpt_zero; - else - output = calculate_gamma22(scaledX); + if (!is_clipped) { + if (use_eetf) { + /*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, + max_content, &scaledX); + } else + scaledX = dc_fixpt_div(coord_x->x, + dc_fixpt_div(max_display, sdr_white_level)); + + if (dc_fixpt_lt(scaledX, clip)) { + if (dc_fixpt_lt(scaledX, dc_fixpt_zero)) + output = dc_fixpt_zero; + else + output = calculate_gamma22(scaledX); - rgb->r = output; - rgb->g = output; - rgb->b = output; + rgb->r = output; + rgb->g = output; + rgb->b = output; + } else { + is_clipped = true; + rgb->r = clip; + rgb->g = clip; + rgb->b = clip; + } } else { rgb->r = clip; rgb->g = clip; -- cgit