| /* |
| * Copyright (c) 2011 Intel Corporation. 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 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: |
| * Zeng Li <zeng.li@intel.com> |
| * Jason Hu <jason.hu@intel.com> |
| * Shengquan Yuan <shengquan.yuan@intel.com> |
| */ |
| |
| #include <va/va.h> |
| #include <va/va_backend.h> |
| #include <va/va_backend_tpi.h> |
| #include <va/va_backend_egl.h> |
| #include <va/va_drmcommon.h> |
| #include "psb_drv_video.h" |
| #include "psb_output.h" |
| #include "android/psb_android_glue.h" |
| #include "psb_drv_debug.h" |
| #include "vc1_defs.h" |
| #include "pnw_rotate.h" |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdarg.h> |
| #include <time.h> |
| #include <unistd.h> |
| #include <wsbm/wsbm_pool.h> |
| #include <wsbm/wsbm_manager.h> |
| #include <wsbm/wsbm_util.h> |
| #include <wsbm/wsbm_fencemgr.h> |
| |
| #ifdef ANROID |
| #include <system/graphics.h> |
| #endif |
| |
| #define INIT_DRIVER_DATA psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData |
| #define INIT_OUTPUT_PRIV unsigned char* output = ((psb_driver_data_p)ctx->pDriverData)->ws_priv |
| #define SURFACE(id) ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id )) |
| #define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id )) |
| #define CONFIG(id) ((object_config_p) object_heap_lookup( &driver_data->config_heap, id )) |
| |
| /*picture structure*/ |
| #define TOP_FIELD 1 |
| #define BOTTOM_FIELD 2 |
| #define FRAME_PICTURE 3 |
| |
| #define CHECK_SURFACE_REALLOC(psb_surface, msvdx_rotate, need) \ |
| do { \ |
| int old_rotate = GET_SURFACE_INFO_rotate(psb_surface); \ |
| switch (msvdx_rotate) { \ |
| case 2: /* 180 */ \ |
| if (old_rotate == 2) \ |
| need = 0; \ |
| else \ |
| need = 1; \ |
| break; \ |
| case 1: /* 90 */ \ |
| case 3: /* 270 */ \ |
| if (old_rotate == 1 || old_rotate == 3) \ |
| need = 0; \ |
| else \ |
| need = 1; \ |
| break; \ |
| } \ |
| } while (0) |
| |
| static int get_surface_stride(int width, int tiling) |
| { |
| int stride = 0; |
| |
| if (0) { |
| ; |
| } else if (512 >= width) { |
| stride = 512; |
| } else if (1024 >= width) { |
| stride = 1024; |
| } else if (1280 >= width) { |
| stride = 1280; |
| #ifdef PSBVIDEO_MSVDX_DEC_TILING |
| if (tiling) { |
| stride = 2048; |
| } |
| #endif |
| } else if (2048 >= width) { |
| stride = 2048; |
| } else if (4096 >= width) { |
| stride = 4096; |
| } else { |
| stride = (width + 0x3f) & ~0x3f; |
| } |
| |
| return stride; |
| } |
| //#define OVERLAY_ENABLE_MIRROR |
| |
| #ifdef PSBVIDEO_MRFL_VPP |
| |
| static int isVppOn(void __maybe_unused *output) { |
| #ifdef TARGET_HAS_MULTIPLE_DISPLAY |
| return psb_android_get_mds_vpp_state(output); |
| #else |
| return psb_android_get_vpp_state(); |
| #endif |
| } |
| #endif |
| |
| void psb_InitOutLoop(VADriverContextP ctx) |
| { |
| char env_value[64]; |
| INIT_DRIVER_DATA; |
| |
| /* VA rotate from APP */ |
| driver_data->va_rotate = VA_ROTATION_NONE; |
| |
| /* window manager rotation from OS */ |
| driver_data->mipi0_rotation = VA_ROTATION_NONE; |
| driver_data->mipi1_rotation = VA_ROTATION_NONE; |
| driver_data->hdmi_rotation = VA_ROTATION_NONE; |
| |
| /* final rotation of VA rotate+WM rotate */ |
| driver_data->local_rotation = VA_ROTATION_NONE; |
| driver_data->extend_rotation = VA_ROTATION_NONE; |
| |
| /* MSVDX rotate */ |
| driver_data->msvdx_rotate_want = ROTATE_VA2MSVDX(VA_ROTATION_NONE); |
| |
| if (psb_parse_config("PSB_VIDEO_NOROTATE", &env_value[0]) == 0) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSVDX: disable MSVDX rotation\n"); |
| driver_data->disable_msvdx_rotate = 1; |
| } |
| /* FIXME: Disable rotation when VPP enabled, just a workround here*/ |
| #ifdef PSBVIDEO_MRFL_VPP |
| if (isVppOn((void*)driver_data->ws_priv)) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "For VPP: disable MSVDX rotation\n"); |
| driver_data->disable_msvdx_rotate = 1; |
| driver_data->vpp_on = 1; |
| } |
| #endif |
| |
| #ifdef BAYTRAIL |
| driver_data->disable_msvdx_rotate = 1; |
| #endif |
| |
| driver_data->disable_msvdx_rotate_backup = driver_data->disable_msvdx_rotate; |
| } |
| |
| void psb_RecalcAlternativeOutput(object_context_p obj_context) |
| { |
| psb_driver_data_p driver_data = obj_context->driver_data; |
| object_surface_p obj_surface = obj_context->current_render_target; |
| int angle, new_rotate, i; |
| int old_rotate = driver_data->msvdx_rotate_want; |
| int mode = INIT_VALUE; |
| #ifdef TARGET_HAS_MULTIPLE_DISPLAY |
| mode = psb_android_get_mds_mode((void*)driver_data->ws_priv); |
| #endif |
| |
| if (mode != INIT_VALUE) { |
| // clear device rotation info |
| if (driver_data->mipi0_rotation != VA_ROTATION_NONE) { |
| driver_data->mipi0_rotation = VA_ROTATION_NONE; |
| driver_data->hdmi_rotation = VA_ROTATION_NONE; |
| } |
| // Disable msvdx rotation if |
| // WIDI video is play and meta data rotation angle is 0 |
| if (mode == WIDI_VIDEO_ISPLAYING) { |
| if (driver_data->va_rotate == VA_ROTATION_NONE) |
| driver_data->disable_msvdx_rotate = 1; |
| else { |
| driver_data->mipi0_rotation = 0; |
| driver_data->hdmi_rotation = 0; |
| driver_data->disable_msvdx_rotate = 0; |
| } |
| } else { |
| if (IS_MOFD(driver_data)) |
| driver_data->disable_msvdx_rotate = 1; |
| else |
| driver_data->disable_msvdx_rotate = driver_data->disable_msvdx_rotate_backup; |
| } |
| } else if (IS_MOFD(driver_data)) { |
| /* Moorefield has overlay rotaion, so decoder doesn't generate rotation |
| * output according to windows manager. It is controlled by payload info |
| * in which HWC signal decoder to generate rotation output |
| */ |
| long long hwc_timestamp = 0; |
| int index = -1; |
| |
| for (i = 0; i < obj_context->num_render_targets; i++) { |
| object_surface_p obj_surface = SURFACE(obj_context->render_targets[i]); |
| /* traverse all surfaces' share info to find out the latest transform info */ |
| if (obj_surface && obj_surface->share_info) { |
| if (obj_surface->share_info->hwc_timestamp > hwc_timestamp) { |
| hwc_timestamp = obj_surface->share_info->hwc_timestamp; |
| index = i; |
| } |
| } |
| } |
| if (index >= 0) { |
| object_surface_p obj_surface = SURFACE(obj_context->render_targets[index]); |
| if (obj_surface && obj_surface->share_info) { |
| int transform = obj_surface->share_info->layer_transform; |
| driver_data->mipi0_rotation = HAL2VAROTATION(transform); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Signal from HWC to rotate %d\n", driver_data->mipi0_rotation); |
| } |
| } |
| } else if (driver_data->native_window) { |
| int display_rotate = 0; |
| psb_android_surfaceflinger_rotate(driver_data->native_window, &display_rotate); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "NativeWindow(0x%x), get surface flinger rotate %d\n", driver_data->native_window, display_rotate); |
| |
| if (driver_data->mipi0_rotation != display_rotate) { |
| driver_data->mipi0_rotation = display_rotate; |
| } |
| } else { |
| long long hwc_timestamp = 0; |
| int index = -1; |
| |
| for (i = 0; i < obj_context->num_render_targets; i++) { |
| object_surface_p obj_surface = SURFACE(obj_context->render_targets[i]); |
| /* traverse all surfaces' share info to find out the latest transform info */ |
| if (obj_surface && obj_surface->share_info) { |
| if (obj_surface->share_info->hwc_timestamp > hwc_timestamp) { |
| hwc_timestamp = obj_surface->share_info->hwc_timestamp; |
| index = i; |
| } |
| } |
| } |
| if (index >= 0) { |
| object_surface_p obj_surface = SURFACE(obj_context->render_targets[index]); |
| if (obj_surface && obj_surface->share_info) { |
| int transform = obj_surface->share_info->layer_transform; |
| driver_data->mipi0_rotation = HAL2VAROTATION(transform); |
| } |
| } |
| } |
| |
| #ifdef PSBVIDEO_MRFL |
| if ((mode == HDMI_VIDEO_ISPLAYING) && driver_data->native_window) { |
| int display_rotate = 0; |
| psb_android_surfaceflinger_rotate(driver_data->native_window, &display_rotate); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "NativeWindow(0x%x), get surface flinger rotate %d\n", driver_data->native_window, display_rotate); |
| |
| if (driver_data->mipi0_rotation != display_rotate && !IS_MOFD(driver_data)) { |
| driver_data->mipi0_rotation = display_rotate; |
| } |
| } |
| #endif |
| |
| /* calc VA rotation and WM rotation, and assign to the final rotation degree */ |
| angle = Rotation2Angle(driver_data->va_rotate) + Rotation2Angle(driver_data->mipi0_rotation); |
| driver_data->local_rotation = Angle2Rotation(angle); |
| angle = Rotation2Angle(driver_data->va_rotate) + Rotation2Angle(driver_data->hdmi_rotation); |
| driver_data->extend_rotation = Angle2Rotation(angle); |
| |
| /* On MOFD, no need to use meta rotation, just use rotation angle signal from HWC */ |
| if (IS_MOFD(driver_data)) { |
| driver_data->local_rotation = driver_data->mipi0_rotation; |
| driver_data->extend_rotation = Rotation2Angle(driver_data->hdmi_rotation); |
| } |
| |
| /* for any case that local and extened rotation are not same, fallback to GPU */ |
| if ((driver_data->mipi1_rotation != VA_ROTATION_NONE) || |
| ((driver_data->local_rotation != VA_ROTATION_NONE) && |
| (driver_data->extend_rotation != VA_ROTATION_NONE) && |
| (driver_data->local_rotation != driver_data->extend_rotation))) { |
| new_rotate = ROTATE_VA2MSVDX(driver_data->local_rotation); |
| if (driver_data->is_android == 0) /*fallback to texblit path*/ |
| driver_data->output_method = PSB_PUTSURFACE_CTEXTURE; |
| } else { |
| if (driver_data->local_rotation == VA_ROTATION_NONE) |
| new_rotate = driver_data->extend_rotation; |
| else |
| new_rotate = driver_data->local_rotation; |
| |
| if (driver_data->is_android == 0) { |
| if (driver_data->output_method != PSB_PUTSURFACE_FORCE_CTEXTURE) |
| driver_data->output_method = PSB_PUTSURFACE_COVERLAY; |
| } |
| } |
| |
| if (old_rotate != new_rotate) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSVDX: new rotation %d desired\n", new_rotate); |
| driver_data->msvdx_rotate_want = new_rotate; |
| } |
| |
| #ifdef TARGET_HAS_MULTIPLE_DISPLAY |
| int scaling_buffer_width = 1920, scaling_buffer_height = 1080 ; |
| int scaling_width = 0, scaling_height = 0; |
| int scaling_offset_x = 0, scaling_offset_y = 0; |
| int old_bufw = 0, old_bufh = 0, old_x = 0, old_y = 0, old_w = 0, old_h = 0; |
| int bScaleChanged = 0, size = 0; |
| unsigned char * surface_data; |
| |
| int ret = psb_android_get_mds_decoder_output_resolution( |
| (void*)driver_data->ws_priv, |
| &scaling_width, &scaling_height, |
| &scaling_offset_x, &scaling_offset_y, |
| &scaling_buffer_width, &scaling_buffer_height); |
| |
| if ((old_bufw != scaling_buffer_width) || (old_bufh != scaling_buffer_height) || |
| (old_x != scaling_offset_x) || (old_y != scaling_offset_y) || |
| (old_w != scaling_width) || (old_h != scaling_height)) { |
| bScaleChanged = 1; |
| } |
| |
| old_x = scaling_offset_x; |
| old_y = scaling_offset_y; |
| old_w = scaling_width; |
| old_h = scaling_height; |
| old_bufw = scaling_buffer_width; |
| old_bufh = scaling_buffer_height; |
| |
| /* turn off ved downscaling if width and height are 0. |
| * Besides, scaling_width and scaling_height must be a multiple of 2. |
| */ |
| if (!ret || (!scaling_width || !scaling_height) || |
| (scaling_width & 1) || (scaling_height & 1)) { |
| obj_context->msvdx_scaling = 0; |
| obj_context->scaling_width = 0; |
| obj_context->scaling_height = 0; |
| obj_context->scaling_offset_x= 0; |
| obj_context->scaling_offset_y = 0; |
| obj_context->scaling_buffer_width = 0; |
| obj_context->scaling_buffer_height = 0; |
| } else { |
| obj_context->msvdx_scaling = 1; |
| obj_context->scaling_width = scaling_width; |
| obj_context->scaling_height = scaling_height; |
| obj_context->scaling_offset_x= scaling_offset_x; |
| obj_context->scaling_offset_y = scaling_offset_y; |
| obj_context->scaling_buffer_width = scaling_buffer_width; |
| obj_context->scaling_buffer_height = scaling_buffer_height; |
| } |
| if (bScaleChanged) { |
| if ((obj_surface != NULL) && |
| (obj_surface->out_loop_surface != NULL)) { |
| if (psb_buffer_map(&obj_surface->out_loop_surface->buf, &surface_data)) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to map rotation buffer before clear it"); |
| } |
| else { |
| size = obj_surface->out_loop_surface->chroma_offset; |
| memset(surface_data, 0, size); |
| memset(surface_data + size, 0x80, obj_surface->out_loop_surface->size - size); |
| psb_buffer_unmap(&obj_context->current_render_target->out_loop_surface->buf); |
| } |
| } |
| } |
| #endif |
| } |
| |
| |
| void psb_CheckInterlaceRotate(object_context_p obj_context, unsigned char *pic_param_tmp) |
| { |
| object_surface_p obj_surface = obj_context->current_render_target; |
| |
| switch (obj_context->profile) { |
| case VAProfileMPEG2Simple: |
| case VAProfileMPEG2Main: { |
| VAPictureParameterBufferMPEG2 *pic_params = (VAPictureParameterBufferMPEG2 *)pic_param_tmp; |
| if ((pic_params->picture_coding_extension.bits.picture_structure == TOP_FIELD) || |
| (pic_params->picture_coding_extension.bits.picture_structure == BOTTOM_FIELD) || |
| ((pic_params->picture_coding_extension.bits.picture_structure == FRAME_PICTURE) && |
| (pic_params->picture_coding_extension.bits.progressive_frame == 0))) |
| obj_context->interlaced_stream = 1; |
| else |
| obj_context->interlaced_stream = 0; |
| break; |
| } |
| case VAProfileMPEG4Simple: |
| case VAProfileMPEG4AdvancedSimple: |
| case VAProfileMPEG4Main: |
| case VAProfileH263Baseline: { |
| VAPictureParameterBufferMPEG4 *pic_params = (VAPictureParameterBufferMPEG4 *)pic_param_tmp; |
| |
| if (pic_params->vol_fields.bits.interlaced) |
| obj_context->interlaced_stream = 1; /* is it the right way to check? */ |
| break; |
| } |
| case VAProfileH264Baseline: |
| case VAProfileH264Main: |
| case VAProfileH264High: |
| case VAProfileH264ConstrainedBaseline: { |
| VAPictureParameterBufferH264 *pic_params = (VAPictureParameterBufferH264 *)pic_param_tmp; |
| /* is it the right way to check? */ |
| if (pic_params->pic_fields.bits.field_pic_flag || pic_params->seq_fields.bits.mb_adaptive_frame_field_flag) |
| obj_context->interlaced_stream = 1; |
| |
| break; |
| } |
| case VAProfileVC1Simple: |
| case VAProfileVC1Main: |
| case VAProfileVC1Advanced: { |
| VAPictureParameterBufferVC1 *pic_params = (VAPictureParameterBufferVC1 *)pic_param_tmp; |
| |
| /* is it the right way to check? */ |
| if (pic_params->sequence_fields.bits.interlace) |
| obj_context->interlaced_stream = 1; |
| |
| break; |
| } |
| default: |
| break; |
| } |
| |
| if (obj_surface->share_info) { |
| psb_surface_share_info_p share_info = obj_surface->share_info; |
| if (obj_context->interlaced_stream) { |
| SET_SURFACE_INFO_rotate(obj_surface->psb_surface, 0); |
| obj_context->msvdx_rotate = 0; |
| share_info->bob_deinterlace = 1; //enable interlace flag |
| } else { |
| share_info->bob_deinterlace = 0; |
| } |
| } |
| } |
| #if 0 |
| /* |
| * Detach a surface from obj_surface |
| */ |
| VAStatus psb_DestroyRotateSurface( |
| VADriverContextP ctx, |
| object_surface_p obj_surface, |
| int rotate |
| ) |
| { |
| INIT_DRIVER_DATA; |
| psb_surface_p psb_surface = obj_surface->out_loop_surface; |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| |
| /* Allocate alternative output surface */ |
| if (psb_surface) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Try to allocate surface for alternative rotate output\n"); |
| psb_surface_destroy(obj_surface->out_loop_surface); |
| free(psb_surface); |
| |
| obj_surface->out_loop_surface = NULL; |
| obj_surface->width_r = obj_surface->width; |
| obj_surface->height_r = obj_surface->height; |
| } |
| |
| return vaStatus; |
| } |
| #endif |
| #ifdef TARGET_HAS_MULTIPLE_DISPLAY |
| /* |
| * Create and attach a downscaling surface to obj_surface |
| */ |
| static void clearScalingInfo(psb_surface_share_info_p share_info) { |
| if (share_info == NULL) |
| return; |
| share_info->width_s = 0; |
| share_info->height_s = 0; |
| share_info->scaling_khandle = 0; |
| |
| share_info->scaling_luma_stride = 0; |
| share_info->scaling_chroma_u_stride = 0; |
| share_info->scaling_chroma_v_stride = 0; |
| return; |
| } |
| |
| VAStatus psb_CreateScalingSurface( |
| object_context_p obj_context, |
| object_surface_p obj_surface |
| ) |
| { |
| psb_surface_p psb_surface; |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| psb_surface_share_info_p share_info = obj_surface->share_info; |
| unsigned int set_flags, clear_flags; |
| int ret = 0; |
| |
| if (obj_context->driver_data->render_rect.width <= obj_context->scaling_width || obj_context->driver_data->render_rect.height <= obj_context->scaling_height) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Either downscaling is not required or upscaling is needed for the target resolution\n"); |
| obj_context->msvdx_scaling = 0; /* Disable downscaling */ |
| clearScalingInfo(share_info); |
| return VA_STATUS_ERROR_OPERATION_FAILED; |
| } |
| |
| psb_surface = obj_surface->scaling_surface; |
| /* Check if downscaling resolution has been changed */ |
| if (psb_surface) { |
| if (obj_surface->width_s != obj_context->scaling_width || obj_surface->height_s != obj_context->scaling_height) { |
| psb_surface_destroy(psb_surface); |
| free(psb_surface); |
| psb_surface = NULL; |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "downscaling buffer realloc: %d x %d -> %d x %d\n", |
| obj_surface->width_s, obj_surface->height_s, obj_context->scaling_width, obj_context->scaling_height); |
| clearScalingInfo(share_info); |
| } |
| } |
| |
| if (!psb_surface) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Try to allocate surface for alternative scaling output: %dx%d\n", |
| obj_context->scaling_width, obj_context->scaling_height); |
| psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s)); |
| CHECK_ALLOCATION(psb_surface); |
| |
| vaStatus = psb_surface_create(obj_context->driver_data, obj_context->scaling_width, |
| (obj_context->scaling_height + 0x1f) & ~0x1f, VA_FOURCC_NV12, |
| 0, psb_surface); |
| |
| //set_flags = WSBM_PL_FLAG_CACHED | DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_SHARED; |
| //clear_flags = WSBM_PL_FLAG_UNCACHED | WSBM_PL_FLAG_WC; |
| //ret = psb_buffer_setstatus(&psb_surface->buf, set_flags, clear_flags); |
| |
| if (VA_STATUS_SUCCESS != vaStatus || ret) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "allocate scaling buffer fail\n"); |
| free(psb_surface); |
| obj_surface->scaling_surface = NULL; |
| vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; |
| DEBUG_FAILURE; |
| return vaStatus; |
| } |
| |
| obj_surface->width_s = obj_context->scaling_width; |
| obj_surface->height_s = obj_context->scaling_height; |
| obj_surface->buffer_width_s = obj_context->scaling_width; |
| obj_surface->buffer_height_s = obj_context->scaling_height; |
| obj_surface->offset_x_s= obj_context->scaling_offset_x; |
| obj_surface->offset_y_s= obj_context->scaling_offset_y; |
| obj_context->scaling_update = 1; |
| } |
| obj_surface->scaling_surface = psb_surface; |
| |
| /* derive the protected flag from the primay surface */ |
| SET_SURFACE_INFO_protect(psb_surface, |
| GET_SURFACE_INFO_protect(obj_surface->psb_surface)); |
| |
| /*notify hwc that rotated buffer is ready to use. |
| * TODO: Do these in psb_SyncSurface() |
| */ |
| if (share_info != NULL) { |
| share_info->width_s = obj_surface->width_s; |
| share_info->height_s = obj_surface->height_s; |
| share_info->scaling_khandle = |
| (uint32_t)(wsbmKBufHandle(wsbmKBuf(psb_surface->buf.drm_buf))); |
| |
| share_info->scaling_luma_stride = psb_surface->stride; |
| share_info->scaling_chroma_u_stride = psb_surface->stride; |
| share_info->scaling_chroma_v_stride = psb_surface->stride; |
| } |
| return vaStatus; |
| } |
| #else |
| VAStatus psb_CreateScalingSurface( |
| object_context_p __maybe_unused obj_context, |
| object_surface_p __maybe_unused obj_surface |
| ) |
| { |
| return VA_STATUS_ERROR_OPERATION_FAILED; |
| } |
| #endif |
| |
| /* |
| * Create and attach a rotate surface to obj_surface |
| */ |
| VAStatus psb_CreateRotateSurface( |
| object_context_p obj_context, |
| object_surface_p obj_surface, |
| int msvdx_rotate |
| ) |
| { |
| int width, height; |
| psb_surface_p rotate_surface; |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| int need_realloc = 0; |
| unsigned int flags = 0; |
| psb_surface_share_info_p share_info = obj_surface->share_info; |
| psb_driver_data_p driver_data = obj_context->driver_data; |
| int rotate_stride = 0, rotate_tiling = 0; |
| object_config_p obj_config = CONFIG(obj_context->config_id); |
| unsigned char * surface_data; |
| |
| CHECK_CONFIG(obj_config); |
| |
| rotate_surface = obj_surface->out_loop_surface; |
| |
| if (msvdx_rotate == 0 |
| #ifdef OVERLAY_ENABLE_MIRROR |
| /*Bypass 180 degree rotate when overlay enabling mirror*/ |
| || msvdx_rotate == VA_ROTATION_180 |
| #endif |
| ) |
| return vaStatus; |
| |
| if (rotate_surface) { |
| CHECK_SURFACE_REALLOC(rotate_surface, msvdx_rotate, need_realloc); |
| if (need_realloc == 0) { |
| goto exit; |
| } else { /* free the old rotate surface */ |
| /*FIX ME: it is not safe to do that because surfaces may be in use for rendering.*/ |
| psb_surface_destroy(obj_surface->out_loop_surface); |
| memset(rotate_surface, 0, sizeof(*rotate_surface)); |
| } |
| } else { |
| rotate_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s)); |
| CHECK_ALLOCATION(rotate_surface); |
| } |
| |
| #ifdef PSBVIDEO_MSVDX_DEC_TILING |
| SET_SURFACE_INFO_tiling(rotate_surface, GET_SURFACE_INFO_tiling(obj_surface->psb_surface)); |
| #endif |
| #ifdef PSBVIDEO_MRFL_VPP_ROTATE |
| SET_SURFACE_INFO_rotate(rotate_surface, msvdx_rotate); |
| #endif |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Try to allocate surface for alternative rotate output\n"); |
| |
| flags = IS_ROTATED; |
| |
| if (msvdx_rotate == 2 /* VA_ROTATION_180 */) { |
| width = obj_surface->width; |
| height = obj_surface->height; |
| |
| #ifdef PSBVIDEO_MRFL_VPP_ROTATE |
| if (obj_config->entrypoint == VAEntrypointVideoProc && |
| share_info && share_info->out_loop_khandle) { |
| vaStatus = psb_surface_create_from_kbuf(driver_data, width, height, |
| obj_surface->psb_surface->size, VA_FOURCC_NV12, |
| share_info->out_loop_khandle, |
| obj_surface->psb_surface->stride, |
| obj_surface->psb_surface->stride, |
| obj_surface->psb_surface->stride, |
| 0, 0, 0, rotate_surface); |
| } else |
| #endif |
| vaStatus = psb_surface_create(driver_data, width, height, VA_FOURCC_NV12, |
| flags, rotate_surface); |
| } else { |
| width = obj_surface->height_origin; |
| height = (obj_surface->width + 0x1f) & ~0x1f; |
| |
| #ifdef PSBVIDEO_MRFL_VPP_ROTATE |
| if (obj_config->entrypoint == VAEntrypointVideoProc && |
| share_info && share_info->out_loop_khandle != 0) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL,"Create the surface from kbuf out_loop_khandle=%x!\n", share_info->out_loop_khandle); |
| rotate_tiling = GET_SURFACE_INFO_tiling(rotate_surface); |
| rotate_stride = get_surface_stride(width, rotate_tiling); |
| vaStatus = psb_surface_create_from_kbuf(driver_data, width, height, |
| (rotate_stride * height * 3) / 2, VA_FOURCC_NV12, |
| share_info->out_loop_khandle, |
| rotate_stride, rotate_stride, rotate_stride, |
| 0, rotate_stride * height, rotate_stride * height, |
| rotate_surface); |
| } else |
| #endif |
| { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL,"Create rotated buffer. width=%d, height=%d\n", width, height); |
| if (CONTEXT_SCALING(obj_context)) { |
| width = obj_context->scaling_buffer_height; |
| height = (obj_context->scaling_buffer_width+ 0x1f) & ~0x1f; |
| } |
| vaStatus = psb_surface_create(driver_data, width, height, VA_FOURCC_NV12, |
| flags, rotate_surface); |
| } |
| } |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| free(rotate_surface); |
| obj_surface->out_loop_surface = NULL; |
| vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; |
| DEBUG_FAILURE; |
| return vaStatus; |
| } |
| |
| //clear rotation surface |
| if (CONTEXT_SCALING(obj_context)) { |
| if (psb_buffer_map(&rotate_surface->buf, &surface_data)) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to map rotation buffer before clear it"); |
| } |
| else { |
| memset(surface_data, 0, rotate_surface->chroma_offset); |
| memset(surface_data + rotate_surface->chroma_offset, 0x80, |
| rotate_surface->size - rotate_surface->chroma_offset); |
| psb_buffer_unmap(&rotate_surface->buf); |
| } |
| } |
| obj_surface->width_r = width; |
| obj_surface->height_r = height; |
| |
| #ifdef PSBVIDEO_MSVDX_DEC_TILING |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "attempt to update tile context\n"); |
| if (GET_SURFACE_INFO_tiling(rotate_surface) && obj_config->entrypoint != VAEntrypointVideoProc) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "update tile context\n"); |
| object_context_p obj_context = CONTEXT(obj_surface->context_id); |
| if (NULL == obj_context) { |
| vaStatus = VA_STATUS_ERROR_INVALID_CONTEXT; |
| DEBUG_FAILURE; |
| return vaStatus; |
| } |
| unsigned long msvdx_tile = psb__tile_stride_log2_256(obj_surface->width_r); |
| 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); |
| } |
| #endif |
| |
| exit: |
| obj_surface->out_loop_surface = rotate_surface; |
| SET_SURFACE_INFO_rotate(rotate_surface, msvdx_rotate); |
| /* derive the protected flag from the primay surface */ |
| SET_SURFACE_INFO_protect(rotate_surface, |
| GET_SURFACE_INFO_protect(obj_surface->psb_surface)); |
| |
| /*notify hwc that rotated buffer is ready to use. |
| * TODO: Do these in psb_SyncSurface() |
| */ |
| if (share_info != NULL) { |
| share_info->width_r = rotate_surface->stride; |
| share_info->height_r = obj_surface->height_r; |
| share_info->out_loop_khandle = |
| (uint32_t)(wsbmKBufHandle(wsbmKBuf(rotate_surface->buf.drm_buf))); |
| share_info->metadata_rotate = VAROTATION2HAL(driver_data->va_rotate); |
| share_info->surface_rotate = VAROTATION2HAL(msvdx_rotate); |
| |
| share_info->out_loop_luma_stride = rotate_surface->stride; |
| share_info->out_loop_chroma_u_stride = rotate_surface->stride; |
| share_info->out_loop_chroma_v_stride = rotate_surface->stride; |
| } |
| |
| return vaStatus; |
| } |
| |
| VAStatus psb_DestroyRotateBuffer( |
| object_context_p obj_context, |
| object_surface_p obj_surface) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| psb_surface_share_info_p share_info = obj_surface->share_info; |
| psb_driver_data_p driver_data = obj_context->driver_data; |
| psb_surface_p rotate_surface = obj_surface->out_loop_surface; |
| struct psb_buffer_s psb_buf; |
| |
| if (share_info && share_info->out_loop_khandle) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL,"psb_DestroyRotateBuffer out_loop_khandle=%x\n", share_info->out_loop_khandle); |
| vaStatus = psb_kbuffer_reference(driver_data, &psb_buf, share_info->out_loop_khandle); |
| if (vaStatus != VA_STATUS_SUCCESS) |
| return vaStatus; |
| psb_buffer_destroy(&psb_buf); |
| share_info->out_loop_khandle = 0; |
| } |
| |
| if (rotate_surface) |
| free(rotate_surface); |
| |
| return vaStatus; |
| } |
| |