OSDN Git Service

drm/amd/display: add odm split logic to scaling calculations
authorDmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Fri, 13 Dec 2019 23:22:40 +0000 (18:22 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 11 Feb 2020 16:50:36 +0000 (11:50 -0500)
Currently odm scaling calculations are only done when adding initial
odm pipe. Any scaling re-calculations will mess up odm because of this.

This change resolves the problem by updating scaling split logic to
handle odm.

Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Reviewed-by: Eric Yang <eric.yang2@amd.com>
Acked-by: Michael Strauss <Michael.Strauss@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h

index cd80d82..a65a1e7 100644 (file)
@@ -532,6 +532,35 @@ static inline void get_vp_scan_direction(
                *flip_horz_scan_dir = !*flip_horz_scan_dir;
 }
 
+static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *split_count, int *split_idx)
+{
+       *split_count = get_num_odm_splits(pipe_ctx);
+       *split_idx = 0;
+       if (*split_count == 0) {
+               /*Check for mpc split*/
+               struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
+
+               while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
+                       (*split_idx)++;
+                       (*split_count)++;
+                       split_pipe = split_pipe->top_pipe;
+               }
+               split_pipe = pipe_ctx->bottom_pipe;
+               while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
+                       (*split_count)++;
+                       split_pipe = split_pipe->bottom_pipe;
+               }
+       } else {
+               /*Get odm split index*/
+               struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe;
+
+               while (split_pipe) {
+                       (*split_idx)++;
+                       split_pipe = split_pipe->prev_odm_pipe;
+               }
+       }
+}
+
 static void calculate_viewport(struct pipe_ctx *pipe_ctx)
 {
        const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
@@ -541,16 +570,16 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
        struct rect clip, dest;
        int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
                        || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
-       bool pri_split = pipe_ctx->bottom_pipe &&
-                       pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state;
-       bool sec_split = pipe_ctx->top_pipe &&
-                       pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
+       int split_count = 0;
+       int split_idx = 0;
        bool orthogonal_rotation, flip_y_start, flip_x_start;
 
+       calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
+
        if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE ||
                stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) {
-               pri_split = false;
-               sec_split = false;
+               split_count = 0;
+               split_idx = 0;
        }
 
        /* The actual clip is an intersection between stream
@@ -609,23 +638,32 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
        data->viewport.height = clip.height * surf_src.height / dest.height;
 
        /* Handle split */
-       if (pri_split || sec_split) {
+       if (split_count) {
+               /* extra pixels in the division remainder need to go to pipes after
+                * the extra pixel index minus one(epimo) defined here as:
+                */
+               int epimo = 0;
+
                if (orthogonal_rotation) {
-                       if (flip_y_start != pri_split)
-                               data->viewport.height /= 2;
-                       else {
-                               data->viewport.y +=  data->viewport.height / 2;
-                               /* Ceil offset pipe */
-                               data->viewport.height = (data->viewport.height + 1) / 2;
-                       }
+                       if (flip_y_start)
+                               split_idx = split_count - split_idx;
+
+                       epimo = split_count - data->viewport.height % (split_count + 1);
+
+                       data->viewport.y += (data->viewport.height / (split_count + 1)) * split_idx;
+                       if (split_idx > epimo)
+                               data->viewport.y += split_idx - epimo - 1;
+                       data->viewport.height = data->viewport.height / (split_count + 1) + (split_idx > epimo ? 1 : 0);
                } else {
-                       if (flip_x_start != pri_split)
-                               data->viewport.width /= 2;
-                       else {
-                               data->viewport.x +=  data->viewport.width / 2;
-                               /* Ceil offset pipe */
-                               data->viewport.width = (data->viewport.width + 1) / 2;
-                       }
+                       if (flip_x_start)
+                               split_idx = split_count - split_idx;
+
+                       epimo = split_count - data->viewport.width % (split_count + 1);
+
+                       data->viewport.x += (data->viewport.width / (split_count + 1)) * split_idx;
+                       if (split_idx > epimo)
+                               data->viewport.x += split_idx - epimo - 1;
+                       data->viewport.width = data->viewport.width / (split_count + 1) + (split_idx > epimo ? 1 : 0);
                }
        }
 
@@ -644,58 +682,58 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx)
 {
        const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
        const struct dc_stream_state *stream = pipe_ctx->stream;
+       struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
        struct rect surf_clip = plane_state->clip_rect;
-       bool pri_split = pipe_ctx->bottom_pipe &&
-                       pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state;
-       bool sec_split = pipe_ctx->top_pipe &&
-                       pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
-       bool top_bottom_split = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
-
-       pipe_ctx->plane_res.scl_data.recout.x = stream->dst.x;
+       bool pri_split_tb = pipe_ctx->bottom_pipe &&
+                       pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state &&
+                       stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
+       bool sec_split_tb = pipe_ctx->top_pipe &&
+                       pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state &&
+                       stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
+       int split_count = 0;
+       int split_idx = 0;
+
+       calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
+
+       data->recout.x = stream->dst.x;
        if (stream->src.x < surf_clip.x)
-               pipe_ctx->plane_res.scl_data.recout.x += (surf_clip.x
-                       - stream->src.x) * stream->dst.width
+               data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width
                                                / stream->src.width;
 
-       pipe_ctx->plane_res.scl_data.recout.width = surf_clip.width *
-                       stream->dst.width / stream->src.width;
-       if (pipe_ctx->plane_res.scl_data.recout.width + pipe_ctx->plane_res.scl_data.recout.x >
-                       stream->dst.x + stream->dst.width)
-               pipe_ctx->plane_res.scl_data.recout.width =
-                       stream->dst.x + stream->dst.width
-                                               - pipe_ctx->plane_res.scl_data.recout.x;
+       data->recout.width = surf_clip.width * stream->dst.width / stream->src.width;
+       if (data->recout.width + data->recout.x > stream->dst.x + stream->dst.width)
+               data->recout.width = stream->dst.x + stream->dst.width - data->recout.x;
 
-       pipe_ctx->plane_res.scl_data.recout.y = stream->dst.y;
+       data->recout.y = stream->dst.y;
        if (stream->src.y < surf_clip.y)
-               pipe_ctx->plane_res.scl_data.recout.y += (surf_clip.y
-                       - stream->src.y) * stream->dst.height
+               data->recout.y += (surf_clip.y - stream->src.y) * stream->dst.height
                                                / stream->src.height;
 
-       pipe_ctx->plane_res.scl_data.recout.height = surf_clip.height *
-                       stream->dst.height / stream->src.height;
-       if (pipe_ctx->plane_res.scl_data.recout.height + pipe_ctx->plane_res.scl_data.recout.y >
-                       stream->dst.y + stream->dst.height)
-               pipe_ctx->plane_res.scl_data.recout.height =
-                       stream->dst.y + stream->dst.height
-                                               - pipe_ctx->plane_res.scl_data.recout.y;
+       data->recout.height = surf_clip.height * stream->dst.height / stream->src.height;
+       if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height)
+               data->recout.height = stream->dst.y + stream->dst.height - data->recout.y;
 
        /* Handle h & v split, handle rotation using viewport */
