blob: 7a36e66869ab787b84abd18afdcc7f91b363bfbc [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:
* Shengquan Yuan <shengquan.yuan@intel.com>
* Zhaohan Ren <zhaohan.ren@intel.com>
*
*/
#include <va/va_backend.h>
#include "psb_surface.h"
#include "psb_output.h"
#include "psb_surface_ext.h"
#include "psb_x11.h"
#include "psb_xrandr.h"
#include "psb_drv_debug.h"
#include <X11/extensions/dpms.h>
#include <wsbm/wsbm_manager.h>
#define INIT_DRIVER_DATA psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
#define INIT_OUTPUT_PRIV psb_x11_output_p output = (psb_x11_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv)
#define SURFACE(id) ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
static int psb_CheckDrawable(VADriverContextP ctx, Drawable draw);
int (*oldHandler)(Display *, XErrorEvent *) = 0;
static int XErrorFlag = 1;
static int psb_XErrorHandler(Display *dpy, XErrorEvent *event)
{
drv_debug_msg(VIDEO_DEBUG_GENERAL, "XErrorEvent caught in psb_XErrorHandler in psb_xvva.c\n");
if (event->type == 0 && event->request_code == 132 && event->error_code == 11 /* BadAlloc */) {
XErrorFlag = 1;
return 0;
}
return oldHandler(dpy, event);
}
static int GetPortId(VADriverContextP ctx, psb_x11_output_p output)
{
int i, j, k;
unsigned int numAdapt;
int numImages;
XvImageFormatValues *formats;
XvAdaptorInfo *info;
int ret, grab_ret;
Display *dpy = (Display *)ctx->native_dpy;
ret = XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &numAdapt, &info);
/*Force overlay port num equal to one. OverlayC can't be used independently now.*/
/* check for numAdapt before modifying the info[1]. Without this check
* it will cause a memory corruption leading to segfaults */
if (numAdapt > 1)
info[1].num_ports = 1;
if (Success != ret) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Can't find Xvideo adaptor\n");
return -1;
}
grab_ret = XGrabServer(ctx->native_dpy);
for (i = 0; i < numAdapt; i++) {
if ((info[i].type & XvImageMask) == 0)
continue;
formats = XvListImageFormats(dpy, info[i].base_id, &numImages);
for (j = 0; j < numImages; j++) {
if (formats[j].id != FOURCC_XVVA) continue;
for (k = 0; k < info[i].num_ports; k++) {
int ret = XvGrabPort(dpy, info[i].base_id + k, CurrentTime);
if (Success == ret) {
/* for textured adaptor 0 */
if (i == 0)
output->textured_portID = info[i].base_id + k;
/* for overlay adaptor 1 */
if (i == 1)
output->overlay_portID = info[i].base_id + k;
break;
}
}
}
XFree(formats);
}
if (grab_ret != 0)
XUngrabServer(ctx->native_dpy);
if ((output->textured_portID == 0) && (output->overlay_portID == 0)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Can't detect any usable Xv XVVA port\n");
return -1;
}
return 0;
}
VAStatus psb_init_xvideo(VADriverContextP ctx, psb_x11_output_p output)
{
#ifdef _FOR_FPGA_
return VA_STATUS_SUCCESS;
#endif
INIT_DRIVER_DATA;
int dummy, ret;
output->textured_portID = output->overlay_portID = 0;
if (GetPortId(ctx, output)) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Grab Xvideo port failed, fallback to software vaPutSurface.\n");
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
if (output->textured_portID)
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected textured Xvideo port_id = %d.\n", (unsigned int)output->textured_portID);
if (output->overlay_portID)
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected overlay Xvideo port_id = %d.\n", (unsigned int)output->overlay_portID);
output->sprite_enabled = 0;
if (getenv("PSB_SPRITE_ENABLE")) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "use sprite plane to playback rotated protected video\n");
output->sprite_enabled = 1;
}
output->ignore_dpm = 1;
if (getenv("PSB_VIDEO_DPMS_HACK")) {
if (DPMSQueryExtension((Display *)ctx->native_dpy, &dummy, &dummy)
&& DPMSCapable((Display *)ctx->native_dpy)) {
BOOL onoff;
CARD16 state;
DPMSInfo((Display *)ctx->native_dpy, &state, &onoff);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "DPMS is %s, monitor state=%s\n", onoff ? "enabled" : "disabled",
(state == DPMSModeOn) ? "on" : (
(state == DPMSModeOff) ? "off" : (
(state == DPMSModeStandby) ? "standby" : (
(state == DPMSModeSuspend) ? "suspend" : "unknow"))));
if (onoff)
output->ignore_dpm = 0;
}
}
/* by default, overlay Xv */
if (output->textured_portID)
driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
if (output->overlay_portID)
driver_data->output_method = PSB_PUTSURFACE_OVERLAY;
ret = psb_xrandr_init(ctx);
if (ret != 0) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to initialize psb xrandr error # %d\n", __func__, ret);
return VA_STATUS_ERROR_UNKNOWN;
}
return VA_STATUS_SUCCESS;
}
VAStatus psb_deinit_xvideo(VADriverContextP ctx)
{
INIT_DRIVER_DATA;
INIT_OUTPUT_PRIV;
if (output->gc) {
XFreeGC((Display *)ctx->native_dpy, output->gc);
output->gc = NULL;
}
if (output->extend_gc) {
XFreeGC((Display *)ctx->native_dpy, output->extend_gc);
output->extend_gc = NULL;
}
if (output->textured_xvimage) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Destroy XvImage for texture Xv\n");
XFree(output->textured_xvimage);
output->textured_xvimage = NULL;
}
if (output->overlay_xvimage) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Destroy XvImage for overlay Xv\n");
XFree(output->overlay_xvimage);
output->textured_xvimage = NULL;
}
if (output->textured_portID) {
if ((output->using_port == USING_TEXTURE_PORT) && output->output_drawable
&& (psb_CheckDrawable(ctx, output->output_drawable) == 0)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Deinit: stop textured Xvideo\n");
XvStopVideo((Display *)ctx->native_dpy, output->textured_portID, output->output_drawable);
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Deinit: ungrab textured Xvideo port\n");
XvUngrabPort((Display *)ctx->native_dpy, output->textured_portID, CurrentTime);
output->textured_portID = 0;
}
if (output->overlay_portID) {
if ((output->using_port == USING_OVERLAY_PORT) && output->output_drawable
&& (psb_CheckDrawable(ctx, output->output_drawable) == 0)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Deinit: stop overlay Xvideo\n");
XvStopVideo((Display *)ctx->native_dpy, output->overlay_portID, output->output_drawable);
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Deinit: ungrab overlay Xvideo port\n");
XvUngrabPort((Display *)ctx->native_dpy, output->overlay_portID, CurrentTime);
output->overlay_portID = 0;
}
if (driver_data->use_xrandr_thread && driver_data->xrandr_thread_id) {
psb_xrandr_thread_exit();
pthread_join(driver_data->xrandr_thread_id, NULL);
driver_data->xrandr_thread_id = 0;
}
psb_xrandr_deinit();
output->using_port = 0;
output->output_drawable = 0;
output->extend_drawable = 0;
#ifndef _FOR_FPGA_
XSync((Display *)ctx->native_dpy, False);
#endif
return VA_STATUS_SUCCESS;
}
static void psb_surface_init(
psb_driver_data_p driver_data,
PsbVASurfaceRec *srf,
int fourcc, int bpp, int w, int h, int stride, int size, unsigned int pre_add,
struct _WsbmBufferObject *bo, int flags
)
{
memset(srf, 0, sizeof(*srf));
srf->fourcc = fourcc;
srf->bo = bo;
if (bo != NULL) {
srf->bufid = wsbmKBufHandle(wsbmKBuf(bo));
srf->pl_flags = wsbmBOPlacementHint(bo);
}
/*
if (srf->pl_flags & DRM_PSB_FLAG_MEM_CI)
srf->reserved_phyaddr = driver_data->camera_phyaddr;
if (srf->pl_flags & DRM_PSB_FLAG_MEM_RAR)
srf->reserved_phyaddr = driver_data->rar_phyaddr;
*/
srf->bytes_pp = bpp;
srf->width = w;
srf->pre_add = pre_add;
if ((flags == VA_TOP_FIELD) || (flags == VA_BOTTOM_FIELD)) {
if (driver_data->output_method == PSB_PUTSURFACE_FORCE_OVERLAY
|| driver_data->output_method == PSB_PUTSURFACE_OVERLAY) {
srf->height = h;
srf->stride = stride;
} else {
srf->height = h / 2;
srf->stride = stride * 2;
}
if (flags == VA_BOTTOM_FIELD)
srf->pre_add += stride;
} else {
srf->height = h;
srf->stride = stride;
}
srf->size = size;
if (flags == VA_CLEAR_DRAWABLE) {
srf->clear_color = driver_data->clear_color; /* color */
return;
}
}
#if 0
#define WINDOW 1
#define PIXMAP 0
/* return 0 for no rotation, 1 for rotation occurs */
/* XRRGetScreenInfo has significant performance drop */
static int psb__CheckCurrentRotation(VADriverContextP ctx)
{
Rotation current_rotation;
XRRScreenConfiguration *scrn_cfg;
scrn_cfg = XRRGetScreenInfo((Display *)ctx->native_dpy, DefaultRootWindow((Display *)ctx->native_dpy));
XRRConfigCurrentConfiguration(scrn_cfg, &current_rotation);
XRRFreeScreenConfigInfo(scrn_cfg);
return (current_rotation & 0x0f);
}
/* Check drawable type, 1 for window, 0 for pixmap
* Have significant performance drop in XFCE environment
*/
static void psb__CheckDrawableType(Display *dpy, Window win, Drawable draw, int *type_ret)
{
unsigned int child_num;
Window root_return;
Window parent_return;
Window *child_return;
int i;
if (win == draw) {
*type_ret = 1;
return;
}
XQueryTree(dpy, win, &root_return, &parent_return, &child_return, &child_num);
if (!child_num)
return;
for (i = 0; i < child_num; i++)
psb__CheckDrawableType(dpy, child_return[i], draw, type_ret);
}
#endif
static int psb_CheckDrawable(VADriverContextP ctx, Drawable draw)
{
INIT_DRIVER_DATA;
INIT_OUTPUT_PRIV;
Atom xvDrawable = XInternAtom((Display *)ctx->native_dpy, "XV_DRAWABLE", 0);
int val = 0;
driver_data->drawable_info = 0;
if (output->overlay_portID) {
XvSetPortAttribute((Display *)ctx->native_dpy, output->overlay_portID, xvDrawable, draw);
XvGetPortAttribute((Display *)ctx->native_dpy, output->overlay_portID, xvDrawable, &val);
} else if (output->textured_portID) {
XvSetPortAttribute((Display *)ctx->native_dpy, output->textured_portID, xvDrawable, draw);
XvGetPortAttribute((Display *)ctx->native_dpy, output->textured_portID, xvDrawable, &val);
}
driver_data->drawable_info = val;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Get xvDrawable = 0x%08x\n", val);
if (driver_data->drawable_info == XVDRAWABLE_INVALID_DRAWABLE)
return -1;
return 0;
}
static int psb__CheckPutSurfaceXvPort(
VADriverContextP ctx,
VASurfaceID surface,
Drawable draw, /* X Drawable */
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 = SURFACE(surface);
uint32_t buf_pl;
/* silent klockwork */
if (obj_surface && obj_surface->psb_surface)
buf_pl = obj_surface->psb_surface->buf.pl_flags;
else
return -1;
if (flags & VA_CLEAR_DRAWABLE)
return 0;
if (output->overlay_portID == 0) { /* no overlay usable */
driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
return 0;
}
if (driver_data->output_method == PSB_PUTSURFACE_FORCE_OVERLAY) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Force Overlay Xvideo for PutSurface\n");
return 0;
}
if ((driver_data->output_method == PSB_PUTSURFACE_FORCE_TEXTURE)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Force Textured Xvideo for PutSurface\n");
return 0;
}
if (((buf_pl & (WSBM_PL_FLAG_TT)) == 0) /* buf not in TT/RAR or CI */
|| (obj_surface->width > 1920) /* overlay have isue to support >1920xXXX resolution */
|| (obj_surface->subpic_count > 0) /* overlay can't support subpicture */
/* || (flags & (VA_TOP_FIELD|VA_BOTTOM_FIELD))*/
) {
driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
return 0;
}
/* Here should be overlay XV by defaut after overlay is stable */
driver_data->output_method = PSB_PUTSURFACE_OVERLAY;
/* driver_data->output_method = PSB_PUTSURFACE_TEXTURE; */
/*
*Query Overlay Adaptor by XvDrawable Attribute to know current
* Xrandr information:rotation/downscaling
* also set target drawable(window vs pixmap) into XvDrawable
* to levage Xserver to determiate it is Pixmap or Window
*/
/*
*ROTATE_90: 0x2, ROTATE_180: 0x4, ROTATE_270:0x8
*Overlay adopator can support video rotation,
*but its performance is lower than texture video path.
*When video protection and rotation are required (use RAR buffer),
*only overlay adaptor will be used.
*other attribute like down scaling and pixmap, use texture adaptor
*/
if (driver_data->drawable_info
& (XVDRAWABLE_ROTATE_180 | XVDRAWABLE_ROTATE_90 | XVDRAWABLE_ROTATE_270)) {
driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
}
if (driver_data->drawable_info & (XVDRAWABLE_PIXMAP | XVDRAWABLE_REDIRECT_WINDOW))
driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
if (srcw >= destw * 8 || srch >= desth * 8)
driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
return 0;
}
static int psb__CheckGCXvImage(
VADriverContextP ctx,
VASurfaceID surface,
Drawable draw,
XvImage **xvImage,
XvPortID *port_id,
unsigned int flags /* de-interlacing flags */
)
{
INIT_DRIVER_DATA;
INIT_OUTPUT_PRIV;
object_surface_p obj_surface = SURFACE(surface); /* surface already checked */
if (output->output_drawable != draw) {
if (output->gc)
XFreeGC((Display *)ctx->native_dpy, output->gc);
output->gc = XCreateGC((Display *)ctx->native_dpy, draw, 0, NULL);
output->output_drawable = draw;
}
if (flags & VA_CLEAR_DRAWABLE) {
if (output->textured_portID && (output->using_port == USING_TEXTURE_PORT)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clear drawable, and stop textured Xvideo\n");
XvStopVideo((Display *)ctx->native_dpy, output->textured_portID, draw);
}
if (output->overlay_portID && (output->using_port == USING_OVERLAY_PORT)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clear drawable, and stop overlay Xvideo\n");
XvStopVideo((Display *)ctx->native_dpy, output->overlay_portID, draw);
}
output->using_port = 0;
XSetForeground((Display *)ctx->native_dpy, output->gc, driver_data->clear_color);
return 0;
}
if ((driver_data->output_method == PSB_PUTSURFACE_FORCE_OVERLAY) ||
(driver_data->output_method == PSB_PUTSURFACE_OVERLAY)) {
/* use OVERLAY XVideo */
if (obj_surface &&
((output->output_width != obj_surface->width) ||
(output->output_height != obj_surface->height) ||
(!output->overlay_xvimage))) {
if (output->overlay_xvimage)
XFree(output->overlay_xvimage);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create new XvImage for overlay\n");
output->overlay_xvimage = XvCreateImage((Display *)ctx->native_dpy, output->overlay_portID,
FOURCC_XVVA, 0,
obj_surface->width, obj_surface->height);
output->overlay_xvimage->data = (char *) & output->imgdata_vasrf;
output->output_width = obj_surface->width;
output->output_height = obj_surface->height;
}
*xvImage = output->overlay_xvimage;
*port_id = output->overlay_portID;
if ((output->textured_portID) && (output->using_port == USING_TEXTURE_PORT)) { /* stop texture port */
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using overlay xvideo, stop textured xvideo\n");
XvStopVideo((Display *)ctx->native_dpy, output->textured_portID, draw);
XSync((Display *)ctx->native_dpy, False);
}
output->using_port = USING_OVERLAY_PORT;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using Overlay Xvideo (%d) for PutSurface\n", output->textured_portID);
return 0;
}
if ((driver_data->output_method == PSB_PUTSURFACE_FORCE_TEXTURE) ||
(driver_data->output_method == PSB_PUTSURFACE_TEXTURE)) {
/* use Textured XVideo */
if (obj_surface &&
((output->output_width != obj_surface->width) ||
(output->output_height != obj_surface->height ||
(!output->textured_xvimage)))) {
if (output->textured_xvimage)
XFree(output->textured_xvimage);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create new XvImage for overlay\n");
output->textured_xvimage = XvCreateImage((Display *)ctx->native_dpy, output->textured_portID, FOURCC_XVVA, 0,
obj_surface->width, obj_surface->height);
output->textured_xvimage->data = (char *) & output->imgdata_vasrf;
output->output_width = obj_surface->width;
output->output_height = obj_surface->height;
}
*xvImage = output->textured_xvimage;
*port_id = output->textured_portID;
if ((output->overlay_portID) && (output->using_port == USING_OVERLAY_PORT)) { /* stop overlay port */
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using textured xvideo, stop Overlay xvideo\n");
XvStopVideo((Display *)ctx->native_dpy, output->overlay_portID, draw);
XSync((Display *)ctx->native_dpy, False);
output->using_port = USING_TEXTURE_PORT;
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using Texture Xvideo (%d) for PutSurface\n", output->textured_portID);
return 0;
}
return 0;
}
static int psb_force_dpms_on(VADriverContextP ctx)
{
BOOL onoff;
CARD16 state;
DPMSInfo((Display *)ctx->native_dpy, &state, &onoff);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "DPMS is %s, monitor state=%s\n", onoff ? "enabled" : "disabled",
(state == DPMSModeOn) ? "on" : (
(state == DPMSModeOff) ? "off" : (
(state == DPMSModeStandby) ? "standby" : (
(state == DPMSModeSuspend) ? "suspend" : "unknow"))));
if (onoff && (state != DPMSModeOn)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "DPMS is enabled, and monitor isn't DPMSModeOn, force it on\n");
DPMSForceLevel((Display *)ctx->native_dpy, DPMSModeOn);
}
return 0;
}
VAStatus psb_check_rotatesurface(
VADriverContextP ctx,
unsigned short rotate_width,
unsigned short rotate_height,
unsigned int protected,
int fourcc
)
{
INIT_DRIVER_DATA;
INIT_OUTPUT_PRIV;
VAStatus vaStatus = VA_STATUS_SUCCESS;
object_surface_p obj_rotate_surface;
unsigned int flags = protected? IS_PROTECTED : 0;
if (output->rotate_surface) {
obj_rotate_surface = SURFACE(output->rotate_surfaceID);
if (obj_rotate_surface &&
((obj_rotate_surface->width != rotate_width)
|| (obj_rotate_surface->height != rotate_height))) {
psb_surface_destroy(output->rotate_surface);
free(output->rotate_surface);
object_heap_free(&driver_data->surface_heap, (object_base_p)obj_rotate_surface);
output->rotate_surface = NULL;
}
}
if (output->rotate_surface == NULL) {
output->rotate_surfaceID = object_heap_allocate(&driver_data->surface_heap);
obj_rotate_surface = SURFACE(output->rotate_surfaceID);
if (NULL == obj_rotate_surface) {
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
obj_rotate_surface->surface_id = output->rotate_surfaceID;
obj_rotate_surface->context_id = -1;
obj_rotate_surface->width = rotate_width;
obj_rotate_surface->height = rotate_height;
obj_rotate_surface->subpictures = NULL;
obj_rotate_surface->subpic_count = 0;
obj_rotate_surface->derived_imgcnt = 0;
output->rotate_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
if (NULL == output->rotate_surface) {
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_rotate_surface);
obj_rotate_surface->surface_id = VA_INVALID_SURFACE;
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
flags |= IS_ROTATED;
vaStatus = psb_surface_create(driver_data, rotate_width, rotate_height,
fourcc, flags, output->rotate_surface);
if (VA_STATUS_SUCCESS != vaStatus) {
free(obj_rotate_surface->psb_surface);
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_rotate_surface);
obj_rotate_surface->surface_id = VA_INVALID_SURFACE;
DEBUG_FAILURE;
return vaStatus;
}
obj_rotate_surface->psb_surface = output->rotate_surface;
}
return vaStatus;
}
VAStatus psb_putsurface_xvideo(
VADriverContextP ctx,
VASurfaceID surface,
Drawable draw,
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;
VAStatus vaStatus = VA_STATUS_SUCCESS;
PsbVASurfaceRec *subpic_surface;
PsbXvVAPutSurfacePtr vaPtr;
XvPortID portID = 0;
XvImage *xvImage = NULL;
object_surface_p obj_surface = SURFACE(surface);
psb_surface_p psb_surface;
int i = 0, j;
if (obj_surface) /* silent klockwork, we already check it */
psb_surface = obj_surface->psb_surface;
else
return VA_STATUS_ERROR_UNKNOWN;
/* Catch X protocol errors with our own error handler */
if (oldHandler == 0)
oldHandler = XSetErrorHandler(psb_XErrorHandler);
if (XErrorFlag == 1) {
if (psb_CheckDrawable(ctx, draw) != 0) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "vaPutSurface: invalidate drawable\n");
return VA_STATUS_ERROR_UNKNOWN;
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "ran psb_CheckDrawable the first time!\n");
XErrorFlag = 0;
}
/* check display configuration for every 100 frames */
if ((driver_data->frame_count % 100) == 0) {
if (psb_CheckDrawable(ctx, draw) != 0) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "vaPutSurface: invalidate drawable\n");
return VA_STATUS_ERROR_UNKNOWN;
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "ran psb_CheckDrawable the first time!\n");
}
psb__CheckPutSurfaceXvPort(ctx, surface, draw,
srcx, srcy, srcw, srch,
destx, desty, destw, desth,
cliprects, number_cliprects, flags);
psb__CheckGCXvImage(ctx, surface, draw, &xvImage, &portID, flags);
if (flags & VA_CLEAR_DRAWABLE) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clean draw with color 0x%08x\n", driver_data->clear_color);
XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, destx, desty, destw, desth);
XSync((Display *)ctx->native_dpy, False);
XFreeGC((Display *)ctx->native_dpy, output->gc);
output->gc = NULL;
output->output_drawable = 0;
XSync((Display *)ctx->native_dpy, False);
driver_data->cur_displaying_surface = VA_INVALID_SURFACE;
driver_data->last_displaying_surface = VA_INVALID_SURFACE;
obj_surface->display_timestamp = 0;
return vaStatus;
}
vaPtr = (PsbXvVAPutSurfacePtr)xvImage->data;
vaPtr->flags = flags;
vaPtr->num_subpicture = obj_surface->subpic_count;
vaPtr->num_clipbox = number_cliprects;
for (j = 0; j < number_cliprects; j++) {
vaPtr->clipbox[j].x = cliprects[j].x;
vaPtr->clipbox[j].y = cliprects[j].y;
vaPtr->clipbox[j].width = cliprects[j].width;
vaPtr->clipbox[j].height = cliprects[j].height;
}
psb_surface_init(driver_data, &vaPtr->src_srf, VA_FOURCC_NV12, 2,
obj_surface->width, obj_surface->height,
psb_surface->stride, psb_surface->size,
psb_surface->buf.buffer_ofs, /* for surface created from RAR/camera device memory
* all surfaces share one BO but with different offset
* pass the offset as the "pre_add"
*/
psb_surface->buf.drm_buf, flags);
if ((driver_data->output_method == PSB_PUTSURFACE_OVERLAY)
&& (driver_data->drawable_info & (XVDRAWABLE_ROTATE_180 | XVDRAWABLE_ROTATE_90 | XVDRAWABLE_ROTATE_270))) {
unsigned int rotate_width, rotate_height;
int fourcc;
if (output->sprite_enabled)
fourcc = VA_FOURCC_RGBA;
else
fourcc = VA_FOURCC_NV12;
if (driver_data->drawable_info & (XVDRAWABLE_ROTATE_90 | XVDRAWABLE_ROTATE_270)) {
rotate_width = obj_surface->height;
rotate_height = obj_surface->width;
} else {
rotate_width = obj_surface->width;
rotate_height = obj_surface->height;
}
unsigned int protected = vaPtr->src_srf.pl_flags & 0;
vaStatus = psb_check_rotatesurface(ctx, rotate_width, rotate_height, protected, fourcc);
if (VA_STATUS_SUCCESS != vaStatus)
return vaStatus;
psb_surface_init(driver_data, &vaPtr->dst_srf, fourcc, 4,
rotate_width, rotate_height,
output->rotate_surface->stride, output->rotate_surface->size,
output->rotate_surface->buf.buffer_ofs, /* for surface created from RAR/camera device memory
* all surfaces share one BO but with different offset
* pass the offset as the "pre_add"
*/
output->rotate_surface->buf.drm_buf, 0);
}
subpic_surface = obj_surface->subpictures;
while (subpic_surface) {
PsbVASurfaceRec *tmp = &vaPtr->subpic_srf[i++];
memcpy(tmp, subpic_surface, sizeof(*tmp));
/* reload palette for paletted subpicture
* palete_ptr point to image palette
*/
if (subpic_surface->palette_ptr)
memcpy(&tmp->palette[0], subpic_surface->palette_ptr, 16 * sizeof(PsbAYUVSample8));
subpic_surface = subpic_surface->next;
}
if (output->ignore_dpm == 0)
psb_force_dpms_on(ctx);
XvPutImage((Display *)ctx->native_dpy, portID, draw, output->gc, xvImage,
srcx, srcy, srcw, srch, destx, desty, destw, desth);
XFlush((Display *)ctx->native_dpy);
//XSync((Display *)ctx->native_dpy, False);
if (portID == output->overlay_portID) {
if (driver_data->cur_displaying_surface != VA_INVALID_SURFACE)
driver_data->last_displaying_surface = driver_data->cur_displaying_surface;
obj_surface->display_timestamp = GetTickCount();
driver_data->cur_displaying_surface = surface;
} else {
driver_data->cur_displaying_surface = VA_INVALID_SURFACE;
driver_data->last_displaying_surface = VA_INVALID_SURFACE;
obj_surface->display_timestamp = 0;
}
return vaStatus;
}