aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0804-drm-amd-display-redesign-scaling-rotation-math.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0804-drm-amd-display-redesign-scaling-rotation-math.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0804-drm-amd-display-redesign-scaling-rotation-math.patch833
1 files changed, 833 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0804-drm-amd-display-redesign-scaling-rotation-math.patch b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0804-drm-amd-display-redesign-scaling-rotation-math.patch
new file mode 100644
index 00000000..da63a807
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0804-drm-amd-display-redesign-scaling-rotation-math.patch
@@ -0,0 +1,833 @@
+From ef48bbf481a707cffe5fc0a4e6c3ff2b2fbc329e Mon Sep 17 00:00:00 2001
+From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
+Date: Fri, 19 Oct 2018 16:17:29 -0400
+Subject: [PATCH 0804/2940] drm/amd/display: redesign scaling rotation math
+
+Change the math to work in viewport rotation when calculating
+viewport and viewport adjustment. This simplifies the math
+for viewport calculation and makes viewport adjustment easier to
+understand.
+
+Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
+Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
+Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+---
+ .../gpu/drm/amd/display/dc/core/dc_resource.c | 654 +++++++-----------
+ 1 file changed, 240 insertions(+), 414 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+index fcb29ca6f0e8..a06ca07c7038 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+@@ -478,10 +478,29 @@ static enum pixel_format convert_pixel_format_to_dalsurface(
+ return dal_pixel_format;
+ }
+
+-static void rect_swap_helper(struct rect *rect)
+-{
+- swap(rect->height, rect->width);
+- swap(rect->x, rect->y);
++static inline void get_vp_scan_direction(
++ enum dc_rotation_angle rotation,
++ bool horizontal_mirror,
++ bool *orthogonal_rotation,
++ bool *flip_vert_scan_dir,
++ bool *flip_horz_scan_dir)
++{
++ *orthogonal_rotation = false;
++ *flip_vert_scan_dir = false;
++ *flip_horz_scan_dir = false;
++ if (rotation == ROTATION_ANGLE_180) {
++ *flip_vert_scan_dir = true;
++ *flip_horz_scan_dir = true;
++ } else if (rotation == ROTATION_ANGLE_90) {
++ *orthogonal_rotation = true;
++ *flip_horz_scan_dir = true;
++ } else if (rotation == ROTATION_ANGLE_270) {
++ *orthogonal_rotation = true;
++ *flip_vert_scan_dir = true;
++ }
++
++ if (horizontal_mirror)
++ *flip_horz_scan_dir = !*flip_horz_scan_dir;
+ }
+
+ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
+@@ -490,33 +509,14 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
+ const struct dc_stream_state *stream = pipe_ctx->stream;
+ struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
+ struct rect surf_src = plane_state->src_rect;
+- struct rect clip = { 0 };
++ 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;
+- bool flip_vert_scan_dir = false, flip_horz_scan_dir = false;
+-
+-
+- /*
+- * We need take horizontal mirror into account. On an unrotated surface this means
+- * that the viewport offset is actually the offset from the other side of source
+- * image so we have to subtract the right edge of the viewport from the right edge of
+- * the source window. Similar to mirror we need to take into account how offset is
+- * affected for 270/180 rotations
+- */
+- if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_180) {
+- flip_vert_scan_dir = true;
+- flip_horz_scan_dir = true;
+- } else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90)
+- flip_vert_scan_dir = true;
+- else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
+- flip_horz_scan_dir = true;
+-
+- if (pipe_ctx->plane_state->horizontal_mirror)
+- flip_horz_scan_dir = !flip_horz_scan_dir;
++ bool orthogonal_rotation, flip_y_start, flip_x_start;
+
+ if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE ||
+ stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) {
+@@ -524,13 +524,10 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
+ sec_split = false;
+ }
+
+- if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
+- pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
+- rect_swap_helper(&surf_src);
+-
+ /* The actual clip is an intersection between stream
+ * source and surface clip
+ */
++ dest = plane_state->dst_rect;
+ clip.x = stream->src.x > plane_state->clip_rect.x ?
+ stream->src.x : plane_state->clip_rect.x;
+
+@@ -547,66 +544,77 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
+ stream->src.y + stream->src.height - clip.y :
+ plane_state->clip_rect.y + plane_state->clip_rect.height - clip.y ;
+
+- /* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio
+- * note: surf_src.ofs should be added after rotation/mirror offset direction
+- * adjustment since it is already in viewport space
+- * num_pixels = clip.num_pix * scl_ratio
++ /*
++ * Need to calculate how scan origin is shifted in vp space
++ * to correctly rotate clip and dst
+ */
+- data->viewport.x = (clip.x - plane_state->dst_rect.x) *
+- surf_src.width / plane_state->dst_rect.width;
+- data->viewport.width = clip.width *
+- surf_src.width / plane_state->dst_rect.width;
++ get_vp_scan_direction(
++ plane_state->rotation,
++ plane_state->horizontal_mirror,
++ &orthogonal_rotation,
++ &flip_y_start,
++ &flip_x_start);
+
+- data->viewport.y = (clip.y - plane_state->dst_rect.y) *
+- surf_src.height / plane_state->dst_rect.height;
+- data->viewport.height = clip.height *
+- surf_src.height / plane_state->dst_rect.height;
+-
+- if (flip_vert_scan_dir)
+- data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height;
+- if (flip_horz_scan_dir)
+- data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width;
++ if (orthogonal_rotation) {
++ swap(clip.x, clip.y);
++ swap(clip.width, clip.height);
++ swap(dest.x, dest.y);
++ swap(dest.width, dest.height);
++ }
++ if (flip_x_start) {
++ clip.x = dest.x + dest.width - clip.x - clip.width;
++ dest.x = 0;
++ }
++ if (flip_y_start) {
++ clip.y = dest.y + dest.height - clip.y - clip.height;
++ dest.y = 0;
++ }
+
+- data->viewport.x += surf_src.x;
+- data->viewport.y += surf_src.y;
++ /* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio
++ * num_pixels = clip.num_pix * scl_ratio
++ */
++ data->viewport.x = surf_src.x + (clip.x - dest.x) * surf_src.width / dest.width;
++ data->viewport.width = clip.width * surf_src.width / dest.width;
++
++ data->viewport.y = surf_src.y + (clip.y - dest.y) * surf_src.height / dest.height;
++ data->viewport.height = clip.height * surf_src.height / dest.height;
++
++ /* Handle split */
++ if (pri_split || sec_split) {
++ 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;
++ }
++ } 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;
++ }
++ }
++ }
+
+ /* Round down, compensate in init */
+ data->viewport_c.x = data->viewport.x / vpc_div;
+ data->viewport_c.y = data->viewport.y / vpc_div;
+- data->inits.h_c = (data->viewport.x % vpc_div) != 0 ?
+- dc_fixpt_half : dc_fixpt_zero;
+- data->inits.v_c = (data->viewport.y % vpc_div) != 0 ?
+- dc_fixpt_half : dc_fixpt_zero;
++ data->inits.h_c = (data->viewport.x % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero;
++ data->inits.v_c = (data->viewport.y % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero;
++
+ /* Round up, assume original video size always even dimensions */
+ data->viewport_c.width = (data->viewport.width + vpc_div - 1) / vpc_div;
+ data->viewport_c.height = (data->viewport.height + vpc_div - 1) / vpc_div;
+-
+- /* Handle hsplit */
+- if (sec_split) {
+- data->viewport.x += data->viewport.width / 2;
+- data->viewport_c.x += data->viewport_c.width / 2;
+- /* Ceil offset pipe */
+- data->viewport.width = (data->viewport.width + 1) / 2;
+- data->viewport_c.width = (data->viewport_c.width + 1) / 2;
+- } else if (pri_split) {
+- if (data->viewport.width > 1)
+- data->viewport.width /= 2;
+- if (data->viewport_c.width > 1)
+- data->viewport_c.width /= 2;
+- }
+-
+- if (plane_state->rotation == ROTATION_ANGLE_90 ||
+- plane_state->rotation == ROTATION_ANGLE_270) {
+- rect_swap_helper(&data->viewport_c);
+- rect_swap_helper(&data->viewport);
+- }
+ }
+
+-static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full)
++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 rect surf_src = plane_state->src_rect;
+ 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;
+@@ -614,10 +622,6 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full
+ pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
+ bool top_bottom_split = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
+
+- if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
+- pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
+- rect_swap_helper(&surf_src);
+-
+ pipe_ctx->plane_res.scl_data.recout.x = stream->dst.x;
+ if (stream->src.x < surf_clip.x)
+ pipe_ctx->plane_res.scl_data.recout.x += (surf_clip.x
+@@ -646,7 +650,7 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full
+ stream->dst.y + stream->dst.height
+ - pipe_ctx->plane_res.scl_data.recout.y;
+
+- /* Handle h & vsplit */
++ /* 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;
+@@ -655,44 +659,14 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full
+ (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 (pri_split || sec_split) {
+- /* HMirror XOR Secondary_pipe XOR Rotation_180 */
+- bool right_view = (sec_split != plane_state->horizontal_mirror) !=
+- (plane_state->rotation == ROTATION_ANGLE_180);
+-
+- if (plane_state->rotation == ROTATION_ANGLE_90
+- || plane_state->rotation == ROTATION_ANGLE_270)
+- /* Secondary_pipe XOR Rotation_270 */
+- right_view = (plane_state->rotation == ROTATION_ANGLE_270) != sec_split;
+-
+- if (right_view) {
+- 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 (pipe_ctx->plane_res.scl_data.recout.width > 1)
+- pipe_ctx->plane_res.scl_data.recout.width /= 2;
+- }
+- }
+- /* Unclipped recout offset = stream dst offset + ((surf dst offset - stream surf_src offset)
+- * * 1/ stream scaling ratio) - (surf surf_src offset * 1/ full scl
+- * ratio)
+- */
+- recout_full->x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
+- * stream->dst.width / stream->src.width -
+- surf_src.x * plane_state->dst_rect.width / surf_src.width
+- * stream->dst.width / stream->src.width;
+- recout_full->y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
+- * stream->dst.height / stream->src.height -
+- surf_src.y * plane_state->dst_rect.height / surf_src.height
+- * stream->dst.height / stream->src.height;
+-
+- recout_full->width = plane_state->dst_rect.width
+- * stream->dst.width / stream->src.width;
+- recout_full->height = plane_state->dst_rect.height
+- * stream->dst.height / stream->src.height;
++ 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;
+ }
+
+ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
+@@ -705,9 +679,10 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
+ const int out_w = stream->dst.width;
+ const int out_h = stream->dst.height;
+
++ /*Swap surf_src height and width since scaling ratios are in recout rotation*/
+ if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
+ pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
+- rect_swap_helper(&surf_src);
++ swap(surf_src.height, surf_src.width);
+
+ pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
+ surf_src.width,
+@@ -744,351 +719,202 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
+ pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
+ }
+
+-static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct rect *recout_full)
++static inline void adjust_vp_and_init_for_seamless_clip(
++ bool flip_scan_dir,
++ int recout_skip,
++ int src_size,
++ int taps,
++ struct fixed31_32 ratio,
++ struct fixed31_32 *init,
++ int *vp_offset,
++ int *vp_size)
+ {
+- struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
+- struct rect src = pipe_ctx->plane_state->src_rect;
+- int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
+- || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
+- bool flip_vert_scan_dir = false, flip_horz_scan_dir = false;
+-
+- /*
+- * Need to calculate the scan direction for viewport to make adjustments
+- */
+- if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_180) {
+- flip_vert_scan_dir = true;
+- flip_horz_scan_dir = true;
+- } else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90)
+- flip_vert_scan_dir = true;
+- else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
+- flip_horz_scan_dir = true;
+-
+- if (pipe_ctx->plane_state->horizontal_mirror)
+- flip_horz_scan_dir = !flip_horz_scan_dir;
+-
+- if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
+- pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
+- rect_swap_helper(&src);
+- rect_swap_helper(&data->viewport_c);
+- rect_swap_helper(&data->viewport);
+- }
+-
+- /*
+- * Init calculated according to formula:
+- * init = (scaling_ratio + number_of_taps + 1) / 2
+- * init_bot = init + scaling_ratio
+- * init_c = init + truncated_vp_c_offset(from calculate viewport)
+- */
+- data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int(
+- dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19);
+-
+- data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int(
+- dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19);
+-
+- data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int(
+- dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19);
+-
+- data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int(
+- dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19);
+-
+- if (!flip_horz_scan_dir) {
++ if (!flip_scan_dir) {
+ /* Adjust for viewport end clip-off */
+- if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) {
+- int vp_clip = src.x + src.width - data->viewport.width - data->viewport.x;
+- int int_part = dc_fixpt_floor(
+- dc_fixpt_sub(data->inits.h, data->ratios.horz));
+-
+- int_part = int_part > 0 ? int_part : 0;
+- data->viewport.width += int_part < vp_clip ? int_part : vp_clip;
+- }
+- if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) {
+- int vp_clip = (src.x + src.width) / vpc_div -
+- data->viewport_c.width - data->viewport_c.x;
+- int int_part = dc_fixpt_floor(
+- dc_fixpt_sub(data->inits.h_c, data->ratios.horz_c));
++ if ((*vp_offset + *vp_size) < src_size) {
++ int vp_clip = src_size - *vp_size - *vp_offset;
++ int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio));
+
+ int_part = int_part > 0 ? int_part : 0;
+- data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip;
++ *vp_size += int_part < vp_clip ? int_part : vp_clip;
+ }
+
+ /* Adjust for non-0 viewport offset */
+- if (data->viewport.x) {
++ if (*vp_offset) {
+ int int_part;
+
+- data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int(
+- data->ratios.horz, data->recout.x - recout_full->x));
+- int_part = dc_fixpt_floor(data->inits.h) - data->viewport.x;
+- if (int_part < data->taps.h_taps) {
+- int int_adj = data->viewport.x >= (data->taps.h_taps - int_part) ?
+- (data->taps.h_taps - int_part) : data->viewport.x;
+- data->viewport.x -= int_adj;
+- data->viewport.width += int_adj;
++ *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip));
++ int_part = dc_fixpt_floor(*init) - *vp_offset;
++ if (int_part < taps) {
++ int int_adj = *vp_offset >= (taps - int_part) ?
++ (taps - int_part) : *vp_offset;
++ *vp_offset -= int_adj;
++ *vp_size += int_adj;
+ int_part += int_adj;
+- } else if (int_part > data->taps.h_taps) {
+- data->viewport.x += int_part - data->taps.h_taps;
+- data->viewport.width -= int_part - data->taps.h_taps;
+- int_part = data->taps.h_taps;
++ } else if (int_part > taps) {
++ *vp_offset += int_part - taps;
++ *vp_size -= int_part - taps;
++ int_part = taps;
+ }
+- data->inits.h.value &= 0xffffffff;
+- data->inits.h = dc_fixpt_add_int(data->inits.h, int_part);
+- }
+-
+- if (data->viewport_c.x) {
+- int int_part;
+-
+- data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int(
+- data->ratios.horz_c, data->recout.x - recout_full->x));
+- int_part = dc_fixpt_floor(data->inits.h_c) - data->viewport_c.x;
+- if (int_part < data->taps.h_taps_c) {
+- int int_adj = data->viewport_c.x >= (data->taps.h_taps_c - int_part) ?
+- (data->taps.h_taps_c - int_part) : data->viewport_c.x;
+- data->viewport_c.x -= int_adj;
+- data->viewport_c.width += int_adj;
+- int_part += int_adj;
+- } else if (int_part > data->taps.h_taps_c) {
+- data->viewport_c.x += int_part - data->taps.h_taps_c;
+- data->viewport_c.width -= int_part - data->taps.h_taps_c;
+- int_part = data->taps.h_taps_c;
+- }
+- data->inits.h_c.value &= 0xffffffff;
+- data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part);
++ init->value &= 0xffffffff;
++ *init = dc_fixpt_add_int(*init, int_part);
+ }
+ } else {
+ /* Adjust for non-0 viewport offset */
+- if (data->viewport.x) {
+- int int_part = dc_fixpt_floor(
+- dc_fixpt_sub(data->inits.h, data->ratios.horz));
+-
+- int_part = int_part > 0 ? int_part : 0;
+- data->viewport.width += int_part < data->viewport.x ? int_part : data->viewport.x;
+- data->viewport.x -= int_part < data->viewport.x ? int_part : data->viewport.x;
+- }
+- if (data->viewport_c.x) {
+- int int_part = dc_fixpt_floor(
+- dc_fixpt_sub(data->inits.h_c, data->ratios.horz_c));
++ if (*vp_offset) {
++ int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio));
+
+ int_part = int_part > 0 ? int_part : 0;
+- data->viewport_c.width += int_part < data->viewport_c.x ? int_part : data->viewport_c.x;
+- data->viewport_c.x -= int_part < data->viewport_c.x ? int_part : data->viewport_c.x;
++ *vp_size += int_part < *vp_offset ? int_part : *vp_offset;
++ *vp_offset -= int_part < *vp_offset ? int_part : *vp_offset;
+ }
+
+ /* Adjust for viewport end clip-off */
+- if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) {
++ if ((*vp_offset + *vp_size) < src_size) {
+ int int_part;
+- int end_offset = src.x + src.width
+- - data->viewport.x - data->viewport.width;
++ int end_offset = src_size - *vp_offset - *vp_size;
+
+ /*
+ * this is init if vp had no offset, keep in mind this is from the
+ * right side of vp due to scan direction
+ */
+- data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int(
+- data->ratios.horz, data->recout.x - recout_full->x));
++ *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip));
+ /*
+ * this is the difference between first pixel of viewport available to read
+ * and init position, takning into account scan direction
+ */
+- int_part = dc_fixpt_floor(data->inits.h) - end_offset;
+- if (int_part < data->taps.h_taps) {
+- int int_adj = end_offset >= (data->taps.h_taps - int_part) ?
+- (data->taps.h_taps - int_part) : end_offset;
+- data->viewport.width += int_adj;
++ int_part = dc_fixpt_floor(*init) - end_offset;
++ if (int_part < taps) {
++ int int_adj = end_offset >= (taps - int_part) ?
++ (taps - int_part) : end_offset;
++ *vp_size += int_adj;
+ int_part += int_adj;
+- } else if (int_part > data->taps.h_taps) {
+- data->viewport.width += int_part - data->taps.h_taps;
+- int_part = data->taps.h_taps;
++ } else if (int_part > taps) {
++ *vp_size += int_part - taps;
++ int_part = taps;
+ }
+- data->inits.h.value &= 0xffffffff;
+- data->inits.h = dc_fixpt_add_int(data->inits.h, int_part);
++ init->value &= 0xffffffff;
++ *init = dc_fixpt_add_int(*init, int_part);
+ }
+-
+- if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) {
+- int int_part;
+- int end_offset = (src.x + src.width) / vpc_div
+- - data->viewport_c.x - data->viewport_c.width;
+-
+- /*
+- * this is init if vp had no offset, keep in mind this is from the
+- * right side of vp due to scan direction
+- */
+- data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int(
+- data->ratios.horz_c, data->recout.x - recout_full->x));
+- /*
+- * this is the difference between first pixel of viewport available to read
+- * and init position, takning into account scan direction
+- */
+- int_part = dc_fixpt_floor(data->inits.h_c) - end_offset;
+- if (int_part < data->taps.h_taps_c) {
+- int int_adj = end_offset >= (data->taps.h_taps_c - int_part) ?
+- (data->taps.h_taps_c - int_part) : end_offset;
+- data->viewport_c.width += int_adj;
+- int_part += int_adj;
+- } else if (int_part > data->taps.h_taps_c) {
+- data->viewport_c.width += int_part - data->taps.h_taps_c;
+- int_part = data->taps.h_taps_c;
+- }
+- data->inits.h_c.value &= 0xffffffff;
+- data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part);
+- }
+-
+ }
+- if (!flip_vert_scan_dir) {
+- /* Adjust for viewport end clip-off */
+- if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) {
+- int vp_clip = src.y + src.height - data->viewport.height - data->viewport.y;
+- int int_part = dc_fixpt_floor(
+- dc_fixpt_sub(data->inits.v, data->ratios.vert));
+-
+- int_part = int_part > 0 ? int_part : 0;
+- data->viewport.height += int_part < vp_clip ? int_part : vp_clip;
+- }
+- if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) {
+- int vp_clip = (src.y + src.height) / vpc_div -
+- data->viewport_c.height - data->viewport_c.y;
+- int int_part = dc_fixpt_floor(
+- dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c));
+-
+- int_part = int_part > 0 ? int_part : 0;
+- data->viewport_c.height += int_part < vp_clip ? int_part : vp_clip;
+- }
+-
+- /* Adjust for non-0 viewport offset */
+- if (data->viewport.y) {
+- int int_part;
+-
+- data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int(
+- data->ratios.vert, data->recout.y - recout_full->y));
+- int_part = dc_fixpt_floor(data->inits.v) - data->viewport.y;
+- if (int_part < data->taps.v_taps) {
+- int int_adj = data->viewport.y >= (data->taps.v_taps - int_part) ?
+- (data->taps.v_taps - int_part) : data->viewport.y;
+- data->viewport.y -= int_adj;
+- data->viewport.height += int_adj;
+- int_part += int_adj;
+- } else if (int_part > data->taps.v_taps) {
+- data->viewport.y += int_part - data->taps.v_taps;
+- data->viewport.height -= int_part - data->taps.v_taps;
+- int_part = data->taps.v_taps;
+- }
+- data->inits.v.value &= 0xffffffff;
+- data->inits.v = dc_fixpt_add_int(data->inits.v, int_part);
+- }
+-
+- if (data->viewport_c.y) {
+- int int_part;
++}
+
+- data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int(
+- data->ratios.vert_c, data->recout.y - recout_full->y));
+- int_part = dc_fixpt_floor(data->inits.v_c) - data->viewport_c.y;
+- if (int_part < data->taps.v_taps_c) {
+- int int_adj = data->viewport_c.y >= (data->taps.v_taps_c - int_part) ?
+- (data->taps.v_taps_c - int_part) : data->viewport_c.y;
+- data->viewport_c.y -= int_adj;
+- data->viewport_c.height += int_adj;
+- int_part += int_adj;
+- } else if (int_part > data->taps.v_taps_c) {
+- data->viewport_c.y += int_part - data->taps.v_taps_c;
+- data->viewport_c.height -= int_part - data->taps.v_taps_c;
+- int_part = data->taps.v_taps_c;
+- }
+- data->inits.v_c.value &= 0xffffffff;
+- data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part);
+- }
+- } else {
+- /* Adjust for non-0 viewport offset */
+- if (data->viewport.y) {
+- int int_part = dc_fixpt_floor(
+- dc_fixpt_sub(data->inits.v, data->ratios.vert));
++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 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;
++ int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
++ || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
++ bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
+
+- int_part = int_part > 0 ? int_part : 0;
+- data->viewport.height += int_part < data->viewport.y ? int_part : data->viewport.y;
+- data->viewport.y -= int_part < data->viewport.y ? int_part : data->viewport.y;
+- }
+- if (data->viewport_c.y) {
+- int int_part = dc_fixpt_floor(
+- dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c));
++ /*
++ * Need to calculate the scan direction for viewport to make adjustments
++ */
++ get_vp_scan_direction(
++ plane_state->rotation,
++ plane_state->horizontal_mirror,
++ &orthogonal_rotation,
++ &flip_vert_scan_dir,
++ &flip_horz_scan_dir);
++
++ /* Calculate src rect rotation adjusted to recout space */
++ surf_size_h = src.x + src.width;
++ surf_size_v = src.y + src.height;
++ if (flip_horz_scan_dir)
++ src.x = 0;
++ if (flip_vert_scan_dir)
++ src.y = 0;
++ if (orthogonal_rotation) {
++ swap(src.x, src.y);
++ swap(src.width, src.height);
++ }
+
+- int_part = int_part > 0 ? int_part : 0;
+- data->viewport_c.height += int_part < data->viewport_c.y ? int_part : data->viewport_c.y;
+- data->viewport_c.y -= int_part < data->viewport_c.y ? int_part : data->viewport_c.y;
+- }
++ /* Recout matching initial vp offset = recout_offset - (stream dst offset +
++ * ((surf dst offset - stream src offset) * 1/ stream scaling ratio)
++ * - (surf surf_src offset * 1/ full scl ratio))
++ */
++ recout_skip_h = data->recout.x - (stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
++ * stream->dst.width / stream->src.width -
++ src.x * plane_state->dst_rect.width / src.width
++ * stream->dst.width / stream->src.width);
++ 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
++ * stream->dst.height / stream->src.height);
++ if (orthogonal_rotation)
++ swap(recout_skip_h, recout_skip_v);
++ /*
++ * Init calculated according to formula:
++ * init = (scaling_ratio + number_of_taps + 1) / 2
++ * init_bot = init + scaling_ratio
++ * init_c = init + truncated_vp_c_offset(from calculate viewport)
++ */
++ data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int(
++ dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19);
+
+- /* Adjust for viewport end clip-off */
+- if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) {
+- int int_part;
+- int end_offset = src.y + src.height
+- - data->viewport.y - data->viewport.height;
++ data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int(
++ dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19);
+
+- /*
+- * this is init if vp had no offset, keep in mind this is from the
+- * right side of vp due to scan direction
+- */
+- data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int(
+- data->ratios.vert, data->recout.y - recout_full->y));
+- /*
+- * this is the difference between first pixel of viewport available to read
+- * and init position, taking into account scan direction
+- */
+- int_part = dc_fixpt_floor(data->inits.v) - end_offset;
+- if (int_part < data->taps.v_taps) {
+- int int_adj = end_offset >= (data->taps.v_taps - int_part) ?
+- (data->taps.v_taps - int_part) : end_offset;
+- data->viewport.height += int_adj;
+- int_part += int_adj;
+- } else if (int_part > data->taps.v_taps) {
+- data->viewport.height += int_part - data->taps.v_taps;
+- int_part = data->taps.v_taps;
+- }
+- data->inits.v.value &= 0xffffffff;
+- data->inits.v = dc_fixpt_add_int(data->inits.v, int_part);
+- }
++ data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int(
++ dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19);
+
+- if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) {
+- int int_part;
+- int end_offset = (src.y + src.height) / vpc_div
+- - data->viewport_c.y - data->viewport_c.height;
++ data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int(
++ dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19);
+
+- /*
+- * this is init if vp had no offset, keep in mind this is from the
+- * right side of vp due to scan direction
+- */
+- data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int(
+- data->ratios.vert_c, data->recout.y - recout_full->y));
+- /*
+- * this is the difference between first pixel of viewport available to read
+- * and init position, taking into account scan direction
+- */
+- int_part = dc_fixpt_floor(data->inits.v_c) - end_offset;
+- if (int_part < data->taps.v_taps_c) {
+- int int_adj = end_offset >= (data->taps.v_taps_c - int_part) ?
+- (data->taps.v_taps_c - int_part) : end_offset;
+- data->viewport_c.height += int_adj;
+- int_part += int_adj;
+- } else if (int_part > data->taps.v_taps_c) {
+- data->viewport_c.height += int_part - data->taps.v_taps_c;
+- int_part = data->taps.v_taps_c;
+- }
+- data->inits.v_c.value &= 0xffffffff;
+- data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part);
+- }
+- }
++ /*
++ * Taps, inits and scaling ratios are in recout space need to rotate
++ * to viewport rotation before adjustment
++ */
++ adjust_vp_and_init_for_seamless_clip(
++ flip_horz_scan_dir,
++ recout_skip_h,
++ surf_size_h,
++ orthogonal_rotation ? data->taps.v_taps : data->taps.h_taps,
++ orthogonal_rotation ? data->ratios.vert : data->ratios.horz,
++ orthogonal_rotation ? &data->inits.v : &data->inits.h,
++ &data->viewport.x,
++ &data->viewport.width);
++ adjust_vp_and_init_for_seamless_clip(
++ flip_horz_scan_dir,
++ recout_skip_h,
++ surf_size_h / vpc_div,
++ orthogonal_rotation ? data->taps.v_taps_c : data->taps.h_taps_c,
++ orthogonal_rotation ? data->ratios.vert_c : data->ratios.horz_c,
++ orthogonal_rotation ? &data->inits.v_c : &data->inits.h_c,
++ &data->viewport_c.x,
++ &data->viewport_c.width);
++ adjust_vp_and_init_for_seamless_clip(
++ flip_vert_scan_dir,
++ recout_skip_v,
++ surf_size_v,
++ orthogonal_rotation ? data->taps.h_taps : data->taps.v_taps,
++ orthogonal_rotation ? data->ratios.horz : data->ratios.vert,
++ orthogonal_rotation ? &data->inits.h : &data->inits.v,
++ &data->viewport.y,
++ &data->viewport.height);
++ adjust_vp_and_init_for_seamless_clip(
++ flip_vert_scan_dir,
++ recout_skip_v,
++ surf_size_v / vpc_div,
++ orthogonal_rotation ? data->taps.h_taps_c : data->taps.v_taps_c,
++ orthogonal_rotation ? data->ratios.horz_c : data->ratios.vert_c,
++ orthogonal_rotation ? &data->inits.h_c : &data->inits.v_c,
++ &data->viewport_c.y,
++ &data->viewport_c.height);
+
+ /* Interlaced inits based on final vert inits */
+ data->inits.v_bot = dc_fixpt_add(data->inits.v, data->ratios.vert);
+ data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c);
+
+- if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
+- pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
+- rect_swap_helper(&data->viewport_c);
+- rect_swap_helper(&data->viewport);
+- }
+ }
+
+ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
+ {
+ const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
+ struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
+- struct rect recout_full = { 0 };
+ bool res = false;
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+ /* Important: scaling ratio calculation requires pixel format,
+@@ -1105,7 +931,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
+ if (pipe_ctx->plane_res.scl_data.viewport.height < 16 || pipe_ctx->plane_res.scl_data.viewport.width < 16)
+ return false;
+
+- calculate_recout(pipe_ctx, &recout_full);
++ calculate_recout(pipe_ctx);
+
+ /**
+ * Setting line buffer pixel depth to 24bpp yields banding
+@@ -1146,7 +972,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
+
+ if (res)
+ /* May need to re-check lb size after this in some obscure scenario */
+- calculate_inits_and_adj_vp(pipe_ctx, &recout_full);
++ calculate_inits_and_adj_vp(pipe_ctx);
+
+ DC_LOG_SCALER(
+ "%s: Viewport:\nheight:%d width:%d x:%d "
+--
+2.17.1
+