drm/amd/display: Handle HDR use cases.
authorVitaly Prosyak <vitaly.prosyak@amd.com>
Tue, 13 Feb 2018 19:18:43 +0000 (13:18 -0600)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 5 Mar 2018 20:34:58 +0000 (15:34 -0500)
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@amd.com>
Reviewed-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h
drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
drivers/gpu/drm/amd/display/modules/color/color_gamma.c

index b3db639..881a1bf 100644 (file)
@@ -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;
+}
index 64e476b..7a531b0 100644 (file)
@@ -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
index 78abc16..c5aae2d 100644 (file)
@@ -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 {
index a5fd14a..57d5c25 100644 (file)
 
 #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 @@ rgb_user_alloc_fail:
        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;