-       if (sec_split && top_bottom_split) {
-               pipe_ctx->plane_res.scl_data.recout.y +=
-                               pipe_ctx->plane_res.scl_data.recout.height / 2;
+       if (sec_split_tb) {
+               data->recout.y += data->recout.height / 2;
                /* Floor primary pipe, ceil 2ndary pipe */
-               pipe_ctx->plane_res.scl_data.recout.height =
-                               (pipe_ctx->plane_res.scl_data.recout.height + 1) / 2;
-       } else if (pri_split && top_bottom_split)
-               pipe_ctx->plane_res.scl_data.recout.height /= 2;
-       else if (sec_split) {
-               pipe_ctx->plane_res.scl_data.recout.x +=
-                               pipe_ctx->plane_res.scl_data.recout.width / 2;
-               /* Ceil offset pipe */
-               pipe_ctx->plane_res.scl_data.recout.width =
-                               (pipe_ctx->plane_res.scl_data.recout.width + 1) / 2;
-       } else if (pri_split)
-               pipe_ctx->plane_res.scl_data.recout.width /= 2;
+               data->recout.height = (data->recout.height + 1) / 2;
+       } else if (pri_split_tb)
+               data->recout.height /= 2;
+       else if (split_count) {
+               /* extra pixels in the division remainder need to go to pipes after
+                * the extra pixel index minus one(epimo) defined here as:
+                */
+               int epimo = split_count - data->recout.width % (split_count + 1);
+
+               /*no recout offset due to odm */
+               if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) {
+                       data->recout.x += (data->recout.width / (split_count + 1)) * split_idx;
+                       if (split_idx > epimo)
+                               data->recout.x += split_idx - epimo - 1;
+               }
+               data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0);
+       }
 }
 
 static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
@@ -832,6 +870,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx)
 {
        const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
        const struct dc_stream_state *stream = pipe_ctx->stream;
+       struct pipe_ctx *odm_pipe = pipe_ctx->prev_odm_pipe;
        struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
        struct rect src = pipe_ctx->plane_state->src_rect;
        int recout_skip_h, recout_skip_v, surf_size_h, surf_size_v;
@@ -869,6 +908,12 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx)
                                        * stream->dst.width / stream->src.width -
                                        src.x * plane_state->dst_rect.width / src.width
                                        * stream->dst.width / stream->src.width);
