[PATCH 19/33] drm/amd/display: Handle HDR use cases.

Harry Wentland harry.wentland at amd.com
Mon Feb 26 20:15:49 UTC 2018


From: Vitaly Prosyak <vitaly.prosyak at amd.com>

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 <vitaly.prosyak at amd.com>
Reviewed-by: Krunoslav Kovac <Krunoslav.Kovac at amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng at amd.com>
Acked-by: Harry Wentland <harry.wentland at amd.com>
---
 .../gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c | 153 +++++++++++++++++++++
 .../gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h |   5 +
 drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h        |   2 +
 .../drm/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;
-- 
2.14.1



More information about the amd-gfx mailing list