From 44c6f2e59ee815711a966a82b7d19dbab2110f4a Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Tue, 13 Feb 2018 13:18:43 -0600 Subject: [PATCH] drm/amd/display: Handle HDR use cases. Implementation of de-gamma, blnd-gamma, shaper and 3d lut's. Removed memory allocations in transfer functions. Refactor color module. Signed-off-by: Vitaly Prosyak Reviewed-by: Krunoslav Kovac Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- .../amd/display/dc/dcn10/dcn10_cm_common.c | 153 ++++++++++++++++++ .../amd/display/dc/dcn10/dcn10_cm_common.h | 5 + drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 2 + .../amd/display/modules/color/color_gamma.c | 143 ++++++++-------- 4 files changed, 227 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index b3db6397d353..881a1bff94d2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -416,3 +416,156 @@ bool cm_helper_translate_curve_to_hw_format( return true; } + +#define NUM_DEGAMMA_REGIONS 12 + + +bool cm_helper_translate_curve_to_degamma_hw_format( + const struct dc_transfer_func *output_tf, + struct pwl_params *lut_params) +{ + struct curve_points *arr_points; + struct pwl_result_data *rgb_resulted; + struct pwl_result_data *rgb; + struct pwl_result_data *rgb_plus_1; + struct fixed31_32 y_r; + struct fixed31_32 y_g; + struct fixed31_32 y_b; + struct fixed31_32 y1_min; + struct fixed31_32 y3_max; + + int32_t region_start, region_end; + int32_t i; + uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points; + + if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) + return false; + + PERF_TRACE(); + + arr_points = lut_params->arr_points; + rgb_resulted = lut_params->rgb_resulted; + hw_points = 0; + + memset(lut_params, 0, sizeof(struct pwl_params)); + memset(seg_distr, 0, sizeof(seg_distr)); + + region_start = -NUM_DEGAMMA_REGIONS; + region_end = 0; + + + for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) + seg_distr[i] = -1; + /* 12 segments + * segments are from 2^-12 to 0 + */ + for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++) + seg_distr[i] = 4; + + for (k = 0; k < MAX_REGIONS_NUMBER; k++) { + if (seg_distr[k] != -1) + hw_points += (1 << seg_distr[k]); + } + + j = 0; + for (k = 0; k < (region_end - region_start); k++) { + increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); + start_index = (region_start + k + MAX_LOW_POINT) * + NUMBER_SW_SEGMENTS; + for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; + i += increment) { + if (j == hw_points - 1) + break; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; + j++; + } + } + + /* last point */ + start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; + rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; + rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; + rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; + + arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), + dal_fixed31_32_from_int(region_start)); + arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), + dal_fixed31_32_from_int(region_end)); + + y_r = rgb_resulted[0].red; + y_g = rgb_resulted[0].green; + y_b = rgb_resulted[0].blue; + + y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b)); + + arr_points[0].y = y1_min; + arr_points[0].slope = dal_fixed31_32_div(arr_points[0].y, arr_points[0].x); + y_r = rgb_resulted[hw_points - 1].red; + y_g = rgb_resulted[hw_points - 1].green; + y_b = rgb_resulted[hw_points - 1].blue; + + /* see comment above, m_arrPoints[1].y should be the Y value for the + * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) + */ + y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b)); + + arr_points[1].y = y3_max; + + arr_points[1].slope = dal_fixed31_32_zero; + + if (output_tf->tf == TRANSFER_FUNCTION_PQ) { + /* for PQ, we want to have a straight line from last HW X point, + * and the slope to be such that we hit 1.0 at 10000 nits. + */ + const struct fixed31_32 end_value = + dal_fixed31_32_from_int(125); + + arr_points[1].slope = dal_fixed31_32_div( + dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y), + dal_fixed31_32_sub(end_value, arr_points[1].x)); + } + + lut_params->hw_points_num = hw_points; + + i = 1; + for (k = 0; k < MAX_REGIONS_NUMBER && i < MAX_REGIONS_NUMBER; k++) { + if (seg_distr[k] != -1) { + lut_params->arr_curve_points[k].segments_num = + seg_distr[k]; + lut_params->arr_curve_points[i].offset = + lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]); + } + i++; + } + + if (seg_distr[k] != -1) + lut_params->arr_curve_points[k].segments_num = seg_distr[k]; + + rgb = rgb_resulted; + rgb_plus_1 = rgb_resulted + 1; + + i = 1; + while (i != hw_points + 1) { + if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red)) + rgb_plus_1->red = rgb->red; + if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green)) + rgb_plus_1->green = rgb->green; + if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue)) + rgb_plus_1->blue = rgb->blue; + + rgb->delta_red = dal_fixed31_32_sub(rgb_plus_1->red, rgb->red); + rgb->delta_green = dal_fixed31_32_sub(rgb_plus_1->green, rgb->green); + rgb->delta_blue = dal_fixed31_32_sub(rgb_plus_1->blue, rgb->blue); + + ++rgb_plus_1; + ++rgb; + ++i; + } + cm_helper_convert_to_custom_float(rgb_resulted, + lut_params->arr_points, + hw_points, false); + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h index 64e476b83bcb..7a531b02871f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h @@ -106,4 +106,9 @@ bool cm_helper_translate_curve_to_hw_format( const struct dc_transfer_func *output_tf, struct pwl_params *lut_params, bool fixpoint); +bool cm_helper_translate_curve_to_degamma_hw_format( + const struct dc_transfer_func *output_tf, + struct pwl_params *lut_params); + + #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 78abc16ec4dc..c5aae2daf442 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -35,6 +35,8 @@ struct dpp { int inst; struct dpp_caps *caps; struct pwl_params regamma_params; + struct pwl_params degamma_params; + }; struct dpp_grph_csc_adjustment { 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 a5fd14a4016f..57d5c2575de1 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -30,15 +30,12 @@ #define NUM_PTS_IN_REGION 16 #define NUM_REGIONS 32 -#define NUM_DEGAMMA_REGIONS 12 #define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS) -#define MAX_HW_DEGAMMA_POINTS (NUM_PTS_IN_REGION*NUM_DEGAMMA_REGIONS) static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2]; -static struct hw_x_point degamma_coordinates_x[MAX_HW_DEGAMMA_POINTS + 2]; static struct fixed31_32 pq_table[MAX_HW_POINTS + 2]; -static struct fixed31_32 de_pq_table[MAX_HW_DEGAMMA_POINTS + 2]; +static struct fixed31_32 de_pq_table[MAX_HW_POINTS + 2]; static bool pq_initialized; /* = false; */ static bool de_pq_initialized; /* = false; */ @@ -69,26 +66,6 @@ void setup_x_points_distribution(void) (coordinates_x[index-1].x, increment); } } - - region_size = dal_fixed31_32_from_int(1); - degamma_coordinates_x[MAX_HW_DEGAMMA_POINTS].x = region_size; - degamma_coordinates_x[MAX_HW_DEGAMMA_POINTS + 1].x = region_size; - - for (segment = -1; segment > -(NUM_DEGAMMA_REGIONS + 1); segment--) { - region_size = dal_fixed31_32_div_int(region_size, 2); - increment = dal_fixed31_32_div_int(region_size, - NUM_PTS_IN_REGION); - seg_offset = (segment + NUM_DEGAMMA_REGIONS) * NUM_PTS_IN_REGION; - degamma_coordinates_x[seg_offset].x = region_size; - - for (index = seg_offset + 1; - index < seg_offset + NUM_PTS_IN_REGION; - index++) { - degamma_coordinates_x[index].x = dal_fixed31_32_add - (degamma_coordinates_x[index-1].x, increment); - } - } - } static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) @@ -179,15 +156,26 @@ void precompute_de_pq(void) { int i; struct fixed31_32 y; - const struct hw_x_point *coord_x = degamma_coordinates_x; + uint32_t begin_index, end_index; + struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125); + /* X points is 2^-25 to 2^7 + * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions + */ + begin_index = 13 * NUM_PTS_IN_REGION; + end_index = begin_index + 12 * NUM_PTS_IN_REGION; - for (i = 0; i <= MAX_HW_DEGAMMA_POINTS; i++) { - compute_de_pq(coord_x->x, &y); + for (i = 0; i <= begin_index; i++) + de_pq_table[i] = dal_fixed31_32_zero; + + for (; i <= end_index; i++) { + compute_de_pq(coordinates_x[i].x, &y); de_pq_table[i] = dal_fixed31_32_mul(y, scaling_factor); - ++coord_x; } + + for (; i <= MAX_HW_POINTS; i++) + de_pq_table[i] = de_pq_table[i-1]; } struct dividers { struct fixed31_32 divider1; @@ -617,8 +605,6 @@ static void build_de_pq(struct pwl_float_data_ex *de_pq, uint32_t i; struct fixed31_32 output; - struct pwl_float_data_ex *rgb = de_pq; - const struct hw_x_point *coord_x = degamma_coordinates_x; struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125); if (!de_pq_initialized) { @@ -634,13 +620,9 @@ static void build_de_pq(struct pwl_float_data_ex *de_pq, output = dal_fixed31_32_zero; else if (dal_fixed31_32_lt(scaling_factor, output)) output = scaling_factor; - - rgb->r = output; - rgb->g = output; - rgb->b = output; - - ++coord_x; - ++rgb; + de_pq[i].r = output; + de_pq[i].g = output; + de_pq[i].b = output; } } @@ -675,24 +657,37 @@ static void build_degamma(struct pwl_float_data_ex *curve, const struct hw_x_point *coordinate_x, bool is_2_4) { uint32_t i; - struct gamma_coefficients coeff; - struct pwl_float_data_ex *rgb = curve; - const struct hw_x_point *coord_x = degamma_coordinates_x; + uint32_t begin_index, end_index; build_coefficients(&coeff, is_2_4); - i = 0; + /* X points is 2^-25 to 2^7 + * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions + */ + begin_index = 13 * NUM_PTS_IN_REGION; + end_index = begin_index + 12 * NUM_PTS_IN_REGION; + + while (i != begin_index) { + curve[i].r = dal_fixed31_32_zero; + curve[i].g = dal_fixed31_32_zero; + curve[i].b = dal_fixed31_32_zero; + i++; + } + + while (i != end_index) { + curve[i].r = translate_to_linear_space_ex( + coordinate_x[i].x, &coeff, 0); + curve[i].g = curve[i].r; + curve[i].b = curve[i].r; + i++; + } while (i != hw_points_num + 1) { - /*TODO use y vs r,g,b*/ - rgb->r = translate_to_linear_space_ex( - coord_x->x, &coeff, 0); - rgb->g = rgb->r; - rgb->b = rgb->r; - ++coord_x; - ++rgb; - ++i; + curve[i].r = dal_fixed31_32_one; + curve[i].g = dal_fixed31_32_one; + curve[i].b = dal_fixed31_32_one; + i++; } } @@ -1173,10 +1168,6 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, return ret; } - -/*TODO fix me should be 2*/ -#define _EXTRA_POINTS 3 - bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, const struct dc_gamma *ramp, bool mapUserRamp) { @@ -1205,7 +1196,7 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, GFP_KERNEL); if (!rgb_user) goto rgb_user_alloc_fail; - curve = kzalloc(sizeof(*curve) * (MAX_HW_DEGAMMA_POINTS + _EXTRA_POINTS), + curve = kzalloc(sizeof(*curve) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); if (!curve) goto curve_alloc_fail; @@ -1213,7 +1204,7 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, GFP_KERNEL); if (!axix_x) goto axix_x_alloc_fail; - coeff = kzalloc(sizeof(*coeff) * (MAX_HW_DEGAMMA_POINTS + _EXTRA_POINTS), GFP_KERNEL); + coeff = kzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); if (!coeff) goto coeff_alloc_fail; @@ -1235,12 +1226,12 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, if (tf == TRANSFER_FUNCTION_PQ) build_de_pq(curve, - MAX_HW_DEGAMMA_POINTS, - degamma_coordinates_x); + MAX_HW_POINTS, + coordinates_x); else build_degamma(curve, - MAX_HW_DEGAMMA_POINTS, - degamma_coordinates_x, + MAX_HW_POINTS, + coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? true:false); tf_pts->end_exponent = 0; @@ -1249,8 +1240,8 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, tf_pts->x_point_at_y1_blue = 1; map_regamma_hw_to_x_user(ramp, coeff, rgb_user, - degamma_coordinates_x, axix_x, curve, - MAX_HW_DEGAMMA_POINTS, tf_pts, + coordinates_x, axix_x, curve, + MAX_HW_POINTS, tf_pts, mapUserRamp); ret = true; @@ -1282,7 +1273,7 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, points->x_point_at_y1_green = 1; points->x_point_at_y1_blue = 1; - for (i = 0; i < MAX_HW_POINTS ; i++) { + for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = coordinates_x[i].x; points->green[i] = coordinates_x[i].x; points->blue[i] = coordinates_x[i].x; @@ -1303,7 +1294,7 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, MAX_HW_POINTS, coordinates_x, 80); - for (i = 0; i < MAX_HW_POINTS ; i++) { + 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; @@ -1325,7 +1316,7 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, build_regamma(rgb_regamma, MAX_HW_POINTS, coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false); - for (i = 0; i < MAX_HW_POINTS ; i++) { + 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; @@ -1348,23 +1339,23 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, if (trans == TRANSFER_FUNCTION_UNITY) { - for (i = 0; i < MAX_HW_DEGAMMA_POINTS ; i++) { - points->red[i] = degamma_coordinates_x[i].x; - points->green[i] = degamma_coordinates_x[i].x; - points->blue[i] = degamma_coordinates_x[i].x; + for (i = 0; i <= MAX_HW_POINTS ; i++) { + points->red[i] = coordinates_x[i].x; + points->green[i] = coordinates_x[i].x; + points->blue[i] = coordinates_x[i].x; } ret = true; } else if (trans == TRANSFER_FUNCTION_PQ) { - rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_DEGAMMA_POINTS + + rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); if (!rgb_degamma) goto rgb_degamma_alloc_fail; build_de_pq(rgb_degamma, - MAX_HW_DEGAMMA_POINTS, - degamma_coordinates_x); - for (i = 0; i < MAX_HW_DEGAMMA_POINTS ; i++) { + MAX_HW_POINTS, + coordinates_x); + 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; @@ -1374,15 +1365,15 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, kfree(rgb_degamma); } else if (trans == TRANSFER_FUNCTION_SRGB || trans == TRANSFER_FUNCTION_BT709) { - rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_DEGAMMA_POINTS + + rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); if (!rgb_degamma) goto rgb_degamma_alloc_fail; build_degamma(rgb_degamma, - MAX_HW_DEGAMMA_POINTS, - degamma_coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false); - for (i = 0; i < MAX_HW_DEGAMMA_POINTS ; i++) { + MAX_HW_POINTS, + coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? 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; -- GitLab