/* full_mblk_width_ub_l/c = malldml2_mall_phantom.c_alloc_width_blk_aligned_l/c; *full_mblk_height_ub_l/c=mall_alloc_height_blk_aligned_l/c; *num_mblk_l/c=(full_mblk_width_ub_l/c/mblk_width_l/c)*(full_mblk_height_ub_l/c/mblk_height_l/c); *(Shouldbedivisible,butroundupifnot)
*/
num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) *
((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height);
bytes_in_mall = num_mblks * ctx->config.mall_cfg.mblk_size_bytes; // cache lines used is total bytes / cache_line size. Add +2 for worst case alignment // (MALL is 64-byte aligned)
cache_lines_per_plane = bytes_in_mall / ctx->config.mall_cfg.cache_line_size_bytes + 2;
// For DCC we must cache the meat surface, so double cache lines required if (pipe->plane_state->dcc.enable)
cache_lines_per_plane *= 2;
cache_lines_used += cache_lines_per_plane;
}
}
staticvoid merge_pipes_for_subvp(struct dml2_context *ctx, struct dc_state *context)
{ int i;
/* merge pipes if necessary */ for (i = 0; i < ctx->config.dcn_pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
// For now merge all pipes for SubVP since pipe split case isn't supported yet
/* if ODM merge we ignore mpc tree, mpo pipes will have their own flags */ if (pipe->prev_odm_pipe) { /*split off odm pipe*/
pipe->prev_odm_pipe->next_odm_pipe = pipe->next_odm_pipe; if (pipe->next_odm_pipe)
pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe;
for (i = 0; i < ctx->config.dcn_pipe_count; i++) { struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
// Find the minimum pipe split count for non SubVP pipes if (pipe->stream && !pipe->top_pipe &&
ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_NONE) {
split_cnt = 0; while (pipe) {
split_cnt++;
pipe = pipe->bottom_pipe;
}
if (split_cnt < min_pipe_split)
min_pipe_split = split_cnt;
}
}
free_pipes = get_num_free_pipes(ctx, state);
// SubVP only possible if at least one pipe is being used (i.e. free_pipes // should not equal to the pipe_count) if (free_pipes >= min_pipe_split && free_pipes < ctx->config.dcn_pipe_count)
subvp_possible = true;
for (i = 0; i < ctx->config.dcn_pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
uint32_t time_us = 0;
/* Loop to calculate the maximum microschedule time between the two SubVP pipes, *andalsotostorethetwomainSubVPpipepointersinsubvp_pipes[2].
*/ if (pipe->stream && pipe->plane_state && !pipe->top_pipe &&
ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) {
phantom = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, pipe->stream);
microschedule_lines = (phantom->timing.v_total - phantom->timing.v_front_porch) +
phantom->timing.v_addressable;
// Round up when calculating microschedule time (+ 1 at the end)
time_us = (microschedule_lines * phantom->timing.h_total) /
(double)(phantom->timing.pix_clk_100hz * 100) * 1000000 +
ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us +
ctx->config.svp_pstate.subvp_fw_processing_delay_us + 1; if (time_us > max_microschedule_us)
max_microschedule_us = time_us;
// Find SubVP pipe for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
// We check for master pipe, but it shouldn't matter since we only need // the pipe for timing info (stream should be same for any pipe splits) if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe) continue;
// Find the SubVP pipe if (ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) break;
}
/* For SubVP + VBLANK/DRR cases, we assume there can only be *asingleVBLANK/DRRdisplay.IfDMLoutputsSubVP+VBLANK *issupported,itiseitherasingleVBLANKcaseortwoVBLANK *displayswhicharesynchronized(inwhichcasetheyhaveidentical *timings).
*/ for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
pipe_mall_type = ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe);
// We check for master pipe, but it shouldn't matter since we only need // the pipe for timing info (stream should be same for any pipe splits) if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe) continue;
if (!found && pipe_mall_type == SUBVP_NONE) { // Found pipe which is not SubVP or Phantom (i.e. the VBLANK pipe).
vblank_index = i;
found = true;
}
if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN)
subvp_pipe = pipe;
} // Use ignore_msa_timing_param flag to identify as DRR if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) { // SUBVP + DRR case
schedulable = dml2_svp_drr_schedulable(ctx, context, &context->res_ctx.pipe_ctx[vblank_index].stream->timing);
} elseif (found) {
phantom_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, subvp_pipe->stream);
main_timing = &subvp_pipe->stream->timing;
phantom_timing = &phantom_stream->timing;
vblank_timing = &context->res_ctx.pipe_ctx[vblank_index].stream->timing; // Prefetch time is equal to VACTIVE + BP + VSYNC of the phantom pipe // Also include the prefetch end to mallstart delay time
prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total /
(double)(phantom_timing->pix_clk_100hz * 100) * 1000000 +
ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us; // P-State allow width and FW delays already included phantom_timing->v_addressable
mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total /
(double)(phantom_timing->pix_clk_100hz * 100) * 1000000;
vblank_frame_us = vblank_timing->v_total * vblank_timing->h_total /
(double)(vblank_timing->pix_clk_100hz * 100) * 1000000;
vblank_blank_us = (vblank_timing->v_total - vblank_timing->v_addressable) * vblank_timing->h_total /
(double)(vblank_timing->pix_clk_100hz * 100) * 1000000;
subvp_active_us = main_timing->v_addressable * main_timing->h_total /
(double)(main_timing->pix_clk_100hz * 100) * 1000000;
max_vblank_mallregion = vblank_blank_us > mall_region_us ? vblank_blank_us : mall_region_us;
// Schedulable if VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time, // and the max of (VBLANK blanking time, MALL region) // TODO: Possibly add some margin (i.e. the below conditions should be [...] > X instead of [...] > 0) if (subvp_active_us - prefetch_us - vblank_frame_us - max_vblank_mallregion > 0)
schedulable = true;
} return schedulable;
}
for (i = 0, pipe_idx = 0; i < ctx->config.dcn_pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; enum mall_stream_type pipe_mall_type = ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe);
if (!pipe->stream) continue;
if (pipe->plane_state && !pipe->top_pipe &&
pipe_mall_type == SUBVP_MAIN)
subvp_count++;
// Count how many planes that aren't SubVP/phantom are capable of VACTIVE // switching (SubVP + VACTIVE unsupported). In situations where we force // SubVP for a VACTIVE plane, we don't want to increment the vactive_count. if (vba->ActiveDRAMClockChangeLatencyMargin[vba->pipe_plane[pipe_idx]] > 0 &&
pipe_mall_type == SUBVP_NONE) {
vactive_count++;
}
pipe_idx++;
}
if (subvp_count == 2) { // Static schedulability check for SubVP + SubVP case
schedulable = subvp_subvp_schedulable(ctx, context);
} elseif (pstate_change_type == dml_dram_clock_change_vblank_w_mall_sub_vp) { // Static schedulability check for SubVP + VBLANK case. Also handle the case where // DML outputs SubVP + VBLANK + VACTIVE (DML will report as SubVP + VBLANK) if (vactive_count > 0)
schedulable = false; else
schedulable = subvp_vblank_schedulable(ctx, context);
} elseif (pstate_change_type == dml_dram_clock_change_vactive_w_mall_sub_vp &&
vactive_count > 0) { // For single display SubVP cases, DML will output dm_dram_clock_change_vactive_w_mall_sub_vp by default. // We tell the difference between SubVP vs. SubVP + VACTIVE by checking the vactive_count. // SubVP + VACTIVE currently unsupported
schedulable = false;
} return schedulable;
}
// Find DML pipe index (pipe_idx) using dc_pipe_idx for (i = 0, pipe_idx = 0; i < ctx->config.dcn_pipe_count; i++) {
pipe = &state->res_ctx.pipe_ctx[i];
// DML calculation for MALL region doesn't take into account FW delay // and required pstate allow width for multi-display cases /* Add 16 lines margin to the MALL REGION because SUB_VP_START_LINE must be aligned *to2swaths(i.e.16lines)
*/
phantom_vactive = svp_height + pstate_width_fw_delay_lines + ctx->config.svp_pstate.subvp_swath_height_margin_lines;
// The index of the DC pipe passed into this function is guarenteed to // be a valid candidate for SubVP (i.e. has a plane, stream, doesn't // already have phantom pipe assigned, etc.) by previous checks.
phantom_stream = enable_phantom_stream(ctx, state, main_pipe_idx, svp_height, vstartup);
enable_phantom_plane(ctx, state, phantom_stream, main_pipe_idx);
for (i = 0; i < ctx->config.dcn_pipe_count; i++) { struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
// Build scaling params for phantom pipes which were newly added. // We determine which phantom pipes were added by comparing with // the phantom stream. if (pipe->plane_state && pipe->stream && pipe->stream == phantom_stream &&
ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) {
pipe->stream->use_dynamic_meta = false;
pipe->plane_state->flip_immediate = false; if (!ctx->config.svp_pstate.callbacks.build_scaling_params(pipe)) { // Log / remove phantom pipes since failed to build scaling params
}
}
}
}
for (i = 0; i < context->stream_count; i++) if (context->streams[i] == stream) {
stream_status = &context->stream_status[i]; break;
}
if (stream_status == NULL) { 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 (!ctx->config.svp_pstate.callbacks.remove_phantom_plane(ctx->config.svp_pstate.callbacks.dc, stream, del_planes[i], context)) returnfalse;
ctx->config.svp_pstate.callbacks.release_phantom_plane(ctx->config.svp_pstate.callbacks.dc, context, del_planes[i]);
}
if (ctx->config.svp_pstate.force_disable_subvp) returnfalse;
if (!all_pipes_have_stream_and_plane(ctx, state)) returnfalse;
if (mpo_in_use(state)) returnfalse;
merge_pipes_for_subvp(ctx, state); // to re-initialize viewport after the pipe merge for (int i = 0; i < ctx->config.dcn_pipe_count; i++) { struct pipe_ctx *pipe_ctx = &state->res_ctx.pipe_ctx[i];
if (!pipe_ctx->plane_state || !pipe_ctx->stream) continue;
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.