+       /*modified recout_skip_h calculation due to odm having no recout offset caused by split*/
+       while (odm_pipe) {
+               recout_skip_h += odm_pipe->plane_res.scl_data.recout.width + odm_pipe->plane_res.scl_data.recout.x;
+               odm_pipe = odm_pipe->prev_odm_pipe;
+       }
+
        recout_skip_v = data->recout.y - (stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
                                        * stream->dst.height / stream->src.height -
                                        src.y * plane_state->dst_rect.height / src.height
@@ -1021,6 +1066,8 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
                store_h_border_left + timing->h_border_right;
        pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable +
                timing->v_border_top + timing->v_border_bottom;
+       if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe)
+               pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1;
 
        /* Taps calculations */
        if (pipe_ctx->plane_res.xfm != NULL)
index 85f90f3..39026df 100644 (file)
@@ -1861,20 +1861,20 @@ void dcn20_populate_dml_writeback_from_context(
 
 }
 
-static int get_num_odm_heads(struct pipe_ctx *pipe)
+int get_num_odm_splits(struct pipe_ctx *pipe)
 {
-       int odm_head_count = 0;
+       int odm_split_count = 0;
        struct pipe_ctx *next_pipe = pipe->next_odm_pipe;
        while (next_pipe) {
-               odm_head_count++;
+               odm_split_count++;
                next_pipe = next_pipe->next_odm_pipe;
        }
        pipe = pipe->prev_odm_pipe;
        while (pipe) {
-               odm_head_count++;
+               odm_split_count++;
                pipe = pipe->prev_odm_pipe;
        }
-       return odm_head_count ? odm_head_count + 1 : 0;
+       return odm_split_count;
 }
 
 int dcn20_populate_dml_pipes_from_context(
@@ -1956,8 +1956,8 @@ int dcn20_populate_dml_pipes_from_context(
                pipes[pipe_cnt].dout.dp_lanes = 4;
                pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min;
                pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max;
-               switch (get_num_odm_heads(&res_ctx->pipe_ctx[i])) {
-               case 2:
+               switch (get_num_odm_splits(&res_ctx->pipe_ctx[i])) {
+               case 1:
                        pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_2to1;
                        break;
                default:
@@ -2124,18 +2124,22 @@ int dcn20_populate_dml_pipes_from_context(
                        pipes[pipe_cnt].pipe.src.dcc = pln->dcc.enable;
                        pipes[pipe_cnt].pipe.dest.recout_width = scl->recout.width;
                        pipes[pipe_cnt].pipe.dest.recout_height = scl->recout.height;
-                       pipes[pipe_cnt].pipe.dest.full_recout_width = scl->recout.width;
                        pipes[pipe_cnt].pipe.dest.full_recout_height = scl->recout.height;
-                       if (res_ctx->pipe_ctx[i].bottom_pipe && res_ctx->pipe_ctx[i].bottom_pipe->plane_state == pln) {
-                               pipes[pipe_cnt].pipe.dest.full_recout_width +=
-                                               res_ctx->pipe_ctx[i].bottom_pipe->plane_res.scl_data.recout.width;
-                               pipes[pipe_cnt].pipe.dest.full_recout_height +=
-                                               res_ctx->pipe_ctx[i].bottom_pipe->plane_res.scl_data.recout.height;
-                       } else if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state == pln) {
-                               pipes[pipe_cnt].pipe.dest.full_recout_width +=
-                                               res_ctx->pipe_ctx[i].top_pipe->plane_res.scl_data.recout.width;
-                               pipes[pipe_cnt].pipe.dest.full_recout_height +=
-                                               res_ctx->pipe_ctx[i].top_pipe->plane_res.scl_data.recout.height;
+                       pipes[pipe_cnt].pipe.dest.full_recout_width = scl->recout.width;
+                       if (pipes[pipe_cnt].pipe.dest.odm_combine == dm_odm_combine_mode_2to1)
+                               pipes[pipe_cnt].pipe.dest.full_recout_width *= 2;
+                       else {
+                               struct pipe_ctx *split_pipe = res_ctx->pipe_ctx[i].bottom_pipe;
+
+                               while (split_pipe && split_pipe->plane_state == pln) {
+                                       pipes[pipe_cnt].pipe.dest.full_recout_width += split_pipe->plane_res.scl_data.recout.width;
+                                       split_pipe = split_pipe->bottom_pipe;
+                               }
+                               split_pipe = res_ctx->pipe_ctx[i].top_pipe;
+                               while (split_pipe && split_pipe->plane_state == pln) {
+                                       pipes[pipe_cnt].pipe.dest.full_recout_width += split_pipe->plane_res.scl_data.recout.width;
+                                       split_pipe = split_pipe->top_pipe;
+                               }
                        }
 
                        pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_16;
index f589384..5180088 100644 (file)
@@ -49,6 +49,7 @@ unsigned int dcn20_calc_max_scaled_time(
                unsigned int time_per_pixel,
                enum mmhubbub_wbif_mode mode,
                unsigned int urgent_watermark);
+int get_num_odm_splits(struct pipe_ctx *pipe);
 int dcn20_populate_dml_pipes_from_context(
                struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes);
 struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer(