amd/vpelib: Visual Confirm Fix

[WHY]
VPE Visual confirm hanging with color format output due to misalignment.
VPE Visual confirm hanging with performance mode.

[HOW]
Adjust bg segment generation
Adjust per op programming and reset second pipe mux.

Signed-off-by: Roy Chan <roy.chan@amd.com>
Acked-by: Chuanyu Tseng <Chuanyu.Tseng@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40210>
This commit is contained in:
Agate, Jesse 2026-02-02 13:56:13 -05:00 committed by Chuanyu Tseng
parent 4f93449774
commit 852b85ed48
10 changed files with 76 additions and 47 deletions

View file

@ -667,6 +667,7 @@ enum vpe_status vpe10_calculate_segments(
const uint32_t max_downscale_factor = vpe_priv->pub.caps->plane_caps.max_downscale_factor;
struct dpp *dpp = vpe_priv->resource.dpp[0];
const uint32_t max_lb_size = dpp->funcs->get_line_buffer_size();
uint16_t alignment = 1;
for (stream_idx = 0; stream_idx < vpe_priv->num_streams; stream_idx++) {
stream_ctx = &vpe_priv->stream_ctx[stream_idx];
@ -747,7 +748,8 @@ enum vpe_status vpe10_calculate_segments(
if (!gaps)
return VPE_STATUS_NO_MEMORY;
gaps_cnt = vpe_priv->resource.find_bg_gaps(vpe_priv, &(params->target_rect), gaps, max_gaps);
gaps_cnt = vpe_priv->resource.find_bg_gaps(
vpe_priv, &(params->target_rect), gaps, alignment, max_gaps);
if (gaps_cnt > 0)
vpe_priv->resource.create_bg_segments(vpe_priv, gaps, gaps_cnt, VPE_CMD_OPS_BG);

View file

@ -122,36 +122,35 @@ void vpe_create_bg_segments(
}
}
void vpe_full_bg_gaps(struct vpe_rect *gaps, const struct vpe_rect *target_rect, uint16_t max_gaps)
void vpe_full_bg_gaps(struct vpe_rect *gaps, const struct vpe_rect *target_rect, uint32_t alignment,
uint16_t max_gaps)
{
uint16_t gap_index;
int32_t last_covered;
uint32_t gap_width, gap_remainder;
if (max_gaps == 0) {
VPE_ASSERT(0);
return;
}
last_covered = target_rect->x;
gap_width = target_rect->width / max_gaps;
gap_remainder = target_rect->width % max_gaps;
for (gap_index = 0; gap_index < max_gaps; gap_index++) {
gaps[gap_index].x = last_covered;
gaps[gap_index].y = target_rect->y;
gaps[gap_index].width = gap_width;
if (gap_index >= max_gaps - gap_remainder) {
gaps[gap_index].width += 1;
}
gaps[gap_index].height = target_rect->height;
last_covered = last_covered + (int32_t)gaps[gap_index].width;
uint32_t gap_width_unaligned = (target_rect->width / max_gaps);
uint32_t gap_width_aligned = vpe_align_seg(gap_width_unaligned, alignment);
uint32_t start_x = target_rect->x;
for (int i = 0; i < max_gaps - 1; i++) {
gaps[i].x = i * gap_width_aligned + start_x;
gaps[i].width = gap_width_aligned;
gaps[i].y = target_rect->y;
gaps[i].height = target_rect->height;
}
gaps[max_gaps - 1].x = (max_gaps - 1) * gap_width_aligned + start_x;
gaps[max_gaps - 1].width = (start_x + target_rect->width) - gaps[max_gaps - 1].x;
gaps[max_gaps - 1].y = target_rect->y;
gaps[max_gaps - 1].height = target_rect->height;
}
/* calculates the gaps in target_rect which are not covered by the first stream
and returns the number of gaps */
uint16_t vpe_find_bg_gaps(struct vpe_priv *vpe_priv, const struct vpe_rect *target_rect,
struct vpe_rect *gaps, uint16_t max_gaps)
struct vpe_rect *gaps, uint32_t alignment, uint16_t max_gaps)
{
uint16_t num_gaps = 0;
uint16_t bg_index = vpe_priv->resource.get_bg_stream_idx(vpe_priv);
@ -219,6 +218,6 @@ uint16_t vpe_find_bg_gaps(struct vpe_priv *vpe_priv, const struct vpe_rect *targ
return num_gaps;
full_bg:
vpe_full_bg_gaps(gaps, target_rect, max_gaps);
vpe_full_bg_gaps(gaps, target_rect, alignment, max_gaps);
return max_gaps;
}

View file

@ -650,3 +650,18 @@ enum vpe_status vpe_check_blending_support(
return result;
}
// Returns the smallest number greater than (or equal to) seg_size divisible by alignment
uint32_t vpe_align_seg(uint32_t seg_size, uint32_t alignment)
{
VPE_ASSERT(alignment != 0);
uint32_t aligned_size = seg_size;
if (alignment != 0) {
uint32_t rem = seg_size % alignment;
if (rem != 0) {
aligned_size = seg_size + alignment - rem;
}
}
return aligned_size;
}

View file

@ -33,9 +33,10 @@ void vpe_create_bg_segments(
struct vpe_priv *vpe_priv, struct vpe_rect *gaps, uint16_t gaps_cnt, enum vpe_cmd_ops ops);
uint16_t vpe_find_bg_gaps(struct vpe_priv *vpe_priv, const struct vpe_rect *target_rect,
struct vpe_rect *gaps, uint16_t max_gaps);
struct vpe_rect *gaps, uint32_t alignment, uint16_t max_gaps);
void vpe_full_bg_gaps(struct vpe_rect *gaps, const struct vpe_rect *target_rect, uint16_t max_gaps);
void vpe_full_bg_gaps(struct vpe_rect *gaps, const struct vpe_rect *target_rect, uint32_t alignment,
uint16_t max_gaps);
#ifdef __cplusplus
}

View file

@ -105,6 +105,8 @@ enum vpe_status vpe_check_blending_support(
uint8_t vpe_get_element_size_in_bytes(enum vpe_surface_pixel_format format, int plane_idx);
uint32_t vpe_align_seg(uint32_t seg_size, uint32_t alignment);
#ifdef __cplusplus
}
#endif

View file

@ -88,7 +88,7 @@ struct resource {
uint16_t (*get_bg_stream_idx)(struct vpe_priv *vpe_priv);
uint16_t (*find_bg_gaps)(struct vpe_priv *vpe_priv, const struct vpe_rect *target_rect,
struct vpe_rect *gaps, uint16_t max_gaps);
struct vpe_rect *gaps, uint32_t alignment, uint16_t max_gaps);
void (*create_bg_segments)(
struct vpe_priv *vpe_priv, struct vpe_rect *gaps, uint16_t gaps_cnt, enum vpe_cmd_ops ops);
@ -190,6 +190,8 @@ const struct vpe_caps *vpe_get_capability(enum vpe_ip_level ip_level);
void vpe_setup_check_funcs(struct vpe_check_support_funcs *funcs, enum vpe_ip_level ip_level);
uint32_t vpe_get_recout_width_alignment(const struct vpe_build_param *params);
#ifdef __cplusplus
}
#endif

View file

@ -60,6 +60,7 @@ extern "C" {
#define MAX_LINE_SIZE 1024 // without 16 pixels for the seams
#define MAX_LINE_CNT 4
#define VPE_NO_ALIGNMENT 1
enum vpe_cmd_ops {
VPE_CMD_OPS_BLENDING,
VPE_CMD_OPS_BG,

View file

@ -833,6 +833,14 @@ void vpe_backend_config_callback(
&vpe_priv->vpe_desc_writer, cfg_base_gpu, false, (uint8_t)vpe_priv->config_writer.buf->tmz);
}
uint32_t vpe_get_recout_width_alignment(const struct vpe_build_param *params)
{
uint16_t recout_alignment;
recout_alignment = VPE_NO_ALIGNMENT;
return recout_alignment;
}
bool vpe_rec_is_equal(struct vpe_rect rec1, struct vpe_rect rec2)
{
return (rec1.x == rec2.x && rec1.y == rec2.y && rec1.width == rec2.width &&

View file

@ -41,12 +41,19 @@ static bool should_generate_visual_confirm(enum vpe_stream_type stream_type)
}
}
static uint16_t get_visual_confirm_segs_count(uint32_t max_seg_width, uint32_t target_rect_width)
static uint16_t get_visual_confirm_segs_count(
uint32_t max_seg_width, uint32_t target_rect_width, uint32_t target_width_alignment)
{
// Unlike max_gaps logic in vpe10_calculate_segments, we are pure BG seg, no need to worry
// stream splitted among one of the segment. so no need to "+1", just round up the calculated
// number of segments.
uint16_t seg_cnt = (uint16_t)(max((target_rect_width + max_seg_width - 1) / max_seg_width, 1));
uint16_t seg_cnt = (uint16_t)(max(int_divide_with_ceil(target_rect_width, max_seg_width), 1));
uint16_t segment_width = (uint16_t)int_divide_with_ceil(target_rect_width, seg_cnt);
uint32_t aligned_segment_width = vpe_align_seg(segment_width, target_width_alignment);
if (aligned_segment_width > max_seg_width) {
seg_cnt++;
}
return seg_cnt;
}
@ -58,19 +65,20 @@ static uint16_t vpe_get_visual_confirm_total_seg_count(
uint16_t total_visual_confirm_segs = 0;
uint16_t stream_idx;
struct stream_ctx *stream_ctx;
uint32_t alignment = vpe_get_recout_width_alignment(params);
if (vpe_priv->init.debug.visual_confirm_params.input_format) {
for (stream_idx = 0; stream_idx < vpe_priv->num_streams; stream_idx++) {
stream_ctx = &vpe_priv->stream_ctx[stream_idx];
if (should_generate_visual_confirm(stream_ctx->stream_type))
total_visual_confirm_segs += get_visual_confirm_segs_count(
max_seg_width, stream_ctx->stream.scaling_info.dst_rect.width);
max_seg_width, stream_ctx->stream.scaling_info.dst_rect.width, alignment);
}
}
if (vpe_priv->init.debug.visual_confirm_params.output_format) {
total_visual_confirm_segs +=
get_visual_confirm_segs_count(max_seg_width, params->target_rect.width);
get_visual_confirm_segs_count(max_seg_width, params->target_rect.width, alignment);
}
return total_visual_confirm_segs;
@ -187,6 +195,7 @@ enum vpe_status vpe_create_visual_confirm_segs(
uint16_t total_seg_cnt =
vpe_get_visual_confirm_total_seg_count(vpe_priv, max_seg_width, params);
uint16_t seg_cnt = 0;
uint32_t recout_alignment = vpe_get_recout_width_alignment(params);
if (!total_seg_cnt)
return VPE_STATUS_OK;
@ -197,7 +206,7 @@ enum vpe_status vpe_create_visual_confirm_segs(
current_gap = visual_confirm_gaps;
// Do visual confirm bg generation for intput format
// Do visual confirm bg generation for input format
if (vpe_priv->init.debug.visual_confirm_params.input_format &&
params->target_rect.height > 2 * VISUAL_CONFIRM_HEIGHT) {
for (stream_idx = 0; stream_idx < params->num_streams; stream_idx++) {
@ -206,8 +215,8 @@ enum vpe_status vpe_create_visual_confirm_segs(
visual_confirm_rect.y += 0;
visual_confirm_rect.height = VISUAL_CONFIRM_HEIGHT;
seg_cnt = get_visual_confirm_segs_count(
max_seg_width, stream_ctx->stream.scaling_info.dst_rect.width);
vpe_full_bg_gaps(current_gap, &visual_confirm_rect, seg_cnt);
max_seg_width, stream_ctx->stream.scaling_info.dst_rect.width, recout_alignment);
vpe_full_bg_gaps(current_gap, &visual_confirm_rect, recout_alignment, seg_cnt);
vpe_priv->resource.create_bg_segments(
vpe_priv, current_gap, seg_cnt, VPE_CMD_OPS_BG_VSCF_INPUT);
current_gap += seg_cnt;
@ -219,8 +228,9 @@ enum vpe_status vpe_create_visual_confirm_segs(
visual_confirm_rect = params->target_rect;
visual_confirm_rect.y += VISUAL_CONFIRM_HEIGHT;
visual_confirm_rect.height = VISUAL_CONFIRM_HEIGHT;
seg_cnt = get_visual_confirm_segs_count(max_seg_width, params->target_rect.width);
vpe_full_bg_gaps(current_gap, &visual_confirm_rect, seg_cnt);
seg_cnt = get_visual_confirm_segs_count(
max_seg_width, params->target_rect.width, recout_alignment);
vpe_full_bg_gaps(current_gap, &visual_confirm_rect, recout_alignment, seg_cnt);
vpe_priv->resource.create_bg_segments(
vpe_priv, current_gap, seg_cnt, VPE_CMD_OPS_BG_VSCF_OUTPUT);
current_gap += seg_cnt;

View file

@ -360,7 +360,6 @@ static enum vpe_status populate_bg_stream(struct vpe_priv *vpe_priv, const struc
if (param->dst_surface.plane_size.surface_size.width < VPE_MIN_VIEWPORT_SIZE ||
param->dst_surface.plane_size.surface_size.height < VPE_MIN_VIEWPORT_SIZE ||
param->dst_surface.plane_size.surface_pitch < 256 / 4 || // 256bytes, 4bpp
param->target_rect.width < VPE_MIN_VIEWPORT_SIZE ||
param->target_rect.height < VPE_MIN_VIEWPORT_SIZE) {
return VPE_STATUS_ERROR;
@ -370,26 +369,16 @@ static enum vpe_status populate_bg_stream(struct vpe_priv *vpe_priv, const struc
surface_info = &stream->surface_info;
scaling_info = &stream->scaling_info;
polyphaseCoeffs = &stream->polyphase_scaling_coeffs;
surface_info->address.type = param->dst_surface.address.type;
surface_info->address.tmz_surface = param->dst_surface.address.tmz_surface;
surface_info->address.grph.addr.quad_part =
param->dst_surface.address.grph.addr.quad_part;
surface_info->swizzle = param->dst_surface.swizzle; // treat it as linear for simple
memcpy(surface_info, &param->dst_surface, sizeof(struct vpe_surface_info));
surface_info->plane_size.surface_size.x = 0;
surface_info->plane_size.surface_size.y = 0;
// min width & height in pixels
surface_info->plane_size.surface_size.width = VPE_MIN_VIEWPORT_SIZE;
surface_info->plane_size.surface_size.height = VPE_MIN_VIEWPORT_SIZE;
surface_info->plane_size.surface_pitch = param->dst_surface.plane_size.surface_pitch;
surface_info->plane_size.surface_aligned_height = param->dst_surface.plane_size.surface_aligned_height;
surface_info->dcc.enable = false;
surface_info->format = param->dst_surface.format;
surface_info->cs.encoding = param->dst_surface.cs.encoding;
surface_info->cs.range = param->dst_surface.cs.range;
surface_info->cs.tf = param->dst_surface.cs.tf;
surface_info->cs.cositing = param->dst_surface.cs.cositing;
surface_info->cs.primaries = param->dst_surface.cs.primaries;
// min width & height in pixels
scaling_info->src_rect.x = 0;
scaling_info->src_rect.y = 0;
scaling_info->src_rect.width = VPE_MIN_VIEWPORT_SIZE;