/* * Copyright 2023 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD *
*/ #include"dc_types.h" #include"core_types.h" #include"core_status.h" #include"dc_state.h" #include"dc_state_priv.h" #include"dc_stream_priv.h" #include"dc_plane_priv.h"
staticbool dc_state_untrack_phantom_stream(struct dc_state *state, struct dc_stream_state *phantom_stream)
{ bool res = false; int i;
/* first find phantom stream in the dc_state */ for (i = 0; i < state->phantom_stream_count; i++) { if (state->phantom_streams[i] == phantom_stream) {
state->phantom_streams[i] = NULL;
res = true; break;
}
}
/* failed to find stream in state */ if (!res) return res;
/* trim back phantom streams */
state->phantom_stream_count--; for (; i < state->phantom_stream_count; i++)
state->phantom_streams[i] = state->phantom_streams[i + 1];
return res;
}
staticbool dc_state_is_phantom_stream_tracked(struct dc_state *state, struct dc_stream_state *phantom_stream)
{ int i;
for (i = 0; i < state->phantom_stream_count; i++) { if (state->phantom_streams[i] == phantom_stream) returntrue;
}
staticbool dc_state_untrack_phantom_plane(struct dc_state *state, struct dc_plane_state *phantom_plane)
{ bool res = false; int i;
/* first find phantom plane in the dc_state */ for (i = 0; i < state->phantom_plane_count; i++) { if (state->phantom_planes[i] == phantom_plane) {
state->phantom_planes[i] = NULL;
res = true; break;
}
}
/* failed to find plane in state */ if (!res) return res;
/* trim back phantom planes */
state->phantom_plane_count--; for (; i < state->phantom_plane_count; i++)
state->phantom_planes[i] = state->phantom_planes[i + 1];
return res;
}
staticbool dc_state_is_phantom_plane_tracked(struct dc_state *state, struct dc_plane_state *phantom_plane)
{ int i;
for (i = 0; i < state->phantom_plane_count; i++) { if (state->phantom_planes[i] == phantom_plane) returntrue;
}
returnfalse;
}
staticvoid dc_state_copy_internal(struct dc_state *dst_state, struct dc_state *src_state)
{ int i, j;
for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *cur_pipe = &dst_state->res_ctx.pipe_ctx[i];
if (cur_pipe->top_pipe)
cur_pipe->top_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
if (cur_pipe->bottom_pipe)
cur_pipe->bottom_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
if (cur_pipe->prev_odm_pipe)
cur_pipe->prev_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
if (cur_pipe->next_odm_pipe)
cur_pipe->next_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
}
/* retain phantoms */ for (i = 0; i < dst_state->phantom_stream_count; i++)
dc_stream_retain(dst_state->phantom_streams[i]);
for (i = 0; i < dst_state->phantom_plane_count; i++)
dc_plane_state_retain(dst_state->phantom_planes[i]);
/* retain streams and planes */ for (i = 0; i < dst_state->stream_count; i++) {
dc_stream_retain(dst_state->streams[i]); for (j = 0; j < dst_state->stream_status[i].plane_count; j++)
dc_plane_state_retain(
dst_state->stream_status[i].plane_states[j]);
}
}
staticvoid init_state(struct dc *dc, struct dc_state *state)
{ /* Each context must have their own instance of VBA and in order to * initialize and obtain IP and SOC the base DML instance from DC is * initially copied into every context
*/
memcpy(&state->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib));
}
/* Public dc_state functions */ struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params)
{ struct dc_state *state;
state = kvzalloc(sizeof(struct dc_state), GFP_KERNEL);
/* Initialise DIG link encoder resource tracking variables. */ if (dc->res_pool)
link_enc_cfg_init(dc, state);
}
void dc_state_destruct(struct dc_state *state)
{ int i, j;
for (i = 0; i < state->stream_count; i++) { for (j = 0; j < state->stream_status[i].plane_count; j++)
dc_plane_state_release(
state->stream_status[i].plane_states[j]);
staticvoid remove_mpc_combine_for_stream(conststruct dc *dc, struct dc_state *new_ctx, conststruct dc_state *cur_ctx, struct dc_stream_status *status)
{ int i;
for (i = 0; i < status->plane_count; i++)
resource_update_pipes_for_plane_with_slice_count(
new_ctx, cur_ctx, dc->res_pool,
status->plane_states[i], 1);
}
stream_status = dc_state_get_stream_status(state, stream);
otg_master_pipe = resource_get_otg_master_for_stream(
&state->res_ctx, stream); if (stream_status == NULL) {
dm_error("Existing stream not found; failed to attach surface!\n"); goto out;
} elseif (stream_status->plane_count == MAX_SURFACES) {
dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
plane_state, MAX_SURFACES); goto out;
} elseif (!otg_master_pipe) { goto out;
}
added = resource_append_dpp_pipes_for_plane_composition(state,
dc->current_state, pool, otg_master_pipe, plane_state);
if (!added) { /* try to remove MPC combine to free up pipes */ for (i = 0; i < state->stream_count; i++)
remove_mpc_combine_for_stream(dc, state,
dc->current_state,
&state->stream_status[i]);
added = resource_append_dpp_pipes_for_plane_composition(state,
dc->current_state, pool,
otg_master_pipe, plane_state);
}
if (!added) { /* try to decrease ODM slice count gradually to free up pipes */
odm_slice_count = resource_get_odm_slice_count(otg_master_pipe); for (i = odm_slice_count - 1; i > 0; i--) {
resource_update_pipes_for_stream_with_slice_count(state,
dc->current_state, dc->res_pool, stream,
i);
added = resource_append_dpp_pipes_for_plane_composition(
state,
dc->current_state, pool,
otg_master_pipe, plane_state); if (added) break;
}
}
if (added) {
stream_status->plane_states[stream_status->plane_count] =
plane_state;
stream_status->plane_count++;
dc_plane_state_retain(plane_state);
}
for (i = 0; i < state->stream_count; i++) if (state->streams[i] == stream) {
stream_status = &state->stream_status[i]; break;
}
if (stream_status == NULL) {
dm_error("Existing stream not found; failed to remove plane.\n"); returnfalse;
}
resource_remove_dpp_pipes_for_plane_composition(
state, pool, plane_state);
for (i = 0; i < stream_status->plane_count; i++) { if (stream_status->plane_states[i] == plane_state) {
dc_plane_state_release(stream_status->plane_states[i]); break;
}
}
if (i == stream_status->plane_count) {
dm_error("Existing plane_state not found; failed to detach it!\n"); returnfalse;
}
stream_status->plane_count--;
/* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */ for (; i < stream_status->plane_count; i++)
stream_status->plane_states[i] = stream_status->plane_states[i + 1];
/** * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream. * * @dc: Current dc state. * @stream: Target stream, which we want to remove the attached plans. * @state: context from which the planes are to be removed. * * Return: * Return true if DC was able to remove all planes from the target * stream, otherwise, return false.
*/ bool dc_state_rem_all_planes_for_stream( conststruct dc *dc, struct dc_stream_state *stream, struct dc_state *state)
{ int i, old_plane_count; struct dc_stream_status *stream_status = NULL; struct dc_plane_state *del_planes[MAX_SURFACES] = { 0 };
for (i = 0; i < state->stream_count; i++) if (state->streams[i] == stream) {
stream_status = &state->stream_status[i]; break;
}
if (stream_status == NULL) {
dm_error("Existing stream %p not found!\n", stream); returnfalse;
}
old_plane_count = stream_status->plane_count;
for (i = 0; i < old_plane_count; i++)
del_planes[i] = stream_status->plane_states[i];
for (i = 0; i < old_plane_count; i++) if (!dc_state_remove_plane(dc, stream, del_planes[i], state)) returnfalse;
returntrue;
}
bool dc_state_add_all_planes_for_stream( conststruct dc *dc, struct dc_stream_state *stream, struct dc_plane_state * const *plane_states, int plane_count, struct dc_state *state)
{ int i; bool result = true;
for (i = 0; i < plane_count; i++) if (!dc_state_add_plane(dc, stream, plane_states[i], state)) {
result = false; break;
}
return result;
}
/* Private dc_state functions */
/** * dc_state_get_stream_status - Get stream status from given dc state * @state: DC state to find the stream status in * @stream: The stream to get the stream status for * * The given stream is expected to exist in the given dc state. Otherwise, NULL * will be returned.
*/ struct dc_stream_status *dc_state_get_stream_status( struct dc_state *state, conststruct dc_stream_state *stream)
{
uint8_t i;
if (state == NULL) return NULL;
for (i = 0; i < state->stream_count; i++) { if (stream == state->streams[i]) return &state->stream_status[i];
}
for (i = 0; i < state->stream_count; i++) { if (state->streams[i] == stream) {
paired_stream = state->stream_status[i].mall_stream_config.paired_stream; break;
}
}
if (!dc_state_untrack_phantom_stream(state, phantom_stream)) {
DC_LOG_ERROR("Failed to free phantom stream %p in dc state %p.\n", phantom_stream, state); return;
}
if (!dc_state_untrack_phantom_plane(state, phantom_plane)) {
DC_LOG_ERROR("Failed to free phantom plane %p in dc state %p.\n", phantom_plane, state); return;
}
dc_plane_state_release(phantom_plane);
}
/* add phantom streams to context and generate correct meta inside dc_state */ enum dc_status dc_state_add_phantom_stream(conststruct dc *dc, struct dc_state *state, struct dc_stream_state *phantom_stream, struct dc_stream_state *main_stream)
{ struct dc_stream_status *main_stream_status; struct dc_stream_status *phantom_stream_status; enum dc_status res = dc_state_add_stream(dc, state, phantom_stream);
/* check if stream is tracked */ if (res == DC_OK && !dc_state_is_phantom_stream_tracked(state, phantom_stream)) { /* stream must be tracked if added to state */
dc_state_track_phantom_stream(state, phantom_stream);
}
/* setup subvp meta */
main_stream_status = dc_state_get_stream_status(state, main_stream); if (main_stream_status) {
main_stream_status->mall_stream_config.type = SUBVP_MAIN;
main_stream_status->mall_stream_config.paired_stream = phantom_stream;
}
/* check if stream is tracked */ if (res && !dc_state_is_phantom_plane_tracked(state, phantom_plane)) { /* stream must be tracked if added to state */
dc_state_track_phantom_plane(state, phantom_plane);
}
bool dc_state_rem_all_phantom_planes_for_stream( conststruct dc *dc, struct dc_stream_state *phantom_stream, struct dc_state *state, bool should_release_planes)
{ int i, old_plane_count; struct dc_stream_status *stream_status = NULL; struct dc_plane_state *del_planes[MAX_SURFACES] = { 0 };
for (i = 0; i < state->stream_count; i++) if (state->streams[i] == phantom_stream) {
stream_status = &state->stream_status[i]; break;
}
if (stream_status == NULL) {
dm_error("Existing stream %p not found!\n", phantom_stream); returnfalse;
}
old_plane_count = stream_status->plane_count;
for (i = 0; i < old_plane_count; i++)
del_planes[i] = stream_status->plane_states[i];
for (i = 0; i < old_plane_count; i++) { if (!dc_state_remove_plane(dc, phantom_stream, del_planes[i], state)) returnfalse; if (should_release_planes)
dc_state_release_phantom_plane(dc, state, del_planes[i]);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.