diff options
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.patch | 833 |
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 + |