blob: 38756f09673e2fc3ed2084fc1a89ae31671c957a [file] [log] [blame]
/*
* 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:
* Zhaohan Ren <zhaohan.ren@intel.com>
* Shengquan Yuan <shengquan.yuan@intel.com>
* Jiang Fei <jiang.fei@intel.com>
* Binglin Chen <binglin.chen@intel.com>
*
*/
#include <va/va_backend.h>
#include "psb_output.h"
#include "psb_surface.h"
#include "psb_buffer.h"
#include "psb_overlay.h"
#include "psb_texture.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "psb_android_glue.h"
#include "psb_output_android.h"
#ifndef BAYTRAIL
#include "psb_HDMIExtMode.h"
#endif
#include "pnw_rotate.h"
#include "psb_drv_debug.h"
#include <wsbm/wsbm_manager.h>
#include <hardware.h>
#define INIT_DRIVER_DATA psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
#define INIT_OUTPUT_PRIV psb_android_output_p output = (psb_android_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv)
#define SURFACE(id) ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
#define BUFFER(id) ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))
#define IMAGE(id) ((object_image_p) object_heap_lookup( &driver_data->image_heap, id ))
#define SUBPIC(id) ((object_subpic_p) object_heap_lookup( &driver_data->subpic_heap, id ))
#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
#define GET_SURFACE_INFO_rotate(psb_surface) ((int) psb_surface->extra_info[5])
#define GET_SURFACE_INFO_protect(psb_surface) ((int) psb_surface->extra_info[6])
#define MAX_OVERLAY_IDLE_FRAME 4
enum {
eWidiOff = 1,
eWidiClone = 2,
eWidiExtendedVideo = 3,
};
extern unsigned int update_forced;
inline int va2hw_rotation(int va_rotate)
{
switch (va_rotate) {
case VA_ROTATION_90:
return HAL_TRANSFORM_ROT_270;
case VA_ROTATION_180:
return HAL_TRANSFORM_ROT_180;
case VA_ROTATION_270:
return HAL_TRANSFORM_ROT_90;
defaut:
return 0;
}
return 0;
}
unsigned char *psb_android_output_init(VADriverContextP ctx)
{
INIT_DRIVER_DATA;
char put_surface[1024];
psb_android_output_p output = calloc(1, sizeof(psb_android_output_s));
struct fb_var_screeninfo vinfo;
int fbfd = -1;
if (output == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Can't malloc memory\n");
return NULL;
}
memset(output, 0, sizeof(psb_android_output_s));
/* Guess the screen size */
output->screen_width = 800;
output->screen_height = 480;
// Open the frame buffer for reading
memset(&vinfo, 0, sizeof(vinfo));
fbfd = open("/dev/graphics/fb0", O_RDONLY);
if (fbfd) {
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Error reading screen information.\n");
}
close(fbfd);
output->screen_width = vinfo.xres;
output->screen_height = vinfo.yres;
/* TS by default */
driver_data->output_method = PSB_PUTSURFACE_OVERLAY;
driver_data->color_key = 0x000001; /*light blue*/
if (psb_parse_config("PSB_VIDEO_CTEXTURES", &put_surface[0]) == 0) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB_VIDEO_CTEXTURES is enabled for vaPutSurfaceBuf\n");
driver_data->ctexture = 1; /* Init CTEXTURE for vaPutSurfaceBuf */
}
if (psb_parse_config("PSB_VIDEO_COVERLAY", &put_surface[0]) == 0) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Putsurface use client overlay\n");
driver_data->output_method = PSB_PUTSURFACE_FORCE_COVERLAY;
}
driver_data->coverlay = 1;
return (unsigned char *)output;
}
VAStatus psb_android_output_deinit(VADriverContextP ctx)
{
INIT_DRIVER_DATA;
INIT_OUTPUT_PRIV;
//psb_android_output_p output = GET_OUTPUT_DATA(ctx);
#ifdef TARGET_HAS_MULTIPLE_DISPLAY
if (output->mds != NULL) {
deinit_mds_listener(output);
}
#endif
return VA_STATUS_SUCCESS;
}
#ifndef BAYTRAIL
static VAStatus psb_putsurface_ctexture(
VADriverContextP ctx,
VASurfaceID surface,
unsigned char* data,
short srcx,
short srcy,
unsigned short srcw,
unsigned short srch,
short destx,
short desty,
unsigned short destw,
unsigned short desth,
unsigned int __maybe_unused flags /* de-interlacing flags */
)
{
INIT_DRIVER_DATA;
INIT_OUTPUT_PRIV;
object_surface_p obj_surface;
int offset = 0;
psb_surface_p psb_surface;
VAStatus vaStatus = VA_STATUS_SUCCESS;
obj_surface = SURFACE(surface);
CHECK_SURFACE(obj_surface);
psb_surface = obj_surface->psb_surface;
// psb_surface->buf.drm_buf;
// psb_surface->buf.pl_flags;
psb_putsurface_textureblit(ctx, data, surface, srcx, srcy, srcw, srch,
destx, desty, destw, desth, 0, /* no subtitle */
obj_surface->width, obj_surface->height,
psb_surface->stride, psb_surface->buf.drm_buf,
psb_surface->buf.pl_flags, 1 /* need wrap dst */);
psb_android_postBuffer(offset);
return VA_STATUS_SUCCESS;
}
#endif
#if 0
VAStatus psb_putsurface_coverlay(
VADriverContextP ctx,
VASurfaceID surface,
short srcx,
short srcy,
unsigned short srcw,
unsigned short srch,
short destx, /* screen cooridination */
short desty,
unsigned short destw,
unsigned short desth,
unsigned int flags /* de-interlacing flags */
)
{
INIT_OUTPUT_PRIV;
VAStatus vaStatus = VA_STATUS_SUCCESS;
/* USE_FIT_SCR_SIZE */
/* calculate fit screen size of frame */
unsigned short _scr_x = output->screen_width;
unsigned short _scr_y = output->screen_height;
float _slope_xy = (float)srch / srcw;
unsigned short _destw = (short)(_scr_y / _slope_xy);
unsigned short _desth = (short)(_scr_x * _slope_xy);
short _pos_x, _pos_y;
if (_destw <= _scr_x) {
_desth = _scr_y;
_pos_x = (_scr_x - _destw) >> 1;
_pos_y = 0;
} else {
_destw = _scr_x;
_pos_x = 0;
_pos_y = (_scr_y - _desth) >> 1;
}
destx += _pos_x;
desty += _pos_y;
destw = _destw;
desth = _desth;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_putsurface_overlay: src (%d, %d, %d, %d), destx (%d, %d, %d, %d).\n",
srcx, srcy, srcw, srch, destx, desty, destw, desth);
/* display by overlay */
vaStatus = psb_putsurface_overlay(
ctx, surface, srcx, srcy, srcw, srch,
destx, desty, destw, desth, /* screen coordinate */
flags, OVERLAY_A, PIPEA);
return vaStatus;
}
#endif
#if 0
static int psb_update_destbox(
VADriverContextP ctx
)
{
INIT_DRIVER_DATA;
INIT_OUTPUT_PRIV;
short destx;
short desty;
unsigned short destw;
unsigned short desth;
VAStatus vaStatus = VA_STATUS_SUCCESS;
psb_android_get_destbox(&destx, &desty, &destw, &desth);
/*drv_debug_msg(VIDEO_DEBUG_GENERAL, "destbox = (%d,%d,%d,%d)\n", destx, desty, destw, desth);*/
if ((destx >= 0) && (desty >= 0) &&
((destx + destw) <= output->screen_width) &&
((desty + desth) <= output->screen_height) &&
(output->destx != destx ||
output->desty != desty ||
output->destw != destw ||
output->desth != desth)) {
output->destx = destx;
output->desty = desty;
output->destw = destw;
output->desth = desth;
output->new_destbox = 1;
LOGD("==========New Destbox=============\n");
LOGD("output->destbox = (%d,%d,%d,%d)\n", output->destx, output->desty, output->destw, output->desth);
}
return vaStatus;
}
#endif
#if 0
static int psb_check_outputmethod(
VADriverContextP ctx,
VASurfaceID surface,
unsigned short srcw,
unsigned short srch,
void *android_isurface,
psb_hdmi_mode *hdmi_mode
)
{
INIT_DRIVER_DATA;
INIT_OUTPUT_PRIV;
psb_HDMIExt_info_p psb_HDMIExt_info = (psb_HDMIExt_info_p)output->psb_HDMIExt_info;
object_surface_p obj_surface;
int rotation = 0, widi = 0;
int delta_rotation = 0;
int srf_rotate; /* primary surface rotation */
psb_surface_p rotate_surface; /* rotate surface */
int rotate_srf_rotate = -1; /* degree of the rotate surface */
if ((srcw >= 2048) || (srch >= 2048)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clip size extend overlay hw limit, use texstreaming\n");
driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
return 0;
}
/* use saved status to avoid per-frame checking */
if ((driver_data->frame_count % driver_data->outputmethod_checkinterval) != 0) {
*hdmi_mode = psb_HDMIExt_get_mode(output);
return 0;
}
/* check the status at outputmethod_checkinterval frequency */
/* at first check HDMI status */
if (psb_HDMIExt_update(ctx, psb_HDMIExt_info)) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to update HDMIExt info.\n", __FUNCTION__);
return -1;
}
obj_surface = SURFACE(surface);
if (obj_surface == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid surface\n");
return -1;
}
*hdmi_mode = psb_HDMIExt_get_mode(output);
if ((*hdmi_mode == EXTENDED_VIDEO) || (*hdmi_mode == CLONE)) {
unsigned short _destw, _desth;
short _pos_x, _pos_y;
unsigned short crtc_width = 0, crtc_height = 0;
float _slope_xy;
/* need to handle VA rotation, and set WM rotate to 0
* for Android, MIPI0/HDMI has the same WM rotation always
*/
if (driver_data->mipi0_rotation != 0 || driver_data->rotation_dirty != 0) {
driver_data->mipi0_rotation = 0;
driver_data->hdmi_rotation = 0;
driver_data->rotation_dirty = 0;
output->new_destbox = 1;
psb_RecalcRotate(ctx, CONTEXT(obj_surface->context_id));
}
psb_HDMIExt_get_prop(output, &crtc_width, &crtc_height);
/*recalculate the render box to fit the ratio of height/width*/
if ((driver_data->extend_rotation == VA_ROTATION_90) ||
(driver_data->extend_rotation == VA_ROTATION_270))
_slope_xy = (float)srcw / srch;
else
_slope_xy = (float)srch / srcw;
_destw = (short)(crtc_height / _slope_xy);
_desth = (short)(crtc_width * _slope_xy);
if (_destw <= crtc_width) {
_desth = crtc_height;
_pos_x = (crtc_width - _destw) >> 1;
_pos_y = 0;
} else {
_destw = crtc_width;
_pos_x = 0;
_pos_y = (crtc_height - _desth) >> 1;
}
driver_data->render_rect.x = _pos_x;
driver_data->render_rect.y = _pos_y;
driver_data->render_rect.width = _destw;
driver_data->render_rect.height = _desth;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "HDMI mode is on (%d), Render Rect: (%d,%d,%d,%d)\n",
*hdmi_mode,
driver_data->render_rect.x, driver_data->render_rect.y,
driver_data->render_rect.width, driver_data->render_rect.height);
return 0;
}
/* HDMI is not enabled */
psb_android_surfaceflinger_status(android_isurface, &output->sf_composition, &rotation, &widi);
/*Update output destbox using layerbuffer's visible region*/
psb_update_destbox(ctx);
if ((driver_data->output_method == PSB_PUTSURFACE_FORCE_COVERLAY)
|| (driver_data->output_method == PSB_PUTSURFACE_FORCE_TEXSTREAMING))
return 0;
/*If overlay can not get correct destbox, use texstreaming.*/
if (output->destw == 0 || output->desth == 0 ||
((output->destw == srcw) && (output->desth == srch))) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "No proper destbox, use texstreaming (%dx%d+%d+%d)\n",
output->destw, output->desth, output->destx, output->desty);
driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
return 0;
}
/* only care local rotation */
delta_rotation = Rotation2Angle(driver_data->mipi0_rotation) - Rotation2Angle(rotation);
if ((((abs(delta_rotation) == 90) || (abs(delta_rotation) == 270)) && output->new_destbox) ||
(abs(delta_rotation) == 180)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "New rotation degree %d of MIPI0 WM, Need to recalc rotation\n", rotation);
driver_data->mipi0_rotation = rotation;
driver_data->hdmi_rotation = rotation;
driver_data->rotation_dirty |= PSB_NEW_WM_ROTATION;
}
output->new_destbox = 0;
if (driver_data->rotation_dirty != 0) {
psb_RecalcRotate(ctx, CONTEXT(obj_surface->context_id));
driver_data->rotation_dirty = 0;
}
if (GET_SURFACE_INFO_protect(obj_surface->psb_surface)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Protected surface, use overlay\n");
driver_data->output_method = PSB_PUTSURFACE_COVERLAY;
return 0;
}
if (widi == eWidiClone) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "WIDI in clone mode, use texstreaming\n");
driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
driver_data->msvdx_rotate_want = 0;/* disable msvdx rotae */
return 0;
}
if (widi == eWidiExtendedVideo) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "WIDI in extend video mode, disable local displaying\n");
driver_data->output_method = PSB_PUTSURFACE_NONE;
driver_data->msvdx_rotate_want = 0;/* disable msvdx rotae */
return 0;
}
if (output->sf_composition) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Composition is detected, use texstreaming\n");
driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
return 0;
}
srf_rotate = GET_SURFACE_INFO_rotate(obj_surface->psb_surface);
rotate_surface = obj_surface->out_loop_surface;
if (rotate_surface != NULL)
rotate_srf_rotate = GET_SURFACE_INFO_rotate(rotate_surface);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "SF rotation %d, VA rotation %d, final MSVDX rotation %d\n",
rotation, driver_data->va_rotate, driver_data->local_rotation);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Primary surface rotation %d, rotated surface rotation %d\n",
srf_rotate, rotate_srf_rotate);
/* The surface rotation is not same with the final rotation */
if ((driver_data->local_rotation != 0) &&
((srf_rotate != driver_data->local_rotation) || (rotate_srf_rotate != driver_data->local_rotation))) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Use texstreaming due to different VA surface rotation and final rotaion\n",
srf_rotate, rotate_srf_rotate);
driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
return 0;
}
driver_data->output_method = PSB_PUTSURFACE_COVERLAY;
return 0;
}
#endif
VAStatus psb_PutSurface(
VADriverContextP ctx,
VASurfaceID surface,
void __maybe_unused * android_isurface,
short srcx,
short srcy,
unsigned short srcw,
unsigned short srch,
short destx,
short desty,
unsigned short destw,
unsigned short desth,
VARectangle *cliprects, /* client supplied clip list */
unsigned int number_cliprects, /* number of clip rects in the clip list */
unsigned int flags /* de-interlacing flags */
)
{
INIT_DRIVER_DATA;
INIT_OUTPUT_PRIV;
object_surface_p obj_surface;
VAStatus vaStatus = VA_STATUS_SUCCESS;
PsbPortPrivPtr pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
int ret = 0;
#ifndef BAYTRAIL
obj_surface = SURFACE(surface);
// psb__dump_NV_buffers(obj_surface,srcx,srcy,srcw,srch);
CHECK_SURFACE(obj_surface);
CHECK_INVALID_PARAM((NULL == cliprects) && (0 != number_cliprects));
if ((srcx < 0) || (srcx > obj_surface->width) || (srcw > (obj_surface->width - srcx)) ||
(srcy < 0) || (srcy > obj_surface->height_origin) || (srch > (obj_surface->height_origin - srcy))) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "vaPutSurface: source rectangle passed from upper layer is not correct.\n");
return VA_STATUS_ERROR_UNKNOWN;
}
if ((destx < 0) || (desty < 0)) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "vaPutSurface: dest rectangle passed from upper layer is not correct.\n");
return VA_STATUS_ERROR_UNKNOWN;
}
if (driver_data->dummy_putsurface) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "vaPutSurface: dummy mode, return directly\n");
return VA_STATUS_SUCCESS;
}
/* init overlay */
if (!driver_data->coverlay_init) {
ret = psb_coverlay_init(ctx);
if (ret != 0) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "vaPutSurface: psb_coverlay_init failed. Fallback to texture streaming.\n");
driver_data->coverlay_init = 0;
} else
driver_data->coverlay_init = 1;
}
/* set the current displaying video frame into kernel */
psb_surface_set_displaying(driver_data, obj_surface->width,
obj_surface->height_origin,
obj_surface->psb_surface);
/* local video playback */
drv_debug_msg(VIDEO_DEBUG_GENERAL, "MIPI: Use overlay to display.\n");
/*initialize output destbox using default destbox if it has not been initialized until here.*/
if (output->destw == 0 || output->desth == 0) {
output->destx = (destx > 0) ? destx : 0;
output->desty = (desty > 0) ? desty : 0;
output->destw = ((output->destx + destw) > output->screen_width) ? (output->screen_width - output->destx) : destw;
output->desth = ((output->desty + desth) > output->screen_height) ? (output->screen_height - output->desty) : desth;
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Overlay position = (%d,%d,%d,%d)\n", output->destx, output->desty, output->destw, output->desth);
srcw = srcw <= 2047? srcw : 2047;
vaStatus = psb_putsurface_overlay(ctx, surface,
srcx, srcy, srcw, srch,
output->destx, output->desty, output->destw, output->desth,
flags, OVERLAY_A, PIPEA);
driver_data->frame_count++;
#endif
return vaStatus;
}