1/*
2 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Shengquan Yuan  <shengquan.yuan@intel.com>
26 *    Zhaohan Ren  <zhaohan.ren@intel.com>
27 *
28 */
29
30
31#include <va/va_backend.h>
32#include "psb_surface.h"
33#include "psb_output.h"
34#include "psb_surface_ext.h"
35#include "psb_x11.h"
36#include "psb_xrandr.h"
37#include "psb_drv_debug.h"
38
39#include <X11/extensions/dpms.h>
40
41#include <wsbm/wsbm_manager.h>
42
43#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
44#define INIT_OUTPUT_PRIV    psb_x11_output_p output = (psb_x11_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv)
45
46#define SURFACE(id)     ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
47
48static int psb_CheckDrawable(VADriverContextP ctx, Drawable draw);
49
50int (*oldHandler)(Display *, XErrorEvent *) = 0;
51static int XErrorFlag = 1;
52static int psb_XErrorHandler(Display *dpy, XErrorEvent *event)
53{
54    drv_debug_msg(VIDEO_DEBUG_GENERAL, "XErrorEvent caught in psb_XErrorHandler in psb_xvva.c\n");
55    if (event->type == 0 && event->request_code == 132 && event->error_code == 11 /* BadAlloc */) {
56        XErrorFlag = 1;
57        return 0;
58    }
59    return oldHandler(dpy, event);
60}
61
62static int GetPortId(VADriverContextP ctx, psb_x11_output_p output)
63{
64    int i, j, k;
65    unsigned int numAdapt;
66    int numImages;
67    XvImageFormatValues *formats;
68    XvAdaptorInfo *info;
69    int ret, grab_ret;
70    Display *dpy = (Display *)ctx->native_dpy;
71
72    ret = XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &numAdapt, &info);
73    /*Force overlay port num equal to one. OverlayC can't be used independently now.*/
74    /* check for numAdapt before modifying the info[1]. Without this check
75     * it will cause a memory corruption leading to segfaults */
76    if (numAdapt > 1)
77        info[1].num_ports = 1;
78
79    if (Success != ret) {
80        drv_debug_msg(VIDEO_DEBUG_ERROR, "Can't find Xvideo adaptor\n");
81        return -1;
82    }
83
84    grab_ret = XGrabServer(ctx->native_dpy);
85    for (i = 0; i < numAdapt; i++) {
86        if ((info[i].type & XvImageMask) == 0)
87            continue;
88
89        formats = XvListImageFormats(dpy, info[i].base_id, &numImages);
90        for (j = 0; j < numImages; j++) {
91            if (formats[j].id != FOURCC_XVVA) continue;
92            for (k = 0; k < info[i].num_ports; k++) {
93                int ret = XvGrabPort(dpy, info[i].base_id + k, CurrentTime);
94
95                if (Success == ret) {
96                    /* for textured adaptor 0 */
97                    if (i == 0)
98                        output->textured_portID = info[i].base_id + k;
99                    /* for overlay adaptor 1 */
100                    if (i == 1)
101                        output->overlay_portID = info[i].base_id + k;
102                    break;
103                }
104            }
105        }
106        XFree(formats);
107    }
108
109    if (grab_ret != 0)
110        XUngrabServer(ctx->native_dpy);
111
112    if ((output->textured_portID == 0) && (output->overlay_portID == 0)) {
113        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Can't detect any usable Xv XVVA port\n");
114        return -1;
115    }
116
117    return 0;
118}
119
120
121VAStatus psb_init_xvideo(VADriverContextP ctx, psb_x11_output_p output)
122{
123#ifdef _FOR_FPGA_
124    return VA_STATUS_SUCCESS;
125#endif
126
127    INIT_DRIVER_DATA;
128    int dummy, ret;
129
130    output->textured_portID = output->overlay_portID = 0;
131    if (GetPortId(ctx, output)) {
132        drv_debug_msg(VIDEO_DEBUG_ERROR, "Grab Xvideo port failed, fallback to software vaPutSurface.\n");
133        return VA_STATUS_ERROR_ALLOCATION_FAILED;
134    }
135
136    if (output->textured_portID)
137        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected textured Xvideo port_id = %d.\n", (unsigned int)output->textured_portID);
138    if (output->overlay_portID)
139        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected overlay  Xvideo port_id = %d.\n", (unsigned int)output->overlay_portID);
140
141    output->sprite_enabled = 0;
142    if (getenv("PSB_SPRITE_ENABLE")) {
143        drv_debug_msg(VIDEO_DEBUG_GENERAL, "use sprite plane to playback rotated protected video\n");
144        output->sprite_enabled = 1;
145    }
146
147    output->ignore_dpm = 1;
148    if (getenv("PSB_VIDEO_DPMS_HACK")) {
149        if (DPMSQueryExtension((Display *)ctx->native_dpy, &dummy, &dummy)
150            && DPMSCapable((Display *)ctx->native_dpy)) {
151            BOOL onoff;
152            CARD16 state;
153
154            DPMSInfo((Display *)ctx->native_dpy, &state, &onoff);
155            drv_debug_msg(VIDEO_DEBUG_GENERAL, "DPMS is %s, monitor state=%s\n", onoff ? "enabled" : "disabled",
156                                     (state == DPMSModeOn) ? "on" : (
157                                         (state == DPMSModeOff) ? "off" : (
158                                             (state == DPMSModeStandby) ? "standby" : (
159                                                 (state == DPMSModeSuspend) ? "suspend" : "unknow"))));
160            if (onoff)
161                output->ignore_dpm = 0;
162        }
163    }
164
165    /* by default, overlay Xv */
166    if (output->textured_portID)
167        driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
168    if (output->overlay_portID)
169        driver_data->output_method = PSB_PUTSURFACE_OVERLAY;
170
171    ret = psb_xrandr_init(ctx);
172    if (ret != 0) {
173        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to initialize psb xrandr error # %d\n", __func__, ret);
174        return VA_STATUS_ERROR_UNKNOWN;
175    }
176
177    return VA_STATUS_SUCCESS;
178}
179
180
181VAStatus psb_deinit_xvideo(VADriverContextP ctx)
182{
183    INIT_DRIVER_DATA;
184    INIT_OUTPUT_PRIV;
185
186    if (output->gc) {
187        XFreeGC((Display *)ctx->native_dpy, output->gc);
188        output->gc = NULL;
189    }
190
191    if (output->extend_gc) {
192        XFreeGC((Display *)ctx->native_dpy, output->extend_gc);
193        output->extend_gc = NULL;
194    }
195
196    if (output->textured_xvimage) {
197        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Destroy XvImage for texture Xv\n");
198        XFree(output->textured_xvimage);
199        output->textured_xvimage = NULL;
200    }
201
202    if (output->overlay_xvimage) {
203        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Destroy XvImage for overlay  Xv\n");
204        XFree(output->overlay_xvimage);
205        output->textured_xvimage = NULL;
206    }
207
208    if (output->textured_portID) {
209        if ((output->using_port == USING_TEXTURE_PORT) && output->output_drawable
210            && (psb_CheckDrawable(ctx, output->output_drawable) == 0)) {
211            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Deinit: stop textured Xvideo\n");
212            XvStopVideo((Display *)ctx->native_dpy, output->textured_portID, output->output_drawable);
213        }
214
215        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Deinit: ungrab textured Xvideo port\n");
216        XvUngrabPort((Display *)ctx->native_dpy, output->textured_portID, CurrentTime);
217        output->textured_portID = 0;
218    }
219
220    if (output->overlay_portID) {
221        if ((output->using_port == USING_OVERLAY_PORT) && output->output_drawable
222            && (psb_CheckDrawable(ctx, output->output_drawable) == 0)) {
223            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Deinit: stop overlay Xvideo\n");
224            XvStopVideo((Display *)ctx->native_dpy, output->overlay_portID, output->output_drawable);
225        }
226
227        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Deinit: ungrab overlay Xvideo port\n");
228        XvUngrabPort((Display *)ctx->native_dpy, output->overlay_portID, CurrentTime);
229        output->overlay_portID = 0;
230    }
231
232    if (driver_data->use_xrandr_thread && driver_data->xrandr_thread_id) {
233        psb_xrandr_thread_exit();
234        pthread_join(driver_data->xrandr_thread_id, NULL);
235        driver_data->xrandr_thread_id = 0;
236    }
237    psb_xrandr_deinit();
238
239    output->using_port = 0;
240    output->output_drawable = 0;
241    output->extend_drawable = 0;
242#ifndef _FOR_FPGA_
243    XSync((Display *)ctx->native_dpy, False);
244#endif
245    return VA_STATUS_SUCCESS;
246}
247
248
249static void psb_surface_init(
250    psb_driver_data_p driver_data,
251    PsbVASurfaceRec *srf,
252    int fourcc, int bpp, int w, int h, int stride, int size, unsigned int pre_add,
253    struct _WsbmBufferObject *bo, int flags
254)
255{
256    memset(srf, 0, sizeof(*srf));
257
258    srf->fourcc = fourcc;
259    srf->bo = bo;
260    if (bo != NULL) {
261        srf->bufid = wsbmKBufHandle(wsbmKBuf(bo));
262        srf->pl_flags = wsbmBOPlacementHint(bo);
263    }
264
265/*
266    if (srf->pl_flags & DRM_PSB_FLAG_MEM_CI)
267        srf->reserved_phyaddr = driver_data->camera_phyaddr;
268    if (srf->pl_flags & DRM_PSB_FLAG_MEM_RAR)
269        srf->reserved_phyaddr = driver_data->rar_phyaddr;
270*/
271    srf->bytes_pp = bpp;
272
273    srf->width = w;
274    srf->pre_add = pre_add;
275    if ((flags == VA_TOP_FIELD) || (flags == VA_BOTTOM_FIELD)) {
276        if (driver_data->output_method ==  PSB_PUTSURFACE_FORCE_OVERLAY
277            || driver_data->output_method == PSB_PUTSURFACE_OVERLAY) {
278            srf->height = h;
279            srf->stride = stride;
280        } else {
281            srf->height = h / 2;
282            srf->stride = stride * 2;
283        }
284        if (flags == VA_BOTTOM_FIELD)
285            srf->pre_add += stride;
286    } else {
287        srf->height = h;
288        srf->stride = stride;
289    }
290
291    srf->size = size;
292
293    if (flags == VA_CLEAR_DRAWABLE) {
294        srf->clear_color = driver_data->clear_color; /* color */
295        return;
296    }
297}
298
299#if 0
300
301#define WINDOW 1
302#define PIXMAP 0
303
304/* return 0 for no rotation, 1 for rotation occurs */
305/* XRRGetScreenInfo has significant performance drop */
306static int  psb__CheckCurrentRotation(VADriverContextP ctx)
307{
308    Rotation current_rotation;
309    XRRScreenConfiguration *scrn_cfg;
310    scrn_cfg = XRRGetScreenInfo((Display *)ctx->native_dpy, DefaultRootWindow((Display *)ctx->native_dpy));
311    XRRConfigCurrentConfiguration(scrn_cfg, &current_rotation);
312    XRRFreeScreenConfigInfo(scrn_cfg);
313    return (current_rotation & 0x0f);
314}
315
316/* Check drawable type, 1 for window, 0 for pixmap
317 * Have significant performance drop in XFCE environment
318 */
319static void psb__CheckDrawableType(Display *dpy, Window win, Drawable draw, int *type_ret)
320{
321
322    unsigned int child_num;
323    Window root_return;
324    Window parent_return;
325    Window *child_return;
326    int i;
327
328    if (win == draw) {
329        *type_ret = 1;
330        return;
331    }
332
333    XQueryTree(dpy, win, &root_return, &parent_return, &child_return, &child_num);
334
335    if (!child_num)
336        return;
337
338    for (i = 0; i < child_num; i++)
339        psb__CheckDrawableType(dpy, child_return[i], draw, type_ret);
340}
341#endif
342
343
344static int psb_CheckDrawable(VADriverContextP ctx, Drawable draw)
345{
346    INIT_DRIVER_DATA;
347    INIT_OUTPUT_PRIV;
348    Atom xvDrawable = XInternAtom((Display *)ctx->native_dpy, "XV_DRAWABLE", 0);
349    int val = 0;
350
351    driver_data->drawable_info = 0;
352    if (output->overlay_portID) {
353        XvSetPortAttribute((Display *)ctx->native_dpy, output->overlay_portID, xvDrawable, draw);
354        XvGetPortAttribute((Display *)ctx->native_dpy, output->overlay_portID, xvDrawable, &val);
355    } else if (output->textured_portID) {
356        XvSetPortAttribute((Display *)ctx->native_dpy, output->textured_portID, xvDrawable, draw);
357        XvGetPortAttribute((Display *)ctx->native_dpy, output->textured_portID, xvDrawable, &val);
358    }
359    driver_data->drawable_info = val;
360
361    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Get xvDrawable = 0x%08x\n", val);
362
363    if (driver_data->drawable_info == XVDRAWABLE_INVALID_DRAWABLE)
364        return -1;
365
366    return 0;
367}
368
369static int psb__CheckPutSurfaceXvPort(
370    VADriverContextP ctx,
371    VASurfaceID surface,
372    Drawable draw, /* X Drawable */
373    short srcx,
374    short srcy,
375    unsigned short srcw,
376    unsigned short srch,
377    short destx,
378    short desty,
379    unsigned short destw,
380    unsigned short desth,
381    VARectangle *cliprects, /* client supplied clip list */
382    unsigned int number_cliprects, /* number of clip rects in the clip list */
383    unsigned int flags /* de-interlacing flags */
384)
385{
386    INIT_DRIVER_DATA;
387    INIT_OUTPUT_PRIV;
388    object_surface_p obj_surface = SURFACE(surface);
389    uint32_t buf_pl;
390
391    /* silent klockwork */
392    if (obj_surface && obj_surface->psb_surface)
393        buf_pl = obj_surface->psb_surface->buf.pl_flags;
394    else
395        return -1;
396
397    if (flags & VA_CLEAR_DRAWABLE)
398        return 0;
399
400    if (output->overlay_portID == 0) { /* no overlay usable */
401        driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
402        return 0;
403    }
404
405    if (driver_data->output_method == PSB_PUTSURFACE_FORCE_OVERLAY) {
406        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Force Overlay Xvideo for PutSurface\n");
407        return 0;
408    }
409
410    if ((driver_data->output_method == PSB_PUTSURFACE_FORCE_TEXTURE)) {
411        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Force Textured Xvideo for PutSurface\n");
412        return 0;
413    }
414
415    if (((buf_pl & (WSBM_PL_FLAG_TT)) == 0) /* buf not in TT/RAR or CI */
416        || (obj_surface->width > 1920)  /* overlay have isue to support >1920xXXX resolution */
417        || (obj_surface->subpic_count > 0)  /* overlay can't support subpicture */
418        /*    || (flags & (VA_TOP_FIELD|VA_BOTTOM_FIELD))*/
419       ) {
420        driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
421        return 0;
422    }
423
424
425    /* Here should be overlay XV by defaut after overlay is stable */
426    driver_data->output_method = PSB_PUTSURFACE_OVERLAY;
427    /* driver_data->output_method = PSB_PUTSURFACE_TEXTURE; */
428
429    /*
430     *Query Overlay Adaptor by XvDrawable Attribute to know current
431     * Xrandr information:rotation/downscaling
432     * also set target drawable(window vs pixmap) into XvDrawable
433     * to levage Xserver to determiate it is Pixmap or Window
434     */
435    /*
436     *ROTATE_90: 0x2, ROTATE_180: 0x4, ROTATE_270:0x8
437     *Overlay adopator can support video rotation,
438     *but its performance is lower than texture video path.
439     *When video protection and rotation are required (use RAR buffer),
440     *only overlay adaptor will be used.
441     *other attribute like down scaling and pixmap, use texture adaptor
442     */
443    if (driver_data->drawable_info
444        & (XVDRAWABLE_ROTATE_180 | XVDRAWABLE_ROTATE_90 | XVDRAWABLE_ROTATE_270)) {
445            driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
446    }
447
448    if (driver_data->drawable_info & (XVDRAWABLE_PIXMAP | XVDRAWABLE_REDIRECT_WINDOW))
449        driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
450
451    if (srcw >= destw * 8 || srch >= desth * 8)
452        driver_data->output_method = PSB_PUTSURFACE_TEXTURE;
453
454    return 0;
455}
456
457
458static int psb__CheckGCXvImage(
459    VADriverContextP ctx,
460    VASurfaceID surface,
461    Drawable draw,
462    XvImage **xvImage,
463    XvPortID *port_id,
464    unsigned int flags /* de-interlacing flags */
465)
466{
467    INIT_DRIVER_DATA;
468    INIT_OUTPUT_PRIV;
469    object_surface_p obj_surface = SURFACE(surface); /* surface already checked */
470
471    if (output->output_drawable != draw) {
472        if (output->gc)
473            XFreeGC((Display *)ctx->native_dpy, output->gc);
474        output->gc = XCreateGC((Display *)ctx->native_dpy, draw, 0, NULL);
475        output->output_drawable = draw;
476    }
477
478    if (flags & VA_CLEAR_DRAWABLE) {
479        if (output->textured_portID && (output->using_port == USING_TEXTURE_PORT)) {
480            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clear drawable, and stop textured Xvideo\n");
481            XvStopVideo((Display *)ctx->native_dpy, output->textured_portID, draw);
482        }
483
484        if (output->overlay_portID && (output->using_port == USING_OVERLAY_PORT)) {
485            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clear drawable, and stop overlay Xvideo\n");
486            XvStopVideo((Display *)ctx->native_dpy, output->overlay_portID, draw);
487        }
488
489        output->using_port = 0;
490
491        XSetForeground((Display *)ctx->native_dpy, output->gc, driver_data->clear_color);
492
493        return 0;
494    }
495
496    if ((driver_data->output_method == PSB_PUTSURFACE_FORCE_OVERLAY) ||
497        (driver_data->output_method == PSB_PUTSURFACE_OVERLAY)) {
498        /* use OVERLAY XVideo */
499        if (obj_surface &&
500            ((output->output_width != obj_surface->width) ||
501             (output->output_height != obj_surface->height) ||
502             (!output->overlay_xvimage))) {
503
504            if (output->overlay_xvimage)
505                XFree(output->overlay_xvimage);
506
507            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create new XvImage for overlay\n");
508            output->overlay_xvimage = XvCreateImage((Display *)ctx->native_dpy, output->overlay_portID,
509                                                    FOURCC_XVVA, 0,
510                                                    obj_surface->width, obj_surface->height);
511
512            output->overlay_xvimage->data = (char *) & output->imgdata_vasrf;
513            output->output_width = obj_surface->width;
514            output->output_height = obj_surface->height;
515        }
516        *xvImage = output->overlay_xvimage;
517        *port_id = output->overlay_portID;
518
519        if ((output->textured_portID) && (output->using_port == USING_TEXTURE_PORT)) { /* stop texture port */
520            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using overlay xvideo, stop textured xvideo\n");
521            XvStopVideo((Display *)ctx->native_dpy, output->textured_portID, draw);
522            XSync((Display *)ctx->native_dpy, False);
523        }
524        output->using_port = USING_OVERLAY_PORT;
525
526        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using Overlay Xvideo (%d) for PutSurface\n", output->textured_portID);
527
528        return 0;
529    }
530
531    if ((driver_data->output_method == PSB_PUTSURFACE_FORCE_TEXTURE) ||
532        (driver_data->output_method == PSB_PUTSURFACE_TEXTURE)) {
533        /* use Textured XVideo */
534        if (obj_surface &&
535            ((output->output_width != obj_surface->width) ||
536             (output->output_height != obj_surface->height ||
537              (!output->textured_xvimage)))) {
538            if (output->textured_xvimage)
539                XFree(output->textured_xvimage);
540
541            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create new XvImage for overlay\n");
542            output->textured_xvimage = XvCreateImage((Display *)ctx->native_dpy, output->textured_portID, FOURCC_XVVA, 0,
543                                       obj_surface->width, obj_surface->height);
544            output->textured_xvimage->data = (char *) & output->imgdata_vasrf;
545            output->output_width = obj_surface->width;
546            output->output_height = obj_surface->height;
547
548        }
549
550        *xvImage = output->textured_xvimage;
551        *port_id = output->textured_portID;
552
553        if ((output->overlay_portID) && (output->using_port == USING_OVERLAY_PORT)) { /* stop overlay port */
554            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using textured xvideo, stop Overlay xvideo\n");
555            XvStopVideo((Display *)ctx->native_dpy, output->overlay_portID, draw);
556            XSync((Display *)ctx->native_dpy, False);
557
558            output->using_port = USING_TEXTURE_PORT;
559        }
560
561        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using Texture Xvideo (%d) for PutSurface\n", output->textured_portID);
562
563        return 0;
564    }
565
566    return 0;
567}
568
569static int psb_force_dpms_on(VADriverContextP ctx)
570{
571    BOOL onoff;
572    CARD16 state;
573
574    DPMSInfo((Display *)ctx->native_dpy, &state, &onoff);
575    drv_debug_msg(VIDEO_DEBUG_GENERAL, "DPMS is %s, monitor state=%s\n", onoff ? "enabled" : "disabled",
576                             (state == DPMSModeOn) ? "on" : (
577                                 (state == DPMSModeOff) ? "off" : (
578                                     (state == DPMSModeStandby) ? "standby" : (
579                                         (state == DPMSModeSuspend) ? "suspend" : "unknow"))));
580    if (onoff && (state != DPMSModeOn)) {
581        drv_debug_msg(VIDEO_DEBUG_GENERAL, "DPMS is enabled, and monitor isn't DPMSModeOn, force it on\n");
582        DPMSForceLevel((Display *)ctx->native_dpy, DPMSModeOn);
583    }
584
585    return 0;
586}
587
588VAStatus psb_check_rotatesurface(
589    VADriverContextP ctx,
590    unsigned short rotate_width,
591    unsigned short rotate_height,
592    unsigned int protected,
593    int fourcc
594)
595{
596    INIT_DRIVER_DATA;
597    INIT_OUTPUT_PRIV;
598    VAStatus vaStatus = VA_STATUS_SUCCESS;
599    object_surface_p obj_rotate_surface;
600    unsigned int flags = protected? IS_PROTECTED : 0;
601
602    if (output->rotate_surface) {
603        obj_rotate_surface = SURFACE(output->rotate_surfaceID);
604        if (obj_rotate_surface &&
605            ((obj_rotate_surface->width != rotate_width)
606             || (obj_rotate_surface->height != rotate_height))) {
607            psb_surface_destroy(output->rotate_surface);
608            free(output->rotate_surface);
609            object_heap_free(&driver_data->surface_heap, (object_base_p)obj_rotate_surface);
610            output->rotate_surface = NULL;
611        }
612    }
613    if (output->rotate_surface == NULL) {
614        output->rotate_surfaceID = object_heap_allocate(&driver_data->surface_heap);
615        obj_rotate_surface = SURFACE(output->rotate_surfaceID);
616        if (NULL == obj_rotate_surface) {
617            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
618            DEBUG_FAILURE;
619
620            return VA_STATUS_ERROR_ALLOCATION_FAILED;
621        }
622
623        obj_rotate_surface->surface_id = output->rotate_surfaceID;
624        obj_rotate_surface->context_id = -1;
625        obj_rotate_surface->width = rotate_width;
626        obj_rotate_surface->height = rotate_height;
627        obj_rotate_surface->subpictures = NULL;
628        obj_rotate_surface->subpic_count = 0;
629        obj_rotate_surface->derived_imgcnt = 0;
630        output->rotate_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
631        if (NULL == output->rotate_surface) {
632            object_heap_free(&driver_data->surface_heap, (object_base_p) obj_rotate_surface);
633            obj_rotate_surface->surface_id = VA_INVALID_SURFACE;
634
635            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
636
637            DEBUG_FAILURE;
638
639            return VA_STATUS_ERROR_ALLOCATION_FAILED;
640        }
641
642        flags |= IS_ROTATED;
643        vaStatus = psb_surface_create(driver_data, rotate_width, rotate_height,
644                                      fourcc, flags, output->rotate_surface);
645        if (VA_STATUS_SUCCESS != vaStatus) {
646            free(obj_rotate_surface->psb_surface);
647            object_heap_free(&driver_data->surface_heap, (object_base_p) obj_rotate_surface);
648            obj_rotate_surface->surface_id = VA_INVALID_SURFACE;
649
650            DEBUG_FAILURE;
651            return vaStatus;
652        }
653        obj_rotate_surface->psb_surface = output->rotate_surface;
654    }
655    return vaStatus;
656}
657
658VAStatus psb_putsurface_xvideo(
659    VADriverContextP ctx,
660    VASurfaceID surface,
661    Drawable draw,
662    short srcx,
663    short srcy,
664    unsigned short srcw,
665    unsigned short srch,
666    short destx,
667    short desty,
668    unsigned short destw,
669    unsigned short desth,
670    VARectangle *cliprects, /* client supplied clip list */
671    unsigned int number_cliprects, /* number of clip rects in the clip list */
672    unsigned int flags /* de-interlacing flags */
673)
674{
675    INIT_DRIVER_DATA;
676    INIT_OUTPUT_PRIV;
677    VAStatus vaStatus = VA_STATUS_SUCCESS;
678    PsbVASurfaceRec *subpic_surface;
679    PsbXvVAPutSurfacePtr vaPtr;
680    XvPortID    portID = 0;
681    XvImage *xvImage = NULL;
682    object_surface_p obj_surface = SURFACE(surface);
683    psb_surface_p psb_surface;
684    int i = 0, j;
685
686
687    if (obj_surface) /* silent klockwork, we already check it */
688        psb_surface = obj_surface->psb_surface;
689    else
690        return VA_STATUS_ERROR_UNKNOWN;
691
692    /* Catch X protocol errors with our own error handler */
693    if (oldHandler == 0)
694        oldHandler = XSetErrorHandler(psb_XErrorHandler);
695
696    if (XErrorFlag == 1) {
697        if (psb_CheckDrawable(ctx, draw) != 0) {
698            drv_debug_msg(VIDEO_DEBUG_ERROR, "vaPutSurface: invalidate drawable\n");
699            return VA_STATUS_ERROR_UNKNOWN;
700        }
701
702        drv_debug_msg(VIDEO_DEBUG_GENERAL, "ran psb_CheckDrawable the first time!\n");
703        XErrorFlag = 0;
704    }
705
706    /* check display configuration for every 100 frames */
707    if ((driver_data->frame_count % 100) == 0) {
708        if (psb_CheckDrawable(ctx, draw) != 0) {
709            drv_debug_msg(VIDEO_DEBUG_ERROR, "vaPutSurface: invalidate drawable\n");
710            return VA_STATUS_ERROR_UNKNOWN;
711        }
712        drv_debug_msg(VIDEO_DEBUG_GENERAL, "ran psb_CheckDrawable the first time!\n");
713    }
714
715
716
717    psb__CheckPutSurfaceXvPort(ctx, surface, draw,
718                               srcx, srcy, srcw, srch,
719                               destx, desty, destw, desth,
720                               cliprects, number_cliprects, flags);
721    psb__CheckGCXvImage(ctx, surface, draw, &xvImage, &portID, flags);
722
723    if (flags & VA_CLEAR_DRAWABLE) {
724        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clean draw with color 0x%08x\n", driver_data->clear_color);
725
726        XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, destx, desty, destw, desth);
727        XSync((Display *)ctx->native_dpy, False);
728
729        XFreeGC((Display *)ctx->native_dpy, output->gc);
730        output->gc = NULL;
731        output->output_drawable = 0;
732
733        XSync((Display *)ctx->native_dpy, False);
734
735        driver_data->cur_displaying_surface = VA_INVALID_SURFACE;
736        driver_data->last_displaying_surface = VA_INVALID_SURFACE;
737        obj_surface->display_timestamp = 0;
738
739
740        return vaStatus;
741    }
742
743    vaPtr = (PsbXvVAPutSurfacePtr)xvImage->data;
744    vaPtr->flags = flags;
745    vaPtr->num_subpicture = obj_surface->subpic_count;
746    vaPtr->num_clipbox = number_cliprects;
747    for (j = 0; j < number_cliprects; j++) {
748        vaPtr->clipbox[j].x = cliprects[j].x;
749        vaPtr->clipbox[j].y = cliprects[j].y;
750        vaPtr->clipbox[j].width = cliprects[j].width;
751        vaPtr->clipbox[j].height = cliprects[j].height;
752    }
753
754    psb_surface_init(driver_data, &vaPtr->src_srf, VA_FOURCC_NV12, 2,
755                     obj_surface->width, obj_surface->height,
756                     psb_surface->stride, psb_surface->size,
757                     psb_surface->buf.buffer_ofs, /* for surface created from RAR/camera device memory
758                                                   * all surfaces share one BO but with different offset
759                                                   * pass the offset as the "pre_add"
760                                                   */
761                     psb_surface->buf.drm_buf, flags);
762
763    if ((driver_data->output_method == PSB_PUTSURFACE_OVERLAY)
764        && (driver_data->drawable_info & (XVDRAWABLE_ROTATE_180 | XVDRAWABLE_ROTATE_90 | XVDRAWABLE_ROTATE_270))) {
765        unsigned int rotate_width, rotate_height;
766        int fourcc;
767        if (output->sprite_enabled)
768            fourcc = VA_FOURCC_RGBA;
769        else
770            fourcc = VA_FOURCC_NV12;
771        if (driver_data->drawable_info & (XVDRAWABLE_ROTATE_90 | XVDRAWABLE_ROTATE_270)) {
772            rotate_width = obj_surface->height;
773            rotate_height = obj_surface->width;
774        } else {
775            rotate_width = obj_surface->width;
776            rotate_height = obj_surface->height;
777        }
778        unsigned int protected = vaPtr->src_srf.pl_flags & 0;
779
780        vaStatus = psb_check_rotatesurface(ctx, rotate_width, rotate_height, protected, fourcc);
781        if (VA_STATUS_SUCCESS != vaStatus)
782            return vaStatus;
783
784        psb_surface_init(driver_data, &vaPtr->dst_srf, fourcc, 4,
785                         rotate_width, rotate_height,
786                         output->rotate_surface->stride, output->rotate_surface->size,
787                         output->rotate_surface->buf.buffer_ofs, /* for surface created from RAR/camera device memory
788                                                          * all surfaces share one BO but with different offset
789                                                          * pass the offset as the "pre_add"
790                                                          */
791                         output->rotate_surface->buf.drm_buf, 0);
792    }
793    subpic_surface = obj_surface->subpictures;
794    while (subpic_surface) {
795        PsbVASurfaceRec *tmp = &vaPtr->subpic_srf[i++];
796
797        memcpy(tmp, subpic_surface, sizeof(*tmp));
798
799        /* reload palette for paletted subpicture
800         * palete_ptr point to image palette
801         */
802        if (subpic_surface->palette_ptr)
803            memcpy(&tmp->palette[0], subpic_surface->palette_ptr, 16 * sizeof(PsbAYUVSample8));
804
805        subpic_surface = subpic_surface->next;
806    }
807
808    if (output->ignore_dpm == 0)
809        psb_force_dpms_on(ctx);
810
811    XvPutImage((Display *)ctx->native_dpy, portID, draw, output->gc, xvImage,
812               srcx, srcy, srcw, srch, destx, desty, destw, desth);
813    XFlush((Display *)ctx->native_dpy);
814    //XSync((Display *)ctx->native_dpy, False);
815
816    if (portID == output->overlay_portID) {
817        if (driver_data->cur_displaying_surface != VA_INVALID_SURFACE)
818            driver_data->last_displaying_surface = driver_data->cur_displaying_surface;
819        obj_surface->display_timestamp = GetTickCount();
820        driver_data->cur_displaying_surface = surface;
821    } else {
822        driver_data->cur_displaying_surface = VA_INVALID_SURFACE;
823        driver_data->last_displaying_surface = VA_INVALID_SURFACE;
824        obj_surface->display_timestamp = 0;
825    }
826
827
828    return vaStatus;
829}
830
831