Commit 460ea898 authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher

drm/amd/display: update add plane to context logic with a new algorithm

[why]
Preivous algorithm for finding an optimal idle pipe for a new plane was
implemented to handle dynamic pipe allocation when MPO plane moves
from one ODM slice to the other. Now pipe allocation is more static so
it no longer depends on the MPO plane's position. We are simplifying
our logic and remove unnecessary handling in our code.

[how]
Apply a new simplified version of pipe resource allocation logic to reduce
unnecessary flip delay caused by swapping secondary dpp pipe to other
MPC blending tree.
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 ca030d83
......@@ -1119,13 +1119,15 @@ static enum dc_status dce110_add_stream_to_ctx(
}
static struct pipe_ctx *dce110_acquire_underlay(
struct dc_state *context,
const struct dc_state *cur_ctx,
struct dc_state *new_ctx,
const struct resource_pool *pool,
struct dc_stream_state *stream)
const struct pipe_ctx *opp_head_pipe)
{
struct dc_stream_state *stream = opp_head_pipe->stream;
struct dc *dc = stream->ctx->dc;
struct dce_hwseq *hws = dc->hwseq;
struct resource_context *res_ctx = &context->res_ctx;
struct resource_context *res_ctx = &new_ctx->res_ctx;
unsigned int underlay_idx = pool->underlay_pipe_index;
struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[underlay_idx];
......@@ -1173,7 +1175,7 @@ static struct pipe_ctx *dce110_acquire_underlay(
stream->timing.h_total,
stream->timing.v_total,
stream->timing.pix_clk_100hz / 10,
context->stream_count);
new_ctx->stream_count);
color_space_to_black_color(dc,
COLOR_SPACE_YCBCR601, &black_color);
......
......@@ -1084,13 +1084,14 @@ static enum dc_status dcn10_add_stream_to_ctx(
}
static struct pipe_ctx *dcn10_acquire_idle_pipe_for_layer(
struct dc_state *context,
const struct dc_state *cur_ctx,
struct dc_state *new_ctx,
const struct resource_pool *pool,
struct dc_stream_state *stream)
const struct pipe_ctx *opp_head_pipe)
{
struct resource_context *res_ctx = &context->res_ctx;
struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
struct pipe_ctx *idle_pipe = find_idle_secondary_pipe(res_ctx, pool, head_pipe);
struct resource_context *res_ctx = &new_ctx->res_ctx;
struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream);
struct pipe_ctx *idle_pipe = find_idle_secondary_pipe_legacy(res_ctx, pool, head_pipe);
if (!head_pipe) {
ASSERT(0);
......
......@@ -2148,13 +2148,14 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context,
}
struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer(
struct dc_state *state,
const struct dc_state *cur_ctx,
struct dc_state *new_ctx,
const struct resource_pool *pool,
struct dc_stream_state *stream)
const struct pipe_ctx *opp_head_pipe)
{
struct resource_context *res_ctx = &state->res_ctx;
struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
struct pipe_ctx *idle_pipe = find_idle_secondary_pipe(res_ctx, pool, head_pipe);
struct resource_context *res_ctx = &new_ctx->res_ctx;
struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream);
struct pipe_ctx *idle_pipe = find_idle_secondary_pipe_legacy(res_ctx, pool, head_pipe);
if (!head_pipe)
ASSERT(0);
......
......@@ -59,9 +59,10 @@ unsigned int dcn20_calc_max_scaled_time(
unsigned int urgent_watermark);
struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer(
struct dc_state *state,
const struct dc_state *cur_ctx,
struct dc_state *new_ctx,
const struct resource_pool *pool,
struct dc_stream_state *stream);
const struct pipe_ctx *opp_head_pipe);
struct stream_encoder *dcn20_stream_encoder_create(
enum engine_id eng_id,
......
......@@ -993,13 +993,14 @@ static struct hubp *dcn201_hubp_create(
}
static struct pipe_ctx *dcn201_acquire_idle_pipe_for_layer(
struct dc_state *context,
const struct dc_state *cur_ctx,
struct dc_state *new_ctx,
const struct resource_pool *pool,
struct dc_stream_state *stream)
const struct pipe_ctx *opp_head_pipe)
{
struct resource_context *res_ctx = &context->res_ctx;
struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
struct pipe_ctx *idle_pipe = find_idle_secondary_pipe(res_ctx, pool, head_pipe);
struct resource_context *res_ctx = &new_ctx->res_ctx;
struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream);
struct pipe_ctx *idle_pipe = find_idle_secondary_pipe_legacy(res_ctx, pool, head_pipe);
if (!head_pipe)
ASSERT(0);
......
......@@ -2038,7 +2038,7 @@ static struct resource_funcs dcn32_res_pool_funcs = {
.validate_bandwidth = dcn32_validate_bandwidth,
.calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg,
.populate_dml_pipes = dcn32_populate_dml_pipes_from_context,
.acquire_idle_pipe_for_head_pipe_in_layer = dcn32_acquire_idle_pipe_for_head_pipe_in_layer,
.acquire_idle_pipe_for_layer = dcn32_acquire_idle_pipe_for_layer,
.add_stream_to_ctx = dcn30_add_stream_to_ctx,
.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
......@@ -2485,108 +2485,31 @@ struct resource_pool *dcn32_create_resource_pool(
return NULL;
}
static struct pipe_ctx *find_idle_secondary_pipe_check_mpo(
struct resource_context *res_ctx,
const struct resource_pool *pool,
const struct pipe_ctx *primary_pipe)
{
int i;
struct pipe_ctx *secondary_pipe = NULL;
struct pipe_ctx *next_odm_mpo_pipe = NULL;
int primary_index, preferred_pipe_idx;
struct pipe_ctx *old_primary_pipe = NULL;
/*
* Modified from find_idle_secondary_pipe
* With windowed MPO and ODM, we want to avoid the case where we want a
* free pipe for the left side but the free pipe is being used on the
* right side.
* Add check on current_state if the primary_pipe is the left side,
* to check the right side ( primary_pipe->next_odm_pipe ) to see if
* it is using a pipe for MPO ( primary_pipe->next_odm_pipe->bottom_pipe )
* - If so, then don't use this pipe
* EXCEPTION - 3 plane ( 2 MPO plane ) case
* - in this case, the primary pipe has already gotten a free pipe for the
* MPO window in the left
* - when it tries to get a free pipe for the MPO window on the right,
* it will see that it is already assigned to the right side
* ( primary_pipe->next_odm_pipe ). But in this case, we want this
* free pipe, since it will be for the right side. So add an
* additional condition, that skipping the free pipe on the right only
* applies if the primary pipe has no bottom pipe currently assigned
*/
if (primary_pipe) {
primary_index = primary_pipe->pipe_idx;
old_primary_pipe = &primary_pipe->stream->ctx->dc->current_state->res_ctx.pipe_ctx[primary_index];
if ((old_primary_pipe->next_odm_pipe) && (old_primary_pipe->next_odm_pipe->bottom_pipe)
&& (!primary_pipe->bottom_pipe))
next_odm_mpo_pipe = old_primary_pipe->next_odm_pipe->bottom_pipe;
preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
if ((res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) &&
!(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == preferred_pipe_idx)) {
secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
secondary_pipe->pipe_idx = preferred_pipe_idx;
}
}
/*
* search backwards for the second pipe to keep pipe
* assignment more consistent
*/
if (!secondary_pipe)
for (i = pool->pipe_count - 1; i >= 0; i--) {
if ((res_ctx->pipe_ctx[i].stream == NULL) &&
!(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == i)) {
secondary_pipe = &res_ctx->pipe_ctx[i];
secondary_pipe->pipe_idx = i;
break;
}
}
return secondary_pipe;
}
struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(
struct dc_state *state,
struct pipe_ctx *dcn32_acquire_idle_pipe_for_layer(
const struct dc_state *cur_ctx,
struct dc_state *new_ctx,
const struct resource_pool *pool,
struct dc_stream_state *stream,
struct pipe_ctx *head_pipe)
const struct pipe_ctx *opp_head_pipe)
{
struct resource_context *res_ctx = &state->res_ctx;
struct pipe_ctx *idle_pipe, *pipe;
struct resource_context *old_ctx = &stream->ctx->dc->current_state->res_ctx;
int head_index;
if (!head_pipe)
ASSERT(0);
/*
* Modified from dcn20_acquire_idle_pipe_for_layer
* Check if head_pipe in old_context already has bottom_pipe allocated.
* - If so, check if that pipe is available in the current context.
* -- If so, reuse pipe from old_context
*/
head_index = head_pipe->pipe_idx;
pipe = &old_ctx->pipe_ctx[head_index];
if (pipe->bottom_pipe && res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx].stream == NULL) {
idle_pipe = &res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx];
idle_pipe->pipe_idx = pipe->bottom_pipe->pipe_idx;
struct pipe_ctx *idle_pipe =
find_optimal_idle_pipe_as_secondary_dpp_pipe(
&cur_ctx->res_ctx, &new_ctx->res_ctx,
pool, opp_head_pipe);
if (idle_pipe) {
idle_pipe->stream = opp_head_pipe->stream;
idle_pipe->stream_res.tg = opp_head_pipe->stream_res.tg;
idle_pipe->stream_res.opp = opp_head_pipe->stream_res.opp;
idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx];
idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx];
idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx];
idle_pipe->plane_res.mpcc_inst =
pool->dpps[idle_pipe->pipe_idx]->inst;
} else {
idle_pipe = find_idle_secondary_pipe_check_mpo(res_ctx, pool, head_pipe);
if (!idle_pipe)
return NULL;
ASSERT(opp_head_pipe);
}
idle_pipe->stream = head_pipe->stream;
idle_pipe->stream_res.tg = head_pipe->stream_res.tg;
idle_pipe->stream_res.opp = head_pipe->stream_res.opp;
idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx];
idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx];
idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx];
idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst;
return idle_pipe;
}
......
......@@ -136,11 +136,11 @@ bool dcn32_any_surfaces_rotated(struct dc *dc, struct dc_state *context);
bool dcn32_is_center_timing(struct pipe_ctx *pipe);
bool dcn32_is_psr_capable(struct pipe_ctx *pipe);
struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(
struct dc_state *state,
struct pipe_ctx *dcn32_acquire_idle_pipe_for_layer(
const struct dc_state *cur_ctx,
struct dc_state *new_ctx,
const struct resource_pool *pool,
struct dc_stream_state *stream,
struct pipe_ctx *head_pipe);
const struct pipe_ctx *opp_head_pipe);
void dcn32_determine_det_override(struct dc *dc,
struct dc_state *context,
......
......@@ -1588,7 +1588,7 @@ static struct resource_funcs dcn321_res_pool_funcs = {
.validate_bandwidth = dcn32_validate_bandwidth,
.calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg,
.populate_dml_pipes = dcn32_populate_dml_pipes_from_context,
.acquire_idle_pipe_for_head_pipe_in_layer = dcn32_acquire_idle_pipe_for_head_pipe_in_layer,
.acquire_idle_pipe_for_layer = dcn32_acquire_idle_pipe_for_layer,
.add_stream_to_ctx = dcn30_add_stream_to_ctx,
.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
......
......@@ -1258,7 +1258,7 @@ bool dcn_validate_bandwidth(
hsplit_pipe->pipe_dlg_param.vblank_end = pipe->pipe_dlg_param.vblank_end;
} else {
/* pipe not split previously needs split */
hsplit_pipe = find_idle_secondary_pipe(&context->res_ctx, pool, pipe);
hsplit_pipe = find_idle_secondary_pipe_legacy(&context->res_ctx, pool, pipe);
ASSERT(hsplit_pipe);
split_stream_across_pipes(&context->res_ctx, pool, pipe, hsplit_pipe);
}
......
......@@ -126,38 +126,24 @@ struct resource_funcs {
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:
* Acquire an idle pipe from context, which could be used as a secondary
* pipe for the otg master pipe associated with the input stream.
*
* 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.
* an idle pipe - a pipe not yet used for any streams or
* planes.
* secondary pipe - a pipe gets inserted to a head OPP pipe's blending
* tree. This is typical used for rendering MPO planes or additional
* offset areas in MPCC combine.
*/
struct pipe_ctx *(*acquire_idle_pipe_for_head_pipe_in_layer)(
struct dc_state *context,
struct pipe_ctx *(*acquire_idle_pipe_for_layer)(
const struct dc_state *cur_ctx,
struct dc_state *new_ctx,
const struct resource_pool *pool,
struct dc_stream_state *stream,
struct pipe_ctx *head_pipe);
const struct pipe_ctx *opp_head_pipe);
enum dc_status (*validate_plane)(const struct dc_plane_state *plane_state, struct dc_caps *caps);
enum dc_status (*validate_plane)(
const struct dc_plane_state *plane_state,
struct dc_caps *caps);
enum dc_status (*add_stream_to_ctx)(
struct dc *dc,
......
......@@ -153,11 +153,17 @@ bool resource_attach_surfaces_to_context(
struct dc_state *context,
const struct resource_pool *pool);
struct pipe_ctx *find_idle_secondary_pipe(
struct pipe_ctx *find_idle_secondary_pipe_legacy(
struct resource_context *res_ctx,
const struct resource_pool *pool,
const struct pipe_ctx *primary_pipe);
struct pipe_ctx *find_optimal_idle_pipe_as_secondary_dpp_pipe(
const struct resource_context *cur_res_ctx,
struct resource_context *new_res_ctx,
const struct resource_pool *pool,
const struct pipe_ctx *new_pri);
bool resource_validate_attach_surfaces(
const struct dc_validation_set set[],
int set_count,
......
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