/* * Copyright (c) 2011 Intel Corporation. All Rights Reserved. * Copyright (c) Imagination Technologies Limited, UK * * 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 PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: * Li Zeng <li.zeng@intel.com> */ #include "tng_vld_dec.h" #include "psb_drv_debug.h" #include "hwdefs/dxva_fw_ctrl.h" #include "hwdefs/reg_io2.h" #include "hwdefs/msvdx_offsets.h" #include "hwdefs/msvdx_cmds_io2.h" #include <malloc.h> #define SURFACE(id) ((object_surface_p) object_heap_lookup( &dec_ctx->obj_context->driver_data->surface_heap, id )) static void tng_yuv_processor_QueryConfigAttributes( VAProfile __maybe_unused rofile, VAEntrypoint __maybe_unused entrypoint, VAConfigAttrib __maybe_unused * attrib_list, int __maybe_unused num_attribs) { /* No specific attributes */ } static VAStatus tng_yuv_processor_ValidateConfig( object_config_p __maybe_unused obj_config) { return VA_STATUS_SUCCESS; } static VAStatus tng_yuv_processor_process_buffer( context_DEC_p, object_buffer_p); static VAStatus tng_yuv_processor_CreateContext( object_context_p obj_context, object_config_p __maybe_unused obj_config) { VAStatus vaStatus = VA_STATUS_SUCCESS; context_DEC_p dec_ctx = (context_DEC_p) obj_context->format_data; context_yuv_processor_p ctx; ctx = (context_yuv_processor_p) malloc(sizeof(struct context_yuv_processor_s)); CHECK_ALLOCATION(ctx); /* ctx could be create in/out another dec context */ ctx->has_dec_ctx = 0; ctx->src_surface = NULL; if (!dec_ctx) { dec_ctx = (context_DEC_p) malloc(sizeof(struct context_DEC_s)); if(dec_ctx == NULL) { free(ctx); vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; drv_debug_msg(VIDEO_DEBUG_ERROR, "%s fails with '%d' at %s:%d\n", __FUNCTION__, vaStatus, __FILE__, __LINE__); return vaStatus; } obj_context->format_data = (void *)dec_ctx; ctx->has_dec_ctx = 1; vaStatus = vld_dec_CreateContext(dec_ctx, obj_context); DEBUG_FAILURE; } dec_ctx->yuv_ctx = ctx; dec_ctx->process_buffer = tng_yuv_processor_process_buffer; return vaStatus; } static void tng_yuv_processor_DestroyContext( object_context_p obj_context) { context_DEC_p dec_ctx = (context_DEC_p) obj_context->format_data; context_yuv_processor_p yuv_ctx = NULL; int has_dec_ctx = 0; if (dec_ctx == NULL) return; yuv_ctx = dec_ctx->yuv_ctx; if (yuv_ctx) { has_dec_ctx = yuv_ctx->has_dec_ctx; free(yuv_ctx); dec_ctx->yuv_ctx = NULL; } if (has_dec_ctx) { free(dec_ctx); obj_context->format_data = NULL; } } static VAStatus tng_yuv_processor_BeginPicture( object_context_p __maybe_unused obj_context) { return VA_STATUS_SUCCESS; } static void tng__yuv_processor_process(context_DEC_p dec_ctx) { context_yuv_processor_p ctx = dec_ctx->yuv_ctx; psb_cmdbuf_p cmdbuf = dec_ctx->obj_context->cmdbuf; /* psb_surface_p target_surface = dec_ctx->obj_context->current_render_target->psb_surface; */ psb_surface_p src_surface = ctx->src_surface; psb_buffer_p buffer; uint32_t reg_value; psb_cmdbuf_rendec_start(cmdbuf, RENDEC_REGISTER_OFFSET(MSVDX_CMDS, DISPLAY_PICTURE_SIZE)); reg_value = 0; REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, DISPLAY_PICTURE_SIZE, DISPLAY_PICTURE_HEIGHT, (ctx->display_height) - 1); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, DISPLAY_PICTURE_SIZE, DISPLAY_PICTURE_WIDTH, (ctx->display_width) - 1); psb_cmdbuf_rendec_write(cmdbuf, reg_value); reg_value = 0; REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, CODED_PICTURE_SIZE, CODED_PICTURE_HEIGHT, (ctx->coded_height) - 1); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, CODED_PICTURE_SIZE, CODED_PICTURE_WIDTH, (ctx->coded_width) - 1); psb_cmdbuf_rendec_write(cmdbuf, reg_value); psb_cmdbuf_rendec_end(cmdbuf); /*TODO add stride and else there*/ reg_value = 0; REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, OPERATING_MODE, CODEC_MODE, 3); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, OPERATING_MODE, ASYNC_MODE, 1); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, OPERATING_MODE, CODEC_PROFILE, 1); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, OPERATING_MODE, CHROMA_FORMAT, 1); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, OPERATING_MODE, ROW_STRIDE, src_surface->stride_mode); psb_cmdbuf_rendec_start(cmdbuf, RENDEC_REGISTER_OFFSET( MSVDX_CMDS, OPERATING_MODE )); psb_cmdbuf_rendec_write(cmdbuf, reg_value); psb_cmdbuf_rendec_end(cmdbuf); psb_cmdbuf_rendec_start(cmdbuf, RENDEC_REGISTER_OFFSET(MSVDX_CMDS, REFERENCE_PICTURE_BASE_ADDRESSES)); buffer = &src_surface->buf; psb_cmdbuf_rendec_write_address(cmdbuf, buffer, buffer->buffer_ofs); psb_cmdbuf_rendec_write_address(cmdbuf, buffer, buffer->buffer_ofs + src_surface->chroma_offset); psb_cmdbuf_rendec_end(cmdbuf); reg_value = 0; REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, SLICE_PARAMS, CONSTRAINED_INTRA_PRED, 0 ); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, SLICE_PARAMS, MODE_CONFIG, 0 ); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, SLICE_PARAMS, DISABLE_DEBLOCK_FILTER_IDC, 1 ); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, SLICE_PARAMS, SLICE_ALPHA_CO_OFFSET_DIV2, 0 ); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, SLICE_PARAMS, SLICE_BETA_OFFSET_DIV2, 0 ); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, SLICE_PARAMS, SLICE_FIELD_TYPE, 2 ); REGIO_WRITE_FIELD_LITE(reg_value, MSVDX_CMDS, SLICE_PARAMS, SLICE_CODE_TYPE, 1 ); // P *dec_ctx->p_slice_params = reg_value; psb_cmdbuf_rendec_start(cmdbuf, RENDEC_REGISTER_OFFSET( MSVDX_CMDS, SLICE_PARAMS ) ); psb_cmdbuf_rendec_write(cmdbuf, reg_value); psb_cmdbuf_rendec_end(cmdbuf); vld_dec_setup_alternative_frame(dec_ctx->obj_context); *cmdbuf->cmd_idx++ = CMD_DEBLOCK | CMD_DEBLOCK_TYPE_SKIP; *cmdbuf->cmd_idx++ = 0; *cmdbuf->cmd_idx++ = ctx->coded_width / 16; *cmdbuf->cmd_idx++ = ctx->coded_height / 16; *cmdbuf->cmd_idx++ = 0; *cmdbuf->cmd_idx++ = 0; } static VAStatus tng__yuv_processor_execute(context_DEC_p dec_ctx, object_buffer_p obj_buffer) { /* psb_surface_p target_surface = dec_ctx->obj_context->current_render_target->psb_surface; */ context_yuv_processor_p ctx = dec_ctx->yuv_ctx; uint32_t reg_value; VAStatus vaStatus; ASSERT(obj_buffer->type == YUVProcessorSurfaceType || obj_buffer->type == VAProcPipelineParameterBufferType); ASSERT(obj_buffer->num_elements == 1); ASSERT(obj_buffer->size == sizeof(struct surface_param_s)); if ((obj_buffer->num_elements != 1) || ((obj_buffer->size != sizeof(struct surface_param_s)) && (obj_buffer->size != sizeof(VAProcPipelineParameterBuffer)))) { return VA_STATUS_ERROR_UNKNOWN; } /* yuv rotation issued from dec driver, TODO removed later */ if (obj_buffer->type == YUVProcessorSurfaceType) { surface_param_p surface_params = (surface_param_p) obj_buffer->buffer_data; psb_surface_p rotate_surface = dec_ctx->obj_context->current_render_target->out_loop_surface; object_context_p obj_context = dec_ctx->obj_context; psb_driver_data_p driver_data = obj_context->driver_data; ctx->display_width = (surface_params->display_width + 0xf) & ~0xf; ctx->display_height = (surface_params->display_height + 0xf) & ~0xf; ctx->coded_width = (surface_params->coded_width + 0xf) & ~0xf; ctx->coded_height = (surface_params->coded_height + 0xf) & ~0xf; ctx->src_surface = surface_params->src_surface; ctx->proc_param = NULL; dec_ctx->obj_context->msvdx_rotate = obj_context->msvdx_rotate; SET_SURFACE_INFO_rotate(rotate_surface, dec_ctx->obj_context->msvdx_rotate); obj_buffer->buffer_data = NULL; obj_buffer->size = 0; #ifdef PSBVIDEO_MSVDX_DEC_TILING if (GET_SURFACE_INFO_tiling(ctx->src_surface)) { unsigned long msvdx_tile = psb__tile_stride_log2_256(rotate_surface->stride); obj_context->msvdx_tile &= 0xf; /* clear rotate tile */ obj_context->msvdx_tile |= (msvdx_tile << 4); obj_context->ctp_type &= (~PSB_CTX_TILING_MASK); /* clear tile context */ obj_context->ctp_type |= ((obj_context->msvdx_tile & 0xff) << 16); psb_update_context(driver_data, obj_context->ctp_type); drv_debug_msg(VIDEO_DEBUG_GENERAL, "update tile context, msvdx_tiled is 0x%08x \n", obj_context->msvdx_tile); } #endif } else if (obj_buffer->type == VAProcPipelineParameterBufferType) { VAProcPipelineParameterBuffer *vpp_params = (VAProcPipelineParameterBuffer *) obj_buffer->buffer_data; object_surface_p obj_surface = SURFACE(vpp_params->surface); psb_surface_p rotate_surface = dec_ctx->obj_context->current_render_target->psb_surface; if (obj_surface == NULL){ vaStatus = VA_STATUS_ERROR_UNKNOWN; return vaStatus; } //ctx->display_width = ((vpp_params->surface_region->width + 0xf) & ~0xf); //ctx->display_height = ((vpp_params->surface_region->height + 0x1f) & ~0x1f); ctx->display_width = ((obj_surface->width + 0xf) & ~0xf); ctx->display_height = ((obj_surface->height + 0xf) & ~0xf); ctx->coded_width = ctx->display_width; ctx->coded_height = ctx->display_height; ctx->src_surface = obj_surface->psb_surface; dec_ctx->obj_context->msvdx_rotate = vpp_params->rotation_state; SET_SURFACE_INFO_rotate(rotate_surface, dec_ctx->obj_context->msvdx_rotate); ctx->proc_param = vpp_params; obj_buffer->buffer_data = NULL; obj_buffer->size = 0; #ifdef PSBVIDEO_MSVDX_DEC_TILING object_context_p obj_context = dec_ctx->obj_context; psb_driver_data_p driver_data = obj_context->driver_data; drv_debug_msg(VIDEO_DEBUG_GENERAL, "attempt to update tile context\n"); if (GET_SURFACE_INFO_tiling(ctx->src_surface)) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "update tile context\n"); unsigned long msvdx_tile = psb__tile_stride_log2_256(rotate_surface->stride); obj_context->msvdx_tile &= 0xf; /* clear rotate tile */ obj_context->msvdx_tile |= (msvdx_tile << 4); obj_context->ctp_type &= (~PSB_CTX_TILING_MASK); /* clear tile context */ obj_context->ctp_type |= ((obj_context->msvdx_tile & 0xff) << 16); psb_update_context(driver_data, obj_context->ctp_type); drv_debug_msg(VIDEO_DEBUG_GENERAL, "update tile context, msvdx_tiled is 0x%08x \n", obj_context->msvdx_tile); } #endif } #ifdef ADNROID LOGV("%s, %d %d %d %d***************************************************\n", __func__, ctx->display_width, ctx->display_height, ctx->coded_width, ctx->coded_height); #endif vaStatus = VA_STATUS_SUCCESS; if (psb_context_get_next_cmdbuf(dec_ctx->obj_context)) { vaStatus = VA_STATUS_ERROR_UNKNOWN; DEBUG_FAILURE; return vaStatus; } /* ctx->begin_slice(ctx, slice_param); */ vld_dec_FE_state(dec_ctx->obj_context, NULL); tng__yuv_processor_process(dec_ctx); /* ctx->process_slice(ctx, slice_param); */ vld_dec_write_kick(dec_ctx->obj_context); dec_ctx->obj_context->video_op = psb_video_vld; dec_ctx->obj_context->flags = 0; /* ctx->end_slice(ctx); */ dec_ctx->obj_context->flags = FW_VA_RENDER_IS_FIRST_SLICE | FW_VA_RENDER_IS_LAST_SLICE | FW_INTERNAL_CONTEXT_SWITCH; if (psb_context_submit_cmdbuf(dec_ctx->obj_context)) { vaStatus = VA_STATUS_ERROR_UNKNOWN; } return vaStatus; } static VAStatus tng_yuv_processor_process_buffer( context_DEC_p dec_ctx, object_buffer_p buffer) { VAStatus vaStatus = VA_STATUS_SUCCESS; object_buffer_p obj_buffer = buffer; unsigned int type = obj_buffer->type; { switch (type) { case YUVProcessorSurfaceType: case VAProcPipelineParameterBufferType: vaStatus = tng__yuv_processor_execute(dec_ctx, obj_buffer); DEBUG_FAILURE; break; default: vaStatus = VA_STATUS_ERROR_UNKNOWN; DEBUG_FAILURE; } } return vaStatus; } static VAStatus tng_yuv_processor_EndPicture( object_context_p obj_context) { context_DEC_p dec_ctx = (context_DEC_p) obj_context->format_data; context_yuv_processor_p ctx = dec_ctx->yuv_ctx; if (psb_context_flush_cmdbuf(obj_context)) { return VA_STATUS_ERROR_UNKNOWN; } if (ctx->proc_param) { free(ctx->proc_param); ctx->proc_param = NULL; } return VA_STATUS_SUCCESS; } struct format_vtable_s tng_yuv_processor_vtable = { queryConfigAttributes: tng_yuv_processor_QueryConfigAttributes, validateConfig: tng_yuv_processor_ValidateConfig, createContext: tng_yuv_processor_CreateContext, destroyContext: tng_yuv_processor_DestroyContext, beginPicture: tng_yuv_processor_BeginPicture, renderPicture: vld_dec_RenderPicture, endPicture: tng_yuv_processor_EndPicture }; #define VED_SUPPORTED_FILTERS_NUM 1 #define INIT_DRIVER_DATA psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData; #define CONFIG(id) ((object_config_p) object_heap_lookup( &driver_data->config_heap, id )) #define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id )) #define BUFFER(id) ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id )) VAStatus ved_QueryVideoProcFilters( VADriverContextP ctx, VAContextID context, VAProcFilterType *filters, unsigned int *num_filters) { INIT_DRIVER_DATA; VAStatus vaStatus = VA_STATUS_SUCCESS; object_context_p obj_context; object_config_p obj_config; VAEntrypoint tmp; int count; /* check if ctx is right */ obj_context = CONTEXT(context); if (NULL == obj_context) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to find context\n"); vaStatus = VA_STATUS_ERROR_INVALID_CONTEXT; goto err; } obj_config = CONFIG(obj_context->config_id); if (NULL == obj_config) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to find config\n"); vaStatus = VA_STATUS_ERROR_INVALID_CONFIG; goto err; } tmp = obj_config->entrypoint; if (tmp != VAEntrypointVideoProc) { drv_debug_msg(VIDEO_DEBUG_ERROR, "current entrypoint is %d, not VAEntrypointVideoProc\n", tmp); vaStatus = VA_STATUS_ERROR_UNKNOWN; goto err; } /* check if filters and num_filters is valid */ if (NULL == num_filters || NULL == filters) { drv_debug_msg(VIDEO_DEBUG_ERROR, "invalide input parameter num_filters %p, filters %p\n", num_filters, filters); vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; goto err; } /* check if the filter array size is valid */ if (*num_filters < VED_SUPPORTED_FILTERS_NUM) { drv_debug_msg(VIDEO_DEBUG_ERROR, "The filters array size(%d) is NOT valid! Supported filters num is %d\n", *num_filters, VED_SUPPORTED_FILTERS_NUM); vaStatus = VA_STATUS_ERROR_MAX_NUM_EXCEEDED; *num_filters = VED_SUPPORTED_FILTERS_NUM; goto err; } count = 0; filters[count++] = VAProcFilterNone; *num_filters = count; err: return vaStatus; } VAStatus ved_QueryVideoProcFilterCaps( VADriverContextP ctx, VAContextID context, VAProcFilterType type, void *filter_caps, unsigned int *num_filter_caps) { INIT_DRIVER_DATA; VAStatus vaStatus = VA_STATUS_SUCCESS; object_context_p obj_context; object_config_p obj_config; VAProcFilterCap *no_cap; /* check if context is right */ obj_context = CONTEXT(context); if (NULL == obj_context) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to find context\n"); vaStatus = VA_STATUS_ERROR_INVALID_CONTEXT; goto err; } obj_config = CONFIG(obj_context->config_id); if (NULL == obj_config) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to find config\n"); vaStatus = VA_STATUS_ERROR_INVALID_CONFIG; goto err; } /* check if filter_caps and num_filter_caps is right */ if (NULL == num_filter_caps || NULL == filter_caps){ drv_debug_msg(VIDEO_DEBUG_ERROR, "invalide input parameter num_filters %p, filters %p\n", num_filter_caps, filter_caps); vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; goto err; } if (*num_filter_caps < 1) { drv_debug_msg(VIDEO_DEBUG_ERROR, "invalide input parameter num_filters == %d (> 1)\n", *num_filter_caps); vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; goto err; } /* check if curent HW support and return corresponding caps */ /* FIXME: we should use a constant table to return caps */ switch (type) { case VAProcFilterNone: no_cap = filter_caps; no_cap->range.min_value = 0; no_cap->range.max_value = 0; no_cap->range.default_value = 0; no_cap->range.step = 0; *num_filter_caps = 1; break; default: drv_debug_msg(VIDEO_DEBUG_ERROR, "invalide filter type %d\n", type); vaStatus = VA_STATUS_ERROR_UNSUPPORTED_FILTER; *num_filter_caps = 0; goto err; } err: return vaStatus; } VAStatus ved_QueryVideoProcPipelineCaps( VADriverContextP ctx, VAContextID context, VABufferID *filters, unsigned int num_filters, VAProcPipelineCaps *pipeline_caps) { INIT_DRIVER_DATA; VAStatus vaStatus = VA_STATUS_SUCCESS; object_context_p obj_context; object_config_p obj_config; VAProcFilterParameterBufferBase *base; object_buffer_p buf; /* check if ctx is right */ obj_context = CONTEXT(context); if (NULL == obj_context) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to find context\n"); vaStatus = VA_STATUS_ERROR_INVALID_CONTEXT; goto err; } obj_config = CONFIG(obj_context->config_id); if (NULL == obj_config) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to find config\n"); vaStatus = VA_STATUS_ERROR_INVALID_CONFIG; goto err; } /* check if filters and num_filters and pipeline-caps are right */ if (num_filters != 1) { drv_debug_msg(VIDEO_DEBUG_ERROR, "invalid num_filters %d\n", num_filters); vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; goto err; } if (NULL == filters || pipeline_caps == NULL) { drv_debug_msg(VIDEO_DEBUG_ERROR, "invalid filters %p or pipeline_caps %p\n", filters, pipeline_caps); vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; goto err; } memset(pipeline_caps, 0, sizeof(*pipeline_caps)); buf = BUFFER(*(filters)); if (buf == NULL){ drv_debug_msg(VIDEO_DEBUG_ERROR, "invalid filter buffer: NULL \n"); vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; goto err; } base = (VAProcFilterParameterBufferBase *)buf->buffer_data; /* check filter buffer setting */ switch (base->type) { case VAProcFilterNone: pipeline_caps->rotation_flags = (1 << VA_ROTATION_NONE); pipeline_caps->rotation_flags |= (1 << VA_ROTATION_90); pipeline_caps->rotation_flags |= (1 << VA_ROTATION_180); pipeline_caps->rotation_flags |= (1 << VA_ROTATION_270); break; default: drv_debug_msg(VIDEO_DEBUG_ERROR, "Do NOT support the filter type %d\n", base->type); vaStatus = VA_STATUS_ERROR_UNKNOWN; goto err; } err: return vaStatus; }