diff options
author | Amy Zhang <Amy.Zhang@amd.com> | 2017-01-05 17:12:20 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2017-09-26 17:09:48 -0400 |
commit | fcd2f4bf8bbe73ac860d1be275a22a54a8d8d385 (patch) | |
tree | 30a5335d72e4447205c7cef07e0c6a0a411edf43 | |
parent | 457b74cb3773a1950e49c2d4826d1b295c59bdf1 (diff) | |
download | linux-stable-fcd2f4bf8bbe73ac860d1be275a22a54a8d8d385.tar.gz linux-stable-fcd2f4bf8bbe73ac860d1be275a22a54a8d8d385.tar.bz2 linux-stable-fcd2f4bf8bbe73ac860d1be275a22a54a8d8d385.zip |
drm/amd/display: Output Transfer Function Regamma Refactor
- Create translation function to translate logical format to hw format
- Refactor to use transfer function in dc instead of input gamma
Signed-off-by: Amy Zhang <Amy.Zhang@amd.com>
Acked-by: Harry Wentland <Harry.Wentland@amd.com>
Reviewed-by: Anthony Koo <Anthony.Koo@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/calcs/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c | 1481 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dc.h | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 440 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/inc/hw/opp.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/include/fixed31_32.h | 8 |
9 files changed, 466 insertions, 1517 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c index 5a6e46843502..546ed67c6f83 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c +++ b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c @@ -246,6 +246,15 @@ struct fixed31_32 dal_fixed31_32_add( return res; } +struct fixed31_32 dal_fixed31_32_add_int( + struct fixed31_32 arg1, + int32_t arg2) +{ + return dal_fixed31_32_add( + arg1, + dal_fixed31_32_from_int(arg2)); +} + struct fixed31_32 dal_fixed31_32_sub_int( struct fixed31_32 arg1, int32_t arg2) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 4001933e7808..4bb08aea6a03 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile @@ -3,7 +3,7 @@ # It calculates Bandwidth and Watermarks values for HW programming # -BW_CALCS = bandwidth_calcs.o bw_fixed.o gamma_calcs.o +BW_CALCS = bandwidth_calcs.o bw_fixed.o AMD_DAL_BW_CALCS = $(addprefix $(AMDDALPATH)/dc/calcs/,$(BW_CALCS)) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c deleted file mode 100644 index fd300db833c7..000000000000 --- a/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c +++ /dev/null @@ -1,1481 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "gamma_calcs.h" - -struct curve_config { - uint32_t offset; - int8_t segments[16]; - int8_t begin; -}; - -static bool build_custom_float( - struct fixed31_32 value, - const struct custom_float_format *format, - bool *negative, - uint32_t *mantissa, - uint32_t *exponenta) -{ - uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1; - - const struct fixed31_32 mantissa_constant_plus_max_fraction = - dal_fixed31_32_from_fraction( - (1LL << (format->mantissa_bits + 1)) - 1, - 1LL << format->mantissa_bits); - - struct fixed31_32 mantiss; - - if (dal_fixed31_32_eq( - value, - dal_fixed31_32_zero)) { - *negative = false; - *mantissa = 0; - *exponenta = 0; - return true; - } - - if (dal_fixed31_32_lt( - value, - dal_fixed31_32_zero)) { - *negative = format->sign; - value = dal_fixed31_32_neg(value); - } else { - *negative = false; - } - - if (dal_fixed31_32_lt( - value, - dal_fixed31_32_one)) { - uint32_t i = 1; - - do { - value = dal_fixed31_32_shl(value, 1); - ++i; - } while (dal_fixed31_32_lt( - value, - dal_fixed31_32_one)); - - --i; - - if (exp_offset <= i) { - *mantissa = 0; - *exponenta = 0; - return true; - } - - *exponenta = exp_offset - i; - } else if (dal_fixed31_32_le( - mantissa_constant_plus_max_fraction, - value)) { - uint32_t i = 1; - - do { - value = dal_fixed31_32_shr(value, 1); - ++i; - } while (dal_fixed31_32_lt( - mantissa_constant_plus_max_fraction, - value)); - - *exponenta = exp_offset + i - 1; - } else { - *exponenta = exp_offset; - } - - mantiss = dal_fixed31_32_sub( - value, - dal_fixed31_32_one); - - if (dal_fixed31_32_lt( - mantiss, - dal_fixed31_32_zero) || - dal_fixed31_32_lt( - dal_fixed31_32_one, - mantiss)) - mantiss = dal_fixed31_32_zero; - else - mantiss = dal_fixed31_32_shl( - mantiss, - format->mantissa_bits); - - *mantissa = dal_fixed31_32_floor(mantiss); - - return true; -} - -static bool setup_custom_float( - const struct custom_float_format *format, - bool negative, - uint32_t mantissa, - uint32_t exponenta, - uint32_t *result) -{ - uint32_t i = 0; - uint32_t j = 0; - - uint32_t value = 0; - - /* verification code: - * once calculation is ok we can remove it - */ - - const uint32_t mantissa_mask = - (1 << (format->mantissa_bits + 1)) - 1; - - const uint32_t exponenta_mask = - (1 << (format->exponenta_bits + 1)) - 1; - - if (mantissa & ~mantissa_mask) { - BREAK_TO_DEBUGGER(); - mantissa = mantissa_mask; - } - - if (exponenta & ~exponenta_mask) { - BREAK_TO_DEBUGGER(); - exponenta = exponenta_mask; - } - - /* end of verification code */ - - while (i < format->mantissa_bits) { - uint32_t mask = 1 << i; - - if (mantissa & mask) - value |= mask; - - ++i; - } - - while (j < format->exponenta_bits) { - uint32_t mask = 1 << j; - - if (exponenta & mask) - value |= mask << i; - - ++j; - } - - if (negative && format->sign) - value |= 1 << (i + j); - - *result = value; - - return true; -} - -static bool build_hw_curve_configuration( - const struct curve_config *curve_config, - struct gamma_curve *gamma_curve, - struct curve_points *curve_points, - struct hw_x_point *points, - uint32_t *number_of_points) -{ - const int8_t max_regions_number = ARRAY_SIZE(curve_config->segments); - - int8_t i; - - uint8_t segments_calculation[8] = { 0 }; - - struct fixed31_32 region1 = dal_fixed31_32_zero; - struct fixed31_32 region2; - struct fixed31_32 increment; - - uint32_t index = 0; - uint32_t segments = 0; - uint32_t max_number; - - int8_t num_regions = 0; - - bool result = false; - - if (!number_of_points) { - BREAK_TO_DEBUGGER(); - return false; - } - - max_number = *number_of_points; - - i = 0; - - while (i != max_regions_number) { - gamma_curve[i].offset = 0; - gamma_curve[i].segments_num = 0; - - ++i; - } - - i = 0; - - while (i != max_regions_number) { - /* number should go in uninterruptible sequence */ - if (curve_config->segments[i] == -1) - break; - - ASSERT(curve_config->segments[i] >= 0); - - segments += (1 << curve_config->segments[i]); - ++num_regions; - - ++i; - } - - if (segments > max_number) { - BREAK_TO_DEBUGGER(); - } else { - int32_t divisor; - uint32_t offset = 0; - int8_t begin = curve_config->begin; - int32_t region_number = 0; - - i = begin; - - while ((index < max_number) && - (region_number < max_regions_number) && - (i < (begin + num_regions))) { - int32_t j = 0; - - segments = curve_config->segments[region_number]; - divisor = 1 << segments; - - if (segments == -1) { - if (i > 0) { - region1 = dal_fixed31_32_shl( - dal_fixed31_32_one, - i - 1); - region2 = dal_fixed31_32_shl( - dal_fixed31_32_one, - i); - } else { - region1 = dal_fixed31_32_shr( - dal_fixed31_32_one, - -(i - 1)); - region2 = dal_fixed31_32_shr( - dal_fixed31_32_one, - -i); - } - - break; - } - - if (i > -1) { - region1 = dal_fixed31_32_shl( - dal_fixed31_32_one, - i); - region2 = dal_fixed31_32_shl( - dal_fixed31_32_one, - i + 1); - } else { - region1 = dal_fixed31_32_shr( - dal_fixed31_32_one, - -i); - region2 = dal_fixed31_32_shr( - dal_fixed31_32_one, - -(i + 1)); - } - - gamma_curve[region_number].offset = offset; - gamma_curve[region_number].segments_num = segments; - - offset += divisor; - - ++segments_calculation[segments]; - - increment = dal_fixed31_32_div_int( - dal_fixed31_32_sub( - region2, - region1), - divisor); - - points[index].x = region1; - points[index].adjusted_x = region1; - - ++index; - ++region_number; - - while ((index < max_number) && (j < divisor - 1)) { - region1 = dal_fixed31_32_add( - region1, - increment); - - points[index].x = region1; - points[index].adjusted_x = region1; - - ++index; - ++j; - } - - ++i; - } - - points[index].x = region1; - points[index].adjusted_x = region1; - - *number_of_points = index; - - result = true; - } - - curve_points[0].x = points[0].adjusted_x; - curve_points[0].offset = dal_fixed31_32_zero; - - curve_points[1].x = points[index - 1].adjusted_x; - curve_points[1].offset = dal_fixed31_32_zero; - - curve_points[2].x = points[index].adjusted_x; - curve_points[2].offset = dal_fixed31_32_zero; - - return result; -} - -static bool setup_distribution_points_pq( - struct gamma_curve *arr_curve_points, - struct curve_points *arr_points, - uint32_t *hw_points_num, - struct hw_x_point *coordinates_x, - enum surface_pixel_format format) -{ - struct curve_config cfg; - - cfg.offset = 0; - cfg.segments[0] = 2; - cfg.segments[1] = 2; - cfg.segments[2] = 2; - cfg.segments[3] = 2; - cfg.segments[4] = 2; - cfg.segments[5] = 2; - cfg.segments[6] = 3; - cfg.segments[7] = 4; - cfg.segments[8] = 4; - cfg.segments[9] = 4; - cfg.segments[10] = 4; - cfg.segments[11] = 5; - cfg.segments[12] = 5; - cfg.segments[13] = 5; - cfg.segments[14] = 5; - cfg.segments[15] = 5; - - if (format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F || - format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) - cfg.begin = -11; - else - cfg.begin = -16; - - if (!build_hw_curve_configuration( - &cfg, arr_curve_points, - arr_points, - coordinates_x, hw_points_num)) { - ASSERT_CRITICAL(false); - return false; - } - return true; -} - -static bool setup_distribution_points( - struct gamma_curve *arr_curve_points, - struct curve_points *arr_points, - uint32_t *hw_points_num, - struct hw_x_point *coordinates_x) -{ - struct curve_config cfg; - - cfg.offset = 0; - cfg.segments[0] = 3; - cfg.segments[1] = 4; - cfg.segments[2] = 4; - cfg.segments[3] = 4; - cfg.segments[4] = 4; - cfg.segments[5] = 4; - cfg.segments[6] = 4; - cfg.segments[7] = 4; - cfg.segments[8] = 5; - cfg.segments[9] = 5; - cfg.segments[10] = 0; - cfg.segments[11] = -1; - cfg.segments[12] = -1; - cfg.segments[13] = -1; - cfg.segments[14] = -1; - cfg.segments[15] = -1; - - cfg.begin = -10; - - if (!build_hw_curve_configuration( - &cfg, arr_curve_points, - arr_points, - coordinates_x, hw_points_num)) { - ASSERT_CRITICAL(false); - return false; - } - return true; -} - -struct dividers { - struct fixed31_32 divider1; - struct fixed31_32 divider2; - struct fixed31_32 divider3; -}; - -static void build_regamma_coefficients(struct gamma_coefficients *coefficients) -{ - /* 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; - - numerator1 = numerator01; - numerator2 = numerator02; - numerator3 = numerator03; - numerator4 = numerator04; - numerator5 = numerator05; - - do { - coefficients->a0[i] = dal_fixed31_32_from_fraction( - numerator1[i], 10000000); - coefficients->a1[i] = dal_fixed31_32_from_fraction( - numerator2[i], 1000); - coefficients->a2[i] = dal_fixed31_32_from_fraction( - numerator3[i], 1000); - coefficients->a3[i] = dal_fixed31_32_from_fraction( - numerator4[i], 1000); - coefficients->user_gamma[i] = dal_fixed31_32_from_fraction( - numerator5[i], 1000); - - ++i; - } while (i != ARRAY_SIZE(coefficients->a0)); -} - -static struct fixed31_32 translate_from_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) -{ - const struct fixed31_32 one = dal_fixed31_32_from_int(1); - - if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0))) - return dal_fixed31_32_sub( - a2, - dal_fixed31_32_mul( - dal_fixed31_32_add( - one, - a3), - dal_fixed31_32_pow( - dal_fixed31_32_neg(arg), - dal_fixed31_32_recip(gamma)))); - else if (dal_fixed31_32_le(a0, arg)) - return dal_fixed31_32_sub( - dal_fixed31_32_mul( - dal_fixed31_32_add( - one, - a3), - dal_fixed31_32_pow( - arg, - dal_fixed31_32_recip(gamma))), - a2); - else - return dal_fixed31_32_mul( - arg, - a1); -} - -static inline struct fixed31_32 translate_from_linear_space_ex( - struct fixed31_32 arg, - struct gamma_coefficients *coeff, - uint32_t color_index) -{ - return translate_from_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 gamma_pixel *axis_x_256, - struct fixed31_32 hw_point, - enum channel_name channel, - uint32_t *index_to_start, - uint32_t *index_left, - uint32_t *index_right, - enum hw_point_position *pos) -{ - const uint32_t max_number = INPUT_LUT_ENTRIES + 3; - - struct fixed31_32 left, right; - - uint32_t i = *index_to_start; - - while (i < max_number) { - if (channel == CHANNEL_NAME_RED) { - left = axis_x_256[i].r; - - if (i < max_number - 1) - right = axis_x_256[i + 1].r; - else - right = axis_x_256[max_number - 1].r; - } else if (channel == CHANNEL_NAME_GREEN) { - left = axis_x_256[i].g; - - if (i < max_number - 1) - right = axis_x_256[i + 1].g; - else - right = axis_x_256[max_number - 1].g; - } else { - left = axis_x_256[i].b; - - if (i < max_number - 1) - right = axis_x_256[i + 1].b; - else - right = axis_x_256[max_number - 1].b; - } - - if (dal_fixed31_32_le(left, hw_point) && - dal_fixed31_32_le(hw_point, right)) { - *index_to_start = i; - *index_left = i; - - if (i < max_number - 1) - *index_right = i + 1; - else - *index_right = max_number - 1; - - *pos = HW_POINT_POSITION_MIDDLE; - - return true; - } else if ((i == *index_to_start) && - dal_fixed31_32_le(hw_point, left)) { - *index_to_start = i; - *index_left = i; - *index_right = i; - - *pos = HW_POINT_POSITION_LEFT; - - return true; - } else if ((i == max_number - 1) && - dal_fixed31_32_le(right, hw_point)) { - *index_to_start = i; - *index_left = i; - *index_right = i; - - *pos = HW_POINT_POSITION_RIGHT; - - return true; - } - - ++i; - } - - return false; -} - -static bool build_custom_gamma_mapping_coefficients_worker( - struct pixel_gamma_point *coeff, - const struct hw_x_point *coordinates_x, - const struct gamma_pixel *axis_x_256, - enum channel_name channel, - uint32_t number_of_points, - enum surface_pixel_format pixel_format) -{ - uint32_t i = 0; - - while (i <= number_of_points) { - struct fixed31_32 coord_x; - - uint32_t index_to_start = 0; - uint32_t index_left = 0; - uint32_t index_right = 0; - - enum hw_point_position hw_pos; - - struct gamma_point *point; - - 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) - coord_x = coordinates_x[i].regamma_y_green; - else - coord_x = coordinates_x[i].regamma_y_blue; - - if (!find_software_points( - axis_x_256, coord_x, channel, - &index_to_start, &index_left, &index_right, &hw_pos)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (index_left >= INPUT_LUT_ENTRIES + 3) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (index_right >= INPUT_LUT_ENTRIES + 3) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (channel == CHANNEL_NAME_RED) { - point = &coeff[i].r; - - left_pos = axis_x_256[index_left].r; - right_pos = axis_x_256[index_right].r; - } else if (channel == CHANNEL_NAME_GREEN) { - point = &coeff[i].g; - - left_pos = axis_x_256[index_left].g; - right_pos = axis_x_256[index_right].g; - } else { - point = &coeff[i].b; - - left_pos = axis_x_256[index_left].b; - right_pos = axis_x_256[index_right].b; - } - - if (hw_pos == HW_POINT_POSITION_MIDDLE) - point->coeff = dal_fixed31_32_div( - dal_fixed31_32_sub( - coord_x, - left_pos), - dal_fixed31_32_sub( - right_pos, - left_pos)); - else if (hw_pos == HW_POINT_POSITION_LEFT) - point->coeff = dal_fixed31_32_zero; - else if (hw_pos == HW_POINT_POSITION_RIGHT) - point->coeff = dal_fixed31_32_from_int(2); - else { - BREAK_TO_DEBUGGER(); - return false; - } - - point->left_index = index_left; - point->right_index = index_right; - point->pos = hw_pos; - - ++i; - } - - return true; -} - -static inline bool build_oem_custom_gamma_mapping_coefficients( - struct pixel_gamma_point *coeff128_oem, - const struct hw_x_point *coordinates_x, - const struct gamma_pixel *axis_x_256, - uint32_t number_of_points, - enum surface_pixel_format pixel_format) -{ - int i; - - for (i = 0; i < 3; i++) { - if (!build_custom_gamma_mapping_coefficients_worker( - coeff128_oem, coordinates_x, axis_x_256, i, - number_of_points, pixel_format)) - return false; - } - return true; -} - -static struct fixed31_32 calculate_mapped_value( - struct pwl_float_data *rgb, - const struct pixel_gamma_point *coeff, - enum channel_name channel, - uint32_t max_index) -{ - const struct gamma_point *point; - - struct fixed31_32 result; - - if (channel == CHANNEL_NAME_RED) - point = &coeff->r; - else if (channel == CHANNEL_NAME_GREEN) - point = &coeff->g; - else - point = &coeff->b; - - if ((point->left_index < 0) || (point->left_index > max_index)) { - BREAK_TO_DEBUGGER(); - return dal_fixed31_32_zero; - } - - if ((point->right_index < 0) || (point->right_index > max_index)) { - BREAK_TO_DEBUGGER(); - return dal_fixed31_32_zero; - } - - if (point->pos == HW_POINT_POSITION_MIDDLE) - if (channel == CHANNEL_NAME_RED) - result = dal_fixed31_32_add( - dal_fixed31_32_mul( - point->coeff, - dal_fixed31_32_sub( - rgb[point->right_index].r, - rgb[point->left_index].r)), - rgb[point->left_index].r); - else if (channel == CHANNEL_NAME_GREEN) - result = dal_fixed31_32_add( - dal_fixed31_32_mul( - point->coeff, - dal_fixed31_32_sub( - rgb[point->right_index].g, - rgb[point->left_index].g)), - rgb[point->left_index].g); - else - result = dal_fixed31_32_add( - dal_fixed31_32_mul( - point->coeff, - dal_fixed31_32_sub( - rgb[point->right_index].b, - rgb[point->left_index].b)), - rgb[point->left_index].b); - else if (point->pos == HW_POINT_POSITION_LEFT) { - BREAK_TO_DEBUGGER(); - result = dal_fixed31_32_zero; - } else { - BREAK_TO_DEBUGGER(); - result = dal_fixed31_32_one; - } - - return result; -} - -static inline struct fixed31_32 calculate_oem_mapped_value( - struct pwl_float_data *rgb_oem, - const struct pixel_gamma_point *coeff, - uint32_t index, - enum channel_name channel, - uint32_t max_index) -{ - return calculate_mapped_value( - rgb_oem, - coeff + index, - channel, - 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, - 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 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. - */ - - i = 0; - - while (i != hw_points_num + 1) { - rgb->r = translate_from_linear_space_ex( - coord_x->adjusted_x, &coeff, 0); - rgb->g = translate_from_linear_space_ex( - coord_x->adjusted_x, &coeff, 1); - rgb->b = translate_from_linear_space_ex( - coord_x->adjusted_x, &coeff, 2); - - ++coord_x; - ++rgb; - ++i; - } -} - -static bool scale_gamma(struct pwl_float_data *pwl_rgb, - const struct core_gamma *ramp, - struct dividers dividers) -{ - const struct dc_gamma *gamma = &ramp->public; - const uint16_t max_driver = 0xFFFF; - const uint16_t max_os = 0xFF00; - uint16_t scaler = max_os; - uint32_t i = 0; - struct pwl_float_data *rgb = pwl_rgb; - struct pwl_float_data *rgb_last = rgb + INPUT_LUT_ENTRIES - 1; - - do { - if ((gamma->red[i] > max_os) || - (gamma->green[i] > max_os) || - (gamma->blue[i] > max_os)) { - scaler = max_driver; - break; - } - ++i; - } while (i != INPUT_LUT_ENTRIES); - - i = 0; - - do { - rgb->r = dal_fixed31_32_from_fraction( - gamma->red[i], scaler); - rgb->g = dal_fixed31_32_from_fraction( - gamma->green[i], scaler); - rgb->b = dal_fixed31_32_from_fraction( - gamma->blue[i], scaler); - - ++rgb; - ++i; - } while (i != INPUT_LUT_ENTRIES); - - rgb->r = dal_fixed31_32_mul(rgb_last->r, - dividers.divider1); - rgb->g = dal_fixed31_32_mul(rgb_last->g, - dividers.divider1); - rgb->b = dal_fixed31_32_mul(rgb_last->b, - dividers.divider1); - - ++rgb; - - rgb->r = dal_fixed31_32_mul(rgb_last->r, - dividers.divider2); - rgb->g = dal_fixed31_32_mul(rgb_last->g, - dividers.divider2); - rgb->b = dal_fixed31_32_mul(rgb_last->b, - dividers.divider2); - - ++rgb; - - rgb->r = dal_fixed31_32_mul(rgb_last->r, - dividers.divider3); - rgb->g = dal_fixed31_32_mul(rgb_last->g, - dividers.divider3); - rgb->b = dal_fixed31_32_mul(rgb_last->b, - dividers.divider3); - - return true; -} - -static void build_evenly_distributed_points( - struct gamma_pixel *points, - uint32_t numberof_points, - struct fixed31_32 max_value, - struct dividers dividers) -{ - struct gamma_pixel *p = points; - struct gamma_pixel *p_last = p + numberof_points - 1; - - uint32_t i = 0; - - do { - struct fixed31_32 value = dal_fixed31_32_div_int( - dal_fixed31_32_mul_int(max_value, i), - numberof_points - 1); - - p->r = value; - p->g = value; - p->b = value; - - ++p; - ++i; - } while (i != numberof_points); - - p->r = dal_fixed31_32_div(p_last->r, dividers.divider1); - p->g = dal_fixed31_32_div(p_last->g, dividers.divider1); - p->b = dal_fixed31_32_div(p_last->b, dividers.divider1); - - ++p; - - p->r = dal_fixed31_32_div(p_last->r, dividers.divider2); - p->g = dal_fixed31_32_div(p_last->g, dividers.divider2); - p->b = dal_fixed31_32_div(p_last->b, dividers.divider2); - - ++p; - - p->r = dal_fixed31_32_div(p_last->r, dividers.divider3); - p->g = dal_fixed31_32_div(p_last->g, dividers.divider3); - p->b = dal_fixed31_32_div(p_last->b, dividers.divider3); -} - -static inline void copy_rgb_regamma_to_coordinates_x( - struct hw_x_point *coordinates_x, - uint32_t hw_points_num, - const struct pwl_float_data_ex *rgb_ex) -{ - struct hw_x_point *coords = coordinates_x; - uint32_t i = 0; - const struct pwl_float_data_ex *rgb_regamma = rgb_ex; - - while (i <= hw_points_num) { - coords->regamma_y_red = rgb_regamma->r; - coords->regamma_y_green = rgb_regamma->g; - coords->regamma_y_blue = rgb_regamma->b; - - ++coords; - ++rgb_regamma; - ++i; - } -} - -static bool calculate_interpolated_hardware_curve( - struct pwl_result_data *rgb, - struct pixel_gamma_point *coeff128, - struct pwl_float_data *rgb_user, - const struct hw_x_point *coordinates_x, - const struct gamma_pixel *axis_x_256, - uint32_t number_of_points, - enum surface_pixel_format pixel_format) -{ - - const struct pixel_gamma_point *coeff; - struct pixel_gamma_point *coeff_128 = coeff128; - uint32_t max_entries = 3 - 1; - struct pwl_result_data *rgb_resulted = rgb; - - uint32_t i = 0; - - if (!build_oem_custom_gamma_mapping_coefficients( - coeff_128, coordinates_x, axis_x_256, - number_of_points, - pixel_format)) - return false; - - coeff = coeff128; - max_entries += INPUT_LUT_ENTRIES; - - /* TODO: float point case */ - - while (i <= number_of_points) { - rgb_resulted->red = calculate_mapped_value( - rgb_user, coeff, CHANNEL_NAME_RED, max_entries); - rgb_resulted->green = calculate_mapped_value( - rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries); - rgb_resulted->blue = calculate_mapped_value( - rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries); - - ++coeff; - ++rgb_resulted; - ++i; - } - - return true; -} - -static bool map_regamma_hw_to_x_user( - struct pixel_gamma_point *coeff128, - struct pwl_float_data *rgb_oem, - struct pwl_result_data *rgb_resulted, - struct pwl_float_data *rgb_user, - struct hw_x_point *coords_x, - const struct gamma_pixel *axis_x, - const struct dc_gamma *gamma, - const struct pwl_float_data_ex *rgb_regamma, - struct dividers dividers, - uint32_t hw_points_num, - const struct core_surface *surface) -{ - /* setup to spare calculated ideal regamma values */ - - struct pixel_gamma_point *coeff = coeff128; - - struct hw_x_point *coords = coords_x; - - copy_rgb_regamma_to_coordinates_x(coords, hw_points_num, rgb_regamma); - - return calculate_interpolated_hardware_curve( - rgb_resulted, coeff, rgb_user, coords, axis_x, - hw_points_num, surface->public.format); -} - -static void build_new_custom_resulted_curve( - struct pwl_result_data *rgb_resulted, - uint32_t hw_points_num) -{ - struct pwl_result_data *rgb = rgb_resulted; - struct pwl_result_data *rgb_plus_1 = rgb + 1; - - uint32_t i; - - i = 0; - - while (i != hw_points_num + 1) { - rgb->red = dal_fixed31_32_clamp( - rgb->red, dal_fixed31_32_zero, - dal_fixed31_32_one); - rgb->green = dal_fixed31_32_clamp( - rgb->green, dal_fixed31_32_zero, - dal_fixed31_32_one); - rgb->blue = dal_fixed31_32_clamp( - rgb->blue, dal_fixed31_32_zero, - dal_fixed31_32_one); - - ++rgb; - ++i; - } - - rgb = rgb_resulted; - - i = 1; - - while (i != hw_points_num + 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; - } -} - -static void rebuild_curve_configuration_magic( - struct curve_points *arr_points, - struct pwl_result_data *rgb_resulted, - const struct hw_x_point *coordinates_x, - uint32_t hw_points_num, - enum dc_transfer_func_predefined tf) -{ - 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; - - 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].x = coordinates_x[0].adjusted_x; - arr_points[0].y = y1_min; - arr_points[0].slope = dal_fixed31_32_div( - arr_points[0].y, - arr_points[0].x); - - /* this should be cleaned up as it's confusing my understanding (KK) is - * that REGAMMA_CNTLA_EXP_REGION_END is the X value for the region end - * REGAMMA_CNTLA_EXP_REGION_END_BASE is Y value for the above X - * REGAMMA_CNTLA_EXP_REGION_END_SLOPE is the slope beyond (X,Y) above - * currently when programming REGION_END = m_arrPoints[1].x, - * REGION_END_BASE = m_arrPoints[1].y, REGION_END_SLOPE=1 - * we don't use m_arrPoints[2] at all after this function, - * and its purpose isn't clear to me - */ - arr_points[1].x = coordinates_x[hw_points_num].adjusted_x; - arr_points[2].x = coordinates_x[hw_points_num].adjusted_x; - - y_r = rgb_resulted[hw_points_num].red; - y_g = rgb_resulted[hw_points_num].green; - y_b = rgb_resulted[hw_points_num].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[2].y = y3_max; - - arr_points[2].slope = dal_fixed31_32_zero; - - /* 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. - */ - if (tf == TRANSFER_FUNCTION_PQ) { - const struct fixed31_32 end_value = - dal_fixed31_32_from_int(125); - - arr_points[2].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)); - } -} - -static bool convert_to_custom_float_format( - struct fixed31_32 value, - const struct custom_float_format *format, - uint32_t *result) -{ - uint32_t mantissa; - uint32_t exponenta; - bool negative; - - return build_custom_float( - value, format, &negative, &mantissa, &exponenta) && - setup_custom_float( - format, negative, mantissa, exponenta, result); -} - -static bool convert_to_custom_float( - struct pwl_result_data *rgb_resulted, - struct curve_points *arr_points, - uint32_t hw_points_num) -{ - struct custom_float_format fmt; - - struct pwl_result_data *rgb = rgb_resulted; - - uint32_t i = 0; - - fmt.exponenta_bits = 6; - fmt.mantissa_bits = 12; - fmt.sign = true; - - if (!convert_to_custom_float_format( - arr_points[0].x, - &fmt, - &arr_points[0].custom_float_x)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format( - arr_points[0].offset, - &fmt, - &arr_points[0].custom_float_offset)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format( - arr_points[0].slope, - &fmt, - &arr_points[0].custom_float_slope)) { - BREAK_TO_DEBUGGER(); - return false; - } - - fmt.mantissa_bits = 10; - fmt.sign = false; - - if (!convert_to_custom_float_format( - arr_points[1].x, - &fmt, - &arr_points[1].custom_float_x)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format( - arr_points[1].y, - &fmt, - &arr_points[1].custom_float_y)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format( - arr_points[2].slope, - &fmt, - &arr_points[2].custom_float_slope)) { - BREAK_TO_DEBUGGER(); - return false; - } - - fmt.mantissa_bits = 12; - fmt.sign = true; - - while (i != hw_points_num) { - if (!convert_to_custom_float_format( - rgb->red, - &fmt, - &rgb->red_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format( - rgb->green, - &fmt, - &rgb->green_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format( - rgb->blue, - &fmt, - &rgb->blue_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format( - rgb->delta_red, - &fmt, - &rgb->delta_red_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format( - rgb->delta_green, - &fmt, - &rgb->delta_green_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format( - rgb->delta_blue, - &fmt, - &rgb->delta_blue_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - ++rgb; - ++i; - } - - return true; -} - -bool calculate_regamma_params(struct pwl_params *params, - const struct core_gamma *ramp, - 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; - struct pwl_result_data *rgb_resulted = params->rgb_resulted; - struct dividers dividers; - - struct hw_x_point *coordinates_x = NULL; - struct pwl_float_data *rgb_user = NULL ; - struct pwl_float_data_ex *rgb_regamma = NULL; - struct pwl_float_data *rgb_oem = NULL; - struct gamma_pixel *axix_x_256 = NULL; - struct pixel_gamma_point *coeff128_oem = NULL; - struct pixel_gamma_point *coeff128 = NULL; - - enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; - - bool ret = false; - - coordinates_x = dm_alloc(sizeof(*coordinates_x)*(256 + 3)); - if (!coordinates_x) - goto coordinates_x_alloc_fail; - rgb_user = dm_alloc(sizeof(*rgb_user) * (TRANSFER_FUNC_POINTS + 3)); - if (!rgb_user) - goto rgb_user_alloc_fail; - rgb_regamma = dm_alloc(sizeof(*rgb_regamma) * (256 + 3)); - if (!rgb_regamma) - goto rgb_regamma_alloc_fail; - rgb_oem = dm_alloc(sizeof(*rgb_oem) * (TRANSFER_FUNC_POINTS + 3)); - if (!rgb_oem) - goto rgb_oem_alloc_fail; - axix_x_256 = dm_alloc(sizeof(*axix_x_256) * (256 + 3)); - if (!axix_x_256) - goto axix_x_256_alloc_fail; - coeff128_oem = dm_alloc(sizeof(*coeff128_oem) * (256 + 3)); - if (!coeff128_oem) - goto coeff128_oem_alloc_fail; - coeff128 = dm_alloc(sizeof(*coeff128) * (256 + 3)); - if (!coeff128) - goto coeff128_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); - - if (stream->public.out_transfer_func) - tf = stream->public.out_transfer_func->tf; - - build_evenly_distributed_points( - axix_x_256, - 256, - dal_fixed31_32_one, - dividers); - - scale_gamma(rgb_user, ramp, dividers); - - if (tf == TRANSFER_FUNCTION_PQ) { - setup_distribution_points_pq(arr_curve_points, arr_points, - ¶ms->hw_points_num, coordinates_x, - surface->public.format); - build_regamma_curve_pq(rgb_regamma, rgb_oem, coeff128_oem, - ramp, surface, params->hw_points_num, - coordinates_x, axix_x_256, dividers); - } else { - 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); - } - - map_regamma_hw_to_x_user(coeff128, rgb_oem, rgb_resulted, rgb_user, - coordinates_x, axix_x_256, &ramp->public, rgb_regamma, - dividers, params->hw_points_num, surface); - - build_new_custom_resulted_curve(rgb_resulted, params->hw_points_num); - - rebuild_curve_configuration_magic( - arr_points, - rgb_resulted, - coordinates_x, - params->hw_points_num, - tf); - - convert_to_custom_float(rgb_resulted, arr_points, - params->hw_points_num); - - ret = true; - - dm_free(coeff128); -coeff128_alloc_fail: - dm_free(coeff128_oem); -coeff128_oem_alloc_fail: - dm_free(axix_x_256); -axix_x_256_alloc_fail: - dm_free(rgb_oem); -rgb_oem_alloc_fail: - dm_free(rgb_regamma); -rgb_regamma_alloc_fail: - dm_free(rgb_user); -rgb_user_alloc_fail: - dm_free(coordinates_x); -coordinates_x_alloc_fail: - return ret; - -} - diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 7d4299b9ee1f..948f82a56472 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1519,23 +1519,23 @@ void dc_update_surfaces_for_stream(struct dc *dc, struct dc_surface_update *upda if (dc->debug.disable_color_module) continue; /* skip below color updates */ - if (updates[i].hdr_static_metadata) { - resource_build_info_frame(pipe_ctx); - core_dc->hwss.update_info_frame(pipe_ctx); - } if (is_new_pipe_surface[j] || updates[i].in_transfer_func) core_dc->hwss.set_input_transfer_func( pipe_ctx, pipe_ctx->surface); if (is_new_pipe_surface[j] || - updates[i].gamma || updates[i].out_transfer_func) core_dc->hwss.set_output_transfer_func( pipe_ctx, pipe_ctx->surface, pipe_ctx->stream); + if (updates[i].hdr_static_metadata) { + resource_build_info_frame(pipe_ctx); + core_dc->hwss.update_info_frame(pipe_ctx); + } + } if (apply_ctx) { core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context); diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index b814e7b76bbc..f53b41339951 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -213,11 +213,14 @@ enum dc_transfer_func_type { }; struct dc_transfer_func_distributed_points { - uint16_t red[TRANSFER_FUNC_POINTS]; - uint16_t green[TRANSFER_FUNC_POINTS]; - uint16_t blue[TRANSFER_FUNC_POINTS]; + struct fixed31_32 red[TRANSFER_FUNC_POINTS]; + struct fixed31_32 green[TRANSFER_FUNC_POINTS]; + struct fixed31_32 blue[TRANSFER_FUNC_POINTS]; + uint16_t end_exponent; - uint16_t x_point_at_y1; + uint16_t x_point_at_y1_red; + uint16_t x_point_at_y1_green; + uint16_t x_point_at_y1_blue; }; enum dc_transfer_func_predefined { diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 415b12accd2c..6e70cf7b99ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -42,7 +42,6 @@ #include "stream_encoder.h" #include "link_encoder.h" #include "clock_source.h" -#include "gamma_calcs.h" #include "audio.h" #include "dce/dce_hwseq.h" @@ -286,6 +285,436 @@ static bool dce110_set_input_transfer_func( return result; } +static bool build_custom_float( + struct fixed31_32 value, + const struct custom_float_format *format, + bool *negative, + uint32_t *mantissa, + uint32_t *exponenta) +{ + uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1; + + const struct fixed31_32 mantissa_constant_plus_max_fraction = + dal_fixed31_32_from_fraction( + (1LL << (format->mantissa_bits + 1)) - 1, + 1LL << format->mantissa_bits); + + struct fixed31_32 mantiss; + + if (dal_fixed31_32_eq( + value, + dal_fixed31_32_zero)) { + *negative = false; + *mantissa = 0; + *exponenta = 0; + return true; + } + + if (dal_fixed31_32_lt( + value, + dal_fixed31_32_zero)) { + *negative = format->sign; + value = dal_fixed31_32_neg(value); + } else { + *negative = false; + } + + if (dal_fixed31_32_lt( + value, + dal_fixed31_32_one)) { + uint32_t i = 1; + + do { + value = dal_fixed31_32_shl(value, 1); + ++i; + } while (dal_fixed31_32_lt( + value, + dal_fixed31_32_one)); + + --i; + + if (exp_offset <= i) { + *mantissa = 0; + *exponenta = 0; + return true; + } + + *exponenta = exp_offset - i; + } else if (dal_fixed31_32_le( + mantissa_constant_plus_max_fraction, + value)) { + uint32_t i = 1; + + do { + value = dal_fixed31_32_shr(value, 1); + ++i; + } while (dal_fixed31_32_lt( + mantissa_constant_plus_max_fraction, + value)); + + *exponenta = exp_offset + i - 1; + } else { + *exponenta = exp_offset; + } + + mantiss = dal_fixed31_32_sub( + value, + dal_fixed31_32_one); + + if (dal_fixed31_32_lt( + mantiss, + dal_fixed31_32_zero) || + dal_fixed31_32_lt( + dal_fixed31_32_one, + mantiss)) + mantiss = dal_fixed31_32_zero; + else + mantiss = dal_fixed31_32_shl( + mantiss, + format->mantissa_bits); + + *mantissa = dal_fixed31_32_floor(mantiss); + + return true; +} + +static bool setup_custom_float( + const struct custom_float_format *format, + bool negative, + uint32_t mantissa, + uint32_t exponenta, + uint32_t *result) +{ + uint32_t i = 0; + uint32_t j = 0; + + uint32_t value = 0; + + /* verification code: + * once calculation is ok we can remove it + */ + + const uint32_t mantissa_mask = + (1 << (format->mantissa_bits + 1)) - 1; + + const uint32_t exponenta_mask = + (1 << (format->exponenta_bits + 1)) - 1; + + if (mantissa & ~mantissa_mask) { + BREAK_TO_DEBUGGER(); + mantissa = mantissa_mask; + } + + if (exponenta & ~exponenta_mask) { + BREAK_TO_DEBUGGER(); + exponenta = exponenta_mask; + } + + /* end of verification code */ + + while (i < format->mantissa_bits) { + uint32_t mask = 1 << i; + + if (mantissa & mask) + value |= mask; + + ++i; + } + + while (j < format->exponenta_bits) { + uint32_t mask = 1 << j; + + if (exponenta & mask) + value |= mask << i; + + ++j; + } + + if (negative && format->sign) + value |= 1 << (i + j); + + *result = value; + + return true; +} + +static bool convert_to_custom_float_format( + struct fixed31_32 value, + const struct custom_float_format *format, + uint32_t *result) +{ + uint32_t mantissa; + uint32_t exponenta; + bool negative; + + return build_custom_float( + value, format, &negative, &mantissa, &exponenta) && + setup_custom_float( + format, negative, mantissa, exponenta, result); +} + +static bool convert_to_custom_float( + struct pwl_result_data *rgb_resulted, + struct curve_points *arr_points, + uint32_t hw_points_num) +{ + struct custom_float_format fmt; + + struct pwl_result_data *rgb = rgb_resulted; + + uint32_t i = 0; + + fmt.exponenta_bits = 6; + fmt.mantissa_bits = 12; + fmt.sign = true; + + if (!convert_to_custom_float_format( + arr_points[0].x, + &fmt, + &arr_points[0].custom_float_x)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format( + arr_points[0].offset, + &fmt, + &arr_points[0].custom_float_offset)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format( + arr_points[0].slope, + &fmt, + &arr_points[0].custom_float_slope)) { + BREAK_TO_DEBUGGER(); + return false; + } + + fmt.mantissa_bits = 10; + fmt.sign = false; + + if (!convert_to_custom_float_format( + arr_points[1].x, + &fmt, + &arr_points[1].custom_float_x)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format( + arr_points[1].y, + &fmt, + &arr_points[1].custom_float_y)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format( + arr_points[2].slope, + &fmt, + &arr_points[2].custom_float_slope)) { + BREAK_TO_DEBUGGER(); + return false; + } + + fmt.mantissa_bits = 12; + fmt.sign = true; + + while (i != hw_points_num) { + if (!convert_to_custom_float_format( + rgb->red, + &fmt, + &rgb->red_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format( + rgb->green, + &fmt, + &rgb->green_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format( + rgb->blue, + &fmt, + &rgb->blue_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format( + rgb->delta_red, + &fmt, + &rgb->delta_red_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format( + rgb->delta_green, + &fmt, + &rgb->delta_green_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format( + rgb->delta_blue, + &fmt, + &rgb->delta_blue_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + ++rgb; + ++i; + } + + return true; +} + +static bool dce110_translate_regamma_to_hw_format(const struct dc_transfer_func + *output_tf, struct pwl_params *regamma_params) +{ + if (output_tf == NULL || regamma_params == NULL) + return false; + + struct gamma_curve *arr_curve_points = regamma_params->arr_curve_points; + struct curve_points *arr_points = regamma_params->arr_points; + struct pwl_result_data *rgb_resulted = regamma_params->rgb_resulted; + 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 segment_start, segment_end; + uint32_t hw_points, start_index; + uint32_t i, j; + + memset(regamma_params, 0, sizeof(struct pwl_params)); + + if (output_tf->tf == TRANSFER_FUNCTION_PQ) { + /* 16 segments x 16 points + * segments are from 2^-11 to 2^5 + */ + segment_start = -11; + segment_end = 5; + + } else { + /* 10 segments x 16 points + * segment is from 2^-10 to 2^0 + */ + segment_start = -10; + segment_end = 0; + } + + hw_points = (segment_end - segment_start) * 16; + j = 0; + /* (segment + 25) * 32, every 2nd point */ + start_index = (segment_start + 25) * 32; + for (i = start_index; i <= 1025; i += 2) { + if (j > hw_points) + 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++; + } + + arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), + dal_fixed31_32_from_int(segment_start)); + arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), + dal_fixed31_32_from_int(segment_end)); + arr_points[2].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), + dal_fixed31_32_from_int(segment_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[2].y = y3_max; + + arr_points[1].slope = dal_fixed31_32_zero; + arr_points[2].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)); + arr_points[2].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)); + } + + regamma_params->hw_points_num = hw_points; + + for (i = 0; i < segment_end - segment_start; i++) { + regamma_params->arr_curve_points[i].offset = i * 16; + regamma_params->arr_curve_points[i].segments_num = 4; + } + + struct pwl_result_data *rgb = rgb_resulted; + struct pwl_result_data *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; + } + + convert_to_custom_float(rgb_resulted, arr_points, hw_points); + + return true; +} + static bool dce110_set_output_transfer_func( struct pipe_ctx *pipe_ctx, const struct core_surface *surface, /* Surface - To be removed */ @@ -308,10 +737,13 @@ static bool dce110_set_output_transfer_func( opp->funcs->opp_power_on_regamma_lut(opp, true); if (stream->public.out_transfer_func && - stream->public.out_transfer_func->type == TF_TYPE_PREDEFINED && - stream->public.out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) { + stream->public.out_transfer_func->type == + TF_TYPE_PREDEFINED && + stream->public.out_transfer_func->tf == + TRANSFER_FUNCTION_SRGB) { opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_SRGB); - } else if (ramp && calculate_regamma_params(regamma_params, ramp, surface, stream)) { + } else if (dce110_translate_regamma_to_hw_format( + stream->public.out_transfer_func, regamma_params)) { opp->funcs->opp_program_regamma_pwl(opp, regamma_params); opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER); } else { diff --git a/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h deleted file mode 100644 index 0712268856c2..000000000000 --- a/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * gamma_calcs.h - * - * Created on: Feb 9, 2016 - * Author: yonsun - */ - -#ifndef DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ -#define DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ - -#include "opp.h" -#include "core_types.h" -#include "dc.h" - -bool calculate_regamma_params(struct pwl_params *params, - const struct core_gamma *ramp, - const struct core_surface *surface, - const struct core_stream *stream); - -#endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h index a1f31a4410a3..bef5e2cacbe3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h @@ -138,9 +138,7 @@ struct custom_float_value { struct hw_x_point { uint32_t custom_float_x; - uint32_t custom_float_x_adjusted; struct fixed31_32 x; - struct fixed31_32 adjusted_x; struct fixed31_32 regamma_y_red; struct fixed31_32 regamma_y_green; struct fixed31_32 regamma_y_blue; diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h b/drivers/gpu/drm/amd/display/include/fixed31_32.h index c28de167250f..5a4364dfd2f7 100644 --- a/drivers/gpu/drm/amd/display/include/fixed31_32.h +++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h @@ -192,6 +192,14 @@ struct fixed31_32 dal_fixed31_32_add( /* * @brief + * result = arg1 + arg2 + */ +struct fixed31_32 dal_fixed31_32_add_int( + struct fixed31_32 arg1, + int32_t arg2); + +/* + * @brief * result = arg1 - arg2 */ struct fixed31_32 dal_fixed31_32_sub_int( |