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 *    Jason Hu  <jason.hu@intel.com>
26 *    Zhaohan Ren  <zhaohan.ren@intel.com>
27 *    Shengquan Yuan  <shengquan.yuan@intel.com>
28 *
29 */
30
31#include <X11/Xutil.h>
32#include <X11/extensions/Xrandr.h>
33#include <va/va_backend.h>
34#include "psb_output.h"
35#include "psb_surface.h"
36#include "psb_buffer.h"
37#include "psb_x11.h"
38#include "psb_drv_debug.h"
39
40#include <stdio.h>
41#include <string.h>
42#include <stdarg.h>
43#include "psb_surface_ext.h"
44#include <wsbm/wsbm_manager.h>
45#include "psb_drv_video.h"
46#include "psb_xrandr.h"
47#include <sys/types.h>
48
49#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData
50#define INIT_OUTPUT_PRIV    psb_x11_output_p output = (psb_x11_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv)
51#define SURFACE(id)     ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
52
53static int
54psb_x11_getWindowCoordinate(Display * display,
55                            Window x11_window_id,
56                            psb_x11_win_t * psX11Window,
57                            int * pbIsVisible)
58{
59    Window DummyWindow;
60    Status status;
61    XWindowAttributes sXWinAttrib;
62
63    if ((status = XGetWindowAttributes(display,
64                                       x11_window_id,
65                                       &sXWinAttrib)) == 0) {
66        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get X11 window coordinates - error %lu\n", __func__, (unsigned long)status);
67        return -1;
68    }
69
70    psX11Window->i32Left = sXWinAttrib.x;
71    psX11Window->i32Top = sXWinAttrib.y;
72    psX11Window->ui32Width = sXWinAttrib.width;
73    psX11Window->ui32Height = sXWinAttrib.height;
74    *pbIsVisible = (sXWinAttrib.map_state == IsViewable);
75
76    if (!*pbIsVisible)
77        return 0;
78
79    if (XTranslateCoordinates(display,
80                              x11_window_id,
81                              DefaultRootWindow(display),
82                              0,
83                              0,
84                              &psX11Window->i32Left,
85                              &psX11Window->i32Top,
86                              &DummyWindow) == 0) {
87        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to tranlate X coordinates - error %lu\n", __func__, (unsigned long)status);
88        return -1;
89    }
90
91    psX11Window->i32Right  = psX11Window->i32Left + psX11Window->ui32Width - 1;
92    psX11Window->i32Bottom = psX11Window->i32Top + psX11Window->ui32Height - 1;
93
94    return 0;
95}
96static psb_x11_clip_list_t *
97psb_x11_createClipBoxNode(psb_x11_win_t *       pRect,
98                          psb_x11_clip_list_t * pClipNext)
99{
100    psb_x11_clip_list_t * pCurrent = NULL;
101
102    pCurrent = (psb_x11_clip_list_t *)calloc(1, sizeof(psb_x11_clip_list_t));
103    if (pCurrent) {
104        pCurrent->rect = *pRect;
105        pCurrent->next = pClipNext;
106
107        return pCurrent;
108    } else
109        return pClipNext;
110}
111
112void
113psb_x11_freeWindowClipBoxList(psb_x11_clip_list_t * pHead)
114{
115    psb_x11_clip_list_t * pNext = NULL;
116
117    while (pHead) {
118        pNext = pHead->next;
119        free(pHead);
120        pHead = pNext;
121    }
122}
123
124#define IS_BETWEEN_RANGE(a,b,c) ((a<=b)&&(b<=c))
125
126static psb_x11_clip_list_t *
127psb_x11_substractRects(Display *             display,
128                       psb_x11_clip_list_t * psRegion,
129                       psb_x11_win_t *       psRect)
130{
131    psb_x11_clip_list_t * psCur, * psPrev, * psFirst, * psNext;
132    psb_x11_win_t sCreateRect;
133    int display_width  = (int)(DisplayWidth(display, DefaultScreen(display))) - 1;
134    int display_height = (int)(DisplayHeight(display, DefaultScreen(display))) - 1;
135
136    psFirst = psb_x11_createClipBoxNode(psRect, NULL);
137
138    if (psFirst->rect.i32Left < 0)
139        psFirst->rect.i32Left = 0;
140    else if (psFirst->rect.i32Left > display_width)
141        psFirst->rect.i32Left = display_width;
142
143    if (psFirst->rect.i32Right < 0)
144        psFirst->rect.i32Right = 0;
145    else if (psFirst->rect.i32Right > display_width)
146        psFirst->rect.i32Right = display_width;
147
148    if (psFirst->rect.i32Top < 0)
149        psFirst->rect.i32Top = 0;
150    else if (psFirst->rect.i32Top > display_height)
151        psFirst->rect.i32Top = display_height;
152
153    if (psFirst->rect.i32Bottom < 0)
154        psFirst->rect.i32Bottom = 0;
155    else if (psFirst->rect.i32Bottom > display_height)
156        psFirst->rect.i32Bottom = display_height;
157
158    while (psRegion) {
159        psCur  = psFirst;
160        psPrev = NULL;
161
162        while (psCur) {
163            psNext = psCur->next;
164
165            if ((psRegion->rect.i32Left > psCur->rect.i32Left) &&
166                (psRegion->rect.i32Left <= psCur->rect.i32Right)) {
167                sCreateRect.i32Right = psRegion->rect.i32Left - 1;
168
169                sCreateRect.i32Left = psCur->rect.i32Left;
170                sCreateRect.i32Top = psCur->rect.i32Top;
171                sCreateRect.i32Bottom = psCur->rect.i32Bottom;
172
173                psFirst = psb_x11_createClipBoxNode(&sCreateRect, psFirst);
174
175                if (!psPrev)
176                    psPrev = psFirst;
177
178                psCur->rect.i32Left = psRegion->rect.i32Left;
179            }
180
181            if ((psRegion->rect.i32Right >= psCur->rect.i32Left) &&
182                (psRegion->rect.i32Right < psCur->rect.i32Right))
183
184            {
185                sCreateRect.i32Left = psRegion->rect.i32Right + 1;
186
187                sCreateRect.i32Right = psCur->rect.i32Right;
188                sCreateRect.i32Top = psCur->rect.i32Top;
189                sCreateRect.i32Bottom = psCur->rect.i32Bottom;
190
191                psFirst = psb_x11_createClipBoxNode(&sCreateRect, psFirst);
192
193                if (!psPrev)
194                    psPrev = psFirst;
195
196                psCur->rect.i32Right = psRegion->rect.i32Right;
197            }
198
199            if ((psRegion->rect.i32Top > psCur->rect.i32Top) &&
200                (psRegion->rect.i32Top <= psCur->rect.i32Bottom)) {
201                sCreateRect.i32Bottom = psRegion->rect.i32Top - 1;
202
203                sCreateRect.i32Left   = psCur->rect.i32Left;
204                sCreateRect.i32Right  = psCur->rect.i32Right;
205                sCreateRect.i32Top    = psCur->rect.i32Top;
206
207                psFirst = psb_x11_createClipBoxNode(&sCreateRect, psFirst);
208
209                if (!psPrev)
210                    psPrev = psFirst;
211
212                psCur->rect.i32Top = psRegion->rect.i32Top;
213            }
214
215            if ((psRegion->rect.i32Bottom >= psCur->rect.i32Top) &&
216                (psRegion->rect.i32Bottom <  psCur->rect.i32Bottom)) {
217                sCreateRect.i32Top    = psRegion->rect.i32Bottom + 1;
218                sCreateRect.i32Left   = psCur->rect.i32Left;
219                sCreateRect.i32Right  = psCur->rect.i32Right;
220                sCreateRect.i32Bottom = psCur->rect.i32Bottom;
221
222                psFirst = psb_x11_createClipBoxNode(&sCreateRect, psFirst);
223
224                if (!psPrev)
225                    psPrev = psFirst;
226
227                psCur->rect.i32Bottom = psRegion->rect.i32Bottom;
228            }
229
230            if ((IS_BETWEEN_RANGE(psRegion->rect.i32Left, psCur->rect.i32Left,   psRegion->rect.i32Right)) &&
231                (IS_BETWEEN_RANGE(psRegion->rect.i32Left, psCur->rect.i32Right,  psRegion->rect.i32Right)) &&
232                (IS_BETWEEN_RANGE(psRegion->rect.i32Top,  psCur->rect.i32Top,    psRegion->rect.i32Bottom)) &&
233                (IS_BETWEEN_RANGE(psRegion->rect.i32Top,  psCur->rect.i32Bottom, psRegion->rect.i32Bottom))) {
234                if (psPrev) {
235                    psPrev->next = psCur->next;
236                    free(psCur);
237                    psCur = psPrev;
238                } else {
239                    free(psCur);
240                    psCur = NULL;
241                    psFirst = psNext;
242                }
243            }
244            psPrev = psCur;
245            psCur  = psNext;
246        }//while(psCur)
247        psRegion = psRegion->next;
248    }//while(psRegion)
249
250    return psFirst;
251}
252
253static int
254psb_x11_createWindowClipBoxList(Display *              display,
255                                Window                 x11_window_id,
256                                psb_x11_clip_list_t ** ppWindowClipBoxList,
257                                unsigned int *         pui32NumClipBoxList)
258{
259    Window CurrentWindow = x11_window_id;
260    Window RootWindow, ParentWindow, ChildWindow;
261    Window * pChildWindow;
262    Status XResult;
263    unsigned int i32NumChildren, i;
264    int bIsVisible;
265    unsigned int ui32NumRects = 0;
266    psb_x11_clip_list_t *psRegions = NULL;
267    psb_x11_win_t sRect;
268
269    if (!display || (!ppWindowClipBoxList) || (!pui32NumClipBoxList))
270        return -1;
271
272    XResult = XQueryTree(display,
273                         CurrentWindow,
274                         &RootWindow,
275                         &ParentWindow,
276                         &pChildWindow,
277                         &i32NumChildren);
278    if (XResult == 0)
279        return -2;
280
281    if (i32NumChildren) {
282        for (i = 0; i < i32NumChildren; i++) {
283
284            psb_x11_getWindowCoordinate(display, x11_window_id, &sRect, &bIsVisible);
285            if (bIsVisible) {
286                psRegions = psb_x11_createClipBoxNode(&sRect, psRegions);
287                ui32NumRects++;
288            }
289        }
290        XFree(pChildWindow);
291        i32NumChildren = 0;
292    }
293
294    while (CurrentWindow != RootWindow) {
295        ChildWindow   = CurrentWindow;
296        CurrentWindow = ParentWindow;
297
298        XResult = XQueryTree(display,
299                             CurrentWindow,
300                             &RootWindow,
301                             &ParentWindow,
302                             &pChildWindow,
303                             &i32NumChildren);
304        if (XResult == 0) {
305            if (i32NumChildren)
306                XFree(pChildWindow);
307
308            psb_x11_freeWindowClipBoxList(psRegions);
309            return -3;
310        }
311
312        if (i32NumChildren) {
313            unsigned int iStartWindow = 0;
314
315            for (i = 0; i < i32NumChildren; i++) {
316                if (pChildWindow[i] == ChildWindow) {
317                    iStartWindow = i;
318                    break;
319                }
320            }
321
322            if (i == i32NumChildren) {
323                XFree(pChildWindow);
324                psb_x11_freeWindowClipBoxList(psRegions);
325                return -4;
326            }
327
328            for (i = iStartWindow + 1; i < i32NumChildren; i++) {
329                psb_x11_getWindowCoordinate(display, pChildWindow[i], &sRect, &bIsVisible);
330                if (bIsVisible) {
331                    psRegions = psb_x11_createClipBoxNode(&sRect, psRegions);
332                    ui32NumRects++;
333                }
334            }
335
336            XFree(pChildWindow);
337        }
338    }
339
340    ui32NumRects = 0;
341
342    if (psRegions) {
343        psb_x11_getWindowCoordinate(display, x11_window_id, &sRect, &bIsVisible);
344        *ppWindowClipBoxList = psb_x11_substractRects(display, psRegions, &sRect);
345        psb_x11_freeWindowClipBoxList(psRegions);
346
347        psRegions = *ppWindowClipBoxList;
348
349        while (psRegions) {
350            ui32NumRects++;
351            psRegions = psRegions->next;
352        }
353    } else {
354        *ppWindowClipBoxList = psb_x11_substractRects(display, NULL, &sRect);
355        ui32NumRects = 1;
356    }
357
358    *pui32NumClipBoxList = ui32NumRects;
359
360    return 0;
361}
362
363static int psb_cleardrawable_stopoverlay(
364    VADriverContextP ctx,
365    Drawable draw, /* X Drawable */
366    short destx,
367    short desty,
368    unsigned short destw,
369    unsigned short desth
370)
371{
372    INIT_DRIVER_DATA;
373    INIT_OUTPUT_PRIV;
374
375    XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, destx, desty, destw, desth);
376    XSync((Display *)ctx->native_dpy, False);
377
378    driver_data->cur_displaying_surface = VA_INVALID_SURFACE;
379    driver_data->last_displaying_surface = VA_INVALID_SURFACE;
380
381    return 0;
382}
383
384static VAStatus psb_DisplayRGBASubpicture(
385    PsbVASurfaceRec *subpicture,
386    VADriverContextP ctx,
387    int win_width,
388    int win_height,
389    int surface_x,
390    int surface_y,
391    int surface_w,
392    int surface_h,
393    psb_extvideo_subtitle subtitle
394)
395{
396    INIT_DRIVER_DATA;
397    INIT_OUTPUT_PRIV;
398    XImage *ximg = NULL;
399    Visual *visual;
400    PsbPortPrivRec *pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
401    struct _WsbmBufferObject *bo = subpicture->bo;
402    int image_width, image_height, width, height, size;
403    int srcx, srcy, srcw, srch;
404    int destx, desty, destw, desth;
405    int depth, i;
406
407    if (subpicture->fourcc != VA_FOURCC_RGBA) {
408        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Invalid image format, ONLY support RGBA subpicture now.\n", __func__);
409        return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
410    }
411
412    for (i = 0; subpicture != NULL; subpicture = subpicture->next, i++) {
413        srcx = subpicture->subpic_srcx;
414        srcy = subpicture->subpic_srcy;
415        srcw = subpicture->subpic_srcw;
416        srch = subpicture->subpic_srch;
417
418        destx = subpicture->subpic_dstx + surface_x;
419        desty = subpicture->subpic_dsty + surface_y;
420        destw = subpicture->subpic_dstw;
421        desth = subpicture->subpic_dsth;
422
423        image_width = subpicture->width;
424        image_height = subpicture->height;
425        size = subpicture->size;
426
427        //clip in image region
428        if (srcx < 0) {
429            srcw += srcx;
430            srcx = 0;
431        }
432
433        if (srcy < 0) {
434            srch += srcy;
435            srcy = 0;
436        }
437
438        if ((srcx + srcw) > image_width)
439            srcw = image_width - srcx;
440        if ((srcy + srch) > image_height)
441            srch = image_height - srcy;
442
443        //clip in drawable region
444        if (destx < 0) {
445            destw += destx;
446            destx = 0;
447        }
448
449        if (desty < 0) {
450            desth += desty;
451            desty = 0;
452        }
453
454        if ((destx + destw) > surface_w)
455            destw = surface_w - destx;
456        if ((desty + desth) > surface_h)
457            desth = surface_h - desty;
458
459        if (srcw <= destw)
460            width = srcw;
461        else
462            width = destw;
463
464        if (srch <= desth)
465            height = srch;
466        else
467            height = desth;
468
469        visual = DefaultVisual(ctx->native_dpy, 0);
470        depth = DefaultDepth(ctx->native_dpy, 0);
471
472        ximg = XCreateImage(ctx->native_dpy, visual, depth, ZPixmap, 0, NULL, image_width, image_height, 32, 0);
473
474        if (NULL == ximg) {
475            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: XCreateImage failed! at L%d\n", __func__, __LINE__);
476            return VA_STATUS_ERROR_UNKNOWN;
477        }
478
479        ximg->data = wsbmBOMap(bo, WSBM_ACCESS_READ);
480        if (NULL == ximg->data) {
481            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to map to ximg->data.\n", __func__);
482            return VA_STATUS_ERROR_ALLOCATION_FAILED;
483        }
484
485        pPriv->clear_key[i].subpic_dstx = destx;
486        pPriv->clear_key[i].subpic_dsty = desty;
487        pPriv->clear_key[i].subpic_dstw = destw;
488        pPriv->clear_key[i].subpic_dsth = desth;
489        if (psb_xrandr_extvideo_mode()) {
490            /*It is a HACK: Adjust subtitle to proper position.*/
491            float xScale, yScale;
492
493            xScale = win_width * 1.0 / surface_w;
494            yScale = win_height * 1.0 / surface_h;
495            destx = subpicture->subpic_dstx * xScale;
496            desty = subpicture->subpic_dsty * yScale;
497        }
498        XPutImage(ctx->native_dpy, output->output_drawable, output->gc, ximg, srcx, srcy, destx, desty, width, height);
499        XSync((Display *)ctx->native_dpy, False);
500
501        if (psb_xrandr_extvideo_mode() &&
502            (subtitle == ONLY_HDMI || subtitle == BOTH)) {
503            float xScale, yScale;
504
505            xScale = pPriv->extend_display_width * 1.0 / surface_w;
506            yScale = pPriv->extend_display_height * 1.0 / surface_h;
507
508            destx = subpicture->subpic_dstx * xScale;
509            desty = subpicture->subpic_dsty * yScale;
510
511            XPutImage(ctx->native_dpy, output->extend_drawable, output->extend_gc, ximg,
512                      srcx, srcy, destx, desty, destw, desth);
513            XSync((Display *)ctx->native_dpy, False);
514        }
515
516        pPriv->subpic_clear_flag = 0;
517        ximg->data = NULL;
518        wsbmBOUnmap(bo);
519        if (NULL != ximg)
520            XDestroyImage(ximg);
521    }
522    return VA_STATUS_SUCCESS;
523}
524
525static VAStatus psb_repaint_colorkey(
526    VADriverContextP ctx,
527    Drawable draw, /* X Drawable */
528    VASurfaceID surface,
529    int x11_window_width,
530    int x11_window_height
531)
532{
533    INIT_DRIVER_DATA;
534    INIT_OUTPUT_PRIV;
535    int i, ret;
536    psb_x11_clip_list_t *pClipNext = NULL;
537    VARectangle *pVaWindowClipRects = NULL;
538    object_surface_p obj_surface = SURFACE(surface);
539    PsbPortPrivRec *pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
540
541    if (output->frame_count % 500 == 0 || driver_data->xrandr_update) {
542        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Repaint color key.\n");
543        if (output->pClipBoxList)
544            psb_x11_freeWindowClipBoxList(output->pClipBoxList);
545        /* get window clipbox */
546        ret = psb_x11_createWindowClipBoxList(ctx->native_dpy, draw, &output->pClipBoxList, &output->ui32NumClipBoxList);
547        if (ret != 0) {
548            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: get window clip boxes error # %d\n", __func__, ret);
549            return VA_STATUS_ERROR_UNKNOWN;
550        }
551        if (output->frame_count == 500)
552            output->frame_count = 0;
553
554        driver_data->xrandr_update = 0;
555    }
556
557    pVaWindowClipRects = (VARectangle *)calloc(1, sizeof(VARectangle) * output->ui32NumClipBoxList);
558    if (!pVaWindowClipRects) {
559        psb_x11_freeWindowClipBoxList(output->pClipBoxList);
560        return VA_STATUS_ERROR_ALLOCATION_FAILED;
561    }
562
563    memset(pVaWindowClipRects, 0, sizeof(VARectangle)*output->ui32NumClipBoxList);
564    pClipNext = output->pClipBoxList;
565#ifdef CLIP_DEBUG
566    drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Total %d clip boxes\n", __func__, output->ui32NumClipBoxList);
567#endif
568    for (i = 0; i < output->ui32NumClipBoxList; i++) {
569        pVaWindowClipRects[i].x      = pClipNext->rect.i32Left;
570        pVaWindowClipRects[i].y      = pClipNext->rect.i32Top;
571        pVaWindowClipRects[i].width  = pClipNext->rect.i32Right - pClipNext->rect.i32Left;
572        pVaWindowClipRects[i].height = pClipNext->rect.i32Bottom - pClipNext->rect.i32Top;
573#ifdef CLIP_DEBUG
574        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: clip boxes Left Top (%d, %d) Right Bottom (%d, %d) width %d height %d\n", __func__,
575                           pClipNext->rect.i32Left, pClipNext->rect.i32Top,
576                           pClipNext->rect.i32Right, pClipNext->rect.i32Bottom,
577                           pVaWindowClipRects[i].width, pVaWindowClipRects[i].height);
578#endif
579        pClipNext = pClipNext->next;
580    }
581
582    /* repaint the color key when window size changed*/
583    if (!obj_surface->subpictures &&
584        ((pPriv->x11_window_width != x11_window_width) ||
585         (pPriv->x11_window_height != x11_window_height))) {
586        pPriv->x11_window_width = x11_window_width;
587        pPriv->x11_window_height = x11_window_height;
588        XSetForeground((Display *)ctx->native_dpy, output->gc, pPriv->colorKey);
589        XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
590        XSync((Display *)ctx->native_dpy, False);
591    }
592
593
594    if ((!obj_surface->subpictures) &&
595        ((output->ui32NumClipBoxList != pPriv->last_num_clipbox) ||
596         (memcmp(&pVaWindowClipRects[0], &(pPriv->last_clipbox[0]), (output->ui32NumClipBoxList > 16 ? 16 : output->ui32NumClipBoxList)*sizeof(VARectangle)) != 0))) {
597        pPriv->last_num_clipbox = output->ui32NumClipBoxList;
598        memcpy(&pPriv->last_clipbox[0], &pVaWindowClipRects[0], (output->ui32NumClipBoxList > 16 ? 16 : output->ui32NumClipBoxList)*sizeof(VARectangle));
599        XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
600        XSync((Display *)ctx->native_dpy, False);
601    }
602
603    free(pVaWindowClipRects);
604
605    return VA_STATUS_SUCCESS;
606}
607
608static VAStatus psb_extendMode_getCoordinate(
609    PsbPortPrivPtr pPriv,
610    psb_xrandr_location extend_location,
611    short destx,
612    short desty,
613    short srcx,
614    short srcy,
615    float xScaleFactor,
616    float yScaleFactor,
617    int *x11_window_width,
618    int *x11_window_height,
619    psb_overlay_rect_p local_rect,
620    psb_overlay_rect_p extend_rect,
621    enum overlay_id_t *extend_overlay
622)
623{
624    switch (extend_location) {
625    case LEFT_OF:
626        if ((destx + *x11_window_width) > (pPriv->display_width + pPriv->extend_display_width)) {
627            *x11_window_width = pPriv->display_width + pPriv->extend_display_width - destx;
628        }
629        if (((desty + *x11_window_height) < pPriv->display_height) &&
630            ((desty + *x11_window_height) < pPriv->extend_display_height))
631            local_rect->dHeight = extend_rect->dHeight = *x11_window_height;
632        else if (pPriv->display_height < pPriv->extend_display_height) {
633            local_rect->dHeight = pPriv->display_height - desty;
634            if ((desty + *x11_window_height) > pPriv->extend_display_height)
635                extend_rect->dHeight = *x11_window_height = pPriv->extend_display_height - desty;
636            else
637                extend_rect->dHeight = *x11_window_height;
638        } else {
639            extend_rect->dHeight = pPriv->extend_display_height - desty;
640            if ((desty + *x11_window_height) > pPriv->display_height)
641                local_rect->dHeight = *x11_window_height = pPriv->display_height - desty;
642            else
643                local_rect->dHeight = *x11_window_height;
644        }
645
646        if ((destx < pPriv->extend_display_width) && ((destx + *x11_window_width) < pPriv->extend_display_width)) {
647            local_rect->dWidth = 0;
648            extend_rect->dWidth = *x11_window_width;
649            *extend_overlay = OVERLAY_A;
650            local_rect->destx = 0;
651        } else if ((destx < pPriv->extend_display_width) && ((destx + *x11_window_width) >= pPriv->extend_display_width)) {
652            extend_rect->dWidth = pPriv->extend_display_width - destx;
653            local_rect->dWidth = *x11_window_width - extend_rect->dWidth;
654            local_rect->destx = 0;
655        } else {
656            local_rect->dWidth = *x11_window_width;
657            extend_rect->dWidth = 0;
658            local_rect->destx = destx - pPriv->extend_display_width;
659        }
660        local_rect->sWidth = (unsigned short)(local_rect->dWidth * xScaleFactor);
661        local_rect->sHeight = (unsigned short)(local_rect->dHeight * yScaleFactor);
662        extend_rect->sWidth = (unsigned short)(extend_rect->dWidth * xScaleFactor);
663        extend_rect->sHeight = (unsigned short)(extend_rect->dHeight * yScaleFactor);
664
665        local_rect->srcx = srcx + extend_rect->sWidth;
666        extend_rect->srcx = srcx;
667        local_rect->srcy = extend_rect->srcy = srcy;
668
669        extend_rect->destx = destx;
670        local_rect->desty = extend_rect->desty = desty;
671        break;
672    case RIGHT_OF:
673        if ((destx + *x11_window_width) > (pPriv->display_width + pPriv->extend_display_width)) {
674            *x11_window_width = pPriv->display_width + pPriv->extend_display_width - destx;
675        }
676        if (((desty + *x11_window_height) < pPriv->display_height) &&
677            ((desty + *x11_window_height) < pPriv->extend_display_height))
678            local_rect->dHeight = extend_rect->dHeight = *x11_window_height;
679        else if (pPriv->display_height < pPriv->extend_display_height) {
680            local_rect->dHeight = pPriv->display_height - desty;
681            if ((desty + *x11_window_height) > pPriv->extend_display_height)
682                extend_rect->dHeight = *x11_window_height = pPriv->extend_display_height - desty;
683            else
684                extend_rect->dHeight = *x11_window_height;
685        } else {
686            extend_rect->dHeight = pPriv->extend_display_height - desty;
687            if ((desty + *x11_window_height) > pPriv->display_height)
688                local_rect->dHeight = *x11_window_height = pPriv->display_height - desty;
689            else
690                local_rect->dHeight = *x11_window_height;
691        }
692
693        if ((destx < pPriv->display_width) && ((destx + *x11_window_width) < pPriv->display_width)) {
694            local_rect->dWidth = *x11_window_width;
695            extend_rect->dWidth = 0;
696            extend_rect->destx = 0;
697        } else if ((destx < pPriv->display_width) && ((destx + *x11_window_width) >= pPriv->display_width)) {
698            local_rect->dWidth = pPriv->display_width - destx;
699            extend_rect->dWidth = *x11_window_width - local_rect->dWidth;
700            extend_rect->destx = 0;
701        } else {
702            local_rect->dWidth = 0;
703            extend_rect->dWidth = *x11_window_width;
704            *extend_overlay = OVERLAY_A;
705            extend_rect->destx = destx - pPriv->display_width;
706        }
707        local_rect->sWidth = (unsigned short)(local_rect->dWidth * xScaleFactor);
708        local_rect->sHeight = (unsigned short)(local_rect->dHeight * yScaleFactor);
709        extend_rect->sWidth = (unsigned short)(extend_rect->dWidth * xScaleFactor);
710        extend_rect->sHeight = (unsigned short)(extend_rect->dHeight * yScaleFactor);
711
712        local_rect->srcx = srcx;
713        extend_rect->srcx = srcx + local_rect->sWidth;
714        local_rect->srcy = extend_rect->srcy = srcy;
715
716        local_rect->destx = destx;
717        local_rect->desty = extend_rect->desty = desty;
718        break;
719    case ABOVE:
720        if (((destx + *x11_window_width) < pPriv->display_width) &&
721            ((destx + *x11_window_width) < pPriv->extend_display_width))
722            local_rect->dWidth = extend_rect->dWidth = *x11_window_width;
723        else if (pPriv->display_width < pPriv->extend_display_width) {
724            local_rect->dWidth = pPriv->display_width - destx;
725            if ((destx + *x11_window_width) > pPriv->extend_display_width)
726                extend_rect->dWidth = *x11_window_width = pPriv->extend_display_width - destx;
727            else
728                extend_rect->dWidth = *x11_window_width;
729        } else {
730            extend_rect->dWidth = pPriv->extend_display_width - destx;
731            if ((destx + *x11_window_width) > pPriv->display_width)
732                local_rect->dWidth = *x11_window_width = pPriv->display_width - destx;
733            else
734                local_rect->dWidth = *x11_window_width;
735        }
736
737        if ((desty + *x11_window_height) > (pPriv->display_height + pPriv->extend_display_height)) {
738            *x11_window_height = pPriv->display_height + pPriv->extend_display_height - desty;
739        }
740
741        if ((desty < pPriv->extend_display_height) && ((desty + *x11_window_height) < pPriv->extend_display_height)) {
742            local_rect->dHeight = 0;
743            extend_rect->dHeight = *x11_window_height;
744            *extend_overlay = OVERLAY_A;
745            local_rect->desty = 0;
746        } else if ((desty < pPriv->extend_display_height) && ((desty + *x11_window_height) >= pPriv->extend_display_height)) {
747            extend_rect->dHeight = pPriv->extend_display_height - desty;
748            local_rect->dHeight = *x11_window_height - extend_rect->dHeight;
749            local_rect->desty = 0;
750        } else {
751            local_rect->dHeight = *x11_window_height;
752            extend_rect->dHeight = 0;
753            local_rect->desty = desty - pPriv->extend_display_height;
754        }
755        local_rect->sWidth = (unsigned short)(local_rect->dWidth * xScaleFactor);
756        local_rect->sHeight = (unsigned short)(local_rect->dHeight * yScaleFactor);
757        extend_rect->sWidth = (unsigned short)(extend_rect->dWidth * xScaleFactor);
758        extend_rect->sHeight = (unsigned short)(extend_rect->dHeight * yScaleFactor);
759
760        local_rect->srcy = srcy + extend_rect->sHeight;
761        extend_rect->srcy = srcy;
762        local_rect->srcx = extend_rect->srcx = srcx;
763
764        extend_rect->desty = desty;
765        local_rect->destx = extend_rect->destx = destx;
766        break;
767    case BELOW:
768        if (((destx + *x11_window_width) < pPriv->display_width) &&
769            ((destx + *x11_window_width) < pPriv->extend_display_width))
770            local_rect->dWidth = extend_rect->dWidth = *x11_window_width;
771        else if (pPriv->display_width < pPriv->extend_display_width) {
772            local_rect->dWidth = pPriv->display_width - destx;
773            if ((destx + *x11_window_width) > pPriv->extend_display_width)
774                extend_rect->dWidth = *x11_window_width = pPriv->extend_display_width - destx;
775            else
776                extend_rect->dWidth = *x11_window_width;
777        } else {
778            extend_rect->dWidth = pPriv->extend_display_width - destx;
779            if ((destx + *x11_window_width) > pPriv->display_width)
780                local_rect->dWidth = *x11_window_width = pPriv->display_width - destx;
781            else
782                local_rect->dWidth = *x11_window_width;
783        }
784
785        if ((desty + *x11_window_height) > (pPriv->display_height + pPriv->extend_display_height)) {
786            *x11_window_height = pPriv->display_height + pPriv->extend_display_height - desty;
787        }
788
789        if ((desty < pPriv->display_height) && ((desty + *x11_window_height) < pPriv->display_height)) {
790            local_rect->dHeight = *x11_window_height;
791            extend_rect->dHeight = 0;
792            extend_rect->desty = 0;
793        } else if ((desty < pPriv->display_height) && ((desty + *x11_window_height) >= pPriv->display_height)) {
794            local_rect->dHeight = pPriv->display_height - desty;
795            extend_rect->dHeight = *x11_window_height - local_rect->dHeight;
796            extend_rect->desty = 0;
797        } else {
798            local_rect->dHeight = 0;
799            extend_rect->dHeight = *x11_window_height;
800            *extend_overlay = OVERLAY_A;
801            extend_rect->desty = desty - pPriv->display_height;
802        }
803        local_rect->sWidth = (unsigned short)(local_rect->dWidth * xScaleFactor);
804        local_rect->sHeight = (unsigned short)(local_rect->dHeight * yScaleFactor);
805        extend_rect->sWidth = (unsigned short)(extend_rect->dWidth * xScaleFactor);
806        extend_rect->sHeight = (unsigned short)(extend_rect->dHeight * yScaleFactor);
807
808        local_rect->srcy = srcy;
809        extend_rect->srcy = srcy + local_rect->sHeight;
810        local_rect->srcx = extend_rect->srcx = srcx;
811
812        local_rect->desty = desty;
813        local_rect->destx = extend_rect->destx = destx;
814        break;
815    case NORMAL:
816    default:
817        break;
818    }
819    return VA_STATUS_SUCCESS;
820}
821
822static void psb_init_subpicture(VADriverContextP ctx, PsbPortPrivPtr pPriv)
823{
824    INIT_DRIVER_DATA;
825    struct drm_psb_register_rw_arg regs;
826    unsigned int subpicture_enable_mask = REGRWBITS_DSPACNTR;
827
828    if (!pPriv->subpicture_enabled) {
829        if (psb_xrandr_hdmi_enabled())
830            subpicture_enable_mask |= REGRWBITS_DSPBCNTR;
831        if (psb_xrandr_mipi1_enabled())
832            subpicture_enable_mask |= REGRWBITS_DSPCCNTR;
833
834        memset(&regs, 0, sizeof(regs));
835        regs.subpicture_enable_mask = subpicture_enable_mask;
836        pPriv->subpicture_enable_mask = subpicture_enable_mask;
837        pPriv->subpicture_enabled = 1;
838        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
839    }
840}
841
842static void psb_clear_subpictures(
843    VADriverContextP ctx,
844    PsbPortPrivPtr pPriv,
845    int win_width,
846    int win_height,
847    object_surface_p obj_surface
848)
849{
850    INIT_OUTPUT_PRIV;
851    PsbVASurfaceRec *subpicture = (PsbVASurfaceRec *)obj_surface->subpictures;
852    int i;
853
854    if (subpicture == NULL) {
855        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Surface has no subpicture to render.\n");
856        return;
857    }
858
859    for (i = 0; subpicture != NULL; subpicture = subpicture->next, i++) {
860        if ((subpicture->subpic_dstx != pPriv->clear_key[i].subpic_dstx) ||
861            (subpicture->subpic_dsty != pPriv->clear_key[i].subpic_dsty) ||
862            (subpicture->subpic_dstw != pPriv->clear_key[i].subpic_dstw) ||
863            (subpicture->subpic_dsth != pPriv->clear_key[i].subpic_dsth)) {
864            XSetForeground((Display *)ctx->native_dpy, output->gc, 0);
865            XFillRectangle((Display *)ctx->native_dpy, output->output_drawable, output->gc, 0, 0, win_width, win_height);
866            XSync((Display *)ctx->native_dpy, False);
867            if (psb_xrandr_extvideo_mode()) {
868                XSetForeground((Display *)ctx->native_dpy, output->extend_gc, 0);
869                XFillRectangle((Display *)ctx->native_dpy, output->extend_drawable, output->extend_gc,
870                               0, 0, pPriv->extend_display_width, pPriv->extend_display_height);
871                XSync((Display *)ctx->native_dpy, False);
872            }
873            pPriv->subpic_clear_flag = 1;
874        }
875    }
876    return;
877}
878
879VAStatus psb_putsurface_coverlay(
880    VADriverContextP ctx,
881    VASurfaceID surface,
882    Drawable draw, /* X Drawable */
883    short srcx,
884    short srcy,
885    unsigned short srcw,
886    unsigned short srch,
887    short destx,
888    short desty,
889    unsigned short destw,
890    unsigned short desth,
891    VARectangle *cliprects, /* client supplied clip list */
892    unsigned int number_cliprects, /* number of clip rects in the clip list */
893    unsigned int flags /* de-interlacing flags */
894)
895{
896    INIT_DRIVER_DATA;
897    INIT_OUTPUT_PRIV;
898    int ret;
899    int x11_window_width = destw, x11_window_height = desth;
900    psb_xrandr_location extend_location;
901    object_surface_p obj_surface = SURFACE(surface);
902    PsbPortPrivRec *pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
903    int primary_crtc_x, primary_crtc_y, extend_crtc_x, extend_crtc_y;
904    enum pipe_id_t local_pipe = PIPEA, extend_pipe = PIPEB;
905    int surfacex = destx, surfacey = desty;
906    float xScaleFactor, yScaleFactor;
907    Rotation rotation = RR_Rotate_0;
908    psb_output_device local_device, extend_device;
909    psb_extvideo_subtitle subtitle;
910
911    if (flags & VA_CLEAR_DRAWABLE) {
912        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clean draw with color 0x%08x\n", driver_data->clear_color);
913        psb_cleardrawable_stopoverlay(ctx, draw, destx, desty, destw, desth);
914
915        return VA_STATUS_SUCCESS;
916    }
917
918    if (output->frame_count % 500 == 0 || driver_data->xrandr_update) {
919        /* get window screen coordination */
920        ret = psb_x11_getWindowCoordinate(ctx->native_dpy, draw, &output->winRect, &output->bIsVisible);
921        if (ret != 0) {
922            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get X11 window coordinates error # %d\n", __func__, ret);
923            return VA_STATUS_ERROR_UNKNOWN;
924        }
925    }
926
927    if (!output->bIsVisible) {
928        return VA_STATUS_SUCCESS;
929    }
930
931    if (NULL == obj_surface) {
932        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Invalid surface id 0x%08x.\n", __func__, surface);
933        return VA_STATUS_ERROR_INVALID_SURFACE;
934    }
935
936    if (output->output_drawable != draw) {
937        output->output_drawable = draw;
938    }
939
940    if (!output->gc) {
941        output->gc = XCreateGC((Display *)ctx->native_dpy, draw, 0, NULL);
942        /* paint the color key */
943        if (!obj_surface->subpictures && !driver_data->overlay_auto_paint_color_key) {
944            XSetForeground((Display *)ctx->native_dpy, output->gc, pPriv->colorKey);
945            XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
946            XSync((Display *)ctx->native_dpy, False);
947        }
948    }
949
950    if (driver_data->use_xrandr_thread && !driver_data->xrandr_thread_id) {
951        ret = psb_xrandr_thread_create(ctx);
952        if (ret != 0) {
953            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to create psb xrandr thread error # %d\n", __func__, ret);
954            return VA_STATUS_ERROR_UNKNOWN;
955        }
956    }
957
958    ret = psb_xrandr_local_crtc_coordinate(&local_device, &primary_crtc_x, &primary_crtc_y, &pPriv->display_width, &pPriv->display_height, &rotation);
959    if (ret != VA_STATUS_SUCCESS) {
960        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get primary crtc coordinates error # %d\n", __func__, ret);
961        return VA_STATUS_ERROR_UNKNOWN;
962    }
963    switch (local_device) {
964    case LVDS0:
965    case MIPI0:
966        local_pipe = PIPEA;
967        break;
968        /* single HDMI */
969    case HDMI:
970        local_pipe = PIPEB;
971        break;
972    case MIPI1:
973        local_pipe = PIPEC;
974        break;
975    }
976
977    if (!psb_xrandr_single_mode()) {
978
979        ret = psb_xrandr_extend_crtc_coordinate(&extend_device, &extend_crtc_x, &extend_crtc_y,
980                                                &pPriv->extend_display_width, &pPriv->extend_display_height, &extend_location, &rotation);
981        if (ret != VA_STATUS_SUCCESS) {
982            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get extend crtc coordinates error # %d\n", __func__, ret);
983            return VA_STATUS_ERROR_UNKNOWN;
984        }
985
986        switch (extend_device) {
987        case HDMI:
988            extend_pipe = PIPEB;
989            break;
990        case MIPI1:
991            extend_pipe = PIPEC;
992            break;
993        default:
994            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get extend pipe\n", __func__);
995            break;
996        }
997    }
998
999    /*clip in the window area*/
1000    if (destx < 0) {
1001        x11_window_width += destx;
1002        destx = 0;
1003    }
1004
1005    if (desty < 0) {
1006        x11_window_height += desty;
1007        desty = 0;
1008    }
1009
1010    if (srcx < 0) {
1011        srcw += srcx;
1012        srcx = 0;
1013    }
1014
1015    if (srcy < 0) {
1016        srch += srcy;
1017        srcy = 0;
1018    }
1019
1020    if ((destx + x11_window_width) > output->winRect.ui32Width)
1021        x11_window_width = output->winRect.ui32Width - destx;
1022
1023    if ((desty + x11_window_height) > output->winRect.ui32Height)
1024        x11_window_height = output->winRect.ui32Height - desty;
1025
1026    /*translate destx, desty into screen coordinate*/
1027    destx += output->winRect.i32Left;
1028    desty += output->winRect.i32Top;
1029
1030    /*clip in the screen area*/
1031    xScaleFactor = srcw * 1.0 / x11_window_width;
1032    yScaleFactor = srch * 1.0 / x11_window_height;
1033
1034    if (destx < 0) {
1035        x11_window_width += destx;
1036        srcx = (short)((-destx) * xScaleFactor);
1037        destx = 0;
1038    }
1039
1040    if (desty < 0) {
1041        x11_window_height += desty;
1042        srcy = (short)((-desty) * yScaleFactor);
1043        desty = 0;
1044    }
1045
1046    /* display by overlay */
1047    if (psb_xrandr_single_mode() || IS_MRST(driver_data)) {
1048        if ((destx + x11_window_width) > pPriv->display_width) {
1049            x11_window_width = pPriv->display_width - destx;
1050            srcw = (unsigned short)(x11_window_width * xScaleFactor);
1051        }
1052
1053        if ((desty + x11_window_height) > pPriv->display_height) {
1054            x11_window_height = pPriv->display_height - desty;
1055            srch = (unsigned short)(x11_window_height * yScaleFactor);
1056        }
1057
1058        if (!driver_data->overlay_auto_paint_color_key) {
1059            ret = psb_repaint_colorkey(ctx, draw, surface, x11_window_width, x11_window_height);
1060            if (ret != 0) {
1061                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to repaint color key error # %d\n", __func__, ret);
1062                return VA_STATUS_ERROR_UNKNOWN;
1063            }
1064        }
1065
1066        psb_putsurface_overlay(
1067            ctx, surface, srcx, srcy, srcw, srch,
1068            /* screen coordinate */
1069            destx, desty, x11_window_width, x11_window_height,
1070            flags, OVERLAY_A, local_pipe);
1071    } else if (psb_xrandr_clone_mode()) {
1072        psb_overlay_rect_t local_rect, extend_rect;
1073
1074        if (output->extend_drawable) {
1075            XDestroyWindow(ctx->native_dpy, output->extend_drawable);
1076            output->extend_drawable = 0;
1077            XFreeGC((Display *)ctx->native_dpy, output->extend_gc);
1078            output->extend_gc = 0;
1079        }
1080
1081        if (((destx + x11_window_width) < pPriv->display_width) &&
1082            ((destx + x11_window_width) < pPriv->extend_display_width))
1083            local_rect.dWidth = extend_rect.dWidth = x11_window_width;
1084        else if (pPriv->display_width < pPriv->extend_display_width) {
1085            local_rect.dWidth = pPriv->display_width - destx;
1086            if ((destx + x11_window_width) > pPriv->extend_display_width)
1087                extend_rect.dWidth = x11_window_width = pPriv->extend_display_width - destx;
1088            else
1089                extend_rect.dWidth = x11_window_width;
1090        } else {
1091            extend_rect.dWidth = pPriv->extend_display_width - destx;
1092            if ((destx + x11_window_width) > pPriv->display_width)
1093                local_rect.dWidth = x11_window_width = pPriv->display_width - destx;
1094            else
1095                local_rect.dWidth = x11_window_width;
1096        }
1097
1098        if (((desty + x11_window_height) < pPriv->display_height) &&
1099            ((desty + x11_window_height) < pPriv->extend_display_height))
1100            local_rect.dHeight = extend_rect.dHeight = x11_window_height;
1101        else if (pPriv->display_height < pPriv->extend_display_height) {
1102            local_rect.dHeight = pPriv->display_height - desty;
1103            if ((desty + x11_window_height) > pPriv->extend_display_height)
1104                extend_rect.dHeight = x11_window_height = pPriv->extend_display_height - desty;
1105            else
1106                extend_rect.dHeight = x11_window_height;
1107        } else {
1108            extend_rect.dHeight = pPriv->extend_display_height - desty;
1109            if ((desty + x11_window_height) > pPriv->display_height)
1110                local_rect.dHeight = x11_window_height = pPriv->display_height - desty;
1111            else
1112                local_rect.dHeight = x11_window_height;
1113        }
1114        if ((driver_data->mipi0_rotation != VA_ROTATION_NONE) ||
1115            (driver_data->hdmi_rotation != VA_ROTATION_NONE)) {
1116            local_rect.sWidth = srcw;
1117            local_rect.sHeight = srch;
1118            extend_rect.sWidth = srcw;
1119            extend_rect.sHeight = srch;
1120        } else {
1121            local_rect.sWidth = (unsigned short)(local_rect.dWidth * xScaleFactor);
1122            local_rect.sHeight = (unsigned short)(local_rect.dHeight * yScaleFactor);
1123            extend_rect.sWidth = (unsigned short)(extend_rect.dWidth * xScaleFactor);
1124            extend_rect.sHeight = (unsigned short)(extend_rect.dHeight * yScaleFactor);
1125        }
1126        ret = psb_repaint_colorkey(ctx, draw, surface, x11_window_width, x11_window_height);
1127        if (ret != 0) {
1128            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to repaint color key error # %d\n", __func__, ret);
1129            return VA_STATUS_ERROR_UNKNOWN;
1130        }
1131        psb_putsurface_overlay(
1132            ctx, surface, srcx, srcy, extend_rect.sWidth, extend_rect.sHeight,
1133            /* screen coordinate */
1134            destx, desty, extend_rect.dWidth, extend_rect.dHeight,
1135            flags, OVERLAY_C, extend_pipe);
1136        psb_putsurface_overlay(
1137            ctx, surface,  srcx, srcy, local_rect.sWidth, local_rect.sHeight,
1138            /* screen coordinate */
1139            destx, desty, local_rect.dWidth, local_rect.dHeight,
1140            flags, OVERLAY_A, local_pipe);
1141    } else if (psb_xrandr_extend_mode()) {
1142        if (driver_data->extend_fullscreen) {
1143            switch (extend_location) {
1144            case RIGHT_OF:
1145                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, pPriv->display_width, 0, pPriv->extend_display_width, pPriv->extend_display_height);
1146                break;
1147            case BELOW:
1148                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, 0, pPriv->display_height, pPriv->extend_display_width, pPriv->extend_display_height);
1149                break;
1150            case LEFT_OF:
1151            case ABOVE:
1152                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, 0, 0, pPriv->extend_display_width, pPriv->extend_display_height);
1153                break;
1154            default:
1155                break;
1156
1157            }
1158            XSetForeground((Display *)ctx->native_dpy, output->gc, pPriv->colorKey);
1159            XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, pPriv->extend_display_width, pPriv->extend_display_height);
1160            XFlush(ctx->native_dpy);
1161
1162            psb_putsurface_overlay(
1163                ctx, surface, srcx, srcy, srcw, srch,
1164                /* screen coordinate */
1165                0, 0, pPriv->extend_display_width, pPriv->extend_display_height,
1166                flags, OVERLAY_A, PIPEB);
1167        } else {
1168            psb_overlay_rect_t local_rect, extend_rect;
1169            enum overlay_id_t extend_overlay = OVERLAY_C;
1170
1171            if (output->extend_drawable) {
1172                XDestroyWindow(ctx->native_dpy, output->extend_drawable);
1173                output->extend_drawable = 0;
1174                XFreeGC((Display *)ctx->native_dpy, output->extend_gc);
1175                output->extend_gc = 0;
1176            }
1177            memset(&local_rect, 0, sizeof(psb_overlay_rect_t));
1178            memset(&extend_rect, 0, sizeof(psb_overlay_rect_t));
1179            psb_extendMode_getCoordinate(pPriv, extend_location, destx, desty, srcx, srcy,
1180                                         xScaleFactor, yScaleFactor, &x11_window_width, &x11_window_height,
1181                                         &local_rect, &extend_rect, &extend_overlay);
1182
1183            ret = psb_repaint_colorkey(ctx, draw, surface, x11_window_width, x11_window_height);
1184            if (ret != 0) {
1185                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to repaint color key error # %d\n", __func__, ret);
1186                return VA_STATUS_ERROR_UNKNOWN;
1187            }
1188
1189            if ((extend_rect.dWidth > 0) && (extend_rect.dHeight > 0)) {
1190                psb_putsurface_overlay(
1191                    ctx, surface,
1192                    extend_rect.srcx, extend_rect.srcy, extend_rect.sWidth, extend_rect.sHeight,
1193                    extend_rect.destx, extend_rect.desty, extend_rect.dWidth, extend_rect.dHeight,
1194                    flags, extend_overlay, extend_pipe);
1195            }
1196            if ((local_rect.dWidth > 0) && (local_rect.dHeight > 0)) {
1197                psb_putsurface_overlay(
1198                    ctx, surface,
1199                    local_rect.srcx, local_rect.srcy, local_rect.sWidth, local_rect.sHeight,
1200                    local_rect.destx, local_rect.desty, local_rect.dWidth, local_rect.dHeight,
1201                    flags, OVERLAY_A, local_pipe);
1202            }
1203        }
1204    } else if (psb_xrandr_extvideo_mode()) {
1205        unsigned int xres, yres, xoffset, yoffset, overscanmode, pannelfitting, x, y;
1206        psb_extvideo_center center;
1207
1208        psb_xrandr_extvideo_prop(&xres, &yres, &xoffset, &yoffset, &center, &subtitle, &overscanmode, &pannelfitting);
1209        x = xoffset;
1210        y = yoffset;
1211
1212        switch (extend_location) {
1213        case RIGHT_OF:
1214            x += pPriv->display_width;
1215            break;
1216        case BELOW:
1217            y += pPriv->display_height;
1218            break;
1219        case NORMAL:
1220            break;
1221        case LEFT_OF:
1222            if (driver_data->xrandr_dirty & PSB_NEW_EXTVIDEO) {
1223                destx += pPriv->extend_display_width;
1224                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, destx, desty, x11_window_width, x11_window_height);
1225                XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
1226                XFlush(ctx->native_dpy);
1227            }
1228            destx = destx - pPriv->extend_display_width;
1229            break;
1230        case ABOVE:
1231            if (driver_data->xrandr_dirty & PSB_NEW_EXTVIDEO) {
1232                desty += pPriv->extend_display_height;
1233                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, destx, desty, x11_window_width, x11_window_height);
1234                XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
1235                XFlush(ctx->native_dpy);
1236            }
1237            desty = desty - pPriv->extend_display_height;
1238            break;
1239        }
1240        if ((destx + x11_window_width) > pPriv->display_width)
1241            x11_window_width = pPriv->display_width - destx;
1242        if ((desty + x11_window_height) > pPriv->display_height)
1243            x11_window_height = pPriv->display_height - desty;
1244
1245        if (driver_data->xrandr_dirty & PSB_NEW_EXTVIDEO) {
1246            Window extend_win;
1247            extend_win = psb_xrandr_create_full_screen_window(x, y, xres, yres);
1248            if (output->extend_drawable != extend_win) {
1249                output->extend_drawable = extend_win;
1250                if (output->extend_gc)
1251                    XFreeGC((Display *)ctx->native_dpy, output->extend_gc);
1252                output->extend_gc = XCreateGC((Display *)ctx->native_dpy, extend_win, 0, NULL);
1253
1254                /* paint the color key */
1255                if (!obj_surface->subpictures) {
1256                    XSetForeground((Display *)ctx->native_dpy, output->extend_gc, pPriv->colorKey);
1257                    XFillRectangle((Display *)ctx->native_dpy, extend_win, output->extend_gc, 0, 0, xres, yres);
1258                    XSync((Display *)ctx->native_dpy, False);
1259                }
1260            }
1261            driver_data->xrandr_dirty &= ~PSB_NEW_EXTVIDEO;
1262        }
1263
1264        ret = psb_repaint_colorkey(ctx, draw, surface, x11_window_width, x11_window_height);
1265        if (ret != 0) {
1266            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to repaint color key error # %d\n", __func__, ret);
1267            return VA_STATUS_ERROR_UNKNOWN;
1268        }
1269
1270        psb_putsurface_overlay(
1271            ctx, surface, srcx, srcy, srcw, srch,
1272            /* screen coordinate */
1273            xoffset, yoffset, xres, yres,
1274            flags, OVERLAY_C, PIPEB);
1275        psb_putsurface_overlay(
1276            ctx, surface, srcx, srcy, srcw, srch,
1277            /* screen coordinate */
1278            destx, desty,
1279            x11_window_width, x11_window_height,
1280            flags, OVERLAY_A, local_pipe);
1281    }
1282
1283    /*Init Overlay subpicuture blending and make proper clear.*/
1284    if (pPriv->is_mfld && obj_surface->subpictures) {
1285        PsbVASurfaceRec *subpicture = (PsbVASurfaceRec *)obj_surface->subpictures;
1286
1287        psb_init_subpicture(ctx, pPriv);
1288        /*clear changed subpicture zones in drawable.*/
1289        psb_clear_subpictures(ctx, pPriv, x11_window_width, x11_window_height, obj_surface);
1290        if (pPriv->subpic_clear_flag) {
1291            psb_DisplayRGBASubpicture(subpicture, ctx, x11_window_width, x11_window_height,
1292                                      surfacex, surfacey, obj_surface->width, obj_surface->height, subtitle);
1293        }
1294    }
1295
1296    output->frame_count++;
1297
1298    return VA_STATUS_SUCCESS;
1299}
1300