From 792474b736274fd698d39708a729b41098ae28de Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Tue, 6 Feb 2018 15:06:23 -0600 Subject: [PATCH] drm/amd/display: De PQ implementation Some refactoring and optimizations in color module. Added de gamma 2.2 & 2.4, also re gamma 2.2. Added interface for diagnostic for de gamma & de pq. Signed-off-by: Vitaly Prosyak Reviewed-by: Krunoslav Kovac Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dcn10/dcn10_dpp_cm.c | 30 +- .../amd/display/modules/color/color_gamma.c | 479 +++++++++++++++--- .../amd/display/modules/color/color_gamma.h | 8 + 3 files changed, 442 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c index 2482390c1557..bd3fcdfb79c5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -298,6 +298,32 @@ static void dpp1_cm_get_reg_field( reg->masks.exp_resion_start_segment = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_B; } +static void dpp1_cm_get_degamma_reg_field( + struct dcn10_dpp *dpp, + struct xfer_func_reg *reg) +{ + reg->shifts.exp_region0_lut_offset = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->masks.exp_region0_lut_offset = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->shifts.exp_region0_num_segments = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->masks.exp_region0_num_segments = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->shifts.exp_region1_lut_offset = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->masks.exp_region1_lut_offset = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->shifts.exp_region1_num_segments = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + reg->masks.exp_region1_num_segments = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + + reg->shifts.field_region_end = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_END_B; + reg->masks.field_region_end = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_END_B; + reg->shifts.field_region_end_slope = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_END_SLOPE_B; + reg->masks.field_region_end_slope = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_END_SLOPE_B; + reg->shifts.field_region_end_base = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_END_BASE_B; + reg->masks.field_region_end_base = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_END_BASE_B; + reg->shifts.field_region_linear_slope = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B; + reg->masks.field_region_linear_slope = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B; + reg->shifts.exp_region_start = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_START_B; + reg->masks.exp_region_start = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_START_B; + reg->shifts.exp_resion_start_segment = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_B; + reg->masks.exp_resion_start_segment = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_B; +} void dpp1_cm_set_output_csc_adjustment( struct dpp *dpp_base, const uint16_t *regval) @@ -502,7 +528,7 @@ void dpp1_program_degamma_lutb_settings( struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); struct xfer_func_reg gam_regs; - dpp1_cm_get_reg_field(dpp, &gam_regs); + dpp1_cm_get_degamma_reg_field(dpp, &gam_regs); gam_regs.start_cntl_b = REG(CM_DGAM_RAMB_START_CNTL_B); gam_regs.start_cntl_g = REG(CM_DGAM_RAMB_START_CNTL_G); @@ -531,7 +557,7 @@ void dpp1_program_degamma_luta_settings( struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); struct xfer_func_reg gam_regs; - dpp1_cm_get_reg_field(dpp, &gam_regs); + dpp1_cm_get_degamma_reg_field(dpp, &gam_regs); gam_regs.start_cntl_b = REG(CM_DGAM_RAMA_START_CNTL_B); gam_regs.start_cntl_g = REG(CM_DGAM_RAMA_START_CNTL_G); 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 fde3ae8b12a5..a5fd14a4016f 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -27,14 +27,21 @@ #include "opp.h" #include "color_gamma.h" -/* MAX_HW_POINTS = NUM_REGIONS * NUM_PTS_IN_REGION */ + #define NUM_PTS_IN_REGION 16 #define NUM_REGIONS 32 -#define MAX_HW_POINTS 512 +#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 bool pq_initialized; /* = false; */ +static bool de_pq_initialized; /* = false; */ /* one-time setup of X points */ void setup_x_points_distribution(void) @@ -45,8 +52,8 @@ void setup_x_points_distribution(void) uint32_t index; struct fixed31_32 increment; - coordinates_x[NUM_REGIONS * NUM_PTS_IN_REGION].x = region_size; - coordinates_x[NUM_REGIONS * NUM_PTS_IN_REGION + 1].x = region_size; + coordinates_x[MAX_HW_POINTS].x = region_size; + coordinates_x[MAX_HW_POINTS + 1].x = region_size; for (segment = 6; segment > (6 - NUM_REGIONS); segment--) { region_size = dal_fixed31_32_div_int(region_size, 2); @@ -62,6 +69,26 @@ 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) @@ -93,6 +120,40 @@ static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) *out_y = dal_fixed31_32_pow(base, m2); } +static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) +{ + /* consts for dePQ 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, div; + + + 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, + dal_fixed31_32_div(dal_fixed31_32_one, m2)); + base = dal_fixed31_32_sub(l_pow_m1, c1); + + if (dal_fixed31_32_lt(base, dal_fixed31_32_zero)) + base = dal_fixed31_32_zero; + + div = dal_fixed31_32_sub(c2, dal_fixed31_32_mul(c3, l_pow_m1)); + + *out_y = dal_fixed31_32_pow(dal_fixed31_32_div(base, div), + dal_fixed31_32_div(dal_fixed31_32_one, m1)); + +} /* one-time pre-compute PQ values - only for sdr_white_level 80 */ void precompute_pq(void) { @@ -113,46 +174,49 @@ void precompute_pq(void) } } +/* one-time pre-compute dePQ values - only for max pixel value 125 FP16 */ +void precompute_de_pq(void) +{ + int i; + struct fixed31_32 y; + const struct hw_x_point *coord_x = degamma_coordinates_x; + struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125); + + + for (i = 0; i <= MAX_HW_DEGAMMA_POINTS; i++) { + compute_de_pq(coord_x->x, &y); + de_pq_table[i] = dal_fixed31_32_mul(y, scaling_factor); + ++coord_x; + } +} struct dividers { struct fixed31_32 divider1; struct fixed31_32 divider2; struct fixed31_32 divider3; }; -static void build_regamma_coefficients(struct gamma_coefficients *coefficients) +static void build_coefficients(struct gamma_coefficients *coefficients, bool is_2_4) { - /* sRGB should apply 2.4 */ - static const int32_t numerator01[3] = { 31308, 31308, 31308 }; - static const int32_t numerator02[3] = { 12920, 12920, 12920 }; - static const int32_t numerator03[3] = { 55, 55, 55 }; - static const int32_t numerator04[3] = { 55, 55, 55 }; - static const int32_t numerator05[3] = { 2400, 2400, 2400 }; - - const int32_t *numerator1; - const int32_t *numerator2; - const int32_t *numerator3; - const int32_t *numerator4; - const int32_t *numerator5; - - uint32_t i = 0; + static const int32_t numerator01[] = { 31308, 180000}; + static const int32_t numerator02[] = { 12920, 4500}; + static const int32_t numerator03[] = { 55, 99}; + static const int32_t numerator04[] = { 55, 99}; + static const int32_t numerator05[] = { 2400, 2200}; - numerator1 = numerator01; - numerator2 = numerator02; - numerator3 = numerator03; - numerator4 = numerator04; - numerator5 = numerator05; + uint32_t i = 0; + uint32_t index = is_2_4 == true ? 0:1; do { coefficients->a0[i] = dal_fixed31_32_from_fraction( - numerator1[i], 10000000); + numerator01[index], 10000000); coefficients->a1[i] = dal_fixed31_32_from_fraction( - numerator2[i], 1000); + numerator02[index], 1000); coefficients->a2[i] = dal_fixed31_32_from_fraction( - numerator3[i], 1000); + numerator03[index], 1000); coefficients->a3[i] = dal_fixed31_32_from_fraction( - numerator4[i], 1000); + numerator04[index], 1000); coefficients->user_gamma[i] = dal_fixed31_32_from_fraction( - numerator5[i], 1000); + numerator05[index], 1000); ++i; } while (i != ARRAY_SIZE(coefficients->a0)); @@ -197,6 +261,39 @@ static struct fixed31_32 translate_from_linear_space( a1); } +static struct fixed31_32 translate_to_linear_space( + struct fixed31_32 arg, + struct fixed31_32 a0, + struct fixed31_32 a1, + struct fixed31_32 a2, + struct fixed31_32 a3, + struct fixed31_32 gamma) +{ + struct fixed31_32 linear; + + a0 = dal_fixed31_32_mul(a0, a1); + if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0))) + + linear = dal_fixed31_32_neg( + dal_fixed31_32_pow( + dal_fixed31_32_div( + dal_fixed31_32_sub(a2, arg), + dal_fixed31_32_add( + dal_fixed31_32_one, a3)), gamma)); + + else if (dal_fixed31_32_le(dal_fixed31_32_neg(a0), arg) && + dal_fixed31_32_le(arg, a0)) + linear = dal_fixed31_32_div(arg, a1); + else + linear = dal_fixed31_32_pow( + dal_fixed31_32_div( + dal_fixed31_32_add(a2, arg), + dal_fixed31_32_add( + dal_fixed31_32_one, a3)), gamma); + + return linear; +} + static inline struct fixed31_32 translate_from_linear_space_ex( struct fixed31_32 arg, struct gamma_coefficients *coeff, @@ -211,6 +308,22 @@ static inline struct fixed31_32 translate_from_linear_space_ex( coeff->user_gamma[color_index]); } + +static inline struct fixed31_32 translate_to_linear_space_ex( + struct fixed31_32 arg, + struct gamma_coefficients *coeff, + uint32_t color_index) +{ + return translate_to_linear_space( + arg, + coeff->a0[color_index], + coeff->a1[color_index], + coeff->a2[color_index], + coeff->a3[color_index], + coeff->user_gamma[color_index]); +} + + static bool find_software_points( const struct dc_gamma *ramp, const struct gamma_pixel *axis_x, @@ -314,12 +427,6 @@ static bool build_custom_gamma_mapping_coefficients_worker( struct fixed31_32 left_pos; struct fixed31_32 right_pos; - /* - * TODO: confirm enum in surface_pixel_format - * if (pixel_format == PIXEL_FORMAT_FP16) - *coord_x = coordinates_x[i].adjusted_x; - *else - */ if (channel == CHANNEL_NAME_RED) coord_x = coordinates_x[i].regamma_y_red; else if (channel == CHANNEL_NAME_GREEN) @@ -451,7 +558,7 @@ static struct fixed31_32 calculate_mapped_value( return result; } -static void build_regamma_curve_pq(struct pwl_float_data_ex *rgb_regamma, +static void build_pq(struct pwl_float_data_ex *rgb_regamma, uint32_t hw_points_num, const struct hw_x_point *coordinate_x, uint32_t sdr_white_level) @@ -477,11 +584,6 @@ static void build_regamma_curve_pq(struct pwl_float_data_ex *rgb_regamma, rgb += start_index; coord_x += start_index; - /* 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 = start_index; i <= hw_points_num; i++) { /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125. * FP 1.0 = 80nits @@ -508,37 +610,86 @@ static void build_regamma_curve_pq(struct pwl_float_data_ex *rgb_regamma, } } -static void build_regamma_curve(struct pwl_float_data_ex *rgb_regamma, +static void build_de_pq(struct pwl_float_data_ex *de_pq, uint32_t hw_points_num, const struct hw_x_point *coordinate_x) { 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) { + precompute_de_pq(); + de_pq_initialized = true; + } + + + for (i = 0; i <= hw_points_num; i++) { + output = de_pq_table[i]; + /* 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(scaling_factor, output)) + output = scaling_factor; + + rgb->r = output; + rgb->g = output; + rgb->b = output; + + ++coord_x; + ++rgb; + } +} + +static void build_regamma(struct pwl_float_data_ex *rgb_regamma, + uint32_t hw_points_num, + const struct hw_x_point *coordinate_x, bool is_2_4) +{ + uint32_t i; struct gamma_coefficients coeff; struct pwl_float_data_ex *rgb = rgb_regamma; const struct hw_x_point *coord_x = coordinate_x; - build_regamma_coefficients(&coeff); - - /* Use opp110->regamma.coordinates_x to retrieve - * coordinates chosen base on given user curve (future task). - * The x values are exponentially distributed and currently - * it is hard-coded, the user curve shape is ignored. - * The future task is to recalculate opp110- - * regamma.coordinates_x based on input/user curve, - * translation from 256/1025 to 128 pwl points. - */ + build_coefficients(&coeff, is_2_4); i = 0; while (i != hw_points_num + 1) { + /*TODO use y vs r,g,b*/ rgb->r = translate_from_linear_space_ex( coord_x->x, &coeff, 0); - rgb->g = translate_from_linear_space_ex( - coord_x->x, &coeff, 1); - rgb->b = translate_from_linear_space_ex( - coord_x->x, &coeff, 2); + rgb->g = rgb->r; + rgb->b = rgb->r; + ++coord_x; + ++rgb; + ++i; + } +} + +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) +{ + uint32_t i; + struct gamma_coefficients coeff; + struct pwl_float_data_ex *rgb = curve; + const struct hw_x_point *coord_x = degamma_coordinates_x; + + build_coefficients(&coeff, is_2_4); + + i = 0; + + 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; @@ -921,6 +1072,8 @@ static bool map_regamma_hw_to_x_user( return true; } +#define _EXTRA_POINTS 3 + bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, const struct dc_gamma *ramp, bool mapUserRamp) { @@ -930,7 +1083,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, struct pwl_float_data *rgb_user = NULL; struct pwl_float_data_ex *rgb_regamma = NULL; struct gamma_pixel *axix_x = NULL; - struct pixel_gamma_point *coeff128 = NULL; + struct pixel_gamma_point *coeff = NULL; enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; bool ret = false; @@ -945,11 +1098,11 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - rgb_user = kzalloc(sizeof(*rgb_user) * (ramp->num_entries + 3), + rgb_user = kzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS), GFP_KERNEL); if (!rgb_user) goto rgb_user_alloc_fail; - rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + 3), + rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; @@ -957,9 +1110,9 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, GFP_KERNEL); if (!axix_x) goto axix_x_alloc_fail; - coeff128 = kzalloc(sizeof(*coeff128) * (MAX_HW_POINTS + 3), GFP_KERNEL); - if (!coeff128) - goto coeff128_alloc_fail; + coeff = kzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); + if (!coeff) + goto coeff_alloc_fail; dividers.divider1 = dal_fixed31_32_from_fraction(3, 2); dividers.divider2 = dal_fixed31_32_from_int(2); @@ -983,7 +1136,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, tf_pts->x_point_at_y1_green = 125; tf_pts->x_point_at_y1_blue = 125; - build_regamma_curve_pq(rgb_regamma, + build_pq(rgb_regamma, MAX_HW_POINTS, coordinates_x, output_tf->sdr_ref_white_level); @@ -993,12 +1146,12 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, tf_pts->x_point_at_y1_green = 1; tf_pts->x_point_at_y1_blue = 1; - build_regamma_curve(rgb_regamma, + build_regamma(rgb_regamma, MAX_HW_POINTS, - coordinates_x); + coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? true:false); } - map_regamma_hw_to_x_user(ramp, coeff128, rgb_user, + map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axix_x, rgb_regamma, MAX_HW_POINTS, tf_pts, (mapUserRamp || ramp->type != GAMMA_RGB_256) && @@ -1009,8 +1162,8 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, ret = true; - kfree(coeff128); -coeff128_alloc_fail: + kfree(coeff); +coeff_alloc_fail: kfree(axix_x); axix_x_alloc_fail: kfree(rgb_regamma); @@ -1024,6 +1177,98 @@ rgb_user_alloc_fail: /*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) +{ + struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts; + struct dividers dividers; + + struct pwl_float_data *rgb_user = NULL; + struct pwl_float_data_ex *curve = NULL; + struct gamma_pixel *axix_x = NULL; + struct pixel_gamma_point *coeff = NULL; + enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; + bool ret = false; + + if (input_tf->type == TF_TYPE_BYPASS) + return false; + + /* we can use hardcoded curve for plain SRGB TF */ + if (input_tf->type == TF_TYPE_PREDEFINED && + input_tf->tf == TRANSFER_FUNCTION_SRGB && + (!mapUserRamp && ramp->type == GAMMA_RGB_256)) + return true; + + input_tf->type = TF_TYPE_DISTRIBUTED_POINTS; + + rgb_user = kzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS), + GFP_KERNEL); + if (!rgb_user) + goto rgb_user_alloc_fail; + curve = kzalloc(sizeof(*curve) * (MAX_HW_DEGAMMA_POINTS + _EXTRA_POINTS), + GFP_KERNEL); + if (!curve) + goto curve_alloc_fail; + axix_x = kzalloc(sizeof(*axix_x) * (ramp->num_entries + _EXTRA_POINTS), + GFP_KERNEL); + if (!axix_x) + goto axix_x_alloc_fail; + coeff = kzalloc(sizeof(*coeff) * (MAX_HW_DEGAMMA_POINTS + _EXTRA_POINTS), GFP_KERNEL); + if (!coeff) + goto coeff_alloc_fail; + + dividers.divider1 = dal_fixed31_32_from_fraction(3, 2); + dividers.divider2 = dal_fixed31_32_from_int(2); + dividers.divider3 = dal_fixed31_32_from_fraction(5, 2); + + tf = input_tf->tf; + + build_evenly_distributed_points( + axix_x, + ramp->num_entries, + dividers); + + if (ramp->type == GAMMA_RGB_256 && mapUserRamp) + scale_gamma(rgb_user, ramp, dividers); + else if (ramp->type == GAMMA_RGB_FLOAT_1024) + scale_gamma_dx(rgb_user, ramp, dividers); + + if (tf == TRANSFER_FUNCTION_PQ) + build_de_pq(curve, + MAX_HW_DEGAMMA_POINTS, + degamma_coordinates_x); + else + build_degamma(curve, + MAX_HW_DEGAMMA_POINTS, + degamma_coordinates_x, + tf == TRANSFER_FUNCTION_SRGB ? true:false); + + tf_pts->end_exponent = 0; + tf_pts->x_point_at_y1_red = 1; + tf_pts->x_point_at_y1_green = 1; + 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, + mapUserRamp); + + ret = true; + + kfree(coeff); +coeff_alloc_fail: + kfree(axix_x); +axix_x_alloc_fail: + kfree(curve); +curve_alloc_fail: + kfree(rgb_user); +rgb_user_alloc_fail: + + return ret; + +} + + bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, struct dc_transfer_func_distributed_points *points) { @@ -1032,7 +1277,11 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, struct pwl_float_data_ex *rgb_regamma = NULL; if (trans == TRANSFER_FUNCTION_UNITY) { - //setup_x_points_distribution(coordinates_x); + points->end_exponent = 0; + points->x_point_at_y1_red = 1; + points->x_point_at_y1_green = 1; + points->x_point_at_y1_blue = 1; + for (i = 0; i < MAX_HW_POINTS ; i++) { points->red[i] = coordinates_x[i].x; points->green[i] = coordinates_x[i].x; @@ -1044,16 +1293,38 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, _EXTRA_POINTS), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; - //setup_x_points_distribution(coordinates_x); + points->end_exponent = 7; + points->x_point_at_y1_red = 125; + points->x_point_at_y1_green = 125; + points->x_point_at_y1_blue = 125; + + + build_pq(rgb_regamma, + MAX_HW_POINTS, + coordinates_x, + 80); + 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; + + kfree(rgb_regamma); + } else if (trans == TRANSFER_FUNCTION_SRGB || + trans == TRANSFER_FUNCTION_BT709) { + rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + + _EXTRA_POINTS), GFP_KERNEL); + if (!rgb_regamma) + goto rgb_regamma_alloc_fail; points->end_exponent = 0; points->x_point_at_y1_red = 1; points->x_point_at_y1_green = 1; points->x_point_at_y1_blue = 1; - build_regamma_curve_pq(rgb_regamma, + build_regamma(rgb_regamma, MAX_HW_POINTS, - coordinates_x, - 80); + coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false); for (i = 0; i < MAX_HW_POINTS ; i++) { points->red[i] = rgb_regamma[i].r; points->green[i] = rgb_regamma[i].g; @@ -1068,3 +1339,65 @@ rgb_regamma_alloc_fail: } +bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, + struct dc_transfer_func_distributed_points *points) +{ + uint32_t i; + bool ret = false; + struct pwl_float_data_ex *rgb_degamma = NULL; + + 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; + } + ret = true; + } else if (trans == TRANSFER_FUNCTION_PQ) { + rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_DEGAMMA_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++) { + points->red[i] = rgb_degamma[i].r; + points->green[i] = rgb_degamma[i].g; + points->blue[i] = rgb_degamma[i].b; + } + ret = true; + + kfree(rgb_degamma); + } else if (trans == TRANSFER_FUNCTION_SRGB || + trans == TRANSFER_FUNCTION_BT709) { + rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_DEGAMMA_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++) { + points->red[i] = rgb_degamma[i].r; + points->green[i] = rgb_degamma[i].g; + points->blue[i] = rgb_degamma[i].b; + } + ret = true; + + kfree(rgb_degamma); + } + points->end_exponent = 0; + points->x_point_at_y1_red = 1; + points->x_point_at_y1_green = 1; + points->x_point_at_y1_blue = 1; + +rgb_degamma_alloc_fail: + return ret; +} + + 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 774c6daa1689..b7f9bc27d101 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h @@ -34,12 +34,20 @@ enum dc_transfer_func_predefined; 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 mod_color_calculate_degamma_params(struct dc_transfer_func *output_tf, + const struct dc_gamma *ramp, bool mapUserRamp); + bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, struct dc_transfer_func_distributed_points *points); +bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, + struct dc_transfer_func_distributed_points *points); + + #endif /* COLOR_MOD_COLOR_GAMMA_H_ */ -- 2.30.2