From 9a08f51fa737d6cc167beb98bc21db8821b2dff2 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Thu, 3 May 2018 13:42:43 -0400 Subject: [PATCH] drm/amd/display: upgrade scaler math This change will allow the viewport overlap to apply to rotated/ mirrored surfaces. Viewport overlap results in extra pixels being added to viewport allowing the first few pixels to be scaled as if there is no cut-off(mpo or pipe split) and allows us to get matching crc's between scaled split and unsplit outputs of the same thing. Signed-off-by: Dmytro Laktyushkin Reviewed-by: Charlene Liu Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 419 ++++++++++++------ 1 file changed, 289 insertions(+), 130 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 751f3ac9d921..1d716171e581 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -522,13 +522,12 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx) } } -static void calculate_recout(struct pipe_ctx *pipe_ctx, struct view *recout_skip) +static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full) { 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; - int recout_full_x, recout_full_y; bool pri_split = pipe_ctx->bottom_pipe && pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state; bool sec_split = pipe_ctx->top_pipe && @@ -597,20 +596,22 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct view *recout_skip } } /* 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) + * * 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) + 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) + 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_skip->width = pipe_ctx->plane_res.scl_data.recout.x - recout_full_x; - recout_skip->height = pipe_ctx->plane_res.scl_data.recout.y - recout_full_y; + 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; } static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) @@ -662,7 +663,7 @@ 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 view *recout_skip) +static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct rect *recout_full) { struct scaler_data *data = &pipe_ctx->plane_res.scl_data; struct rect src = pipe_ctx->plane_state->src_rect; @@ -680,15 +681,14 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r 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); - } + } else if (pipe_ctx->plane_state->horizontal_mirror) + flip_horz_scan_dir = !flip_horz_scan_dir; /* * Init calculated according to formula: @@ -708,127 +708,286 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r 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) { + /* 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)); + + int_part = int_part > 0 ? int_part : 0; + data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip; + } - /* Adjust for viewport end clip-off */ - if ((data->viewport.x + data->viewport.width) < (src.x + src.width) && !flip_horz_scan_dir) { - 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.y + data->viewport.height) < (src.y + src.height) && !flip_vert_scan_dir) { - 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.x + data->viewport_c.width) < (src.x + src.width) / vpc_div && !flip_horz_scan_dir) { - 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)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip; - } - if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div && !flip_vert_scan_dir) { - 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.x && !flip_horz_scan_dir) { - int int_part; - - data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int( - data->ratios.horz, recout_skip->width)); - 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; - 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; + /* Adjust for non-0 viewport offset */ + if (data->viewport.x) { + 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; + 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; + } + data->inits.h.value &= 0xffffffff; + data->inits.h = dc_fixpt_add_int(data->inits.h, int_part); } - data->inits.h.value &= 0xffffffff; - data->inits.h = dc_fixpt_add_int(data->inits.h, int_part); - } - - if (data->viewport_c.x && !flip_horz_scan_dir) { - int int_part; - - data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int( - data->ratios.horz_c, recout_skip->width)); - 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; + + 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); } - data->inits.h_c.value &= 0xffffffff; - data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part); - } - - if (data->viewport.y && !flip_vert_scan_dir) { - int int_part; - - data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int( - data->ratios.vert, recout_skip->height)); - 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; + } 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)); + + 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; } - data->inits.v.value &= 0xffffffff; - data->inits.v = dc_fixpt_add_int(data->inits.v, int_part); - } - - if (data->viewport_c.y && !flip_vert_scan_dir) { - int int_part; - - data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int( - data->ratios.vert_c, recout_skip->height)); - 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; + + /* Adjust for viewport end clip-off */ + if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) { + int int_part; + int end_offset = src.x + src.width + - data->viewport.x - data->viewport.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 = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int( + data->ratios.horz, 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) - 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 += 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; + } + data->inits.h.value &= 0xffffffff; + data->inits.h = dc_fixpt_add_int(data->inits.h, 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)); + + 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)); + + 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; + } + + /* 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; + + /* + * 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); + } + + 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; + + /* + * 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); } - data->inits.v_c.value &= 0xffffffff; - data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part); } /* Interlaced inits based on final vert inits */ @@ -846,7 +1005,7 @@ 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 view recout_skip = { 0 }; + struct rect recout_full = { 0 }; bool res = false; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); /* Important: scaling ratio calculation requires pixel format, @@ -866,7 +1025,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_skip); + calculate_recout(pipe_ctx, &recout_full); /** * Setting line buffer pixel depth to 24bpp yields banding @@ -910,7 +1069,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_skip); + calculate_inits_and_adj_vp(pipe_ctx, &recout_full); DC_LOG_SCALER( "%s: Viewport:\nheight:%d width:%d x:%d " -- 2.30.2