Commit 652284d6 authored by Samson Tam's avatar Samson Tam Committed by Alex Deucher

drm/amd/display: Fix lag when moving windowed MPO across display using ODM 2:1 combine

[Why]
With single display odm 2:1 policy, when moving windowed MPO across
 the display, we experience a momentary lag when we move between the
 centre of the display and the right half of the display.  This is
 caused by the MPO pipe being reallocated when it crosses this
 boundary

[How]
Handle two cases:
1. if the head pipe has a MPO pipe already allocated in the old
 context, then use that pipe if it is available in the current
 context
2. if the head pipe is on the left side, check the right side to
 see if it has a MPO pipe already allocated.  If so, don't use
 that pipe if it is selected as the idle pipe in the current
 context
Add new function pointer called .acquire_idle_pipe_for_head_pipe
 that will pass in the head pipe and handle case 1
Add find_idle_secondary_pipe_check_mpo() to handle case 2
 if we don't hit case 1.

In dc_add_plane_to_context(), start with head pipe and check
 case 1 and 2 in call acquire_free_pipe_for_head().
If we are on the right side of the display, check case 1
 again by passing in right side pipe as the new head in
 call acquire_free_pipe_for_head().
Reviewed-by: default avatarDmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Reviewed-by: default avatarAriel Bernstein <Eric.Bernstein@amd.com>
Acked-by: default avatarSolomon Chiu <solomon.chiu@amd.com>
Signed-off-by: default avatarSamson Tam <Samson.Tam@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 2a93292f
......@@ -1397,8 +1397,12 @@ static struct pipe_ctx *acquire_free_pipe_for_head(
* to acquire an idle one to satisfy the request
*/
if (!pool->funcs->acquire_idle_pipe_for_layer)
return NULL;
if (!pool->funcs->acquire_idle_pipe_for_layer) {
if (!pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer)
return NULL;
else
return pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer(context, pool, head_pipe->stream, head_pipe);
}
return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream);
}
......@@ -1448,6 +1452,8 @@ 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;
DC_LOGGER_INIT(stream->ctx->logger);
for (i = 0; i < context->stream_count; i++)
......@@ -1507,6 +1513,28 @@ bool dc_add_plane_to_context(
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
*/
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);
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;
......
......@@ -143,11 +143,38 @@ struct resource_funcs {
struct dc *dc,
struct dc_state *context);
/*
* Acquires a free pipe for the head pipe.
* The head pipe is first pipe in the current context that matches the stream
* and does not have a top pipe or prev_odm_pipe.
*/
struct pipe_ctx *(*acquire_idle_pipe_for_layer)(
struct dc_state *context,
const struct resource_pool *pool,
struct dc_stream_state *stream);
/*
* Acquires a free pipe for the head pipe with some additional checks for odm.
* The head pipe is passed in as an argument unlike acquire_idle_pipe_for_layer
* where it is read from the context. So this allows us look for different
* idle_pipe if the head_pipes are different ( ex. in odm 2:1 when we have
* a left and right pipe ).
*
* It also checks the old context to see if:
*
* 1. a pipe has already been allocated for the head pipe. If so, it will
* try to select that pipe as the idle pipe if it is available in the current
* context.
* 2. if the head_pipe is on the left, it will check if the right pipe has
* a pipe already allocated. If so, it will not use that pipe if it is
* selected as the idle pipe.
*/
struct pipe_ctx *(*acquire_idle_pipe_for_head_pipe_in_layer)(
struct dc_state *context,
const struct resource_pool *pool,
struct dc_stream_state *stream,
struct pipe_ctx *head_pipe);
enum dc_status (*validate_plane)(const struct dc_plane_state *plane_state, struct dc_caps *caps);
enum dc_status (*add_stream_to_ctx)(
......
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