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 
48 static int psb_CheckDrawable(VADriverContextP ctx, Drawable draw);
49 
50 int (*oldHandler)(Display *, XErrorEvent *) = 0;
51 static int XErrorFlag = 1;
psb_XErrorHandler(Display * dpy,XErrorEvent * event)52 static 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 
GetPortId(VADriverContextP ctx,psb_x11_output_p output)62 static 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 
psb_init_xvideo(VADriverContextP ctx,psb_x11_output_p output)121 VAStatus 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 
psb_deinit_xvideo(VADriverContextP ctx)181 VAStatus 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 
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)249 static 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 */
306 static 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  */
319 static 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 
psb_CheckDrawable(VADriverContextP ctx,Drawable draw)344 static 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 
psb__CheckPutSurfaceXvPort(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,unsigned int number_cliprects,unsigned int flags)369 static 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 
psb__CheckGCXvImage(VADriverContextP ctx,VASurfaceID surface,Drawable draw,XvImage ** xvImage,XvPortID * port_id,unsigned int flags)458 static 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 
psb_force_dpms_on(VADriverContextP ctx)569 static 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 
psb_check_rotatesurface(VADriverContextP ctx,unsigned short rotate_width,unsigned short rotate_height,unsigned int protected,int fourcc)588 VAStatus 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 
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,unsigned int number_cliprects,unsigned int flags)658 VAStatus 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