Commit ca030d83 authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher

drm/amd/display: always acquire MPO pipe for every blending tree

[why]
We only acquire MPO pipe for blending tree where the plane clip will
be rendered. If an MPO plane is outside current ODM slice rect, we will
skip pipe allocation. With new programming policy we want to allocate
pipes for every ODM slice blending tree even for those whose ODM slice
rect doesn't intersect with plane clip. This is aligned with DML validation
so the pipe topology is programmed independently from the plane's
position and dst plane size.

[how]
- Remove the logic to allocate pipe only when the MPO plane intersects
with ODM slice and replace with the new logic to always allocate pipes.
- Remove the logic to tear down ODM configuration in favor for supporting
secondary MPO planes.
- Remove the logic to use full update when MPO goes accross ODM slice
boundary.
Reviewed-by: default avatarJun Lei <jun.lei@amd.com>
Acked-by: default avatarTom Chung <chiahsuan.chung@amd.com>
Signed-off-by: default avatarWenjing Liu <wenjing.liu@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent e75b965e
......@@ -2701,96 +2701,6 @@ 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)
*
......@@ -2822,10 +2732,6 @@ 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) {
......
......@@ -76,7 +76,6 @@
#define DC_LOGGER_INIT(logger)
#define HEAD_NOT_IN_ODM -2
#define UNABLE_TO_SPLIT -1
enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
......@@ -1715,48 +1714,6 @@ static int acquire_first_split_pipe(
split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
split_pipe->pipe_idx = i;
split_pipe->stream = stream;
return i;
} else if (split_pipe->prev_odm_pipe &&
split_pipe->prev_odm_pipe->plane_state == split_pipe->plane_state) {
// Fix case where ODM slice has child planes
// Re-attach child planes
struct pipe_ctx *temp_head_pipe = resource_get_head_pipe_for_stream(res_ctx, split_pipe->stream);
if (split_pipe->bottom_pipe && temp_head_pipe) {
struct pipe_ctx *temp_tail_pipe = resource_get_tail_pipe(res_ctx, temp_head_pipe);
if (temp_tail_pipe) {
split_pipe->bottom_pipe->top_pipe = temp_tail_pipe;
temp_tail_pipe->bottom_pipe = split_pipe->bottom_pipe;
}
}
split_pipe->prev_odm_pipe->next_odm_pipe = split_pipe->next_odm_pipe;
if (split_pipe->next_odm_pipe)
split_pipe->next_odm_pipe->prev_odm_pipe = split_pipe->prev_odm_pipe;
if (split_pipe->prev_odm_pipe->plane_state)
resource_build_scaling_params(split_pipe->prev_odm_pipe);
memset(split_pipe, 0, sizeof(*split_pipe));
// We cannot split if head pipe is not odm
if (temp_head_pipe && !temp_head_pipe->next_odm_pipe && !temp_head_pipe->prev_odm_pipe)
return HEAD_NOT_IN_ODM;
split_pipe->stream_res.tg = pool->timing_generators[i];
split_pipe->plane_res.hubp = pool->hubps[i];
split_pipe->plane_res.ipp = pool->ipps[i];
split_pipe->plane_res.dpp = pool->dpps[i];
split_pipe->stream_res.opp = pool->opps[i];
split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
split_pipe->pipe_idx = i;
split_pipe->stream = stream;
return i;
}
......@@ -1774,9 +1731,6 @@ bool dc_add_plane_to_context(
struct resource_pool *pool = dc->res_pool;
struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe;
struct dc_stream_status *stream_status = NULL;
struct pipe_ctx *prev_right_head = NULL;
struct pipe_ctx *free_right_pipe = NULL;
struct pipe_ctx *prev_left_head = NULL;
DC_LOGGER_INIT(stream->ctx->logger);
for (i = 0; i < context->stream_count; i++)
......@@ -1813,10 +1767,6 @@ bool dc_add_plane_to_context(
int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
if (pipe_idx >= 0)
free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
else if (pipe_idx == HEAD_NOT_IN_ODM)
break;
else
ASSERT(false);
}
if (!free_pipe) {
......@@ -1830,184 +1780,23 @@ bool dc_add_plane_to_context(
tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
ASSERT(tail_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) {
/* For ODM + window MPO, in 3 plane case, if we already have a MPO window on
* the right side, then we will invalidate a 2nd one on the right side
*/
if (head_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) {
dc_plane_state_release(plane_state);
return false;
}
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);
/*
* We want to avoid the case where the right side already has a pipe assigned to
* it and is different from free_pipe ( which would cause trigger a pipe
* reallocation ).
* Check the old context to see if the right side already has a pipe allocated
* - If not, continue to use free_pipe
* - If the right side already has a pipe, use that pipe instead if its available
*/
/*
* We also want to avoid the case where with three plane ( 2 MPO videos ), we have
* both videos on the left side so one of the videos is invalidated. Then we
* move the invalidated video back to the right side. If the order of the plane
* states is such that the right MPO plane is processed first, the free pipe
* selected by the head will be the left MPO pipe. But since there was no right
* MPO pipe, it will assign the free pipe to the right MPO pipe instead and
* a pipe reallocation will occur.
* Check the old context to see if the left side already has a pipe allocated
* - If not, continue to use free_pipe
* - If the left side is already using this pipe, then pick another pipe for right
*/
prev_right_head = &dc->current_state->res_ctx.pipe_ctx[tail_pipe->next_odm_pipe->pipe_idx];
if ((prev_right_head->bottom_pipe) &&
(free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) {
free_right_pipe = acquire_free_pipe_for_head(context, pool, tail_pipe->next_odm_pipe);
} else {
prev_left_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->pipe_idx];
if ((prev_left_head->bottom_pipe) &&
(free_pipe->pipe_idx == prev_left_head->bottom_pipe->pipe_idx)) {
free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
}
}
if (free_right_pipe) {
free_pipe->stream = NULL;
memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource));
memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource));
free_pipe->plane_state = NULL;
free_pipe->pipe_idx = 0;
free_right_pipe->plane_state = plane_state;
free_pipe = free_right_pipe;
}
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 if (free_pipe->plane_state &&
(free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2)
&& head_pipe->next_odm_pipe) {
/* For ODM + window MPO, support 3 plane ( 2 MPO ) case.
* Here we have a desktop ODM + left window MPO and a new MPO window appears
* on the right side only. It fails the first case, because tail_pipe is the
* left window MPO, so it has no next_odm_pipe. So in this scenario, we check
* for head_pipe->next_odm_pipe instead
*/
DC_LOG_SCALER("%s - ODM + win MPO (left) + win MPO (right). free_pipe:%d head_pipe->next_odm:%d\n",
__func__,
free_pipe->pipe_idx,
head_pipe->next_odm_pipe ? head_pipe->next_odm_pipe->pipe_idx : -1);
/*
* We want to avoid the case where the right side already has a pipe assigned to
* it and is different from free_pipe ( which would cause trigger a pipe
* reallocation ).
* Check the old context to see if the right side already has a pipe allocated
* - If not, continue to use free_pipe
* - If the right side already has a pipe, use that pipe instead if its available
*/
prev_right_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->next_odm_pipe->pipe_idx];
if ((prev_right_head->bottom_pipe) &&
(free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) {
free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe->next_odm_pipe);
if (free_right_pipe) {
free_pipe->stream = NULL;
memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource));
memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource));
free_pipe->plane_state = NULL;
free_pipe->pipe_idx = 0;
free_right_pipe->plane_state = plane_state;
free_pipe = free_right_pipe;
}
}
free_pipe->stream_res.tg = head_pipe->next_odm_pipe->stream_res.tg;
free_pipe->stream_res.abm = head_pipe->next_odm_pipe->stream_res.abm;
free_pipe->stream_res.opp = head_pipe->next_odm_pipe->stream_res.opp;
free_pipe->stream_res.stream_enc = head_pipe->next_odm_pipe->stream_res.stream_enc;
free_pipe->stream_res.audio = head_pipe->next_odm_pipe->stream_res.audio;
free_pipe->clock_source = head_pipe->next_odm_pipe->clock_source;
free_pipe->top_pipe = head_pipe->next_odm_pipe;
head_pipe->next_odm_pipe->bottom_pipe = free_pipe;
} else {
/* For ODM + window MPO, in 3 plane case, if we already have a MPO window on
* the left side, then we will invalidate a 2nd one on the left side
*/
if (head_pipe->next_odm_pipe && tail_pipe->top_pipe) {
dc_plane_state_release(plane_state);
return false;
}
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;
/* Connect MPO pipes together if MPO window is in the centre */
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))) {
if (!free_pipe->next_odm_pipe &&
tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe &&
tail_pipe->next_odm_pipe->bottom_pipe->plane_state == free_pipe->plane_state) {
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 &&
tail_pipe->prev_odm_pipe->bottom_pipe->plane_state == free_pipe->plane_state) {
free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_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 (tail_pipe->prev_odm_pipe) {
tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe;
free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_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*/
stream_status->plane_states[stream_status->plane_count] = plane_state;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment