From e85a6b6a63a6e30072ffb1bd423c51d14d3f9ab9 Mon Sep 17 00:00:00 2001 From: Peyton Lee Date: Thu, 20 Feb 2025 10:48:35 +0800 Subject: [PATCH] radeonsi/vpe: check reduction ratio Check the reduction ratio is within the hardware capablity. Signed-off-by: Peyton Lee Reviewed-by: David Rosca Cc: mesa-stable Part-of: --- src/gallium/drivers/radeonsi/si_vpe.c | 232 ++++++++++++++++++++------ src/gallium/drivers/radeonsi/si_vpe.h | 8 + 2 files changed, 186 insertions(+), 54 deletions(-) diff --git a/src/gallium/drivers/radeonsi/si_vpe.c b/src/gallium/drivers/radeonsi/si_vpe.c index 2a69eb176ab..e4da38fd9ed 100644 --- a/src/gallium/drivers/radeonsi/si_vpe.c +++ b/src/gallium/drivers/radeonsi/si_vpe.c @@ -712,6 +712,15 @@ si_vpe_processor_destroy(struct pipe_video_codec *codec) FREE(vpeproc->emb_buffers); } + if (vpeproc->geometric_scaling_ratios) + FREE(vpeproc->geometric_scaling_ratios); + + if (vpeproc->geometric_buf[0]) + vpeproc->geometric_buf[0]->destroy(vpeproc->geometric_buf[0]); + + if (vpeproc->geometric_buf[1]) + vpeproc->geometric_buf[1]->destroy(vpeproc->geometric_buf[1]); + vpeproc->bufs_num = 0; vpeproc->ws->cs_destroy(&vpeproc->cs); SIVPE_DBG(vpeproc->log_level, "Success\n"); @@ -836,30 +845,17 @@ si_vpe_show_process_settings(struct vpe_video_processor *vpeproc, } } -static int -si_vpe_processor_is_process_supported(struct pipe_video_codec *codec, - struct pipe_video_buffer *input_texture, - const struct pipe_vpp_desc *process_properties) +static enum vpe_status +si_vpe_processor_check_and_build_settins(struct vpe_video_processor *vpeproc, + const struct pipe_vpp_desc *process_properties, + struct pipe_surface **src_surfaces, + struct pipe_surface **dst_surfaces) { enum vpe_status result = VPE_STATUS_OK; - struct vpe_video_processor *vpeproc = (struct vpe_video_processor *)codec; struct vpe *vpe_handle = vpeproc->vpe_handle; struct vpe_build_param *build_param = vpeproc->vpe_build_param; - struct pipe_surface **src_surfaces; struct vpe_bufs_req bufs_required; - assert(codec); - assert(process_properties); - assert(vpeproc->dst_surfaces); - - /* Get input surface */ - src_surfaces = input_texture->get_surfaces(input_texture); - if (!src_surfaces || !src_surfaces[0]) { - SIVPE_ERR("Get source surface failed\n"); - return 1; - } - vpeproc->src_surfaces = src_surfaces; - /* Mesa only sends one input frame at one time (one stream pipe). * If there is more than one pipe need to be handled, it have to re-locate memory. * But now we only focuse on handling one stream pipe. @@ -870,12 +866,12 @@ si_vpe_processor_is_process_supported(struct pipe_video_codec *codec, /* Init input surface setting */ result = si_vpe_set_surface_info(vpeproc, process_properties, - vpeproc->src_surfaces, + src_surfaces, USE_SRC_SURFACE, &build_param->streams[0].surface_info); if (VPE_STATUS_OK != result) { SIVPE_ERR("Set Src surface failed with result: %d\n", result); - return 1; + return result; } /* Init input stream setting */ @@ -887,12 +883,12 @@ si_vpe_processor_is_process_supported(struct pipe_video_codec *codec, /* Init output surface setting */ result = si_vpe_set_surface_info(vpeproc, process_properties, - vpeproc->dst_surfaces, + dst_surfaces, USE_DST_SURFACE, &build_param->dst_surface); if (VPE_STATUS_OK != result) { SIVPE_ERR("Set Dst surface failed with result: %d\n", result); - return 1; + return result; } /* Init output stream setting */ @@ -915,39 +911,50 @@ si_vpe_processor_is_process_supported(struct pipe_video_codec *codec, result = vpe_check_support(vpe_handle, build_param, &bufs_required); if (VPE_STATUS_OK != result) { SIVPE_WARN(vpeproc->log_level, "Check support failed with result: %d\n", result); - return 1; + return result; } if (VPE_EMBBUF_SIZE < bufs_required.emb_buf_size) { SIVPE_ERR("Required Buffer size is out of allocated: %" PRIu64 "\n", bufs_required.emb_buf_size); - return 1; + return VPE_STATUS_NO_MEMORY; } - return 0; + return result; } -static int -si_vpe_processor_process_frame(struct pipe_video_codec *codec, - struct pipe_video_buffer *input_texture, - const struct pipe_vpp_desc *process_properties) +static enum vpe_status +si_vpe_construct_blt(struct vpe_video_processor *vpeproc, + const struct pipe_vpp_desc *process_properties, + struct pipe_surface **src_surfaces, + struct pipe_surface **dst_surfaces) { enum vpe_status result = VPE_STATUS_OK; - struct vpe_video_processor *vpeproc = (struct vpe_video_processor *)codec; struct vpe *vpe_handle = vpeproc->vpe_handle; struct vpe_build_param *build_param = vpeproc->vpe_build_param; + struct vpe_build_bufs *build_bufs = vpeproc->vpe_build_bufs; struct rvid_buffer *emb_buf; uint64_t *vpe_ptr; - /* Check if the required options are supported */ - if(si_vpe_processor_is_process_supported(codec, input_texture, process_properties)) - return 1; + assert(process_properties); + assert(src_surfaces); + assert(dst_surfaces); + /* Check if the blt operation is supported and build related settings. + * Command settings will be is stored in vpeproc->vpe_build_param. + */ + result = si_vpe_processor_check_and_build_settins(vpeproc, process_properties, src_surfaces, dst_surfaces); + if (VPE_STATUS_OK != result) { + SIVPE_ERR("Failed in checking process operation and build settings(%d)\n", result); + return result; + } + + /* Prepare cmd_bud and emb_buf for building commands from settings */ /* Init CmdBuf address and size information */ vpe_ptr = (uint64_t *)vpeproc->cs.current.buf; - vpeproc->vpe_build_bufs->cmd_buf.cpu_va = (uintptr_t)vpe_ptr; - vpeproc->vpe_build_bufs->cmd_buf.gpu_va = 0; - vpeproc->vpe_build_bufs->cmd_buf.size = vpeproc->cs.current.max_dw; - vpeproc->vpe_build_bufs->cmd_buf.tmz = false; + build_bufs->cmd_buf.cpu_va = (uintptr_t)vpe_ptr; + build_bufs->cmd_buf.gpu_va = 0; + build_bufs->cmd_buf.size = vpeproc->cs.current.max_dw; + build_bufs->cmd_buf.tmz = false; /* Init EmbBuf address and size information */ emb_buf = &vpeproc->emb_buffers[vpeproc->cur_buf]; @@ -960,28 +967,30 @@ si_vpe_processor_process_frame(struct pipe_video_codec *codec, SIVPE_ERR("Mapping Embbuf failed\n"); return 1; } - vpeproc->vpe_build_bufs->emb_buf.cpu_va = (uintptr_t)vpe_ptr; - vpeproc->vpe_build_bufs->emb_buf.gpu_va = vpeproc->ws->buffer_get_virtual_address(emb_buf->res->buf); - vpeproc->vpe_build_bufs->emb_buf.size = VPE_EMBBUF_SIZE; - vpeproc->vpe_build_bufs->emb_buf.tmz = false; + build_bufs->emb_buf.cpu_va = (uintptr_t)vpe_ptr; + build_bufs->emb_buf.gpu_va = vpeproc->ws->buffer_get_virtual_address(emb_buf->res->buf); + build_bufs->emb_buf.size = VPE_EMBBUF_SIZE; + build_bufs->emb_buf.tmz = false; - result = vpe_build_commands(vpe_handle, build_param, vpeproc->vpe_build_bufs); - if (VPE_STATUS_OK != result) { - SIVPE_ERR("Build commands failed with result: %d\n", result); - goto fail; - } + result = vpe_build_commands(vpe_handle, build_param, build_bufs); /* Un-map Emb_buf */ vpeproc->ws->buffer_unmap(vpeproc->ws, emb_buf->res->buf); + if (VPE_STATUS_OK != result) { + SIVPE_ERR("Build commands failed with result: %d\n", result); + return VPE_STATUS_NO_MEMORY; + } + + /* Check buffer size */ if (vpeproc->vpe_build_bufs->cmd_buf.size == 0 || vpeproc->vpe_build_bufs->cmd_buf.size == vpeproc->cs.current.max_dw) { SIVPE_ERR("Cmdbuf size wrong\n"); - goto fail; + return VPE_STATUS_NO_MEMORY; } if (vpeproc->vpe_build_bufs->emb_buf.size == 0 || vpeproc->vpe_build_bufs->emb_buf.size == VPE_EMBBUF_SIZE) { SIVPE_ERR("Embbuf size wrong\n"); - goto fail; + return VPE_STATUS_NO_MEMORY; } SIVPE_DBG(vpeproc->log_level, "Used buf size: %" PRIu64 ", %" PRIu64 "\n", vpeproc->vpe_build_bufs->cmd_buf.size, vpeproc->vpe_build_bufs->emb_buf.size); @@ -993,14 +1002,129 @@ si_vpe_processor_process_frame(struct pipe_video_codec *codec, vpeproc->ws->cs_add_buffer(&vpeproc->cs, emb_buf->res->buf, RADEON_USAGE_READ | RADEON_USAGE_SYNCHRONIZED, RADEON_DOMAIN_GTT); /* Add surface buffers into bo_handle list */ - si_vpe_cs_add_surface_buffer(vpeproc, vpeproc->src_surfaces, RADEON_USAGE_READ); - si_vpe_cs_add_surface_buffer(vpeproc, vpeproc->dst_surfaces, RADEON_USAGE_WRITE); + si_vpe_cs_add_surface_buffer(vpeproc, src_surfaces, RADEON_USAGE_READ); + si_vpe_cs_add_surface_buffer(vpeproc, dst_surfaces, RADEON_USAGE_WRITE); - return 0; + return VPE_STATUS_OK; +} + +static void +si_vpe_find_substage_scal_ratios(float *p_scale_ratios, + float scaling_ratio, + float max_scale, + uint32_t num_stages) +{ + uint32_t i; + + for (i = 0; i < num_stages; i++) { + if (i == num_stages - 1) + p_scale_ratios[i] = scaling_ratio/(float)(pow(max_scale, num_stages - 1)); + else + p_scale_ratios[i] = max_scale; + } +} + +static enum vpe_status +si_vpe_decide_substage_scal_ratios(struct vpe_video_processor *vpeproc, + float *p_target_ratios) +{ + uint8_t no_horizontal_passes, no_vertical_passes, no_of_passes; + float *pHrSr, *pVtSr; + uint32_t idx; + + /* The scaling ratios are the same as pre-processing */ + if (vpeproc->geometric_scaling_ratios && + vpeproc->scaling_ratios[0] == p_target_ratios[0] && + vpeproc->scaling_ratios[1] == p_target_ratios[1]) + return VPE_STATUS_OK; + + if (vpeproc->geometric_scaling_ratios) { + FREE(vpeproc->geometric_scaling_ratios); + vpeproc->geometric_scaling_ratios = NULL; + } + + /* How many passes we need */ + no_horizontal_passes = (p_target_ratios[0] > VPE_MAX_GEOMETRIC_DOWNSCALE) ? + (uint8_t)(ceil(log(p_target_ratios[0]) / log(VPE_MAX_GEOMETRIC_DOWNSCALE))) : 1; + no_vertical_passes = (p_target_ratios[1] > VPE_MAX_GEOMETRIC_DOWNSCALE) ? + (uint8_t)(ceil(log(p_target_ratios[1]) / log(VPE_MAX_GEOMETRIC_DOWNSCALE))) : 1; + no_of_passes = MAX2(no_horizontal_passes, no_vertical_passes); + + /* Allocate ratio array depends on no_of_passes */ + pHrSr = (float *)CALLOC(2 * no_of_passes, sizeof(float)); + if (NULL == pHrSr) { + SIVPE_ERR("no_of_passes times float of array memory allocation failed\n"); + return VPE_STATUS_NO_MEMORY; + } + pVtSr = pHrSr + no_of_passes; + for (idx = 0; idx < no_of_passes; idx++) { + pHrSr[idx] = 1.0f; + pVtSr[idx] = 1.0f; + } + + /* Calculate scaling ratios of every pass */ + if (no_horizontal_passes > 1) + si_vpe_find_substage_scal_ratios(pHrSr, p_target_ratios[0], VPE_MAX_GEOMETRIC_DOWNSCALE, no_horizontal_passes); + else + pHrSr[0] = p_target_ratios[0]; + + if (no_vertical_passes > 1) + si_vpe_find_substage_scal_ratios(pVtSr, p_target_ratios[1], VPE_MAX_GEOMETRIC_DOWNSCALE, no_vertical_passes); + else + pVtSr[0] = p_target_ratios[1]; + + if (no_vertical_passes < no_horizontal_passes) { + pVtSr[no_horizontal_passes - 1] = pVtSr[no_vertical_passes - 1]; + pVtSr[no_vertical_passes - 1] = 1.0f; + } else if (no_vertical_passes > no_horizontal_passes) { + pHrSr[no_vertical_passes - 1] = pHrSr[no_horizontal_passes - 1]; + pHrSr[no_horizontal_passes - 1] = 1.0f; + } + + /* Store the ratio information in vpeproc */ + vpeproc->scaling_ratios[0] = p_target_ratios[0]; + vpeproc->scaling_ratios[1] = p_target_ratios[1]; + vpeproc->geometric_scaling_ratios = pHrSr; + vpeproc->geometric_passes = no_of_passes; + + return VPE_STATUS_OK; +} + +static int +si_vpe_processor_process_frame(struct pipe_video_codec *codec, + struct pipe_video_buffer *input_texture, + const struct pipe_vpp_desc *process_properties) +{ + struct vpe_video_processor *vpeproc = (struct vpe_video_processor *)codec; + uint32_t src_rect_width, src_rect_height, dst_rect_width, dst_rect_height; + uint32_t idx; + float scaling_ratio[2]; + float *pHrSr, *pVtSr; + + /* Variables for allocating temp working buffer */ + struct pipe_surface **tmp_geo_scaling_surf_1; + struct pipe_surface **tmp_geo_scaling_surf_2; + + /* Get input surface */ + vpeproc->src_surfaces = input_texture->get_surfaces(input_texture); + if (!vpeproc->src_surfaces || !vpeproc->src_surfaces[0]) { + SIVPE_ERR("Get source surface failed\n"); + return 1; + } + + /* Get scaling ratio info */ + src_rect_width = process_properties->src_region.x1 - process_properties->src_region.x0; + src_rect_height = process_properties->src_region.y1 - process_properties->src_region.y0; + dst_rect_width = process_properties->dst_region.x1 - process_properties->dst_region.x0; + dst_rect_height = process_properties->dst_region.y1 - process_properties->dst_region.y0; + + scaling_ratio[0] = src_rect_width / dst_rect_width; + scaling_ratio[1] = src_rect_height / dst_rect_height; + + /* Check if the reduction ratio is within capability */ + if ((scaling_ratio[0] <= VPE_MAX_GEOMETRIC_DOWNSCALE) && (scaling_ratio[1] <= VPE_MAX_GEOMETRIC_DOWNSCALE)) + return si_vpe_construct_blt(vpeproc, process_properties, vpeproc->src_surfaces, vpeproc->dst_surfaces); -fail: - vpeproc->ws->buffer_unmap(vpeproc->ws, emb_buf->res->buf); - SIVPE_ERR("Process frame failed\n"); return 1; } diff --git a/src/gallium/drivers/radeonsi/si_vpe.h b/src/gallium/drivers/radeonsi/si_vpe.h index b4b6c49486a..9d0e4e1ccc7 100644 --- a/src/gallium/drivers/radeonsi/si_vpe.h +++ b/src/gallium/drivers/radeonsi/si_vpe.h @@ -45,6 +45,8 @@ #define VPE_BUFFERS_NUM 6 #define VPE_EMBBUF_SIZE 20000 +#define VPE_MAX_GEOMETRIC_DOWNSCALE 4.f + /* For Hooking VPE as a decoder instance */ struct vpe_video_processor { struct pipe_video_codec base; @@ -70,6 +72,12 @@ struct vpe_video_processor { struct pipe_surface **src_surfaces; struct pipe_surface **dst_surfaces; + + /* For Geometric scaling */ + float scaling_ratios[2]; + float *geometric_scaling_ratios; + uint8_t geometric_passes; + struct pipe_video_buffer *geometric_buf[2]; }; struct pipe_video_codec*