1/*
2 * XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com)
3 */
4/*
5 * Copyright (c) 1998-2003 by The XFree86 Project, Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Except as contained in this notice, the name of the copyright holder(s)
26 * and author(s) shall not be used in advertising or otherwise to promote
27 * the sale, use or other dealings in this Software without prior written
28 * authorization from the copyright holder(s) and author(s).
29 */
30
31#ifdef HAVE_XORG_CONFIG_H
32#include <xorg-config.h>
33#endif
34
35#include "misc.h"
36#include "xf86.h"
37#include "xf86_OSproc.h"
38
39#include <X11/X.h>
40#include <X11/Xproto.h>
41#include "scrnintstr.h"
42#include "regionstr.h"
43#include "windowstr.h"
44#include "pixmapstr.h"
45#include "mivalidate.h"
46#include "validate.h"
47#include "resource.h"
48#include "gcstruct.h"
49#include "dixstruct.h"
50
51#include <X11/extensions/Xv.h>
52#include <X11/extensions/Xvproto.h>
53#include "xvdix.h"
54
55#include "xf86xvpriv.h"
56
57/* XvAdaptorRec fields */
58
59static int xf86XVPutVideo(DrawablePtr, XvPortPtr, GCPtr,
60                          INT16, INT16, CARD16, CARD16,
61                          INT16, INT16, CARD16, CARD16);
62static int xf86XVPutStill(DrawablePtr, XvPortPtr, GCPtr,
63                          INT16, INT16, CARD16, CARD16,
64                          INT16, INT16, CARD16, CARD16);
65static int xf86XVGetVideo(DrawablePtr, XvPortPtr, GCPtr,
66                          INT16, INT16, CARD16, CARD16,
67                          INT16, INT16, CARD16, CARD16);
68static int xf86XVGetStill(DrawablePtr, XvPortPtr, GCPtr,
69                          INT16, INT16, CARD16, CARD16,
70                          INT16, INT16, CARD16, CARD16);
71static int xf86XVStopVideo(XvPortPtr, DrawablePtr);
72static int xf86XVSetPortAttribute(XvPortPtr, Atom, INT32);
73static int xf86XVGetPortAttribute(XvPortPtr, Atom, INT32 *);
74static int xf86XVQueryBestSize(XvPortPtr, CARD8,
75                               CARD16, CARD16, CARD16, CARD16,
76                               unsigned int *, unsigned int *);
77static int xf86XVPutImage(DrawablePtr, XvPortPtr, GCPtr,
78                          INT16, INT16, CARD16, CARD16,
79                          INT16, INT16, CARD16, CARD16,
80                          XvImagePtr, unsigned char *, Bool, CARD16, CARD16);
81static int xf86XVQueryImageAttributes(XvPortPtr, XvImagePtr,
82                                      CARD16 *, CARD16 *, int *, int *);
83
84/* ScreenRec fields */
85
86static Bool xf86XVDestroyWindow(WindowPtr pWin);
87static void xf86XVWindowExposures(WindowPtr pWin, RegionPtr r1);
88static void xf86XVPostValidateTree(WindowPtr pWin, WindowPtr pLayerWin,
89                                   VTKind kind);
90static void xf86XVClipNotify(WindowPtr pWin, int dx, int dy);
91static Bool xf86XVCloseScreen(ScreenPtr);
92
93#define PostValidateTreeUndefined ((PostValidateTreeProcPtr)-1)
94
95/* ScrnInfoRec functions */
96
97static Bool xf86XVEnterVT(ScrnInfoPtr);
98static void xf86XVLeaveVT(ScrnInfoPtr);
99static void xf86XVAdjustFrame(ScrnInfoPtr, int x, int y);
100static void xf86XVModeSet(ScrnInfoPtr pScrn);
101
102/* misc */
103
104static Bool xf86XVInitAdaptors(ScreenPtr, XF86VideoAdaptorPtr *, int);
105
106static DevPrivateKeyRec XF86XVWindowKeyRec;
107
108#define XF86XVWindowKey (&XF86XVWindowKeyRec)
109
110/* dixmain.c XvScreenPtr screen private */
111DevPrivateKey XF86XvScreenKey;
112/** xf86xv.c XF86XVScreenPtr screen private */
113static DevPrivateKeyRec XF86XVScreenPrivateKey;
114
115static unsigned long PortResource = 0;
116
117#define GET_XV_SCREEN(pScreen) \
118    ((XvScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, XF86XvScreenKey))
119
120#define GET_XF86XV_SCREEN(pScreen) \
121    ((XF86XVScreenPtr)(dixGetPrivate(&pScreen->devPrivates, &XF86XVScreenPrivateKey)))
122
123#define GET_XF86XV_WINDOW(pWin) \
124    ((XF86XVWindowPtr)dixLookupPrivate(&(pWin)->devPrivates, XF86XVWindowKey))
125
126static xf86XVInitGenericAdaptorPtr *GenDrivers = NULL;
127static int NumGenDrivers = 0;
128
129int
130xf86XVRegisterGenericAdaptorDriver(xf86XVInitGenericAdaptorPtr InitFunc)
131{
132    xf86XVInitGenericAdaptorPtr *newdrivers;
133
134    newdrivers = reallocarray(GenDrivers, 1 + NumGenDrivers,
135                              sizeof(xf86XVInitGenericAdaptorPtr));
136    if (!newdrivers)
137        return 0;
138    GenDrivers = newdrivers;
139
140    GenDrivers[NumGenDrivers++] = InitFunc;
141
142    return 1;
143}
144
145int
146xf86XVListGenericAdaptors(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr ** adaptors)
147{
148    int i, j, n, num;
149    XF86VideoAdaptorPtr *DrivAdap, *new;
150
151    num = 0;
152    *adaptors = NULL;
153    /*
154     * The v4l driver registers itself first, but can use surfaces registered
155     * by other drivers.  So, call the v4l driver last.
156     */
157    for (i = NumGenDrivers; --i >= 0;) {
158        DrivAdap = NULL;
159        n = (*GenDrivers[i]) (pScrn, &DrivAdap);
160        if (0 == n)
161            continue;
162        new = reallocarray(*adaptors, num + n, sizeof(XF86VideoAdaptorPtr));
163        if (NULL == new)
164            continue;
165        *adaptors = new;
166        for (j = 0; j < n; j++, num++)
167            (*adaptors)[num] = DrivAdap[j];
168    }
169    return num;
170}
171
172/****************  Offscreen surface stuff *******************/
173
174typedef struct {
175    XF86OffscreenImagePtr images;
176    int num;
177} OffscreenImageRec;
178
179static DevPrivateKeyRec OffscreenPrivateKeyRec;
180
181#define OffscreenPrivateKey (&OffscreenPrivateKeyRec)
182#define GetOffscreenImage(pScreen) ((OffscreenImageRec *) dixLookupPrivate(&(pScreen)->devPrivates, OffscreenPrivateKey))
183
184Bool
185xf86XVRegisterOffscreenImages(ScreenPtr pScreen,
186                              XF86OffscreenImagePtr images, int num)
187{
188    OffscreenImageRec *OffscreenImage;
189
190    /* This function may be called before xf86XVScreenInit, so there's
191     * no better place than this to call dixRegisterPrivateKey to ensure we
192     * have space reserved. After the first call it is a no-op. */
193    if (!dixRegisterPrivateKey
194        (OffscreenPrivateKey, PRIVATE_SCREEN, sizeof(OffscreenImageRec)) ||
195        !(OffscreenImage = GetOffscreenImage(pScreen)))
196        /* Every X.org driver assumes this function always succeeds, so
197         * just die on allocation failure. */
198        FatalError
199            ("Could not allocate private storage for XV offscreen images.\n");
200
201    OffscreenImage->num = num;
202    OffscreenImage->images = images;
203    return TRUE;
204}
205
206XF86OffscreenImagePtr
207xf86XVQueryOffscreenImages(ScreenPtr pScreen, int *num)
208{
209    OffscreenImageRec *OffscreenImage = GetOffscreenImage(pScreen);
210
211    *num = OffscreenImage->num;
212    return OffscreenImage->images;
213}
214
215XF86VideoAdaptorPtr
216xf86XVAllocateVideoAdaptorRec(ScrnInfoPtr pScrn)
217{
218    return calloc(1, sizeof(XF86VideoAdaptorRec));
219}
220
221void
222xf86XVFreeVideoAdaptorRec(XF86VideoAdaptorPtr ptr)
223{
224    free(ptr);
225}
226
227Bool
228xf86XVScreenInit(ScreenPtr pScreen, XF86VideoAdaptorPtr * adaptors, int num)
229{
230    ScrnInfoPtr pScrn;
231    XF86XVScreenPtr ScreenPriv;
232
233    if (num <= 0 || noXvExtension)
234        return FALSE;
235
236    if (Success != XvScreenInit(pScreen))
237        return FALSE;
238
239    if (!dixRegisterPrivateKey(&XF86XVWindowKeyRec, PRIVATE_WINDOW, 0))
240        return FALSE;
241    if (!dixRegisterPrivateKey(&XF86XVScreenPrivateKey, PRIVATE_SCREEN, 0))
242        return FALSE;
243
244    XF86XvScreenKey = XvGetScreenKey();
245
246    PortResource = XvGetRTPort();
247
248    ScreenPriv = malloc(sizeof(XF86XVScreenRec));
249    dixSetPrivate(&pScreen->devPrivates, &XF86XVScreenPrivateKey, ScreenPriv);
250
251    if (!ScreenPriv)
252        return FALSE;
253
254    pScrn = xf86ScreenToScrn(pScreen);
255
256    ScreenPriv->DestroyWindow = pScreen->DestroyWindow;
257    ScreenPriv->WindowExposures = pScreen->WindowExposures;
258    ScreenPriv->PostValidateTree = PostValidateTreeUndefined;
259    ScreenPriv->ClipNotify = pScreen->ClipNotify;
260    ScreenPriv->CloseScreen = pScreen->CloseScreen;
261    ScreenPriv->EnterVT = pScrn->EnterVT;
262    ScreenPriv->LeaveVT = pScrn->LeaveVT;
263    ScreenPriv->AdjustFrame = pScrn->AdjustFrame;
264    ScreenPriv->ModeSet = pScrn->ModeSet;
265
266    pScreen->DestroyWindow = xf86XVDestroyWindow;
267    pScreen->WindowExposures = xf86XVWindowExposures;
268    pScreen->ClipNotify = xf86XVClipNotify;
269    pScreen->CloseScreen = xf86XVCloseScreen;
270    pScrn->EnterVT = xf86XVEnterVT;
271    pScrn->LeaveVT = xf86XVLeaveVT;
272    if (pScrn->AdjustFrame)
273        pScrn->AdjustFrame = xf86XVAdjustFrame;
274    pScrn->ModeSet = xf86XVModeSet;
275
276    if (!xf86XVInitAdaptors(pScreen, adaptors, num))
277        return FALSE;
278
279    return TRUE;
280}
281
282static void
283xf86XVFreeAdaptor(XvAdaptorPtr pAdaptor)
284{
285    int i;
286
287    if (pAdaptor->pPorts) {
288        XvPortPtr pPort = pAdaptor->pPorts;
289        XvPortRecPrivatePtr pPriv;
290
291        for (i = 0; i < pAdaptor->nPorts; i++, pPort++) {
292            pPriv = (XvPortRecPrivatePtr) pPort->devPriv.ptr;
293            if (pPriv) {
294                if (pPriv->clientClip)
295                    RegionDestroy(pPriv->clientClip);
296                if (pPriv->pCompositeClip && pPriv->FreeCompositeClip)
297                    RegionDestroy(pPriv->pCompositeClip);
298                if (pPriv->ckeyFilled)
299                    RegionDestroy(pPriv->ckeyFilled);
300                free(pPriv);
301            }
302        }
303    }
304
305    XvFreeAdaptor(pAdaptor);
306}
307
308static Bool
309xf86XVInitAdaptors(ScreenPtr pScreen, XF86VideoAdaptorPtr * infoPtr, int number)
310{
311    XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
312    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
313    XF86VideoAdaptorPtr adaptorPtr;
314    XvAdaptorPtr pAdaptor, pa;
315    XvAdaptorRecPrivatePtr adaptorPriv;
316    int na, numAdaptor;
317    XvPortRecPrivatePtr portPriv;
318    XvPortPtr pPort, pp;
319    int numPort;
320    XF86VideoFormatPtr formatPtr;
321    XvFormatPtr pFormat, pf;
322    int numFormat, totFormat;
323    XF86VideoEncodingPtr encodingPtr;
324    XvEncodingPtr pEncode, pe;
325    int numVisuals;
326    VisualPtr pVisual;
327    int i;
328
329    pxvs->nAdaptors = 0;
330    pxvs->pAdaptors = NULL;
331
332    if (!(pAdaptor = calloc(number, sizeof(XvAdaptorRec))))
333        return FALSE;
334
335    for (pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) {
336        adaptorPtr = infoPtr[na];
337
338        if (!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute ||
339            !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize)
340            continue;
341
342        /* client libs expect at least one encoding */
343        if (!adaptorPtr->nEncodings || !adaptorPtr->pEncodings)
344            continue;
345
346        pa->type = adaptorPtr->type;
347
348        if (!adaptorPtr->PutVideo && !adaptorPtr->GetVideo)
349            pa->type &= ~XvVideoMask;
350
351        if (!adaptorPtr->PutStill && !adaptorPtr->GetStill)
352            pa->type &= ~XvStillMask;
353
354        if (!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes)
355            pa->type &= ~XvImageMask;
356
357        if (!adaptorPtr->PutVideo && !adaptorPtr->PutImage &&
358            !adaptorPtr->PutStill)
359            pa->type &= ~XvInputMask;
360
361        if (!adaptorPtr->GetVideo && !adaptorPtr->GetStill)
362            pa->type &= ~XvOutputMask;
363
364        if (!(adaptorPtr->type & (XvPixmapMask | XvWindowMask)))
365            continue;
366        if (!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask)))
367            continue;
368
369        pa->pScreen = pScreen;
370        pa->ddPutVideo = xf86XVPutVideo;
371        pa->ddPutStill = xf86XVPutStill;
372        pa->ddGetVideo = xf86XVGetVideo;
373        pa->ddGetStill = xf86XVGetStill;
374        pa->ddStopVideo = xf86XVStopVideo;
375        pa->ddPutImage = xf86XVPutImage;
376        pa->ddSetPortAttribute = xf86XVSetPortAttribute;
377        pa->ddGetPortAttribute = xf86XVGetPortAttribute;
378        pa->ddQueryBestSize = xf86XVQueryBestSize;
379        pa->ddQueryImageAttributes = xf86XVQueryImageAttributes;
380        pa->name = strdup(adaptorPtr->name);
381
382        if (adaptorPtr->nEncodings &&
383            (pEncode = calloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) {
384
385            for (pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0;
386                 i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) {
387                pe->id = encodingPtr->id;
388                pe->pScreen = pScreen;
389                pe->name = strdup(encodingPtr->name);
390                pe->width = encodingPtr->width;
391                pe->height = encodingPtr->height;
392                pe->rate.numerator = encodingPtr->rate.numerator;
393                pe->rate.denominator = encodingPtr->rate.denominator;
394            }
395            pa->nEncodings = adaptorPtr->nEncodings;
396            pa->pEncodings = pEncode;
397        }
398
399        if (adaptorPtr->nImages &&
400            (pa->pImages = calloc(adaptorPtr->nImages, sizeof(XvImageRec)))) {
401            memcpy(pa->pImages, adaptorPtr->pImages,
402                   adaptorPtr->nImages * sizeof(XvImageRec));
403            pa->nImages = adaptorPtr->nImages;
404        }
405
406        if (adaptorPtr->nAttributes &&
407            (pa->pAttributes = calloc(adaptorPtr->nAttributes,
408                                      sizeof(XvAttributeRec)))) {
409            memcpy(pa->pAttributes, adaptorPtr->pAttributes,
410                   adaptorPtr->nAttributes * sizeof(XvAttributeRec));
411
412            for (i = 0; i < adaptorPtr->nAttributes; i++) {
413                pa->pAttributes[i].name =
414                    strdup(adaptorPtr->pAttributes[i].name);
415            }
416
417            pa->nAttributes = adaptorPtr->nAttributes;
418        }
419
420        totFormat = adaptorPtr->nFormats;
421
422        if (!(pFormat = calloc(totFormat, sizeof(XvFormatRec)))) {
423            xf86XVFreeAdaptor(pa);
424            continue;
425        }
426        for (pf = pFormat, i = 0, numFormat = 0, formatPtr =
427             adaptorPtr->pFormats; i < adaptorPtr->nFormats; i++, formatPtr++) {
428            numVisuals = pScreen->numVisuals;
429            pVisual = pScreen->visuals;
430
431            while (numVisuals--) {
432                if ((pVisual->class == formatPtr->class) &&
433                    (pVisual->nplanes == formatPtr->depth)) {
434
435                    if (numFormat >= totFormat) {
436                        void *moreSpace;
437
438                        totFormat *= 2;
439                        moreSpace = reallocarray(pFormat, totFormat,
440                                                 sizeof(XvFormatRec));
441                        if (!moreSpace)
442                            break;
443                        pFormat = moreSpace;
444                        pf = pFormat + numFormat;
445                    }
446
447                    pf->visual = pVisual->vid;
448                    pf->depth = formatPtr->depth;
449
450                    pf++;
451                    numFormat++;
452                }
453                pVisual++;
454            }
455        }
456        pa->nFormats = numFormat;
457        pa->pFormats = pFormat;
458        if (!numFormat) {
459            xf86XVFreeAdaptor(pa);
460            continue;
461        }
462
463        if (!(adaptorPriv = calloc(1, sizeof(XvAdaptorRecPrivate)))) {
464            xf86XVFreeAdaptor(pa);
465            continue;
466        }
467
468        adaptorPriv->flags = adaptorPtr->flags;
469        adaptorPriv->PutVideo = adaptorPtr->PutVideo;
470        adaptorPriv->PutStill = adaptorPtr->PutStill;
471        adaptorPriv->GetVideo = adaptorPtr->GetVideo;
472        adaptorPriv->GetStill = adaptorPtr->GetStill;
473        adaptorPriv->StopVideo = adaptorPtr->StopVideo;
474        adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute;
475        adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute;
476        adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize;
477        adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes;
478        adaptorPriv->PutImage = adaptorPtr->PutImage;
479        adaptorPriv->ReputImage = adaptorPtr->ReputImage;       /* image/still */
480
481        pa->devPriv.ptr = (void *) adaptorPriv;
482
483        if (!(pPort = calloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) {
484            xf86XVFreeAdaptor(pa);
485            continue;
486        }
487        for (pp = pPort, i = 0, numPort = 0; i < adaptorPtr->nPorts; i++) {
488
489            if (!(pp->id = FakeClientID(0)))
490                continue;
491
492            if (!(portPriv = calloc(1, sizeof(XvPortRecPrivate))))
493                continue;
494
495            if (!AddResource(pp->id, PortResource, pp)) {
496                free(portPriv);
497                continue;
498            }
499
500            pp->pAdaptor = pa;
501            pp->pNotify = (XvPortNotifyPtr) NULL;
502            pp->pDraw = (DrawablePtr) NULL;
503            pp->client = (ClientPtr) NULL;
504            pp->grab.client = (ClientPtr) NULL;
505            pp->time = currentTime;
506            pp->devPriv.ptr = portPriv;
507
508            portPriv->pScrn = pScrn;
509            portPriv->AdaptorRec = adaptorPriv;
510            portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr;
511
512            pp++;
513            numPort++;
514        }
515        pa->nPorts = numPort;
516        pa->pPorts = pPort;
517        if (!numPort) {
518            xf86XVFreeAdaptor(pa);
519            continue;
520        }
521
522        pa->base_id = pPort->id;
523
524        pa++;
525        numAdaptor++;
526    }
527
528    if (numAdaptor) {
529        pxvs->nAdaptors = numAdaptor;
530        pxvs->pAdaptors = pAdaptor;
531    }
532    else {
533        free(pAdaptor);
534        return FALSE;
535    }
536
537    return TRUE;
538}
539
540/* Video should be clipped to the intersection of the window cliplist
541   and the client cliplist specified in the GC for which the video was
542   initialized.  When we need to reclip a window, the GC that started
543   the video may not even be around anymore.  That's why we save the
544   client clip from the GC when the video is initialized.  We then
545   use xf86XVUpdateCompositeClip to calculate the new composite clip
546   when we need it.  This is different from what DEC did.  They saved
547   the GC and used its clip list when they needed to reclip the window,
548   even if the client clip was different from the one the video was
549   initialized with.  If the original GC was destroyed, they had to stop
550   the video.  I like the new method better (MArk).
551
552   This function only works for windows.  Will need to rewrite when
553   (if) we support pixmap rendering.
554*/
555
556static void
557xf86XVUpdateCompositeClip(XvPortRecPrivatePtr portPriv)
558{
559    RegionPtr pregWin, pCompositeClip;
560    WindowPtr pWin;
561    Bool freeCompClip = FALSE;
562
563    if (portPriv->pCompositeClip)
564        return;
565
566    pWin = (WindowPtr) portPriv->pDraw;
567
568    /* get window clip list */
569    if (portPriv->subWindowMode == IncludeInferiors) {
570        pregWin = NotClippedByChildren(pWin);
571        freeCompClip = TRUE;
572    }
573    else
574        pregWin = &pWin->clipList;
575
576    if (!portPriv->clientClip) {
577        portPriv->pCompositeClip = pregWin;
578        portPriv->FreeCompositeClip = freeCompClip;
579        return;
580    }
581
582    pCompositeClip = RegionCreate(NullBox, 1);
583    RegionCopy(pCompositeClip, portPriv->clientClip);
584    RegionTranslate(pCompositeClip, portPriv->pDraw->x, portPriv->pDraw->y);
585    RegionIntersect(pCompositeClip, pregWin, pCompositeClip);
586
587    portPriv->pCompositeClip = pCompositeClip;
588    portPriv->FreeCompositeClip = TRUE;
589
590    if (freeCompClip) {
591        RegionDestroy(pregWin);
592    }
593}
594
595/* Save the current clientClip and update the CompositeClip whenever
596   we have a fresh GC */
597
598static void
599xf86XVCopyClip(XvPortRecPrivatePtr portPriv, GCPtr pGC)
600{
601    /* copy the new clip if it exists */
602    if (pGC->clientClip) {
603        if (!portPriv->clientClip)
604            portPriv->clientClip = RegionCreate(NullBox, 1);
605        /* Note: this is in window coordinates */
606        RegionCopy(portPriv->clientClip, pGC->clientClip);
607        RegionTranslate(portPriv->clientClip, pGC->clipOrg.x, pGC->clipOrg.y);
608    }
609    else if (portPriv->clientClip) {    /* free the old clientClip */
610        RegionDestroy(portPriv->clientClip);
611        portPriv->clientClip = NULL;
612    }
613
614    /* get rid of the old clip list */
615    if (portPriv->pCompositeClip && portPriv->FreeCompositeClip) {
616        RegionDestroy(portPriv->pCompositeClip);
617    }
618
619    portPriv->pCompositeClip = pGC->pCompositeClip;
620    portPriv->FreeCompositeClip = FALSE;
621    portPriv->subWindowMode = pGC->subWindowMode;
622}
623
624static void
625xf86XVCopyCompositeClip(XvPortRecPrivatePtr portPriv,
626                        GCPtr pGC, DrawablePtr pDraw)
627{
628    if (!portPriv->clientClip)
629        portPriv->clientClip = RegionCreate(NullBox, 1);
630    /* Keep the original GC composite clip around for ReputImage */
631    RegionCopy(portPriv->clientClip, pGC->pCompositeClip);
632    RegionTranslate(portPriv->clientClip, -pDraw->x, -pDraw->y);
633
634    /* get rid of the old clip list */
635    if (portPriv->pCompositeClip && portPriv->FreeCompositeClip)
636        RegionDestroy(portPriv->pCompositeClip);
637
638    portPriv->pCompositeClip = pGC->pCompositeClip;
639    portPriv->FreeCompositeClip = FALSE;
640    portPriv->subWindowMode = pGC->subWindowMode;
641}
642
643static int
644xf86XVRegetVideo(XvPortRecPrivatePtr portPriv)
645{
646    RegionRec WinRegion;
647    RegionRec ClipRegion;
648    BoxRec WinBox;
649    int ret = Success;
650    Bool clippedAway = FALSE;
651
652    xf86XVUpdateCompositeClip(portPriv);
653
654    /* translate the video region to the screen */
655    WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x;
656    WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y;
657    WinBox.x2 = WinBox.x1 + portPriv->drw_w;
658    WinBox.y2 = WinBox.y1 + portPriv->drw_h;
659
660    /* clip to the window composite clip */
661    RegionInit(&WinRegion, &WinBox, 1);
662    RegionNull(&ClipRegion);
663    RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip);
664
665    /* that's all if it's totally obscured */
666    if (!RegionNotEmpty(&ClipRegion)) {
667        clippedAway = TRUE;
668        goto CLIP_VIDEO_BAILOUT;
669    }
670
671    ret = (*portPriv->AdaptorRec->GetVideo) (portPriv->pScrn,
672                                             portPriv->vid_x, portPriv->vid_y,
673                                             WinBox.x1, WinBox.y1,
674                                             portPriv->vid_w, portPriv->vid_h,
675                                             portPriv->drw_w, portPriv->drw_h,
676                                             &ClipRegion, portPriv->DevPriv.ptr,
677                                             portPriv->pDraw);
678
679    if (ret == Success)
680        portPriv->isOn = XV_ON;
681
682 CLIP_VIDEO_BAILOUT:
683
684    if ((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) {
685        (*portPriv->AdaptorRec->StopVideo) (portPriv->pScrn,
686                                            portPriv->DevPriv.ptr, FALSE);
687        portPriv->isOn = XV_PENDING;
688    }
689
690    /* This clip was copied and only good for one shot */
691    if (!portPriv->FreeCompositeClip)
692        portPriv->pCompositeClip = NULL;
693
694    RegionUninit(&WinRegion);
695    RegionUninit(&ClipRegion);
696
697    return ret;
698}
699
700static int
701xf86XVReputVideo(XvPortRecPrivatePtr portPriv)
702{
703    RegionRec WinRegion;
704    RegionRec ClipRegion;
705    BoxRec WinBox;
706    int ret = Success;
707    Bool clippedAway = FALSE;
708
709    xf86XVUpdateCompositeClip(portPriv);
710
711    /* translate the video region to the screen */
712    WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x;
713    WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y;
714    WinBox.x2 = WinBox.x1 + portPriv->drw_w;
715    WinBox.y2 = WinBox.y1 + portPriv->drw_h;
716
717    /* clip to the window composite clip */
718    RegionInit(&WinRegion, &WinBox, 1);
719    RegionNull(&ClipRegion);
720    RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip);
721
722    /* clip and translate to the viewport */
723    if (portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
724        RegionRec VPReg;
725        BoxRec VPBox;
726
727        VPBox.x1 = portPriv->pScrn->frameX0;
728        VPBox.y1 = portPriv->pScrn->frameY0;
729        VPBox.x2 = portPriv->pScrn->frameX1 + 1;
730        VPBox.y2 = portPriv->pScrn->frameY1 + 1;
731
732        RegionInit(&VPReg, &VPBox, 1);
733        RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
734        RegionUninit(&VPReg);
735    }
736
737    /* that's all if it's totally obscured */
738    if (!RegionNotEmpty(&ClipRegion)) {
739        clippedAway = TRUE;
740        goto CLIP_VIDEO_BAILOUT;
741    }
742
743    ret = (*portPriv->AdaptorRec->PutVideo) (portPriv->pScrn,
744                                             portPriv->vid_x, portPriv->vid_y,
745                                             WinBox.x1, WinBox.y1,
746                                             portPriv->vid_w, portPriv->vid_h,
747                                             portPriv->drw_w, portPriv->drw_h,
748                                             &ClipRegion, portPriv->DevPriv.ptr,
749                                             portPriv->pDraw);
750
751    if (ret == Success)
752        portPriv->isOn = XV_ON;
753
754 CLIP_VIDEO_BAILOUT:
755
756    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
757        (*portPriv->AdaptorRec->StopVideo) (portPriv->pScrn,
758                                            portPriv->DevPriv.ptr, FALSE);
759        portPriv->isOn = XV_PENDING;
760    }
761
762    /* This clip was copied and only good for one shot */
763    if (!portPriv->FreeCompositeClip)
764        portPriv->pCompositeClip = NULL;
765
766    RegionUninit(&WinRegion);
767    RegionUninit(&ClipRegion);
768
769    return ret;
770}
771
772/* Reput image/still */
773static int
774xf86XVReputImage(XvPortRecPrivatePtr portPriv)
775{
776    RegionRec WinRegion;
777    RegionRec ClipRegion;
778    BoxRec WinBox;
779    int ret = Success;
780    Bool clippedAway = FALSE;
781
782    xf86XVUpdateCompositeClip(portPriv);
783
784    /* the clip can get smaller over time */
785    RegionCopy(portPriv->clientClip, portPriv->pCompositeClip);
786    RegionTranslate(portPriv->clientClip,
787                    -portPriv->pDraw->x, -portPriv->pDraw->y);
788
789    /* translate the video region to the screen */
790    WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x;
791    WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y;
792    WinBox.x2 = WinBox.x1 + portPriv->drw_w;
793    WinBox.y2 = WinBox.y1 + portPriv->drw_h;
794
795    /* clip to the window composite clip */
796    RegionInit(&WinRegion, &WinBox, 1);
797    RegionNull(&ClipRegion);
798    RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip);
799
800    /* clip and translate to the viewport */
801    if (portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
802        RegionRec VPReg;
803        BoxRec VPBox;
804
805        VPBox.x1 = portPriv->pScrn->frameX0;
806        VPBox.y1 = portPriv->pScrn->frameY0;
807        VPBox.x2 = portPriv->pScrn->frameX1 + 1;
808        VPBox.y2 = portPriv->pScrn->frameY1 + 1;
809
810        RegionInit(&VPReg, &VPBox, 1);
811        RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
812        RegionUninit(&VPReg);
813    }
814
815    /* that's all if it's totally obscured */
816    if (!RegionNotEmpty(&ClipRegion)) {
817        clippedAway = TRUE;
818        goto CLIP_VIDEO_BAILOUT;
819    }
820
821    ret = (*portPriv->AdaptorRec->ReputImage) (portPriv->pScrn,
822                                               portPriv->vid_x, portPriv->vid_y,
823                                               WinBox.x1, WinBox.y1,
824                                               portPriv->vid_w, portPriv->vid_h,
825                                               portPriv->drw_w, portPriv->drw_h,
826                                               &ClipRegion,
827                                               portPriv->DevPriv.ptr,
828                                               portPriv->pDraw);
829
830    portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF;
831
832 CLIP_VIDEO_BAILOUT:
833
834    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
835        (*portPriv->AdaptorRec->StopVideo) (portPriv->pScrn,
836                                            portPriv->DevPriv.ptr, FALSE);
837        portPriv->isOn = XV_PENDING;
838    }
839
840    /* This clip was copied and only good for one shot */
841    if (!portPriv->FreeCompositeClip)
842        portPriv->pCompositeClip = NULL;
843
844    RegionUninit(&WinRegion);
845    RegionUninit(&ClipRegion);
846
847    return ret;
848}
849
850static int
851xf86XVReputAllVideo(WindowPtr pWin, void *data)
852{
853    XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin);
854
855    while (WinPriv) {
856        if (WinPriv->PortRec->type == XvInputMask)
857            xf86XVReputVideo(WinPriv->PortRec);
858        else
859            xf86XVRegetVideo(WinPriv->PortRec);
860        WinPriv = WinPriv->next;
861    }
862
863    return WT_WALKCHILDREN;
864}
865
866static int
867xf86XVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv)
868{
869    XF86XVWindowPtr winPriv, PrivRoot;
870
871    winPriv = PrivRoot = GET_XF86XV_WINDOW(pWin);
872
873    /* Enlist our port in the window private */
874    while (winPriv) {
875        if (winPriv->PortRec == portPriv)       /* we're already listed */
876            break;
877        winPriv = winPriv->next;
878    }
879
880    if (!winPriv) {
881        winPriv = calloc(1, sizeof(XF86XVWindowRec));
882        if (!winPriv)
883            return BadAlloc;
884        winPriv->PortRec = portPriv;
885        winPriv->next = PrivRoot;
886        dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, winPriv);
887    }
888
889    portPriv->pDraw = (DrawablePtr) pWin;
890
891    return Success;
892}
893
894static void
895xf86XVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv)
896{
897    XF86XVWindowPtr winPriv, prevPriv = NULL;
898
899    winPriv = GET_XF86XV_WINDOW(pWin);
900
901    while (winPriv) {
902        if (winPriv->PortRec == portPriv) {
903            if (prevPriv)
904                prevPriv->next = winPriv->next;
905            else
906                dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey,
907                              winPriv->next);
908            free(winPriv);
909            break;
910        }
911        prevPriv = winPriv;
912        winPriv = winPriv->next;
913    }
914    portPriv->pDraw = NULL;
915    if (portPriv->ckeyFilled) {
916        RegionDestroy(portPriv->ckeyFilled);
917        portPriv->ckeyFilled = NULL;
918    }
919    portPriv->clipChanged = FALSE;
920}
921
922static void
923xf86XVReputOrStopPort(XvPortRecPrivatePtr pPriv, WindowPtr pWin, Bool visible)
924{
925    if (!visible) {
926        if (pPriv->isOn == XV_ON) {
927            (*pPriv->AdaptorRec->StopVideo) (pPriv->pScrn, pPriv->DevPriv.ptr,
928                                             FALSE);
929            pPriv->isOn = XV_PENDING;
930        }
931
932        if (!pPriv->type)       /* overlaid still/image */
933            xf86XVRemovePortFromWindow(pWin, pPriv);
934
935        return;
936    }
937
938    switch (pPriv->type) {
939    case XvInputMask:
940        xf86XVReputVideo(pPriv);
941        break;
942    case XvOutputMask:
943        xf86XVRegetVideo(pPriv);
944        break;
945    default:                   /* overlaid still/image */
946        if (pPriv->AdaptorRec->ReputImage)
947            xf86XVReputImage(pPriv);
948        break;
949    }
950}
951
952static void
953xf86XVReputOrStopAllPorts(ScrnInfoPtr pScrn, Bool onlyChanged)
954{
955    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
956    XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
957    XvAdaptorPtr pa;
958    int c, i;
959
960    for (c = pxvs->nAdaptors, pa = pxvs->pAdaptors; c > 0; c--, pa++) {
961        XvPortPtr pPort = pa->pPorts;
962
963        for (i = pa->nPorts; i > 0; i--, pPort++) {
964            XvPortRecPrivatePtr pPriv =
965                (XvPortRecPrivatePtr) pPort->devPriv.ptr;
966            WindowPtr pWin = (WindowPtr) pPriv->pDraw;
967            Bool visible;
968
969            if (pPriv->isOn == XV_OFF || !pWin)
970                continue;
971
972            if (onlyChanged && !pPriv->clipChanged)
973                continue;
974
975            visible = pWin->visibility == VisibilityUnobscured ||
976                pWin->visibility == VisibilityPartiallyObscured;
977
978            /*
979             * Stop and remove still/images if
980             * ReputImage isn't supported.
981             */
982            if (!pPriv->type && !pPriv->AdaptorRec->ReputImage)
983                visible = FALSE;
984
985            xf86XVReputOrStopPort(pPriv, pWin, visible);
986
987            pPriv->clipChanged = FALSE;
988        }
989    }
990}
991
992/****  ScreenRec fields ****/
993
994static Bool
995xf86XVDestroyWindow(WindowPtr pWin)
996{
997    ScreenPtr pScreen = pWin->drawable.pScreen;
998    XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
999    XF86XVWindowPtr tmp, WinPriv = GET_XF86XV_WINDOW(pWin);
1000    int ret;
1001
1002    while (WinPriv) {
1003        XvPortRecPrivatePtr pPriv = WinPriv->PortRec;
1004
1005        if (pPriv->isOn > XV_OFF) {
1006            (*pPriv->AdaptorRec->StopVideo) (pPriv->pScrn, pPriv->DevPriv.ptr,
1007                                             TRUE);
1008            pPriv->isOn = XV_OFF;
1009        }
1010
1011        pPriv->pDraw = NULL;
1012        tmp = WinPriv;
1013        WinPriv = WinPriv->next;
1014        free(tmp);
1015    }
1016
1017    dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, NULL);
1018
1019    pScreen->DestroyWindow = ScreenPriv->DestroyWindow;
1020    ret = (*pScreen->DestroyWindow) (pWin);
1021    pScreen->DestroyWindow = xf86XVDestroyWindow;
1022
1023    return ret;
1024}
1025
1026static void
1027xf86XVPostValidateTree(WindowPtr pWin, WindowPtr pLayerWin, VTKind kind)
1028{
1029    ScreenPtr pScreen;
1030    XF86XVScreenPtr ScreenPriv;
1031    ScrnInfoPtr pScrn;
1032
1033    if (pWin)
1034        pScreen = pWin->drawable.pScreen;
1035    else
1036        pScreen = pLayerWin->drawable.pScreen;
1037
1038    ScreenPriv = GET_XF86XV_SCREEN(pScreen);
1039    pScrn = xf86ScreenToScrn(pScreen);
1040
1041    xf86XVReputOrStopAllPorts(pScrn, TRUE);
1042
1043    pScreen->PostValidateTree = ScreenPriv->PostValidateTree;
1044    if (pScreen->PostValidateTree) {
1045        (*pScreen->PostValidateTree) (pWin, pLayerWin, kind);
1046    }
1047    ScreenPriv->PostValidateTree = PostValidateTreeUndefined;
1048}
1049
1050static void
1051xf86XVWindowExposures(WindowPtr pWin, RegionPtr reg1)
1052{
1053    ScreenPtr pScreen = pWin->drawable.pScreen;
1054    XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
1055    XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin);
1056    XvPortRecPrivatePtr pPriv;
1057    Bool AreasExposed;
1058
1059    AreasExposed = (WinPriv && reg1 && RegionNotEmpty(reg1));
1060
1061    pScreen->WindowExposures = ScreenPriv->WindowExposures;
1062    (*pScreen->WindowExposures) (pWin, reg1);
1063    pScreen->WindowExposures = xf86XVWindowExposures;
1064
1065    /* filter out XClearWindow/Area */
1066    if (!pWin->valdata)
1067        return;
1068
1069    while (WinPriv) {
1070        Bool visible = TRUE;
1071
1072        pPriv = WinPriv->PortRec;
1073
1074        /*
1075         * Stop and remove still/images if areas were exposed and
1076         * ReputImage isn't supported.
1077         */
1078        if (!pPriv->type && !pPriv->AdaptorRec->ReputImage)
1079            visible = !AreasExposed;
1080
1081        /*
1082         * Subtract exposed areas from overlaid image to match textured video
1083         * behavior.
1084         */
1085        if (!pPriv->type && pPriv->clientClip)
1086            RegionSubtract(pPriv->clientClip, pPriv->clientClip, reg1);
1087
1088        if (visible && pPriv->ckeyFilled) {
1089            RegionRec tmp;
1090
1091            RegionNull(&tmp);
1092            RegionCopy(&tmp, reg1);
1093            RegionTranslate(&tmp, pWin->drawable.x, pWin->drawable.y);
1094            RegionSubtract(pPriv->ckeyFilled, pPriv->ckeyFilled, &tmp);
1095        }
1096
1097        WinPriv = WinPriv->next;
1098        xf86XVReputOrStopPort(pPriv, pWin, visible);
1099
1100        pPriv->clipChanged = FALSE;
1101    }
1102}
1103
1104static void
1105xf86XVClipNotify(WindowPtr pWin, int dx, int dy)
1106{
1107    ScreenPtr pScreen = pWin->drawable.pScreen;
1108    XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
1109    XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin);
1110    XvPortRecPrivatePtr pPriv;
1111
1112    while (WinPriv) {
1113        pPriv = WinPriv->PortRec;
1114
1115        if (pPriv->pCompositeClip && pPriv->FreeCompositeClip)
1116            RegionDestroy(pPriv->pCompositeClip);
1117
1118        pPriv->pCompositeClip = NULL;
1119
1120        pPriv->clipChanged = TRUE;
1121
1122        if (ScreenPriv->PostValidateTree == PostValidateTreeUndefined) {
1123            ScreenPriv->PostValidateTree = pScreen->PostValidateTree;
1124            pScreen->PostValidateTree = xf86XVPostValidateTree;
1125        }
1126
1127        WinPriv = WinPriv->next;
1128    }
1129
1130    if (ScreenPriv->ClipNotify) {
1131        pScreen->ClipNotify = ScreenPriv->ClipNotify;
1132        (*pScreen->ClipNotify) (pWin, dx, dy);
1133        pScreen->ClipNotify = xf86XVClipNotify;
1134    }
1135}
1136
1137/**** Required XvScreenRec fields ****/
1138
1139static Bool
1140xf86XVCloseScreen(ScreenPtr pScreen)
1141{
1142    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1143    XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
1144    XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
1145    XvAdaptorPtr pa;
1146    int c;
1147
1148    if (!ScreenPriv)
1149        return TRUE;
1150
1151    pScreen->DestroyWindow = ScreenPriv->DestroyWindow;
1152    pScreen->WindowExposures = ScreenPriv->WindowExposures;
1153    pScreen->ClipNotify = ScreenPriv->ClipNotify;
1154    pScreen->CloseScreen = ScreenPriv->CloseScreen;
1155
1156    pScrn->EnterVT = ScreenPriv->EnterVT;
1157    pScrn->LeaveVT = ScreenPriv->LeaveVT;
1158    pScrn->AdjustFrame = ScreenPriv->AdjustFrame;
1159    pScrn->ModeSet = ScreenPriv->ModeSet;
1160
1161    for (c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) {
1162        xf86XVFreeAdaptor(pa);
1163    }
1164
1165    free(pxvs->pAdaptors);
1166    free(ScreenPriv);
1167
1168    return pScreen->CloseScreen(pScreen);
1169}
1170
1171/**** ScrnInfoRec fields ****/
1172
1173static Bool
1174xf86XVEnterVT(ScrnInfoPtr pScrn)
1175{
1176    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1177    XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
1178    Bool ret;
1179
1180    pScrn->EnterVT = ScreenPriv->EnterVT;
1181    ret = (*ScreenPriv->EnterVT) (pScrn);
1182    ScreenPriv->EnterVT = pScrn->EnterVT;
1183    pScrn->EnterVT = xf86XVEnterVT;
1184
1185    if (ret)
1186        WalkTree(pScreen, xf86XVReputAllVideo, 0);
1187
1188    return ret;
1189}
1190
1191static void
1192xf86XVLeaveVT(ScrnInfoPtr pScrn)
1193{
1194    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1195    XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
1196    XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
1197    XvAdaptorPtr pAdaptor;
1198    XvPortPtr pPort;
1199    XvPortRecPrivatePtr pPriv;
1200    int i, j;
1201
1202    for (i = 0; i < pxvs->nAdaptors; i++) {
1203        pAdaptor = &pxvs->pAdaptors[i];
1204        for (j = 0; j < pAdaptor->nPorts; j++) {
1205            pPort = &pAdaptor->pPorts[j];
1206            pPriv = (XvPortRecPrivatePtr) pPort->devPriv.ptr;
1207            if (pPriv->isOn > XV_OFF) {
1208
1209                (*pPriv->AdaptorRec->StopVideo) (pPriv->pScrn,
1210                                                 pPriv->DevPriv.ptr, TRUE);
1211                pPriv->isOn = XV_OFF;
1212
1213                if (pPriv->pCompositeClip && pPriv->FreeCompositeClip)
1214                    RegionDestroy(pPriv->pCompositeClip);
1215
1216                pPriv->pCompositeClip = NULL;
1217
1218                if (!pPriv->type && pPriv->pDraw) {     /* still */
1219                    xf86XVRemovePortFromWindow((WindowPtr) pPriv->pDraw, pPriv);
1220                }
1221            }
1222        }
1223    }
1224
1225    pScrn->LeaveVT = ScreenPriv->LeaveVT;
1226    (*ScreenPriv->LeaveVT) (pScrn);
1227    ScreenPriv->LeaveVT = pScrn->LeaveVT;
1228    pScrn->LeaveVT = xf86XVLeaveVT;
1229}
1230
1231static void
1232xf86XVAdjustFrame(ScrnInfoPtr pScrn, int x, int y)
1233{
1234    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1235    XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
1236
1237    if (ScreenPriv->AdjustFrame) {
1238        pScrn->AdjustFrame = ScreenPriv->AdjustFrame;
1239        (*pScrn->AdjustFrame) (pScrn, x, y);
1240        pScrn->AdjustFrame = xf86XVAdjustFrame;
1241    }
1242
1243    xf86XVReputOrStopAllPorts(pScrn, FALSE);
1244}
1245
1246static void
1247xf86XVModeSet(ScrnInfoPtr pScrn)
1248{
1249    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1250    XF86XVScreenPtr ScreenPriv;
1251
1252    /* Can be called before pScrn->pScreen is set */
1253    if (!pScreen)
1254        return;
1255
1256    ScreenPriv = GET_XF86XV_SCREEN(pScreen);
1257
1258    if (ScreenPriv->ModeSet) {
1259        pScrn->ModeSet = ScreenPriv->ModeSet;
1260        (*pScrn->ModeSet) (pScrn);
1261        pScrn->ModeSet = xf86XVModeSet;
1262    }
1263
1264    xf86XVReputOrStopAllPorts(pScrn, FALSE);
1265}
1266
1267/**** XvAdaptorRec fields ****/
1268
1269static int
1270xf86XVPutVideo(DrawablePtr pDraw,
1271               XvPortPtr pPort,
1272               GCPtr pGC,
1273               INT16 vid_x, INT16 vid_y,
1274               CARD16 vid_w, CARD16 vid_h,
1275               INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
1276{
1277    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1278    int result;
1279
1280    /* No dumping video to pixmaps... For now anyhow */
1281    if (pDraw->type != DRAWABLE_WINDOW) {
1282        pPort->pDraw = (DrawablePtr) NULL;
1283        return BadAlloc;
1284    }
1285
1286    /* If we are changing windows, unregister our port in the old window */
1287    if (portPriv->pDraw && (portPriv->pDraw != pDraw))
1288        xf86XVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1289
1290    /* Register our port with the new window */
1291    result = xf86XVEnlistPortInWindow((WindowPtr) pDraw, portPriv);
1292    if (result != Success)
1293        return result;
1294
1295    portPriv->type = XvInputMask;
1296
1297    /* save a copy of these parameters */
1298    portPriv->vid_x = vid_x;
1299    portPriv->vid_y = vid_y;
1300    portPriv->vid_w = vid_w;
1301    portPriv->vid_h = vid_h;
1302    portPriv->drw_x = drw_x;
1303    portPriv->drw_y = drw_y;
1304    portPriv->drw_w = drw_w;
1305    portPriv->drw_h = drw_h;
1306
1307    /* make sure we have the most recent copy of the clientClip */
1308    xf86XVCopyClip(portPriv, pGC);
1309
1310    /* To indicate to the DI layer that we were successful */
1311    pPort->pDraw = pDraw;
1312
1313    if (!portPriv->pScrn->vtSema)
1314        return Success;         /* Success ? */
1315
1316    return (xf86XVReputVideo(portPriv));
1317}
1318
1319static int
1320xf86XVPutStill(DrawablePtr pDraw,
1321               XvPortPtr pPort,
1322               GCPtr pGC,
1323               INT16 vid_x, INT16 vid_y,
1324               CARD16 vid_w, CARD16 vid_h,
1325               INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
1326{
1327    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1328    RegionRec WinRegion;
1329    RegionRec ClipRegion;
1330    BoxRec WinBox;
1331    int ret = Success;
1332    Bool clippedAway = FALSE;
1333
1334    if (pDraw->type != DRAWABLE_WINDOW)
1335        return BadAlloc;
1336
1337    if (!portPriv->pScrn->vtSema)
1338        return Success;         /* Success ? */
1339
1340    WinBox.x1 = pDraw->x + drw_x;
1341    WinBox.y1 = pDraw->y + drw_y;
1342    WinBox.x2 = WinBox.x1 + drw_w;
1343    WinBox.y2 = WinBox.y1 + drw_h;
1344
1345    xf86XVCopyCompositeClip(portPriv, pGC, pDraw);
1346
1347    RegionInit(&WinRegion, &WinBox, 1);
1348    RegionNull(&ClipRegion);
1349    RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
1350
1351    if (portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
1352        RegionRec VPReg;
1353        BoxRec VPBox;
1354
1355        VPBox.x1 = portPriv->pScrn->frameX0;
1356        VPBox.y1 = portPriv->pScrn->frameY0;
1357        VPBox.x2 = portPriv->pScrn->frameX1 + 1;
1358        VPBox.y2 = portPriv->pScrn->frameY1 + 1;
1359
1360        RegionInit(&VPReg, &VPBox, 1);
1361        RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
1362        RegionUninit(&VPReg);
1363    }
1364
1365    if (portPriv->pDraw) {
1366        xf86XVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1367    }
1368
1369    if (!RegionNotEmpty(&ClipRegion)) {
1370        clippedAway = TRUE;
1371        goto PUT_STILL_BAILOUT;
1372    }
1373
1374    ret = (*portPriv->AdaptorRec->PutStill) (portPriv->pScrn,
1375                                             vid_x, vid_y, WinBox.x1, WinBox.y1,
1376                                             vid_w, vid_h, drw_w, drw_h,
1377                                             &ClipRegion, portPriv->DevPriv.ptr,
1378                                             pDraw);
1379
1380    if ((ret == Success) &&
1381        (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) {
1382
1383        xf86XVEnlistPortInWindow((WindowPtr) pDraw, portPriv);
1384        portPriv->isOn = XV_ON;
1385        portPriv->vid_x = vid_x;
1386        portPriv->vid_y = vid_y;
1387        portPriv->vid_w = vid_w;
1388        portPriv->vid_h = vid_h;
1389        portPriv->drw_x = drw_x;
1390        portPriv->drw_y = drw_y;
1391        portPriv->drw_w = drw_w;
1392        portPriv->drw_h = drw_h;
1393        portPriv->type = 0;     /* no mask means it's transient and should
1394                                   not be reput once it's removed */
1395        pPort->pDraw = pDraw;   /* make sure we can get stop requests */
1396    }
1397
1398 PUT_STILL_BAILOUT:
1399
1400    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
1401        (*portPriv->AdaptorRec->StopVideo) (portPriv->pScrn,
1402                                            portPriv->DevPriv.ptr, FALSE);
1403        portPriv->isOn = XV_PENDING;
1404    }
1405
1406    /* This clip was copied and only good for one shot */
1407    if (!portPriv->FreeCompositeClip)
1408        portPriv->pCompositeClip = NULL;
1409
1410    RegionUninit(&WinRegion);
1411    RegionUninit(&ClipRegion);
1412
1413    return ret;
1414}
1415
1416static int
1417xf86XVGetVideo(DrawablePtr pDraw,
1418               XvPortPtr pPort,
1419               GCPtr pGC,
1420               INT16 vid_x, INT16 vid_y,
1421               CARD16 vid_w, CARD16 vid_h,
1422               INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
1423{
1424    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1425    int result;
1426
1427    /* No pixmaps... For now anyhow */
1428    if (pDraw->type != DRAWABLE_WINDOW) {
1429        pPort->pDraw = (DrawablePtr) NULL;
1430        return BadAlloc;
1431    }
1432
1433    /* If we are changing windows, unregister our port in the old window */
1434    if (portPriv->pDraw && (portPriv->pDraw != pDraw))
1435        xf86XVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1436
1437    /* Register our port with the new window */
1438    result = xf86XVEnlistPortInWindow((WindowPtr) pDraw, portPriv);
1439    if (result != Success)
1440        return result;
1441
1442    portPriv->type = XvOutputMask;
1443
1444    /* save a copy of these parameters */
1445    portPriv->vid_x = vid_x;
1446    portPriv->vid_y = vid_y;
1447    portPriv->vid_w = vid_w;
1448    portPriv->vid_h = vid_h;
1449    portPriv->drw_x = drw_x;
1450    portPriv->drw_y = drw_y;
1451    portPriv->drw_w = drw_w;
1452    portPriv->drw_h = drw_h;
1453
1454    /* make sure we have the most recent copy of the clientClip */
1455    xf86XVCopyClip(portPriv, pGC);
1456
1457    /* To indicate to the DI layer that we were successful */
1458    pPort->pDraw = pDraw;
1459
1460    if (!portPriv->pScrn->vtSema)
1461        return Success;         /* Success ? */
1462
1463    return (xf86XVRegetVideo(portPriv));
1464}
1465
1466static int
1467xf86XVGetStill(DrawablePtr pDraw,
1468               XvPortPtr pPort,
1469               GCPtr pGC,
1470               INT16 vid_x, INT16 vid_y,
1471               CARD16 vid_w, CARD16 vid_h,
1472               INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
1473{
1474    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1475    RegionRec WinRegion;
1476    RegionRec ClipRegion;
1477    BoxRec WinBox;
1478    int ret = Success;
1479    Bool clippedAway = FALSE;
1480
1481    if (pDraw->type != DRAWABLE_WINDOW)
1482        return BadAlloc;
1483
1484    if (!portPriv->pScrn->vtSema)
1485        return Success;         /* Success ? */
1486
1487    WinBox.x1 = pDraw->x + drw_x;
1488    WinBox.y1 = pDraw->y + drw_y;
1489    WinBox.x2 = WinBox.x1 + drw_w;
1490    WinBox.y2 = WinBox.y1 + drw_h;
1491
1492    RegionInit(&WinRegion, &WinBox, 1);
1493    RegionNull(&ClipRegion);
1494    RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
1495
1496    if (portPriv->pDraw) {
1497        xf86XVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1498    }
1499
1500    if (!RegionNotEmpty(&ClipRegion)) {
1501        clippedAway = TRUE;
1502        goto GET_STILL_BAILOUT;
1503    }
1504
1505    ret = (*portPriv->AdaptorRec->GetStill) (portPriv->pScrn,
1506                                             vid_x, vid_y, WinBox.x1, WinBox.y1,
1507                                             vid_w, vid_h, drw_w, drw_h,
1508                                             &ClipRegion, portPriv->DevPriv.ptr,
1509                                             pDraw);
1510
1511 GET_STILL_BAILOUT:
1512
1513    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
1514        (*portPriv->AdaptorRec->StopVideo) (portPriv->pScrn,
1515                                            portPriv->DevPriv.ptr, FALSE);
1516        portPriv->isOn = XV_PENDING;
1517    }
1518
1519    RegionUninit(&WinRegion);
1520    RegionUninit(&ClipRegion);
1521
1522    return ret;
1523}
1524
1525static int
1526xf86XVStopVideo(XvPortPtr pPort, DrawablePtr pDraw)
1527{
1528    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1529
1530    if (pDraw->type != DRAWABLE_WINDOW)
1531        return BadAlloc;
1532
1533    xf86XVRemovePortFromWindow((WindowPtr) pDraw, portPriv);
1534
1535    if (!portPriv->pScrn->vtSema)
1536        return Success;         /* Success ? */
1537
1538    /* Must free resources. */
1539
1540    if (portPriv->isOn > XV_OFF) {
1541        (*portPriv->AdaptorRec->StopVideo) (portPriv->pScrn,
1542                                            portPriv->DevPriv.ptr, TRUE);
1543        portPriv->isOn = XV_OFF;
1544    }
1545
1546    return Success;
1547}
1548
1549static int
1550xf86XVSetPortAttribute(XvPortPtr pPort, Atom attribute, INT32 value)
1551{
1552    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1553
1554    return ((*portPriv->AdaptorRec->SetPortAttribute) (portPriv->pScrn,
1555                                                       attribute, value,
1556                                                       portPriv->DevPriv.ptr));
1557}
1558
1559static int
1560xf86XVGetPortAttribute(XvPortPtr pPort, Atom attribute, INT32 *p_value)
1561{
1562    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1563
1564    return ((*portPriv->AdaptorRec->GetPortAttribute) (portPriv->pScrn,
1565                                                       attribute, p_value,
1566                                                       portPriv->DevPriv.ptr));
1567}
1568
1569static int
1570xf86XVQueryBestSize(XvPortPtr pPort,
1571                    CARD8 motion,
1572                    CARD16 vid_w, CARD16 vid_h,
1573                    CARD16 drw_w, CARD16 drw_h,
1574                    unsigned int *p_w, unsigned int *p_h)
1575{
1576    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1577
1578    (*portPriv->AdaptorRec->QueryBestSize) (portPriv->pScrn,
1579                                            (Bool) motion, vid_w, vid_h, drw_w,
1580                                            drw_h, p_w, p_h,
1581                                            portPriv->DevPriv.ptr);
1582
1583    return Success;
1584}
1585
1586static int
1587xf86XVPutImage(DrawablePtr pDraw,
1588               XvPortPtr pPort,
1589               GCPtr pGC,
1590               INT16 src_x, INT16 src_y,
1591               CARD16 src_w, CARD16 src_h,
1592               INT16 drw_x, INT16 drw_y,
1593               CARD16 drw_w, CARD16 drw_h,
1594               XvImagePtr format,
1595               unsigned char *data, Bool sync, CARD16 width, CARD16 height)
1596{
1597    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1598    RegionRec WinRegion;
1599    RegionRec ClipRegion;
1600    BoxRec WinBox;
1601    int ret = Success;
1602    Bool clippedAway = FALSE;
1603
1604    if (pDraw->type != DRAWABLE_WINDOW)
1605        return BadAlloc;
1606
1607    if (!portPriv->pScrn->vtSema)
1608        return Success;         /* Success ? */
1609
1610    xf86XVCopyCompositeClip(portPriv, pGC, pDraw);
1611
1612    WinBox.x1 = pDraw->x + drw_x;
1613    WinBox.y1 = pDraw->y + drw_y;
1614    WinBox.x2 = WinBox.x1 + drw_w;
1615    WinBox.y2 = WinBox.y1 + drw_h;
1616
1617    RegionInit(&WinRegion, &WinBox, 1);
1618    RegionNull(&ClipRegion);
1619    RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
1620
1621    if (portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
1622        RegionRec VPReg;
1623        BoxRec VPBox;
1624
1625        VPBox.x1 = portPriv->pScrn->frameX0;
1626        VPBox.y1 = portPriv->pScrn->frameY0;
1627        VPBox.x2 = portPriv->pScrn->frameX1 + 1;
1628        VPBox.y2 = portPriv->pScrn->frameY1 + 1;
1629
1630        RegionInit(&VPReg, &VPBox, 1);
1631        RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
1632        RegionUninit(&VPReg);
1633    }
1634
1635    /* If we are changing windows, unregister our port in the old window */
1636    if (portPriv->pDraw && (portPriv->pDraw != pDraw))
1637        xf86XVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1638
1639    /* Register our port with the new window */
1640    ret = xf86XVEnlistPortInWindow((WindowPtr) pDraw, portPriv);
1641    if (ret != Success)
1642        goto PUT_IMAGE_BAILOUT;
1643
1644    if (!RegionNotEmpty(&ClipRegion)) {
1645        clippedAway = TRUE;
1646        goto PUT_IMAGE_BAILOUT;
1647    }
1648
1649    ret = (*portPriv->AdaptorRec->PutImage) (portPriv->pScrn,
1650                                             src_x, src_y, WinBox.x1, WinBox.y1,
1651                                             src_w, src_h, drw_w, drw_h,
1652                                             format->id, data, width, height,
1653                                             sync, &ClipRegion,
1654                                             portPriv->DevPriv.ptr, pDraw);
1655
1656    if ((ret == Success) &&
1657        (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) {
1658
1659        portPriv->isOn = XV_ON;
1660        portPriv->vid_x = src_x;
1661        portPriv->vid_y = src_y;
1662        portPriv->vid_w = src_w;
1663        portPriv->vid_h = src_h;
1664        portPriv->drw_x = drw_x;
1665        portPriv->drw_y = drw_y;
1666        portPriv->drw_w = drw_w;
1667        portPriv->drw_h = drw_h;
1668        portPriv->type = 0;     /* no mask means it's transient and should
1669                                   not be reput once it's removed */
1670        pPort->pDraw = pDraw;   /* make sure we can get stop requests */
1671    }
1672
1673 PUT_IMAGE_BAILOUT:
1674
1675    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
1676        (*portPriv->AdaptorRec->StopVideo) (portPriv->pScrn,
1677                                            portPriv->DevPriv.ptr, FALSE);
1678        portPriv->isOn = XV_PENDING;
1679    }
1680
1681    /* This clip was copied and only good for one shot */
1682    if (!portPriv->FreeCompositeClip)
1683        portPriv->pCompositeClip = NULL;
1684
1685    RegionUninit(&WinRegion);
1686    RegionUninit(&ClipRegion);
1687
1688    return ret;
1689}
1690
1691static int
1692xf86XVQueryImageAttributes(XvPortPtr pPort,
1693                           XvImagePtr format,
1694                           CARD16 *width,
1695                           CARD16 *height, int *pitches, int *offsets)
1696{
1697    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1698
1699    return (*portPriv->AdaptorRec->QueryImageAttributes) (portPriv->pScrn,
1700                                                          format->id, width,
1701                                                          height, pitches,
1702                                                          offsets);
1703}
1704
1705void
1706xf86XVFillKeyHelperDrawable(DrawablePtr pDraw, CARD32 key, RegionPtr fillboxes)
1707{
1708    ScreenPtr pScreen = pDraw->pScreen;
1709
1710    if (!xf86ScreenToScrn(pScreen)->vtSema)
1711        return;
1712
1713    XvFillColorKey(pDraw, key, fillboxes);
1714}
1715
1716void
1717xf86XVFillKeyHelper(ScreenPtr pScreen, CARD32 key, RegionPtr fillboxes)
1718{
1719    xf86XVFillKeyHelperDrawable(&pScreen->root->drawable, key, fillboxes);
1720}
1721
1722void
1723xf86XVFillKeyHelperPort(DrawablePtr pDraw, void *data, CARD32 key,
1724                        RegionPtr clipboxes, Bool fillEverything)
1725{
1726    WindowPtr pWin = (WindowPtr) pDraw;
1727    XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin);
1728    XvPortRecPrivatePtr portPriv = NULL;
1729    RegionRec reg;
1730    RegionPtr fillboxes;
1731
1732    while (WinPriv) {
1733        XvPortRecPrivatePtr pPriv = WinPriv->PortRec;
1734
1735        if (data == pPriv->DevPriv.ptr) {
1736            portPriv = pPriv;
1737            break;
1738        }
1739
1740        WinPriv = WinPriv->next;
1741    }
1742
1743    if (!portPriv)
1744        return;
1745
1746    if (!portPriv->ckeyFilled)
1747        portPriv->ckeyFilled = RegionCreate(NULL, 0);
1748
1749    if (!fillEverything) {
1750        RegionNull(&reg);
1751        fillboxes = &reg;
1752        RegionSubtract(fillboxes, clipboxes, portPriv->ckeyFilled);
1753
1754        if (!RegionNotEmpty(fillboxes))
1755            goto out;
1756    }
1757    else
1758        fillboxes = clipboxes;
1759
1760    RegionCopy(portPriv->ckeyFilled, clipboxes);
1761
1762    xf86XVFillKeyHelperDrawable(pDraw, key, fillboxes);
1763 out:
1764    if (!fillEverything)
1765        RegionUninit(&reg);
1766}
1767
1768/* xf86XVClipVideoHelper -
1769
1770   Takes the dst box in standard X BoxRec form (top and left
1771   edges inclusive, bottom and right exclusive).  The new dst
1772   box is returned.  The source boundaries are given (x1, y1
1773   inclusive, x2, y2 exclusive) and returned are the new source
1774   boundaries in 16.16 fixed point.
1775*/
1776
1777Bool
1778xf86XVClipVideoHelper(BoxPtr dst,
1779                      INT32 *xa,
1780                      INT32 *xb,
1781                      INT32 *ya,
1782                      INT32 *yb, RegionPtr reg, INT32 width, INT32 height)
1783{
1784    double xsw, xdw, ysw, ydw;
1785    INT32 delta;
1786    BoxPtr extents = RegionExtents(reg);
1787    int diff;
1788
1789    xsw = (*xb - *xa) << 16;
1790    xdw = dst->x2 - dst->x1;
1791    ysw = (*yb - *ya) << 16;
1792    ydw = dst->y2 - dst->y1;
1793
1794    *xa <<= 16;
1795    *xb <<= 16;
1796    *ya <<= 16;
1797    *yb <<= 16;
1798
1799    diff = extents->x1 - dst->x1;
1800    if (diff > 0) {
1801        dst->x1 = extents->x1;
1802        *xa += (diff * xsw) / xdw;
1803    }
1804    diff = dst->x2 - extents->x2;
1805    if (diff > 0) {
1806        dst->x2 = extents->x2;
1807        *xb -= (diff * xsw) / xdw;
1808    }
1809    diff = extents->y1 - dst->y1;
1810    if (diff > 0) {
1811        dst->y1 = extents->y1;
1812        *ya += (diff * ysw) / ydw;
1813    }
1814    diff = dst->y2 - extents->y2;
1815    if (diff > 0) {
1816        dst->y2 = extents->y2;
1817        *yb -= (diff * ysw) / ydw;
1818    }
1819
1820    if (*xa < 0) {
1821        diff = (((-*xa) * xdw) + xsw - 1) / xsw;
1822        dst->x1 += diff;
1823        *xa += (diff * xsw) / xdw;
1824    }
1825    delta = *xb - (width << 16);
1826    if (delta > 0) {
1827        diff = ((delta * xdw) + xsw - 1) / xsw;
1828        dst->x2 -= diff;
1829        *xb -= (diff * xsw) / xdw;
1830    }
1831    if (*xa >= *xb)
1832        return FALSE;
1833
1834    if (*ya < 0) {
1835        diff = (((-*ya) * ydw) + ysw - 1) / ysw;
1836        dst->y1 += diff;
1837        *ya += (diff * ysw) / ydw;
1838    }
1839    delta = *yb - (height << 16);
1840    if (delta > 0) {
1841        diff = ((delta * ydw) + ysw - 1) / ysw;
1842        dst->y2 -= diff;
1843        *yb -= (diff * ysw) / ydw;
1844    }
1845    if (*ya >= *yb)
1846        return FALSE;
1847
1848    if ((dst->x1 > extents->x1) || (dst->x2 < extents->x2) ||
1849        (dst->y1 > extents->y1) || (dst->y2 < extents->y2)) {
1850        RegionRec clipReg;
1851
1852        RegionInit(&clipReg, dst, 1);
1853        RegionIntersect(reg, reg, &clipReg);
1854        RegionUninit(&clipReg);
1855    }
1856    return TRUE;
1857}
1858
1859void
1860xf86XVCopyYUV12ToPacked(const void *srcy,
1861                        const void *srcv,
1862                        const void *srcu,
1863                        void *dst,
1864                        int srcPitchy,
1865                        int srcPitchuv, int dstPitch, int h, int w)
1866{
1867    CARD32 *Dst;
1868    const CARD8 *Y, *U, *V;
1869    int i, j;
1870
1871    w >>= 1;
1872
1873    for (j = 0; j < h; j++) {
1874        Dst = dst;
1875        Y = srcy;
1876        V = srcv;
1877        U = srcu;
1878        i = w;
1879        while (i >= 4) {
1880#if X_BYTE_ORDER == X_LITTLE_ENDIAN
1881            Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24);
1882            Dst[1] = Y[2] | (Y[3] << 16) | (U[1] << 8) | (V[1] << 24);
1883            Dst[2] = Y[4] | (Y[5] << 16) | (U[2] << 8) | (V[2] << 24);
1884            Dst[3] = Y[6] | (Y[7] << 16) | (U[3] << 8) | (V[3] << 24);
1885#else
1886            /* This assumes a little-endian framebuffer */
1887            Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0];
1888            Dst[1] = (Y[2] << 24) | (Y[3] << 8) | (U[1] << 16) | V[1];
1889            Dst[2] = (Y[4] << 24) | (Y[5] << 8) | (U[2] << 16) | V[2];
1890            Dst[3] = (Y[6] << 24) | (Y[7] << 8) | (U[3] << 16) | V[3];
1891#endif
1892            Dst += 4;
1893            Y += 8;
1894            V += 4;
1895            U += 4;
1896            i -= 4;
1897        }
1898
1899        while (i--) {
1900#if X_BYTE_ORDER == X_LITTLE_ENDIAN
1901            Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24);
1902#else
1903            /* This assumes a little-endian framebuffer */
1904            Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0];
1905#endif
1906            Dst++;
1907            Y += 2;
1908            V++;
1909            U++;
1910        }
1911
1912        dst = (CARD8 *) dst + dstPitch;
1913        srcy = (const CARD8 *) srcy + srcPitchy;
1914        if (j & 1) {
1915            srcu = (const CARD8 *) srcu + srcPitchuv;
1916            srcv = (const CARD8 *) srcv + srcPitchuv;
1917        }
1918    }
1919}
1920
1921void
1922xf86XVCopyPacked(const void *src,
1923                 void *dst, int srcPitch, int dstPitch, int h, int w)
1924{
1925    const CARD32 *Src;
1926    CARD32 *Dst;
1927    int i;
1928
1929    w >>= 1;
1930    while (--h >= 0) {
1931        do {
1932            Dst = dst;
1933            Src = src;
1934            i = w;
1935            while (i >= 4) {
1936                Dst[0] = Src[0];
1937                Dst[1] = Src[1];
1938                Dst[2] = Src[2];
1939                Dst[3] = Src[3];
1940                Dst += 4;
1941                Src += 4;
1942                i -= 4;
1943            }
1944            if (!i)
1945                break;
1946            Dst[0] = Src[0];
1947            if (i == 1)
1948                break;
1949            Dst[1] = Src[1];
1950            if (i == 2)
1951                break;
1952            Dst[2] = Src[2];
1953        } while (0);
1954
1955        src = (const CARD8 *) src + srcPitch;
1956        dst = (CARD8 *) dst + dstPitch;
1957    }
1958}
1959