[PATCH 08/22] drm/amd/display: Implement PQ curve based on output transfer function

Harry Wentland harry.wentland at amd.com
Wed Dec 21 16:30:02 UTC 2016


From: Anthony Koo <Anthony.Koo at amd.com>

Refactor part 5 - Regamma programming should be dependent on Output
transfer function type

Program sRGB gamma or PQ transfer function based on output transfer
function.

Change-Id: I442fba3003068a15bfd6959b3ec69f0dd42c4d22
Signed-off-by: Anthony Koo <anthony.koo at amd.com>
Reviewed-by: Aric Cyr <Aric.Cyr at amd.com>
Acked-by: Harry Wentland <Harry.Wentland at amd.com>
---
 drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c | 93 ++++++++++++++++++++--
 .../amd/display/dc/dce110/dce110_hw_sequencer.c    |  3 +-
 drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h   |  3 +-
 3 files changed, 92 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c
index 854796aa0c71..973be8f649cc 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c
@@ -791,6 +791,82 @@ static inline struct fixed31_32 calculate_oem_mapped_value(
 			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,
@@ -1286,7 +1362,8 @@ static bool convert_to_custom_float(
 
 bool calculate_regamma_params(struct pwl_params *params,
 		const struct core_gamma *ramp,
-		const struct core_surface *surface)
+		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;
@@ -1301,7 +1378,6 @@ bool calculate_regamma_params(struct pwl_params *params,
 	struct pixel_gamma_point *coeff128_oem = NULL;
 	struct pixel_gamma_point *coeff128 = NULL;
 
-
 	bool ret = false;
 
 	coordinates_x = dm_alloc(sizeof(*coordinates_x)*(256 + 3));
@@ -1341,9 +1417,16 @@ bool calculate_regamma_params(struct pwl_params *params,
 	setup_distribution_points(arr_curve_points, arr_points,
 			&params->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);
+	if (stream->public.out_transfer_func &&
+		stream->public.out_transfer_func->tf == TRANSFER_FUNCTION_PQ) {
+		build_regamma_curve_pq(rgb_regamma, rgb_oem, coeff128_oem,
+				ramp, surface, params->hw_points_num,
+				coordinates_x, axix_x_256, dividers);
+	} else {
+		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,
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 72017d5a8252..2f790753b559 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
@@ -303,7 +303,8 @@ static bool dce110_set_output_transfer_func(
 
 	opp->funcs->opp_power_on_regamma_lut(opp, true);
 
-	if (ramp && calculate_regamma_params(regamma_params, ramp, surface)) {
+	if (ramp && calculate_regamma_params(
+				regamma_params, ramp, surface, stream)) {
 		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
index e2c63fd4fe92..0712268856c2 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h
@@ -14,6 +14,7 @@
 
 bool calculate_regamma_params(struct pwl_params *params,
 		const struct core_gamma *ramp,
-		const struct core_surface *surface);
+		const struct core_surface *surface,
+		const struct core_stream *stream);
 
 #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ */
-- 
2.9.3



More information about the amd-gfx mailing list