mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
drm/amd/display: Fix windowed MPO video with ODM combine for DCN32
[Why] In single display configuration, windowed MPO does not work with ODM combine. [How] For ODM + MPO window on one half of ODM, only 3 pipes should be allocated and scaling parameters adjusted to handle this case. Otherwise, we use 4 pipes. Move copy_surface_update_to_plane() before dc_add_plane_to_context() so that it gets the updated rect information when setting up the pipes. Add dc_check_boundary_crossing_for_windowed_mpo_with_odm() to force a full update when we cross a boundary requiring us to reconfigure the number of pipes between 3 and 4 pipes. Set config.enable_windowed_mpo_odm to true when we have the debug.enable_single_display_2to1_odm_policy set to true. Don't fail validating ODM with windowed MPO if config.enable_windowed_mpo_odm is true. Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Solomon Chiu <solomon.chiu@amd.com> Signed-off-by: Samson Tam <Samson.Tam@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
149f6d1a60
commit
9dfc3ee1b0
|
|
@ -2415,6 +2415,96 @@ static enum surface_update_type check_update_surfaces_for_stream(
|
|||
return overall_type;
|
||||
}
|
||||
|
||||
static bool dc_check_is_fullscreen_video(struct rect src, struct rect clip_rect)
|
||||
{
|
||||
int view_height, view_width, clip_x, clip_y, clip_width, clip_height;
|
||||
|
||||
view_height = src.height;
|
||||
view_width = src.width;
|
||||
|
||||
clip_x = clip_rect.x;
|
||||
clip_y = clip_rect.y;
|
||||
|
||||
clip_width = clip_rect.width;
|
||||
clip_height = clip_rect.height;
|
||||
|
||||
/* check for centered video accounting for off by 1 scaling truncation */
|
||||
if ((view_height - clip_y - clip_height <= clip_y + 1) &&
|
||||
(view_width - clip_x - clip_width <= clip_x + 1) &&
|
||||
(view_height - clip_y - clip_height >= clip_y - 1) &&
|
||||
(view_width - clip_x - clip_width >= clip_x - 1)) {
|
||||
|
||||
/* when OS scales up/down to letter box, it may end up
|
||||
* with few blank pixels on the border due to truncating.
|
||||
* Add offset margin to account for this
|
||||
*/
|
||||
if (clip_x <= 4 || clip_y <= 4)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum surface_update_type check_boundary_crossing_for_windowed_mpo_with_odm(struct dc *dc,
|
||||
struct dc_surface_update *srf_updates, int surface_count,
|
||||
enum surface_update_type update_type)
|
||||
{
|
||||
enum surface_update_type new_update_type = update_type;
|
||||
int i, j;
|
||||
struct pipe_ctx *pipe = NULL;
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
/* Check that we are in windowed MPO with ODM
|
||||
* - look for MPO pipe by scanning pipes for first pipe matching
|
||||
* surface that has moved ( position change )
|
||||
* - MPO pipe will have top pipe
|
||||
* - check that top pipe has ODM pointer
|
||||
*/
|
||||
if ((surface_count > 1) && dc->config.enable_windowed_mpo_odm) {
|
||||
for (i = 0; i < surface_count; i++) {
|
||||
if (srf_updates[i].surface && srf_updates[i].scaling_info
|
||||
&& srf_updates[i].surface->update_flags.bits.position_change) {
|
||||
|
||||
for (j = 0; j < dc->res_pool->pipe_count; j++) {
|
||||
if (srf_updates[i].surface == dc->current_state->res_ctx.pipe_ctx[j].plane_state) {
|
||||
pipe = &dc->current_state->res_ctx.pipe_ctx[j];
|
||||
stream = pipe->stream;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pipe && pipe->top_pipe && (get_num_odm_splits(pipe->top_pipe) > 0) && stream
|
||||
&& !dc_check_is_fullscreen_video(stream->src, srf_updates[i].scaling_info->clip_rect)) {
|
||||
struct rect old_clip_rect, new_clip_rect;
|
||||
bool old_clip_rect_left, old_clip_rect_right, old_clip_rect_middle;
|
||||
bool new_clip_rect_left, new_clip_rect_right, new_clip_rect_middle;
|
||||
|
||||
old_clip_rect = srf_updates[i].surface->clip_rect;
|
||||
new_clip_rect = srf_updates[i].scaling_info->clip_rect;
|
||||
|
||||
old_clip_rect_left = ((old_clip_rect.x + old_clip_rect.width) <= (stream->src.x + (stream->src.width/2)));
|
||||
old_clip_rect_right = (old_clip_rect.x >= (stream->src.x + (stream->src.width/2)));
|
||||
old_clip_rect_middle = !old_clip_rect_left && !old_clip_rect_right;
|
||||
|
||||
new_clip_rect_left = ((new_clip_rect.x + new_clip_rect.width) <= (stream->src.x + (stream->src.width/2)));
|
||||
new_clip_rect_right = (new_clip_rect.x >= (stream->src.x + (stream->src.width/2)));
|
||||
new_clip_rect_middle = !new_clip_rect_left && !new_clip_rect_right;
|
||||
|
||||
if (old_clip_rect_left && new_clip_rect_middle)
|
||||
new_update_type = UPDATE_TYPE_FULL;
|
||||
else if (old_clip_rect_middle && new_clip_rect_right)
|
||||
new_update_type = UPDATE_TYPE_FULL;
|
||||
else if (old_clip_rect_right && new_clip_rect_middle)
|
||||
new_update_type = UPDATE_TYPE_FULL;
|
||||
else if (old_clip_rect_middle && new_clip_rect_left)
|
||||
new_update_type = UPDATE_TYPE_FULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new_update_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* dc_check_update_surfaces_for_stream() - Determine update type (fast, med, or full)
|
||||
*
|
||||
|
|
@ -2446,6 +2536,10 @@ enum surface_update_type dc_check_update_surfaces_for_stream(
|
|||
updates[i].surface->update_flags.raw = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
if (type == UPDATE_TYPE_MED)
|
||||
type = check_boundary_crossing_for_windowed_mpo_with_odm(dc,
|
||||
updates, surface_count, type);
|
||||
|
||||
if (type == UPDATE_TYPE_FAST) {
|
||||
// If there's an available clock comparator, we use that.
|
||||
if (dc->clk_mgr->funcs->are_clock_states_equal) {
|
||||
|
|
|
|||
|
|
@ -757,6 +757,10 @@ static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *spli
|
|||
(*split_idx)++;
|
||||
split_pipe = split_pipe->top_pipe;
|
||||
}
|
||||
|
||||
/* MPO window on right side of ODM split */
|
||||
if (split_pipe && split_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe)
|
||||
(*split_idx)++;
|
||||
} else {
|
||||
/*Get odm split index*/
|
||||
struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe;
|
||||
|
|
@ -803,7 +807,11 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx)
|
|||
/*
|
||||
* Only the leftmost ODM pipe should be offset by a nonzero distance
|
||||
*/
|
||||
if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) {
|
||||
if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) {
|
||||
/* MPO window on right side of ODM split */
|
||||
data->recout.x = stream->dst.x + (surf_clip.x - stream->src.x - stream->src.width/2) *
|
||||
stream->dst.width / stream->src.width;
|
||||
} else if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) {
|
||||
data->recout.x = stream->dst.x;
|
||||
if (stream->src.x < surf_clip.x)
|
||||
data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width
|
||||
|
|
@ -1001,6 +1009,8 @@ static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
|
|||
* stream->dst.height / stream->src.height;
|
||||
if (pipe_ctx->prev_odm_pipe && split_idx)
|
||||
ro_lb = data->h_active * split_idx - recout_full_x;
|
||||
else if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe)
|
||||
ro_lb = data->h_active * split_idx - recout_full_x + data->recout.x;
|
||||
else
|
||||
ro_lb = data->recout.x - recout_full_x;
|
||||
ro_tb = data->recout.y - recout_full_y;
|
||||
|
|
@ -1106,9 +1116,26 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
|
|||
timing->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)
|
||||
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;
|
||||
|
||||
DC_LOG_SCALER("%s pipe %d: next_odm_pipe:%d prev_odm_pipe:%d\n",
|
||||
__func__,
|
||||
pipe_ctx->pipe_idx,
|
||||
pipe_ctx->next_odm_pipe ? pipe_ctx->next_odm_pipe->pipe_idx : -1,
|
||||
pipe_ctx->prev_odm_pipe ? pipe_ctx->prev_odm_pipe->pipe_idx : -1);
|
||||
} /* ODM + windows MPO, where window is on either right or left ODM half */
|
||||
else if (pipe_ctx->top_pipe && (pipe_ctx->top_pipe->next_odm_pipe || pipe_ctx->top_pipe->prev_odm_pipe)) {
|
||||
|
||||
pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx->top_pipe) + 1;
|
||||
|
||||
DC_LOG_SCALER("%s ODM + windows MPO: pipe:%d top_pipe:%d top_pipe->next_odm_pipe:%d top_pipe->prev_odm_pipe:%d\n",
|
||||
__func__,
|
||||
pipe_ctx->pipe_idx,
|
||||
pipe_ctx->top_pipe->pipe_idx,
|
||||
pipe_ctx->top_pipe->next_odm_pipe ? pipe_ctx->top_pipe->next_odm_pipe->pipe_idx : -1,
|
||||
pipe_ctx->top_pipe->prev_odm_pipe ? pipe_ctx->top_pipe->prev_odm_pipe->pipe_idx : -1);
|
||||
}
|
||||
/* depends on h_active */
|
||||
calculate_recout(pipe_ctx);
|
||||
/* depends on pixel format */
|
||||
|
|
@ -1116,10 +1143,12 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
|
|||
/* depends on scaling ratios and recout, does not calculate offset yet */
|
||||
calculate_viewport_size(pipe_ctx);
|
||||
|
||||
/* Stopgap for validation of ODM + MPO on one side of screen case */
|
||||
if (pipe_ctx->plane_res.scl_data.viewport.height < 1 ||
|
||||
pipe_ctx->plane_res.scl_data.viewport.width < 1)
|
||||
return false;
|
||||
if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) {
|
||||
/* Stopgap for validation of ODM + MPO on one side of screen case */
|
||||
if (pipe_ctx->plane_res.scl_data.viewport.height < 1 ||
|
||||
pipe_ctx->plane_res.scl_data.viewport.width < 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* LB calculations depend on vp size, h/v_active and scaling ratios
|
||||
|
|
@ -1420,6 +1449,7 @@ bool dc_add_plane_to_context(
|
|||
struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe;
|
||||
struct dc_stream_status *stream_status = NULL;
|
||||
|
||||
DC_LOGGER_INIT(stream->ctx->logger);
|
||||
for (i = 0; i < context->stream_count; i++)
|
||||
if (context->streams[i] == stream) {
|
||||
stream_status = &context->stream_status[i];
|
||||
|
|
@ -1466,23 +1496,66 @@ bool dc_add_plane_to_context(
|
|||
if (head_pipe != free_pipe) {
|
||||
tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
|
||||
ASSERT(tail_pipe);
|
||||
free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
|
||||
free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
|
||||
free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
|
||||
free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
|
||||
free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
|
||||
free_pipe->clock_source = tail_pipe->clock_source;
|
||||
free_pipe->top_pipe = tail_pipe;
|
||||
tail_pipe->bottom_pipe = free_pipe;
|
||||
if (!free_pipe->next_odm_pipe && tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) {
|
||||
free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe;
|
||||
tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe;
|
||||
}
|
||||
if (!free_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) {
|
||||
free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
|
||||
tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe;
|
||||
|
||||
/* ODM + window MPO, where MPO window is on right half only */
|
||||
if (free_pipe->plane_state &&
|
||||
(free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2) &&
|
||||
tail_pipe->next_odm_pipe) {
|
||||
|
||||
DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d tail_pipe->next_odm_pipe:%d\n",
|
||||
__func__,
|
||||
free_pipe->pipe_idx,
|
||||
tail_pipe->next_odm_pipe ? tail_pipe->next_odm_pipe->pipe_idx : -1);
|
||||
|
||||
free_pipe->stream_res.tg = tail_pipe->next_odm_pipe->stream_res.tg;
|
||||
free_pipe->stream_res.abm = tail_pipe->next_odm_pipe->stream_res.abm;
|
||||
free_pipe->stream_res.opp = tail_pipe->next_odm_pipe->stream_res.opp;
|
||||
free_pipe->stream_res.stream_enc = tail_pipe->next_odm_pipe->stream_res.stream_enc;
|
||||
free_pipe->stream_res.audio = tail_pipe->next_odm_pipe->stream_res.audio;
|
||||
free_pipe->clock_source = tail_pipe->next_odm_pipe->clock_source;
|
||||
|
||||
free_pipe->top_pipe = tail_pipe->next_odm_pipe;
|
||||
tail_pipe->next_odm_pipe->bottom_pipe = free_pipe;
|
||||
} else {
|
||||
free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
|
||||
free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
|
||||
free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
|
||||
free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
|
||||
free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
|
||||
free_pipe->clock_source = tail_pipe->clock_source;
|
||||
|
||||
free_pipe->top_pipe = tail_pipe;
|
||||
tail_pipe->bottom_pipe = free_pipe;
|
||||
|
||||
if (!free_pipe->next_odm_pipe && tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) {
|
||||
free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe;
|
||||
tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe;
|
||||
}
|
||||
if (!free_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) {
|
||||
free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
|
||||
tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ODM + window MPO, where MPO window is on left half only */
|
||||
if (free_pipe->plane_state &&
|
||||
(free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <=
|
||||
free_pipe->stream->src.x + free_pipe->stream->src.width/2)) {
|
||||
DC_LOG_SCALER("%s - ODM + window MPO(left). free_pipe:%d\n",
|
||||
__func__,
|
||||
free_pipe->pipe_idx);
|
||||
break;
|
||||
}
|
||||
/* ODM + window MPO, where MPO window is on right half only */
|
||||
if (free_pipe->plane_state &&
|
||||
(free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2)) {
|
||||
DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d\n",
|
||||
__func__,
|
||||
free_pipe->pipe_idx);
|
||||
break;
|
||||
}
|
||||
|
||||
head_pipe = head_pipe->next_odm_pipe;
|
||||
}
|
||||
/* assign new surfaces*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user