Module: Mesa Branch: main Commit: ed176e2c715ce2958b60754a2449eabb3fae3d35 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=ed176e2c715ce2958b60754a2449eabb3fae3d35
Author: Peyton Lee <peyto...@amd.com> Date: Thu Oct 12 14:29:24 2023 +0800 amd, radeonsi: add si_vpe.c with helper functions of VPE lib Signed-off-by: Peyton Lee <peyto...@amd.com> Acked-by: Leo Liu <leo....@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25713> --- src/gallium/drivers/radeonsi/meson.build | 6 +- src/gallium/drivers/radeonsi/si_vpe.c | 1065 ++++++++++++++++++++++++++++++ src/gallium/drivers/radeonsi/si_vpe.h | 75 +++ 3 files changed, 1144 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/radeonsi/meson.build b/src/gallium/drivers/radeonsi/meson.build index f9b3dc45861..29afa87c0b6 100644 --- a/src/gallium/drivers/radeonsi/meson.build +++ b/src/gallium/drivers/radeonsi/meson.build @@ -89,6 +89,8 @@ files_libradeonsi = files( 'si_utrace.c', 'si_utrace.h', 'si_uvd.c', + 'si_vpe.c', + 'si_vpe.h', 'pspdecryptionparam.h', 'radeon_temporal.h', 'radeon_uvd.c', @@ -117,8 +119,8 @@ files_libradeonsi = files( ) radeonsi_include_dirs = [inc_src, inc_include, inc_gallium, inc_gallium_aux, inc_amd_common, - inc_gallium_drivers] -radeonsi_deps = [dep_clock, dep_libdrm_radeon, idep_nir_headers, idep_amdgfxregs_h, idep_mesautil, idep_aco, idep_u_tracepoints, idep_si_tracepoints] + inc_amd_common_llvm, inc_gallium_drivers, inc_compiler, inc_amd, inc_amd_vpe] +radeonsi_deps = [dep_llvm, dep_clock, dep_libdrm_radeon, idep_nir_headers, idep_amdgfxregs_h, idep_mesautil, idep_aco, idep_u_tracepoints, idep_si_tracepoints] if with_perfetto radeonsi_deps += dep_perfetto diff --git a/src/gallium/drivers/radeonsi/si_vpe.c b/src/gallium/drivers/radeonsi/si_vpe.c new file mode 100755 index 00000000000..dcb2c81a573 --- /dev/null +++ b/src/gallium/drivers/radeonsi/si_vpe.c @@ -0,0 +1,1065 @@ +/************************************************************************** + * + * Copyright 2022 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. + * 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. + * + **************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <pipe/p_state.h> +#include <si_pipe.h> +#include "si_vpe.h" + +#define SI_VPE_PRETAG "" +#define SI_VPE_LOG_LEVEL_DEFAULT 1 +#define SI_VPE_LOG_LEVEL_INFO 1 +#define SI_VPE_LOG_LEVEL_WARNING 2 +#define SI_VPE_LOG_LEVEL_DEBUG 3 + +#define SIVPE_INFO(dblv, fmt, args...) \ + if ((dblv) >= SI_VPE_LOG_LEVEL_INFO) { \ + printf("SIVPE INFO: %s: " fmt, __func__, ##args); \ + } + +#define SIVPE_WARN(dblv, fmt, args...) \ + if ((dblv) >= SI_VPE_LOG_LEVEL_WARNING) { \ + printf("SIVPE WARNING: %s: " fmt, __func__, ##args); \ + } + +#define SIVPE_DBG(dblv, fmt, args...) \ + if ((dblv) >= SI_VPE_LOG_LEVEL_DEBUG) { \ + printf("SIVPE DBG: %s: " fmt, __func__, ##args); \ + } + +#define SIVPE_ERR(fmt, args...) \ + fprintf(stderr, "SIVPE ERROR %s:%d %s " fmt, __FILE__, __LINE__, __func__, ##args) + +/* Use this enum to help us for accessing the anonymous struct src, dst + * in blit_info. + */ +enum { + USE_SRC_SURFACE, + USE_DST_SURFACE +}; + + +static void * +si_vpe_zalloc(void* mem_ctx, size_t size) +{ + /* mem_ctx is optional for now */ + return CALLOC(1, size); +} + + +static void +si_vpe_free(void* mem_ctx, void *ptr) +{ + /* mem_ctx is optional for now */ + if (ptr != NULL) { + FREE(ptr); + ptr = NULL; + } +} + + +static void +si_vpe_log(void* log_ctx, const char* fmt, ...) +{ + /* log_ctx is optional for now */ + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + + +static void +si_vpe_populate_debug_options(struct vpe_debug_options* debug) +{ + /* ref: vpe-utils */ + debug->flags.cm_in_bypass = 0; + debug->identity_3dlut = 0; + debug->sce_3dlut = 0; + debug->disable_reuse_bit = 0; +} + + +static void +si_vpe_populate_callback_modules(struct vpe_callback_funcs* funcs) +{ + funcs->log = si_vpe_log; + funcs->zalloc = si_vpe_zalloc; + funcs->free = si_vpe_free; + return; +} + +static char* +si_vpe_get_cositing_str(enum vpe_chroma_cositing cositing) +{ + switch (cositing) { + case VPE_CHROMA_COSITING_NONE: + return "NONE"; + case VPE_CHROMA_COSITING_LEFT: + return "LEFT"; + case VPE_CHROMA_COSITING_TOPLEFT: + return "TOPLEFT"; + case VPE_CHROMA_COSITING_COUNT: + default: + return "ERROR"; + } +} + +static char* +si_vpe_get_primarie_str(enum vpe_color_primaries primarie) +{ + switch (primarie) { + case VPE_PRIMARIES_BT601: + return "BT601"; + case VPE_PRIMARIES_BT709: + return "BT709"; + case VPE_PRIMARIES_BT2020: + return "BT2020"; + case VPE_PRIMARIES_JFIF: + return "JFIF"; + case VPE_PRIMARIES_COUNT: + default: + return "ERROR"; + } +} + +static char* +si_vpe_get_tf_str(enum vpe_transfer_function tf) +{ + switch (tf) { + case VPE_TF_G22: + return "G22"; + case VPE_TF_G24: + return "G24"; + case VPE_TF_G10: + return "G10"; + case VPE_TF_PQ: + return "PQ"; + case VPE_TF_PQ_NORMALIZED: + return "PQ_NORMALIZED"; + case VPE_TF_HLG: + return "HLG"; + case VPE_TF_COUNT: + default: + return "ERROR"; + } +} + +static enum vpe_status +si_vpe_populate_init_data(struct si_context *sctx, struct vpe_init_data* params, uint8_t log_level) +{ + if (!sctx || !params) { + return VPE_STATUS_ERROR; + } + + params->ver_major = sctx->screen->info.ip[AMD_IP_VPE].ver_major; + params->ver_minor = sctx->screen->info.ip[AMD_IP_VPE].ver_minor; + params->ver_rev = sctx->screen->info.ip[AMD_IP_VPE].ver_rev; + + si_vpe_populate_debug_options(¶ms->debug); + si_vpe_populate_callback_modules(¶ms->funcs); + + SIVPE_DBG(log_level, "Get family: %d\n", sctx->family); + SIVPE_DBG(log_level, "Get gfx_level: %d\n", sctx->gfx_level); + SIVPE_DBG(log_level, "Set ver_major: %d\n", params->ver_major); + SIVPE_DBG(log_level, "Set ver_minor: %d\n", params->ver_minor); + SIVPE_DBG(log_level, "Set ver_rev: %d\n", params->ver_rev); + + return VPE_STATUS_OK; +} + + +static enum vpe_status +si_vpe_allocate_buffer(struct vpe_build_bufs **bufs) +{ + if (!bufs) { + return VPE_STATUS_ERROR; + } + + *bufs = (struct vpe_build_bufs *)malloc(sizeof(struct vpe_build_bufs)); + if (!*bufs) { + return VPE_STATUS_NO_MEMORY; + } + + (*bufs)->cmd_buf.cpu_va = 0; + (*bufs)->emb_buf.cpu_va = 0; + (*bufs)->cmd_buf.size = 0; + (*bufs)->emb_buf.size = 0; + + return VPE_STATUS_OK; +} + +static void +si_vpe_free_buffer(struct vpe_build_bufs *bufs) +{ + if (!bufs) { + return; + } + free(bufs); +} + +static enum vpe_surface_pixel_format +si_vpe_format(enum pipe_format format) +{ + enum vpe_surface_pixel_format ret; + + switch (format) { + /* VPE input format: */ + case PIPE_FORMAT_NV12: + ret = VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb; + break; + case PIPE_FORMAT_NV21: + ret = VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr; + break; + case PIPE_FORMAT_P010: + ret = VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr; + break; + /* VPE output format: */ + case PIPE_FORMAT_A8R8G8B8_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_BGRA8888; + break; + case PIPE_FORMAT_A8B8G8R8_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBA8888; + break; + case PIPE_FORMAT_R8G8B8A8_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_ABGR8888; + break; + case PIPE_FORMAT_B8G8R8A8_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_ARGB8888; + break; + case PIPE_FORMAT_X8R8G8B8_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_BGRX8888; + break; + case PIPE_FORMAT_X8B8G8R8_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBX8888; + break; + case PIPE_FORMAT_R8G8B8X8_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_XBGR8888; + break; + case PIPE_FORMAT_B8G8R8X8_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_XRGB8888; + break; + case PIPE_FORMAT_A2R10G10B10_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_BGRA1010102; + break; + case PIPE_FORMAT_A2B10G10R10_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBA1010102; + break; + case PIPE_FORMAT_B10G10R10A2_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010; + break; + case PIPE_FORMAT_R10G10B10A2_UNORM: + ret = VPE_SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010; + break; + default: + ret = VPE_SURFACE_PIXEL_FORMAT_INVALID; + break; + } + return ret; +} + +static enum vpe_status +si_vpe_set_color_space(const struct pipe_vpp_desc *process_properties, + struct vpe_color_space *color_space, + enum pipe_format format, + int which_surface) +{ + enum pipe_video_vpp_color_standard_type colors_standard; + enum pipe_video_vpp_color_range color_range; + enum pipe_video_vpp_chroma_siting chroma_siting; + + if (which_surface == USE_SRC_SURFACE) { + colors_standard = process_properties->in_colors_standard; + color_range = process_properties->in_color_range; + chroma_siting = process_properties->in_chroma_siting; + } else { + colors_standard = process_properties->out_colors_standard; + color_range = process_properties->out_color_range; + chroma_siting = process_properties->out_chroma_siting; + } + + switch (colors_standard) { + case PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_BT601: + color_space->primaries = VPE_PRIMARIES_BT601; + color_space->tf = VPE_TF_G24; + break; + case PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_BT709: + color_space->primaries = VPE_PRIMARIES_BT709; + color_space->tf = VPE_TF_G22; + break; + case PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_BT2020: + color_space->primaries = VPE_PRIMARIES_BT2020; + color_space->tf = VPE_TF_PQ; + break; + default: + color_space->primaries = VPE_PRIMARIES_BT709; + color_space->tf = VPE_TF_G22; + break; + } + + switch (color_range) { + case PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_REDUCED: + color_space->range = VPE_COLOR_RANGE_STUDIO; + break; + case PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_FULL: + color_space->range = VPE_COLOR_RANGE_FULL; + break; + default: + color_space->range = VPE_COLOR_RANGE_FULL; + break; + } + + /* Default use VPE_CHROMA_COSITING_NONE (CENTER | CENTER) */ + color_space->cositing = VPE_CHROMA_COSITING_NONE; + if (chroma_siting & PIPE_VIDEO_VPP_CHROMA_SITING_VERTICAL_CENTER){ + if (chroma_siting & PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_LEFT) + color_space->cositing = VPE_CHROMA_COSITING_LEFT; + //else if (chroma_siting & PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_CENTER) + // color_space->cositing = VPE_CHROMA_COSITING_NONE; + } else if (chroma_siting & PIPE_VIDEO_VPP_CHROMA_SITING_VERTICAL_TOP) { + if (chroma_siting & PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_LEFT) + color_space->cositing = VPE_CHROMA_COSITING_TOPLEFT; + //else if (chroma_siting & PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_CENTER) + // color_space->cositing = VPE_CHROMA_COSITING_NONE; + } else if (chroma_siting & PIPE_VIDEO_VPP_CHROMA_SITING_VERTICAL_BOTTOM) { + if (chroma_siting & PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_LEFT) + color_space->cositing = VPE_CHROMA_COSITING_LEFT; + //else if (chroma_siting & PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_CENTER) + // color_space->cositing = VPE_CHROMA_COSITING_NONE; + } + + /* VPE 1.0 Input format only supports NV12 and NV21 now */ + switch (format) { + case PIPE_FORMAT_NV12: + case PIPE_FORMAT_NV21: + case PIPE_FORMAT_P010: + color_space->encoding = VPE_PIXEL_ENCODING_YCbCr; + break; + case PIPE_FORMAT_A8R8G8B8_UNORM: + case PIPE_FORMAT_A8B8G8R8_UNORM: + case PIPE_FORMAT_R8G8B8A8_UNORM: + case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_X8R8G8B8_UNORM: + case PIPE_FORMAT_X8B8G8R8_UNORM: + case PIPE_FORMAT_R8G8B8X8_UNORM: + case PIPE_FORMAT_B8G8R8X8_UNORM: + case PIPE_FORMAT_A2R10G10B10_UNORM: + case PIPE_FORMAT_R10G10B10A2_UNORM: + case PIPE_FORMAT_A2B10G10R10_UNORM: + case PIPE_FORMAT_B10G10R10A2_UNORM: + default: + color_space->encoding = VPE_PIXEL_ENCODING_RGB; + break; + } + return VPE_STATUS_OK; +} + +/* Combine si_vpe_set_plane_address and si_vpe_set_plane_size*/ +static enum vpe_status +si_vpe_set_plane_info(struct vpe_video_processor *vpeproc, + const struct pipe_vpp_desc *process_properties, + struct pipe_surface **surfaces, + int which_surface, + struct vpe_surface_info *surface_info) +{ + struct vpe_plane_address *plane_address = &surface_info->address; + struct vpe_plane_size *plane_size = &surface_info->plane_size; + struct si_resource *si_res; + uint32_t width, height, pitch, pos_x, pos_y, offset; + enum pipe_format format; + + if (which_surface == USE_SRC_SURFACE) { + pos_x = process_properties->src_region.x0; + pos_y = process_properties->src_region.y0; + width = process_properties->src_region.x1 - pos_x; + height = process_properties->src_region.y1 - pos_y; + format = process_properties->base.input_format; + } else { + pos_x = process_properties->dst_region.x0; + pos_y = process_properties->dst_region.y0; + width = process_properties->dst_region.x1 - pos_x; + height = process_properties->dst_region.y1 - pos_y; + format = process_properties->base.output_format; + } + + /* Formate Color Space */ + surface_info->format = si_vpe_format(format); + si_vpe_set_color_space(process_properties, &surface_info->cs, format, which_surface); + + /* Get surface info, such as buffer alignment and offset */ + if (vpeproc->base.context->screen && vpeproc->base.context->screen->resource_get_info) + vpeproc->base.context->screen->resource_get_info(vpeproc->base.context->screen, + surfaces[0]->texture, + &pitch, + &offset); + else + SIVPE_ERR("Get plane pitch and offset info failed\n"); + + si_res = si_resource(surfaces[0]->texture); + plane_address->tmz_surface = false; + + /* here is the SURFACE size, not image rect */ + plane_size->surface_size.x = 0; + plane_size->surface_size.y = 0; + plane_size->surface_size.width = surfaces[0]->width; + plane_size->surface_size.height = surfaces[0]->height; + plane_size->surface_pitch = pitch; // Byte alignment + + switch (format) { + case PIPE_FORMAT_NV12: + case PIPE_FORMAT_NV21: + plane_address->type = VPE_PLN_ADDR_TYPE_VIDEO_PROGRESSIVE; + plane_address->video_progressive.luma_addr.quad_part = si_res->gpu_address + offset; + plane_address->video_progressive.luma_meta_addr.quad_part = 0; + plane_address->video_progressive.luma_dcc_const_color.quad_part = 0; + //plane_size->surface_pitch /= 1; // Byte alignment to Pixel alignment + /* Get 2nd plane buffer info */ + if (surfaces[1] && vpeproc->base.context->screen && vpeproc->base.context->screen->resource_get_info) + vpeproc->base.context->screen->resource_get_info(vpeproc->base.context->screen, + surfaces[1]->texture, + &pitch, + &offset); + else { + SIVPE_ERR("Get 2nd plane pitch and offset info failed\n"); + return VPE_STATUS_ERROR; + } + si_res = si_resource(surfaces[1]->texture); + plane_address->video_progressive.chroma_addr.quad_part = si_res->gpu_address + offset; + plane_address->video_progressive.chroma_meta_addr.quad_part = 0; + plane_address->video_progressive.chroma_dcc_const_color.quad_part = 0; + + plane_size->chroma_size.x = pos_x; + plane_size->chroma_size.y = pos_y; + plane_size->chroma_size.width = (width + 1) / 2; // 2 pixel-width alignment + plane_size->chroma_size.height = (height + 1) / 2; // 2 pixel-height alignment + plane_size->chroma_pitch = pitch / 2; // Byte alignment to Pixel alignment (NV12/NV21 2nd plane is 16 bits per pixel) + break; + case PIPE_FORMAT_A8R8G8B8_UNORM: + case PIPE_FORMAT_A8B8G8R8_UNORM: + case PIPE_FORMAT_R8G8B8A8_UNORM: + case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_X8R8G8B8_UNORM: + case PIPE_FORMAT_X8B8G8R8_UNORM: + case PIPE_FORMAT_R8G8B8X8_UNORM: + case PIPE_FORMAT_B8G8R8X8_UNORM: + case PIPE_FORMAT_A2R10G10B10_UNORM: + case PIPE_FORMAT_R10G10B10A2_UNORM: + case PIPE_FORMAT_A2B10G10R10_UNORM: + case PIPE_FORMAT_B10G10R10A2_UNORM: + default: + plane_address->type = VPE_PLN_ADDR_TYPE_GRAPHICS; + plane_address->grph.addr.quad_part = si_res->gpu_address + offset; + plane_address->grph.meta_addr.quad_part = 0; + plane_address->grph.dcc_const_color.quad_part = 0; + plane_size->surface_pitch /= 4; // Byte alignment to Pixel alignment (RGBA plane is 32 bits per pixel) + + plane_size->chroma_size.x = 0; + plane_size->chroma_size.y = 0; + plane_size->chroma_size.width = 0; + plane_size->chroma_size.height = 0; + plane_size->chroma_pitch = 0; + break; + } + return VPE_STATUS_OK; +} + +static enum vpe_status +si_vpe_set_surface_info(struct vpe_video_processor *vpeproc, + const struct pipe_vpp_desc *process_properties, + struct pipe_surface **surfaces, + int which_surface, + struct vpe_surface_info *surface_info) +{ + assert(surface_info); + + /* Set up surface pitch, plane address, color space */ + si_vpe_set_plane_info(vpeproc, process_properties, surfaces, which_surface, surface_info); + + /* VAAPI does not provide swizzle info right now. + * Swizzle mode is strongly releated to hardware DMA design, + * intel-vaapi-driver/i965_drv_video.c also does not handle swizzle information, + * maybe this is the reason why it is not currently supported. + * + * Just default to linear or none temporarily. + */ + surface_info->swizzle = VPE_SW_LINEAR; + + struct vpe_plane_dcc_param *dcc_param = &surface_info->dcc; + dcc_param->enable = false; + dcc_param->meta_pitch = 0; + dcc_param->independent_64b_blks = false; + dcc_param->dcc_ind_blk = 0; + dcc_param->meta_pitch_c = 0; + dcc_param->independent_64b_blks_c = false; + dcc_param->dcc_ind_blk_c = 0; + + return VPE_STATUS_OK; +} + +static enum vpe_status +si_vpe_set_stream(const struct pipe_vpp_desc *process_properties, + struct vpe_stream *stream) +{ + struct vpe_scaling_info *scaling_info = &stream->scaling_info; + scaling_info->src_rect.x = process_properties->src_region.x0; + scaling_info->src_rect.y = process_properties->src_region.y0; + scaling_info->src_rect.width = process_properties->src_region.x1 - process_properties->src_region.x0; + scaling_info->src_rect.height = process_properties->src_region.y1 - process_properties->src_region.y0; + scaling_info->dst_rect.x = process_properties->dst_region.x0; + scaling_info->dst_rect.y = process_properties->dst_region.y0; + scaling_info->dst_rect.width = process_properties->dst_region.x1 - process_properties->dst_region.x0; + scaling_info->dst_rect.height = process_properties->dst_region.y1 - process_properties->dst_region.y0; + /* Programmable 1 to 8 taps of vertical polyphase filter, and + * programmable 1, 2, 4, 6, 8 taps of horizontal polyphase filter. + */ + scaling_info->taps.v_taps = 4; + scaling_info->taps.h_taps = 4; + scaling_info->taps.v_taps_c = 2; + scaling_info->taps.h_taps_c = 2; + + /* Blending is not supported for now */ + struct vpe_blend_info *blend_info = &stream->blend_info; + blend_info->blending = false; + blend_info->pre_multiplied_alpha = false; + blend_info->global_alpha = false; + blend_info->global_alpha_value = 0.0; + /* Global Alpha for Background ? */ + if (process_properties->blend.mode == PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA) { + blend_info->global_alpha = true; + blend_info->global_alpha_value = process_properties->blend.global_alpha; + } + + /* TODO: do ProcAmp in next stage */ + struct vpe_color_adjust *color_adj = &stream->color_adj; + color_adj->brightness = 0.0; + color_adj->contrast = 1.0; + color_adj->hue = 0.0; + color_adj->saturation = 1.0; + + /* TODO: Tone Mapping */ + //struct vpe_tonemap_params *tm_params = &stream->tm_params; + + + stream->horizontal_mirror = false; + stream->vertical_mirror = false; + switch (process_properties->orientation & 0xF) { + case PIPE_VIDEO_VPP_ROTATION_90: + stream->rotation = VPE_ROTATION_ANGLE_90; + break; + case PIPE_VIDEO_VPP_ROTATION_180: + stream->rotation = VPE_ROTATION_ANGLE_180; + break; + case PIPE_VIDEO_VPP_ROTATION_270: + stream->rotation = VPE_ROTATION_ANGLE_270; + break; + default: + stream->rotation = VPE_ROTATION_ANGLE_0; + break; + } + if (process_properties->orientation & PIPE_VIDEO_VPP_FLIP_HORIZONTAL) { + stream->horizontal_mirror = true; + } + if (process_properties->orientation & PIPE_VIDEO_VPP_FLIP_VERTICAL) + stream->vertical_mirror = true; + + stream->enable_luma_key = false; + stream->lower_luma_bound = 0.5; + stream->upper_luma_bound = 0.5; + + stream->flags.hdr_metadata = 0; + stream->flags.reserved = 0; + + /* TODO: hdr_metadata support in next stage */ + stream->hdr_metadata.redX = 1; + stream->hdr_metadata.redY = 1; + stream->hdr_metadata.greenX = 1; + stream->hdr_metadata.greenY = 1; + stream->hdr_metadata.blueX = 1; + stream->hdr_metadata.blueY = 1; + stream->hdr_metadata.whiteX = 1; + stream->hdr_metadata.whiteY = 1; + + stream->hdr_metadata.min_mastering = 1; + stream->hdr_metadata.max_mastering = 1; + stream->hdr_metadata.max_content = 1; + stream->hdr_metadata.avg_content = 1; + + return VPE_STATUS_OK; +} + +static void +si_vpe_processor_destroy(struct pipe_video_codec *codec) +{ + struct vpe_video_processor *vpeproc = (struct vpe_video_processor *)codec; + assert(codec); + + if (vpeproc->process_fence) { + SIVPE_INFO(vpeproc->log_level, "Wait fence\n"); + vpeproc->ws->fence_wait(vpeproc->ws, vpeproc->process_fence, PIPE_DEFAULT_DECODER_FEEDBACK_TIMEOUT_NS); + } + vpeproc->ws->cs_destroy(&vpeproc->cs); + si_vid_destroy_buffer(&vpeproc->emb_buffer); + + if (vpeproc->vpe_build_bufs) + si_vpe_free_buffer(vpeproc->vpe_build_bufs); + if (vpeproc->vpe_handle) + vpe_destroy(&vpeproc->vpe_handle); + if (vpeproc->vpe_build_param) + FREE(vpeproc->vpe_build_param); + + SIVPE_DBG(vpeproc->log_level, "Success\n"); + FREE(vpeproc); +} + +static void +si_vpe_processor_begin_frame(struct pipe_video_codec *codec, + struct pipe_video_buffer *target, + struct pipe_picture_desc *picture) +{ + struct vpe_video_processor *vpeproc = (struct vpe_video_processor *)codec; + struct pipe_surface **dst_surfaces; + assert(codec); + + dst_surfaces = target->get_surfaces(target); + if (!dst_surfaces || !dst_surfaces[0]) { + SIVPE_ERR("Get target surface failed\n"); + return; + } + vpeproc->dst_surfaces = dst_surfaces; +} + +static void +si_vpe_cs_add_surface_buffer(struct vpe_video_processor *vpeproc, + struct pipe_surface **surfaces, + unsigned usage) +{ + struct si_resource *si_res; + int i; + + for (i = 0; i < VL_MAX_SURFACES; ++i) { + if (!surfaces[i]) + continue; + + si_res = si_resource(surfaces[i]->texture); + vpeproc->ws->cs_add_buffer(&vpeproc->cs, si_res->buf, usage | RADEON_USAGE_SYNCHRONIZED, 0); + } +} + +static void +si_vpe_processor_process_frame(struct pipe_video_codec *codec, + struct pipe_video_buffer *input_texture, + const struct pipe_vpp_desc *process_properties) +{ + 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; + struct pipe_fence_handle *process_fence = NULL; + + assert(codec); + assert(process_properties); + assert(vpeproc->dst_surfaces); + + src_surfaces = input_texture->get_surfaces(input_texture); + if (!src_surfaces || !src_surfaces[0]) { + SIVPE_ERR("Get source surface failed\n"); + return; + } + vpeproc->src_surfaces = src_surfaces; + + /* Following setting is from si_vpe_set_build_param()*/ + /* VPE 1.0 only support one input */ + build_param->num_streams = 1; + + /* Allocate array "streams" */ + build_param->streams = (struct vpe_stream *)CALLOC(build_param->num_streams, sizeof(struct vpe_stream)); + if (!build_param->streams) { + SIVPE_ERR("Allocate streams failed\n"); + free(build_param); + return; + } + + si_vpe_set_surface_info(vpeproc, + process_properties, + vpeproc->src_surfaces, + USE_SRC_SURFACE, + &build_param->streams[0].surface_info); + + si_vpe_set_stream(process_properties, &build_param->streams[0]); + + si_vpe_set_surface_info(vpeproc, + process_properties, + vpeproc->dst_surfaces, + USE_DST_SURFACE, + &build_param->dst_surface); + + if (process_properties->background_color) { + build_param->target_rect.x = 0; + build_param->target_rect.y = 0; + build_param->target_rect.width = vpeproc->dst_surfaces[0]->width; + build_param->target_rect.height = vpeproc->dst_surfaces[0]->height; + } else { + build_param->target_rect.x = process_properties->dst_region.x0; + build_param->target_rect.y = process_properties->dst_region.y0; + build_param->target_rect.width = process_properties->dst_region.x1 - process_properties->dst_region.x0; + build_param->target_rect.height = process_properties->dst_region.y1 - process_properties->dst_region.y0; + } + + /* TODO: background color is not specified in pipe_vpp_desc structure. + * Need to add this filed in pipe_vpp_desc. + */ + build_param->bg_color.is_ycbcr = false; + + if (!(process_properties->background_color & 0xFFFFFF) && + (build_param->dst_surface.cs.range == VPE_COLOR_RANGE_STUDIO)) { + build_param->bg_color.rgba.a = + (float)((process_properties->background_color & 0xFF000000) >> 24) / 255.0; + build_param->bg_color.rgba.r = 0.0628; + build_param->bg_color.rgba.g = 0.0628; + build_param->bg_color.rgba.b = 0.0628; + } else if (process_properties->background_color) { + build_param->bg_color.rgba.a = + (float)((process_properties->background_color & 0xFF000000) >> 24) / 255.0; + build_param->bg_color.rgba.r = + (float)((process_properties->background_color & 0x00FF0000) >> 16) / 255.0; + build_param->bg_color.rgba.g = + (float)((process_properties->background_color & 0x0000FF00) >> 8) / 255.0; + build_param->bg_color.rgba.b = + (float)(process_properties->background_color & 0x000000FF) / 255.0; + } else { + build_param->bg_color.rgba.r = 0; + build_param->bg_color.rgba.g = 0; + build_param->bg_color.rgba.b = 0; + build_param->bg_color.rgba.a = 0; + } + + build_param->alpha_mode = VPE_ALPHA_OPAQUE; + + build_param->flags.hdr_metadata = 0; + build_param->flags.reserved = 1; + + /* TODO: hdr_metadata support in next stage */ + build_param->hdr_metadata.redX = 1; + build_param->hdr_metadata.redY = 1; + build_param->hdr_metadata.greenX = 1; + build_param->hdr_metadata.greenY = 1; + build_param->hdr_metadata.blueX = 1; + build_param->hdr_metadata.blueY = 1; + build_param->hdr_metadata.whiteX = 1; + build_param->hdr_metadata.whiteY = 1; + + build_param->hdr_metadata.min_mastering = 1; + build_param->hdr_metadata.max_mastering = 1; + build_param->hdr_metadata.max_content = 1; + build_param->hdr_metadata.avg_content = 1; + + uint64_t *vpe_ptr; + 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; + + vpe_ptr = (uint64_t *)vpeproc->ws->buffer_map(vpeproc->ws, vpeproc->emb_buffer.res->buf, + &vpeproc->cs, PIPE_MAP_WRITE | RADEON_MAP_TEMPORARY); + 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(vpeproc->emb_buffer.res->buf); + vpeproc->vpe_build_bufs->emb_buf.size = VPE_BUILD_BUFS_SIZE; + vpeproc->vpe_build_bufs->emb_buf.tmz = false; + + if (vpeproc->log_level >= SI_VPE_LOG_LEVEL_DEBUG) { + SIVPE_DBG(vpeproc->log_level, "src surface format(%d) rect (%d, %d, %d, %d)\n", + build_param->streams[0].surface_info.format, + build_param->streams[0].surface_info.plane_size.surface_size.x, + build_param->streams[0].surface_info.plane_size.surface_size.y, + build_param->streams[0].surface_info.plane_size.surface_size.width, + build_param->streams[0].surface_info.plane_size.surface_size.height); + + SIVPE_DBG(vpeproc->log_level, "src surface Cositing(%s), primaries(%s), tf(%s), range(%s)\n", + si_vpe_get_cositing_str(build_param->streams[0].surface_info.cs.cositing), + si_vpe_get_primarie_str(build_param->streams[0].surface_info.cs.primaries), + si_vpe_get_tf_str(build_param->streams[0].surface_info.cs.tf), + (build_param->streams[0].surface_info.cs.range == VPE_COLOR_RANGE_FULL)?"FULL":"STUDIO"); + + SIVPE_DBG(vpeproc->log_level, "dst surface format(%d) rect (%d, %d, %d, %d)\n", + build_param->dst_surface.format, + build_param->dst_surface.plane_size.surface_size.x, + build_param->dst_surface.plane_size.surface_size.y, + build_param->dst_surface.plane_size.surface_size.width, + build_param->dst_surface.plane_size.surface_size.height); + + SIVPE_DBG(vpeproc->log_level, "dst surface Cositing(%s), primaries(%s), tf(%s), range(%s)\n", + si_vpe_get_cositing_str(build_param->dst_surface.cs.cositing), + si_vpe_get_primarie_str(build_param->dst_surface.cs.primaries), + si_vpe_get_tf_str(build_param->dst_surface.cs.tf), + (build_param->dst_surface.cs.range == VPE_COLOR_RANGE_FULL)?"FULL":"STUDIO"); + + SIVPE_DBG(vpeproc->log_level, "background color RGBA(%0.3f, %0.3f, %0.3f, %0.3f)\n", + build_param->bg_color.rgba.r, + build_param->bg_color.rgba.g, + build_param->bg_color.rgba.b, + build_param->bg_color.rgba.a); + + SIVPE_DBG(vpeproc->log_level, "target_rect(%d, %d, %d, %d)\n", + build_param->target_rect.x, + build_param->target_rect.y, + build_param->target_rect.width, + build_param->target_rect.height); + + SIVPE_DBG(vpeproc->log_level, "rotation(%d) horizontal_mirror(%d) vertical_mirror(%d)\n", + build_param->streams[0].rotation, + build_param->streams[0].horizontal_mirror, + build_param->streams[0].vertical_mirror); + + SIVPE_DBG(vpeproc->log_level, "scaling_src_rect(%d, %d, %d, %d)\n", + build_param->streams[0].scaling_info.src_rect.x, + build_param->streams[0].scaling_info.src_rect.y, + build_param->streams[0].scaling_info.src_rect.width, + build_param->streams[0].scaling_info.src_rect.height); + + SIVPE_DBG(vpeproc->log_level, "scaling_dst_rect(%d, %d, %d, %d)\n", + build_param->streams[0].scaling_info.dst_rect.x, + build_param->streams[0].scaling_info.dst_rect.y, + build_param->streams[0].scaling_info.dst_rect.width, + build_param->streams[0].scaling_info.dst_rect.height); + + SIVPE_DBG(vpeproc->log_level, "scaling_taps h_taps(%d) v_taps(%d) h_taps_c(%d) v_taps_c(%d)\n", + build_param->streams[0].scaling_info.taps.h_taps, + build_param->streams[0].scaling_info.taps.v_taps, + build_param->streams[0].scaling_info.taps.h_taps_c, + build_param->streams[0].scaling_info.taps.v_taps_c); + + SIVPE_DBG(vpeproc->log_level, "blend global_alpha(%d): %0.3f\n", + build_param->streams[0].blend_info.global_alpha, + build_param->streams[0].blend_info.global_alpha_value); + + SIVPE_DBG(vpeproc->log_level, "ToneMapping shaper_tf(%d) lut_out_tf(%d) lut_in_gamut(%d) lut_out_gamut(%d)\n", + build_param->streams[0].tm_params.shaper_tf, + build_param->streams[0].tm_params.lut_out_tf, + build_param->streams[0].tm_params.lut_in_gamut, + build_param->streams[0].tm_params.lut_out_gamut); + + //SIVPE_DBG(vpeproc->log_level, "ToneMapping update_3dlut(%d) enable_3dlut(%d)\n", + // build_param->streams[0].tm_params.update_3dlut, + // build_param->streams[0].tm_params.enable_3dlut); + } + + result = vpe_check_support(vpe_handle, build_param, &bufs_required); + if (VPE_STATUS_OK != result) { + SIVPE_ERR("Check support failed with result: %d\n", result); + goto fail; + } + + 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; + } + + /* 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; + } + if (vpeproc->vpe_build_bufs->emb_buf.size == 0 || vpeproc->vpe_build_bufs->emb_buf.size == VPE_BUILD_BUFS_SIZE) { + SIVPE_ERR("Embbuf size wrong\n"); + goto fail; + } + + /* Wait Source Surface fence */ + if (process_properties->src_surface_fence) { + struct pipe_fence_handle *input_fence = (struct pipe_fence_handle *)process_properties->src_surface_fence; + while (!vpeproc->ws->fence_wait(vpeproc->ws, input_fence, VPE_FENCE_TIMEOUT_NS)) + SIVPE_INFO(vpeproc->log_level, "Wait source surface fence fail\n"); + } + + /* Have to tell Command Submission context the command length wrote by libvpe */ + vpeproc->cs.current.cdw += (vpeproc->vpe_build_bufs->cmd_buf.size / 4); + + /* Add embbuf into bo_handle list */ + vpeproc->ws->buffer_unmap(vpeproc->ws, vpeproc->emb_buffer.res->buf); + vpeproc->ws->cs_add_buffer(&vpeproc->cs, vpeproc->emb_buffer.res->buf, RADEON_USAGE_READ | RADEON_USAGE_SYNCHRONIZED, RADEON_DOMAIN_GTT); + + 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); + + vpeproc->ws->cs_flush(&vpeproc->cs, PIPE_FLUSH_ASYNC, &process_fence); + + if (process_fence) + vpeproc->process_fence = process_fence; + SIVPE_INFO(vpeproc->log_level, "Flush success\n"); + + FREE(build_param->streams); + SIVPE_DBG(vpeproc->log_level, "Success\n"); + return; + +fail: + vpeproc->ws->buffer_unmap(vpeproc->ws, vpeproc->emb_buffer.res->buf); + FREE(build_param->streams); + SIVPE_ERR("Failed\n"); + return; +} + +static void +si_vpe_processor_end_frame(struct pipe_video_codec *codec, + struct pipe_video_buffer *target, + struct pipe_picture_desc *picture) +{ + struct vpe_video_processor *vpeproc = (struct vpe_video_processor *)codec; + assert(codec); + + if (picture->fence && vpeproc->process_fence) { + *picture->fence = vpeproc->process_fence; + SIVPE_INFO(vpeproc->log_level, "Assign process fence\n"); + } + SIVPE_INFO(vpeproc->log_level, "Success\n"); +} + +static void +si_vpe_processor_flush(struct pipe_video_codec *codec) +{ + struct vpe_video_processor *vpeproc = (struct vpe_video_processor *)codec; + assert(codec); + + SIVPE_DBG(vpeproc->log_level, "Success\n"); + return; +} + +static int si_vpe_processor_get_processor_fence(struct pipe_video_codec *codec, + struct pipe_fence_handle *fence, + uint64_t timeout) +{ + struct vpe_video_processor *vpeproc = (struct vpe_video_processor *)codec; + assert(codec); + + SIVPE_INFO(vpeproc->log_level, "Wait processor fence\n"); + while (!vpeproc->ws->fence_wait(vpeproc->ws, fence, timeout)) + SIVPE_DBG(vpeproc->log_level, "Wait processor fence fail\n"); + SIVPE_INFO(vpeproc->log_level, "Wait processor fence success\n"); + return 1; +} + +struct pipe_video_codec* +si_vpe_create_processor(struct pipe_context *context, const struct pipe_video_codec *templ) +{ + struct si_context *sctx = (struct si_context *)context; + struct radeon_winsys *ws = sctx->ws; + struct vpe_video_processor *vpeproc; + struct vpe_init_data *init_data; + const char *str = getenv("AMDGPU_SIVPE_LOG_LEVEL"); + + vpeproc = CALLOC_STRUCT(vpe_video_processor); + if (!vpeproc) { + SIVPE_ERR("Allocate struct failed\n"); + return NULL; + } + + /* get SI_VPE debug log level */ + if (str == NULL) + vpeproc->log_level = SI_VPE_LOG_LEVEL_DEFAULT; + else + vpeproc->log_level = atoi(str); + + vpeproc->base = *templ; + vpeproc->base.context = context; + vpeproc->base.width = templ->width; + vpeproc->base.height = templ->height; + + vpeproc->base.destroy = si_vpe_processor_destroy; + vpeproc->base.begin_frame = si_vpe_processor_begin_frame; + vpeproc->base.process_frame = si_vpe_processor_process_frame; + vpeproc->base.end_frame = si_vpe_processor_end_frame; + vpeproc->base.flush = si_vpe_processor_flush; + vpeproc->base.get_processor_fence = si_vpe_processor_get_processor_fence; + + vpeproc->ver_major = sctx->screen->info.ip[AMD_IP_VPE].ver_major; + vpeproc->ver_minor = sctx->screen->info.ip[AMD_IP_VPE].ver_minor; + + vpeproc->screen = context->screen; + vpeproc->ws = ws; + vpeproc->process_fence = NULL; + + init_data = &vpeproc->vpe_data; + if (VPE_STATUS_OK != si_vpe_populate_init_data(sctx, init_data, vpeproc->log_level)){ + SIVPE_ERR("Init VPE populate data failed\n"); + goto fail; + } + + vpeproc->vpe_handle = vpe_create(init_data); + if (!vpeproc->vpe_handle) { + SIVPE_ERR("Create VPE handle failed\n"); + goto fail; + } + + if (VPE_STATUS_OK != si_vpe_allocate_buffer(&vpeproc->vpe_build_bufs)) { + SIVPE_ERR("Allocate VPE buffers failed\n"); + goto fail; + } + + /* Create Command Submission context. + * The cmdbuf (Vpe Descriptor) will be stored in cs.current.buf + * there is no needs to allocate another buffer handle for cmdbuf. + */ + if (!ws->cs_create(&vpeproc->cs, sctx->ctx, AMD_IP_VPE, NULL, NULL)) { + SIVPE_ERR("Get command submission context failed.\n"); + goto fail; + } + vpeproc->vpe_build_bufs->cmd_buf.size = vpeproc->cs.current.max_dw; + + /* Creste Vpblit Descriptor buffer. + * This buffer will store plane config / VPEP config commands + */ + if (!si_vid_create_buffer(vpeproc->screen, &vpeproc->emb_buffer, VPE_BUILD_BUFS_SIZE, + PIPE_USAGE_DEFAULT)) { + SIVPE_ERR("Allocate VPE emb buffers failed.\n"); + goto fail; + } + si_vid_clear_buffer(context, &vpeproc->emb_buffer); + vpeproc->vpe_build_bufs->emb_buf.size = VPE_BUILD_BUFS_SIZE; + + /* Create VPE parameters structure */ + vpeproc->vpe_build_param = CALLOC_STRUCT(vpe_build_param); + if (!vpeproc->vpe_build_param) { + SIVPE_ERR("Allocate build-paramaters sturcture failed\n"); + goto fail; + } + + return &vpeproc->base; + +fail: + SIVPE_ERR("Failed\n"); + if (vpeproc) { + si_vpe_processor_destroy(&vpeproc->base); + } + return NULL; +} diff --git a/src/gallium/drivers/radeonsi/si_vpe.h b/src/gallium/drivers/radeonsi/si_vpe.h new file mode 100755 index 00000000000..09ca8eb045d --- /dev/null +++ b/src/gallium/drivers/radeonsi/si_vpe.h @@ -0,0 +1,75 @@ +/************************************************************************** + * + * Copyright 2022 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. + * 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. + * + **************************************************************************/ + +#ifndef SI_VPE_H +#define SI_VPE_H + +#include "pipe/p_screen.h" +#include "pipe/p_video_codec.h" +#include "vpelib/inc/vpelib.h" +#include "radeon_video.h" + +/* The buffer size of cmd_buf and emb_buf in bytes + * + * TODO: vpe-utils also use this value. Need to be reviewed further. + */ +#define VPE_BUILD_BUFS_SIZE 1000000 +#define VPE_FENCE_TIMEOUT_NS 1000000000 + +/* For Hooking VPE as a decoder instance */ +struct vpe_video_processor { + struct pipe_video_codec base; + + struct pipe_screen *screen; + struct radeon_winsys *ws; + struct radeon_cmdbuf cs; + + struct rvid_buffer cmd_buffer; + struct rvid_buffer emb_buffer; + + struct pipe_fence_handle *process_fence; + + /* VPE HW version */ + uint8_t ver_major; + uint8_t ver_minor; + + struct vpe *vpe_handle; + struct vpe_init_data vpe_data; + struct vpe_build_bufs *vpe_build_bufs; + struct vpe_build_param *vpe_build_param; + + uint8_t log_level; + + struct pipe_surface **src_surfaces; + struct pipe_surface **dst_surfaces; +}; + +struct pipe_video_codec* +si_vpe_create_processor(struct pipe_context *context, + const struct pipe_video_codec *templ); + +#endif