kxv.c revision 35c4bbdf
1/*
2
3   XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com)
4   Adapted for KDrive by Pontus Lidman <pontus.lidman@nokia.com>
5
6   Copyright (C) 2000, 2001 - Nokia Home Communications
7   Copyright (C) 1998, 1999 - The XFree86 Project Inc.
8
9All rights reserved.
10
11Permission is hereby granted, free of charge, to any person obtaining
12a copy of this software and associated documentation files (the
13"Software"), to deal in the Software without restriction, including
14without limitation the rights to use, copy, modify, merge, publish,
15distribute, and/or sell copies of the Software, and to permit persons
16to whom the Software is furnished to do so, provided that the above
17copyright notice(s) and this permission notice appear in all copies of
18the Software and that both the above copyright notice(s) and this
19permission notice appear in supporting documentation.
20
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
24OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
25HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
26SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
27RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
28CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
29CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30
31Except as contained in this notice, the name of a copyright holder
32shall not be used in advertising or otherwise to promote the sale, use
33or other dealings in this Software without prior written authorization
34of the copyright holder.
35
36*/
37
38#ifdef HAVE_CONFIG_H
39#include <kdrive-config.h>
40#endif
41#include "kdrive.h"
42
43#include "scrnintstr.h"
44#include "regionstr.h"
45#include "windowstr.h"
46#include "pixmapstr.h"
47#include "mivalidate.h"
48#include "validate.h"
49#include "resource.h"
50#include "gcstruct.h"
51#include "dixstruct.h"
52
53#include <X11/extensions/Xv.h>
54#include <X11/extensions/Xvproto.h>
55
56#include "kxv.h"
57#include "fourcc.h"
58
59/* XvAdaptorRec fields */
60
61static int KdXVPutVideo(DrawablePtr, XvPortPtr, GCPtr,
62                        INT16, INT16, CARD16, CARD16,
63                        INT16, INT16, CARD16, CARD16);
64static int KdXVPutStill(DrawablePtr, XvPortPtr, GCPtr,
65                        INT16, INT16, CARD16, CARD16,
66                        INT16, INT16, CARD16, CARD16);
67static int KdXVGetVideo(DrawablePtr, XvPortPtr, GCPtr,
68                        INT16, INT16, CARD16, CARD16,
69                        INT16, INT16, CARD16, CARD16);
70static int KdXVGetStill(DrawablePtr, XvPortPtr, GCPtr,
71                        INT16, INT16, CARD16, CARD16,
72                        INT16, INT16, CARD16, CARD16);
73static int KdXVStopVideo(XvPortPtr, DrawablePtr);
74static int KdXVSetPortAttribute(XvPortPtr, Atom, INT32);
75static int KdXVGetPortAttribute(XvPortPtr, Atom, INT32 *);
76static int KdXVQueryBestSize(XvPortPtr, CARD8,
77                             CARD16, CARD16, CARD16, CARD16,
78                             unsigned int *, unsigned int *);
79static int KdXVPutImage(DrawablePtr, XvPortPtr, GCPtr,
80                        INT16, INT16, CARD16, CARD16,
81                        INT16, INT16, CARD16, CARD16,
82                        XvImagePtr, unsigned char *, Bool, CARD16, CARD16);
83static int KdXVQueryImageAttributes(XvPortPtr, XvImagePtr,
84                                    CARD16 *, CARD16 *, int *, int *);
85
86/* ScreenRec fields */
87
88static Bool KdXVDestroyWindow(WindowPtr pWin);
89static void KdXVWindowExposures(WindowPtr pWin, RegionPtr r1);
90static void KdXVClipNotify(WindowPtr pWin, int dx, int dy);
91static Bool KdXVCloseScreen(ScreenPtr);
92
93/* misc */
94static Bool KdXVInitAdaptors(ScreenPtr, KdVideoAdaptorPtr, int);
95
96static DevPrivateKeyRec KdXVWindowKeyRec;
97
98#define KdXVWindowKey (&KdXVWindowKeyRec)
99static DevPrivateKey KdXvScreenKey;
100static DevPrivateKeyRec KdXVScreenPrivateKey;
101static unsigned long KdXVGeneration = 0;
102static unsigned long PortResource = 0;
103
104#define GET_XV_SCREEN(pScreen) ((XvScreenPtr) \
105    dixLookupPrivate(&(pScreen)->devPrivates, KdXvScreenKey))
106
107#define GET_KDXV_SCREEN(pScreen) \
108    ((KdXVScreenPtr)(dixGetPrivate(&pScreen->devPrivates, &KdXVScreenPrivateKey)))
109
110#define GET_KDXV_WINDOW(pWin) ((KdXVWindowPtr) \
111    dixLookupPrivate(&(pWin)->devPrivates, KdXVWindowKey))
112
113KdVideoAdaptorPtr
114KdXVAllocateVideoAdaptorRec(KdScreenInfo * screen)
115{
116    return calloc(1, sizeof(KdVideoAdaptorRec));
117}
118
119void
120KdXVFreeVideoAdaptorRec(KdVideoAdaptorPtr ptr)
121{
122    free(ptr);
123}
124
125Bool
126KdXVScreenInit(ScreenPtr pScreen, KdVideoAdaptorPtr adaptors, int num)
127{
128    KdXVScreenPtr ScreenPriv;
129
130/*   fprintf(stderr,"KdXVScreenInit initializing %d adaptors\n",num); */
131
132    if (KdXVGeneration != serverGeneration)
133        KdXVGeneration = serverGeneration;
134
135    if (noXvExtension)
136        return FALSE;
137
138    if (!dixRegisterPrivateKey(&KdXVWindowKeyRec, PRIVATE_WINDOW, 0))
139        return FALSE;
140    if (!dixRegisterPrivateKey(&KdXVScreenPrivateKey, PRIVATE_SCREEN, 0))
141        return FALSE;
142
143    if (Success != XvScreenInit(pScreen))
144        return FALSE;
145
146    KdXvScreenKey = XvGetScreenKey();
147    PortResource = XvGetRTPort();
148
149    ScreenPriv = malloc(sizeof(KdXVScreenRec));
150    dixSetPrivate(&pScreen->devPrivates, &KdXVScreenPrivateKey, ScreenPriv);
151
152    if (!ScreenPriv)
153        return FALSE;
154
155    ScreenPriv->DestroyWindow = pScreen->DestroyWindow;
156    ScreenPriv->WindowExposures = pScreen->WindowExposures;
157    ScreenPriv->ClipNotify = pScreen->ClipNotify;
158    ScreenPriv->CloseScreen = pScreen->CloseScreen;
159
160/*   fprintf(stderr,"XV: Wrapping screen funcs\n"); */
161
162    pScreen->DestroyWindow = KdXVDestroyWindow;
163    pScreen->WindowExposures = KdXVWindowExposures;
164    pScreen->ClipNotify = KdXVClipNotify;
165    pScreen->CloseScreen = KdXVCloseScreen;
166
167    if (!KdXVInitAdaptors(pScreen, adaptors, num))
168        return FALSE;
169
170    return TRUE;
171}
172
173static void
174KdXVFreeAdaptor(XvAdaptorPtr pAdaptor)
175{
176    int i;
177
178    if (pAdaptor->pPorts) {
179        XvPortPtr pPort = pAdaptor->pPorts;
180        XvPortRecPrivatePtr pPriv;
181
182        for (i = 0; i < pAdaptor->nPorts; i++, pPort++) {
183            pPriv = (XvPortRecPrivatePtr) pPort->devPriv.ptr;
184            if (pPriv) {
185                if (pPriv->clientClip)
186                    RegionDestroy(pPriv->clientClip);
187                if (pPriv->pCompositeClip && pPriv->FreeCompositeClip)
188                    RegionDestroy(pPriv->pCompositeClip);
189                free(pPriv);
190            }
191        }
192    }
193
194    XvFreeAdaptor(pAdaptor);
195}
196
197static Bool
198KdXVInitAdaptors(ScreenPtr pScreen, KdVideoAdaptorPtr infoPtr, int number)
199{
200    KdScreenPriv(pScreen);
201    KdScreenInfo *screen = pScreenPriv->screen;
202
203    XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
204    KdVideoAdaptorPtr adaptorPtr;
205    XvAdaptorPtr pAdaptor, pa;
206    XvAdaptorRecPrivatePtr adaptorPriv;
207    int na, numAdaptor;
208    XvPortRecPrivatePtr portPriv;
209    XvPortPtr pPort, pp;
210    int numPort;
211    KdVideoFormatPtr formatPtr;
212    XvFormatPtr pFormat, pf;
213    int numFormat, totFormat;
214    KdVideoEncodingPtr encodingPtr;
215    XvEncodingPtr pEncode, pe;
216    int numVisuals;
217    VisualPtr pVisual;
218    int i;
219
220    pxvs->nAdaptors = 0;
221    pxvs->pAdaptors = NULL;
222
223    if (!(pAdaptor = calloc(number, sizeof(XvAdaptorRec))))
224        return FALSE;
225
226    for (pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) {
227        adaptorPtr = &infoPtr[na];
228
229        if (!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute ||
230            !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize)
231            continue;
232
233        /* client libs expect at least one encoding */
234        if (!adaptorPtr->nEncodings || !adaptorPtr->pEncodings)
235            continue;
236
237        pa->type = adaptorPtr->type;
238
239        if (!adaptorPtr->PutVideo && !adaptorPtr->GetVideo)
240            pa->type &= ~XvVideoMask;
241
242        if (!adaptorPtr->PutStill && !adaptorPtr->GetStill)
243            pa->type &= ~XvStillMask;
244
245        if (!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes)
246            pa->type &= ~XvImageMask;
247
248        if (!adaptorPtr->PutVideo && !adaptorPtr->PutImage &&
249            !adaptorPtr->PutStill)
250            pa->type &= ~XvInputMask;
251
252        if (!adaptorPtr->GetVideo && !adaptorPtr->GetStill)
253            pa->type &= ~XvOutputMask;
254
255        if (!(adaptorPtr->type & (XvPixmapMask | XvWindowMask)))
256            continue;
257        if (!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask)))
258            continue;
259
260        pa->pScreen = pScreen;
261        pa->ddPutVideo = KdXVPutVideo;
262        pa->ddPutStill = KdXVPutStill;
263        pa->ddGetVideo = KdXVGetVideo;
264        pa->ddGetStill = KdXVGetStill;
265        pa->ddStopVideo = KdXVStopVideo;
266        pa->ddPutImage = KdXVPutImage;
267        pa->ddSetPortAttribute = KdXVSetPortAttribute;
268        pa->ddGetPortAttribute = KdXVGetPortAttribute;
269        pa->ddQueryBestSize = KdXVQueryBestSize;
270        pa->ddQueryImageAttributes = KdXVQueryImageAttributes;
271        pa->name = strdup(adaptorPtr->name);
272
273        if (adaptorPtr->nEncodings &&
274            (pEncode = calloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) {
275
276            for (pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0;
277                 i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) {
278                pe->id = encodingPtr->id;
279                pe->pScreen = pScreen;
280                pe->name = strdup(encodingPtr->name);
281                pe->width = encodingPtr->width;
282                pe->height = encodingPtr->height;
283                pe->rate.numerator = encodingPtr->rate.numerator;
284                pe->rate.denominator = encodingPtr->rate.denominator;
285            }
286            pa->nEncodings = adaptorPtr->nEncodings;
287            pa->pEncodings = pEncode;
288        }
289
290        if (adaptorPtr->nImages &&
291            (pa->pImages = calloc(adaptorPtr->nImages, sizeof(XvImageRec)))) {
292            memcpy(pa->pImages, adaptorPtr->pImages,
293                   adaptorPtr->nImages * sizeof(XvImageRec));
294            pa->nImages = adaptorPtr->nImages;
295        }
296
297        if (adaptorPtr->nAttributes &&
298            (pa->pAttributes = calloc(adaptorPtr->nAttributes,
299                                      sizeof(XvAttributeRec)))) {
300            memcpy(pa->pAttributes, adaptorPtr->pAttributes,
301                   adaptorPtr->nAttributes * sizeof(XvAttributeRec));
302
303            for (i = 0; i < adaptorPtr->nAttributes; i++) {
304                pa->pAttributes[i].name =
305                    strdup(adaptorPtr->pAttributes[i].name);
306            }
307
308            pa->nAttributes = adaptorPtr->nAttributes;
309        }
310
311        totFormat = adaptorPtr->nFormats;
312
313        if (!(pFormat = calloc(totFormat, sizeof(XvFormatRec)))) {
314            KdXVFreeAdaptor(pa);
315            continue;
316        }
317        for (pf = pFormat, i = 0, numFormat = 0, formatPtr =
318             adaptorPtr->pFormats; i < adaptorPtr->nFormats; i++, formatPtr++) {
319            numVisuals = pScreen->numVisuals;
320            pVisual = pScreen->visuals;
321
322            while (numVisuals--) {
323                if ((pVisual->class == formatPtr->class) &&
324                    (pVisual->nplanes == formatPtr->depth)) {
325
326                    if (numFormat >= totFormat) {
327                        void *moreSpace;
328
329                        totFormat *= 2;
330                        moreSpace = reallocarray(pFormat, totFormat,
331                                                 sizeof(XvFormatRec));
332                        if (!moreSpace)
333                            break;
334                        pFormat = moreSpace;
335                        pf = pFormat + numFormat;
336                    }
337
338                    pf->visual = pVisual->vid;
339                    pf->depth = formatPtr->depth;
340
341                    pf++;
342                    numFormat++;
343                }
344                pVisual++;
345            }
346        }
347        pa->nFormats = numFormat;
348        pa->pFormats = pFormat;
349        if (!numFormat) {
350            KdXVFreeAdaptor(pa);
351            continue;
352        }
353
354        if (!(adaptorPriv = calloc(1, sizeof(XvAdaptorRecPrivate)))) {
355            KdXVFreeAdaptor(pa);
356            continue;
357        }
358
359        adaptorPriv->flags = adaptorPtr->flags;
360        adaptorPriv->PutVideo = adaptorPtr->PutVideo;
361        adaptorPriv->PutStill = adaptorPtr->PutStill;
362        adaptorPriv->GetVideo = adaptorPtr->GetVideo;
363        adaptorPriv->GetStill = adaptorPtr->GetStill;
364        adaptorPriv->StopVideo = adaptorPtr->StopVideo;
365        adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute;
366        adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute;
367        adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize;
368        adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes;
369        adaptorPriv->PutImage = adaptorPtr->PutImage;
370        adaptorPriv->ReputImage = adaptorPtr->ReputImage;
371
372        pa->devPriv.ptr = (void *) adaptorPriv;
373
374        if (!(pPort = calloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) {
375            KdXVFreeAdaptor(pa);
376            continue;
377        }
378        for (pp = pPort, i = 0, numPort = 0; i < adaptorPtr->nPorts; i++) {
379
380            if (!(pp->id = FakeClientID(0)))
381                continue;
382
383            if (!(portPriv = calloc(1, sizeof(XvPortRecPrivate))))
384                continue;
385
386            if (!AddResource(pp->id, PortResource, pp)) {
387                free(portPriv);
388                continue;
389            }
390
391            pp->pAdaptor = pa;
392            pp->pNotify = (XvPortNotifyPtr) NULL;
393            pp->pDraw = (DrawablePtr) NULL;
394            pp->client = (ClientPtr) NULL;
395            pp->grab.client = (ClientPtr) NULL;
396            pp->time = currentTime;
397            pp->devPriv.ptr = portPriv;
398
399            portPriv->screen = screen;
400            portPriv->AdaptorRec = adaptorPriv;
401            portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr;
402
403            pp++;
404            numPort++;
405        }
406        pa->nPorts = numPort;
407        pa->pPorts = pPort;
408        if (!numPort) {
409            KdXVFreeAdaptor(pa);
410            continue;
411        }
412
413        pa->base_id = pPort->id;
414
415        pa++;
416        numAdaptor++;
417    }
418
419    if (numAdaptor) {
420        pxvs->nAdaptors = numAdaptor;
421        pxvs->pAdaptors = pAdaptor;
422    }
423    else {
424        free(pAdaptor);
425        return FALSE;
426    }
427
428    return TRUE;
429}
430
431/* Video should be clipped to the intersection of the window cliplist
432   and the client cliplist specified in the GC for which the video was
433   initialized.  When we need to reclip a window, the GC that started
434   the video may not even be around anymore.  That's why we save the
435   client clip from the GC when the video is initialized.  We then
436   use KdXVUpdateCompositeClip to calculate the new composite clip
437   when we need it.  This is different from what DEC did.  They saved
438   the GC and used it's clip list when they needed to reclip the window,
439   even if the client clip was different from the one the video was
440   initialized with.  If the original GC was destroyed, they had to stop
441   the video.  I like the new method better (MArk).
442
443   This function only works for windows.  Will need to rewrite when
444   (if) we support pixmap rendering.
445*/
446
447static void
448KdXVUpdateCompositeClip(XvPortRecPrivatePtr portPriv)
449{
450    RegionPtr pregWin, pCompositeClip;
451    WindowPtr pWin;
452    Bool freeCompClip = FALSE;
453
454    if (portPriv->pCompositeClip)
455        return;
456
457    pWin = (WindowPtr) portPriv->pDraw;
458
459    /* get window clip list */
460    if (portPriv->subWindowMode == IncludeInferiors) {
461        pregWin = NotClippedByChildren(pWin);
462        freeCompClip = TRUE;
463    }
464    else
465        pregWin = &pWin->clipList;
466
467    if (!portPriv->clientClip) {
468        portPriv->pCompositeClip = pregWin;
469        portPriv->FreeCompositeClip = freeCompClip;
470        return;
471    }
472
473    pCompositeClip = RegionCreate(NullBox, 1);
474    RegionCopy(pCompositeClip, portPriv->clientClip);
475    RegionTranslate(pCompositeClip,
476                    portPriv->pDraw->x + portPriv->clipOrg.x,
477                    portPriv->pDraw->y + portPriv->clipOrg.y);
478    RegionIntersect(pCompositeClip, pregWin, pCompositeClip);
479
480    portPriv->pCompositeClip = pCompositeClip;
481    portPriv->FreeCompositeClip = TRUE;
482
483    if (freeCompClip) {
484        RegionDestroy(pregWin);
485    }
486}
487
488/* Save the current clientClip and update the CompositeClip whenever
489   we have a fresh GC */
490
491static void
492KdXVCopyClip(XvPortRecPrivatePtr portPriv, GCPtr pGC)
493{
494    /* copy the new clip if it exists */
495    if (pGC->clientClip) {
496        if (!portPriv->clientClip)
497            portPriv->clientClip = RegionCreate(NullBox, 1);
498        /* Note: this is in window coordinates */
499        RegionCopy(portPriv->clientClip, pGC->clientClip);
500    }
501    else if (portPriv->clientClip) {    /* free the old clientClip */
502        RegionDestroy(portPriv->clientClip);
503        portPriv->clientClip = NULL;
504    }
505
506    /* get rid of the old clip list */
507    if (portPriv->pCompositeClip && portPriv->FreeCompositeClip) {
508        RegionDestroy(portPriv->pCompositeClip);
509    }
510
511    portPriv->clipOrg = pGC->clipOrg;
512    portPriv->pCompositeClip = pGC->pCompositeClip;
513    portPriv->FreeCompositeClip = FALSE;
514    portPriv->subWindowMode = pGC->subWindowMode;
515}
516
517static int
518KdXVRegetVideo(XvPortRecPrivatePtr portPriv)
519{
520    RegionRec WinRegion;
521    RegionRec ClipRegion;
522    BoxRec WinBox;
523    int ret = Success;
524    Bool clippedAway = FALSE;
525
526    KdXVUpdateCompositeClip(portPriv);
527
528    /* translate the video region to the screen */
529    WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x;
530    WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y;
531    WinBox.x2 = WinBox.x1 + portPriv->drw_w;
532    WinBox.y2 = WinBox.y1 + portPriv->drw_h;
533
534    /* clip to the window composite clip */
535    RegionInit(&WinRegion, &WinBox, 1);
536    RegionInit(&ClipRegion, NullBox, 1);
537    RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip);
538
539    /* that's all if it's totally obscured */
540    if (!RegionNotEmpty(&ClipRegion)) {
541        clippedAway = TRUE;
542        goto CLIP_VIDEO_BAILOUT;
543    }
544
545    ret = (*portPriv->AdaptorRec->GetVideo) (portPriv->screen, portPriv->pDraw,
546                                             portPriv->vid_x, portPriv->vid_y,
547                                             WinBox.x1, WinBox.y1,
548                                             portPriv->vid_w, portPriv->vid_h,
549                                             portPriv->drw_w, portPriv->drw_h,
550                                             &ClipRegion,
551                                             portPriv->DevPriv.ptr);
552
553    if (ret == Success)
554        portPriv->isOn = XV_ON;
555
556 CLIP_VIDEO_BAILOUT:
557
558    if ((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) {
559        (*portPriv->AdaptorRec->StopVideo) (portPriv->screen,
560                                            portPriv->DevPriv.ptr, FALSE);
561        portPriv->isOn = XV_PENDING;
562    }
563
564    /* This clip was copied and only good for one shot */
565    if (!portPriv->FreeCompositeClip)
566        portPriv->pCompositeClip = NULL;
567
568    RegionUninit(&WinRegion);
569    RegionUninit(&ClipRegion);
570
571    return ret;
572}
573
574static int
575KdXVReputVideo(XvPortRecPrivatePtr portPriv)
576{
577    RegionRec WinRegion;
578    RegionRec ClipRegion;
579    BoxRec WinBox;
580    ScreenPtr pScreen = portPriv->pDraw->pScreen;
581
582    KdScreenPriv(pScreen);
583    KdScreenInfo *screen = pScreenPriv->screen;
584    int ret = Success;
585    Bool clippedAway = FALSE;
586
587    KdXVUpdateCompositeClip(portPriv);
588
589    /* translate the video region to the screen */
590    WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x;
591    WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y;
592    WinBox.x2 = WinBox.x1 + portPriv->drw_w;
593    WinBox.y2 = WinBox.y1 + portPriv->drw_h;
594
595    /* clip to the window composite clip */
596    RegionInit(&WinRegion, &WinBox, 1);
597    RegionInit(&ClipRegion, NullBox, 1);
598    RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip);
599
600    /* clip and translate to the viewport */
601    if (portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
602        RegionRec VPReg;
603        BoxRec VPBox;
604
605        VPBox.x1 = 0;
606        VPBox.y1 = 0;
607        VPBox.x2 = screen->width;
608        VPBox.y2 = screen->height;
609
610        RegionInit(&VPReg, &VPBox, 1);
611        RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
612        RegionUninit(&VPReg);
613    }
614
615    /* that's all if it's totally obscured */
616    if (!RegionNotEmpty(&ClipRegion)) {
617        clippedAway = TRUE;
618        goto CLIP_VIDEO_BAILOUT;
619    }
620
621    ret = (*portPriv->AdaptorRec->PutVideo) (portPriv->screen, portPriv->pDraw,
622                                             portPriv->vid_x, portPriv->vid_y,
623                                             WinBox.x1, WinBox.y1,
624                                             portPriv->vid_w, portPriv->vid_h,
625                                             portPriv->drw_w, portPriv->drw_h,
626                                             &ClipRegion,
627                                             portPriv->DevPriv.ptr);
628
629    if (ret == Success)
630        portPriv->isOn = XV_ON;
631
632 CLIP_VIDEO_BAILOUT:
633
634    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
635        (*portPriv->AdaptorRec->StopVideo) (portPriv->screen,
636                                            portPriv->DevPriv.ptr, FALSE);
637        portPriv->isOn = XV_PENDING;
638    }
639
640    /* This clip was copied and only good for one shot */
641    if (!portPriv->FreeCompositeClip)
642        portPriv->pCompositeClip = NULL;
643
644    RegionUninit(&WinRegion);
645    RegionUninit(&ClipRegion);
646
647    return ret;
648}
649
650static int
651KdXVReputImage(XvPortRecPrivatePtr portPriv)
652{
653    RegionRec WinRegion;
654    RegionRec ClipRegion;
655    BoxRec WinBox;
656    ScreenPtr pScreen = portPriv->pDraw->pScreen;
657
658    KdScreenPriv(pScreen);
659    KdScreenInfo *screen = pScreenPriv->screen;
660    int ret = Success;
661    Bool clippedAway = FALSE;
662
663    KdXVUpdateCompositeClip(portPriv);
664
665    /* translate the video region to the screen */
666    WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x;
667    WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y;
668    WinBox.x2 = WinBox.x1 + portPriv->drw_w;
669    WinBox.y2 = WinBox.y1 + portPriv->drw_h;
670
671    /* clip to the window composite clip */
672    RegionInit(&WinRegion, &WinBox, 1);
673    RegionInit(&ClipRegion, NullBox, 1);
674    RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip);
675
676    /* clip and translate to the viewport */
677    if (portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
678        RegionRec VPReg;
679        BoxRec VPBox;
680
681        VPBox.x1 = 0;
682        VPBox.y1 = 0;
683        VPBox.x2 = screen->width;
684        VPBox.y2 = screen->height;
685
686        RegionInit(&VPReg, &VPBox, 1);
687        RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
688        RegionUninit(&VPReg);
689    }
690
691    /* that's all if it's totally obscured */
692    if (!RegionNotEmpty(&ClipRegion)) {
693        clippedAway = TRUE;
694        goto CLIP_VIDEO_BAILOUT;
695    }
696
697    ret =
698        (*portPriv->AdaptorRec->ReputImage) (portPriv->screen, portPriv->pDraw,
699                                             WinBox.x1, WinBox.y1, &ClipRegion,
700                                             portPriv->DevPriv.ptr);
701
702    portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF;
703
704 CLIP_VIDEO_BAILOUT:
705
706    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
707        (*portPriv->AdaptorRec->StopVideo) (portPriv->screen,
708                                            portPriv->DevPriv.ptr, FALSE);
709        portPriv->isOn = XV_PENDING;
710    }
711
712    /* This clip was copied and only good for one shot */
713    if (!portPriv->FreeCompositeClip)
714        portPriv->pCompositeClip = NULL;
715
716    RegionUninit(&WinRegion);
717    RegionUninit(&ClipRegion);
718
719    return ret;
720}
721
722static int
723KdXVReputAllVideo(WindowPtr pWin, void *data)
724{
725    KdXVWindowPtr WinPriv;
726
727    if (pWin->drawable.type != DRAWABLE_WINDOW)
728        return WT_DONTWALKCHILDREN;
729
730    WinPriv = GET_KDXV_WINDOW(pWin);
731
732    while (WinPriv) {
733        if (WinPriv->PortRec->type == XvInputMask)
734            KdXVReputVideo(WinPriv->PortRec);
735        else
736            KdXVRegetVideo(WinPriv->PortRec);
737        WinPriv = WinPriv->next;
738    }
739
740    return WT_WALKCHILDREN;
741}
742
743static int
744KdXVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv)
745{
746    KdXVWindowPtr winPriv, PrivRoot;
747
748    winPriv = PrivRoot = GET_KDXV_WINDOW(pWin);
749
750    /* Enlist our port in the window private */
751    while (winPriv) {
752        if (winPriv->PortRec == portPriv)       /* we're already listed */
753            break;
754        winPriv = winPriv->next;
755    }
756
757    if (!winPriv) {
758        winPriv = malloc(sizeof(KdXVWindowRec));
759        if (!winPriv)
760            return BadAlloc;
761        winPriv->PortRec = portPriv;
762        winPriv->next = PrivRoot;
763        dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv);
764    }
765    return Success;
766}
767
768static void
769KdXVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv)
770{
771    KdXVWindowPtr winPriv, prevPriv = NULL;
772
773    winPriv = GET_KDXV_WINDOW(pWin);
774
775    while (winPriv) {
776        if (winPriv->PortRec == portPriv) {
777            if (prevPriv)
778                prevPriv->next = winPriv->next;
779            else
780                dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv->next);
781            free(winPriv);
782            break;
783        }
784        prevPriv = winPriv;
785        winPriv = winPriv->next;
786    }
787    portPriv->pDraw = NULL;
788}
789
790/****  ScreenRec fields ****/
791
792static Bool
793KdXVDestroyWindow(WindowPtr pWin)
794{
795    ScreenPtr pScreen = pWin->drawable.pScreen;
796    KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen);
797    KdXVWindowPtr tmp, WinPriv = GET_KDXV_WINDOW(pWin);
798    int ret;
799
800    while (WinPriv) {
801        XvPortRecPrivatePtr pPriv = WinPriv->PortRec;
802
803        if (pPriv->isOn > XV_OFF) {
804            (*pPriv->AdaptorRec->StopVideo) (pPriv->screen, pPriv->DevPriv.ptr,
805                                             TRUE);
806            pPriv->isOn = XV_OFF;
807        }
808
809        pPriv->pDraw = NULL;
810        tmp = WinPriv;
811        WinPriv = WinPriv->next;
812        free(tmp);
813    }
814
815    dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, NULL);
816
817    pScreen->DestroyWindow = ScreenPriv->DestroyWindow;
818    ret = (*pScreen->DestroyWindow) (pWin);
819    pScreen->DestroyWindow = KdXVDestroyWindow;
820
821    return ret;
822}
823
824static void
825KdXVWindowExposures(WindowPtr pWin, RegionPtr reg1)
826{
827    ScreenPtr pScreen = pWin->drawable.pScreen;
828    KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen);
829    KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin);
830    KdXVWindowPtr pPrev;
831    XvPortRecPrivatePtr pPriv;
832    Bool AreasExposed;
833
834    AreasExposed = (WinPriv && reg1 && RegionNotEmpty(reg1));
835
836    pScreen->WindowExposures = ScreenPriv->WindowExposures;
837    (*pScreen->WindowExposures) (pWin, reg1);
838    pScreen->WindowExposures = KdXVWindowExposures;
839
840    /* filter out XClearWindow/Area */
841    if (!pWin->valdata)
842        return;
843
844    pPrev = NULL;
845
846    while (WinPriv) {
847        pPriv = WinPriv->PortRec;
848
849        /* Reput anyone with a reput function */
850
851        switch (pPriv->type) {
852        case XvInputMask:
853            KdXVReputVideo(pPriv);
854            break;
855        case XvOutputMask:
856            KdXVRegetVideo(pPriv);
857            break;
858        default:               /* overlaid still/image */
859            if (pPriv->AdaptorRec->ReputImage)
860                KdXVReputImage(pPriv);
861            else if (AreasExposed) {
862                KdXVWindowPtr tmp;
863
864                if (pPriv->isOn == XV_ON) {
865                    (*pPriv->AdaptorRec->StopVideo) (pPriv->screen,
866                                                     pPriv->DevPriv.ptr, FALSE);
867                    pPriv->isOn = XV_PENDING;
868                }
869                pPriv->pDraw = NULL;
870
871                if (!pPrev)
872                    dixSetPrivate(&pWin->devPrivates, KdXVWindowKey,
873                                  WinPriv->next);
874                else
875                    pPrev->next = WinPriv->next;
876                tmp = WinPriv;
877                WinPriv = WinPriv->next;
878                free(tmp);
879                continue;
880            }
881            break;
882        }
883        pPrev = WinPriv;
884        WinPriv = WinPriv->next;
885    }
886}
887
888static void
889KdXVClipNotify(WindowPtr pWin, int dx, int dy)
890{
891    ScreenPtr pScreen = pWin->drawable.pScreen;
892    KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen);
893    KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin);
894    KdXVWindowPtr tmp, pPrev = NULL;
895    XvPortRecPrivatePtr pPriv;
896    Bool visible = (pWin->visibility == VisibilityUnobscured) ||
897        (pWin->visibility == VisibilityPartiallyObscured);
898
899    while (WinPriv) {
900        pPriv = WinPriv->PortRec;
901
902        if (pPriv->pCompositeClip && pPriv->FreeCompositeClip)
903            RegionDestroy(pPriv->pCompositeClip);
904
905        pPriv->pCompositeClip = NULL;
906
907        /* Stop everything except images, but stop them too if the
908           window isn't visible.  But we only remove the images. */
909
910        if (pPriv->type || !visible) {
911            if (pPriv->isOn == XV_ON) {
912                (*pPriv->AdaptorRec->StopVideo) (pPriv->screen,
913                                                 pPriv->DevPriv.ptr, FALSE);
914                pPriv->isOn = XV_PENDING;
915            }
916
917            if (!pPriv->type) { /* overlaid still/image */
918                pPriv->pDraw = NULL;
919
920                if (!pPrev)
921                    dixSetPrivate(&pWin->devPrivates, KdXVWindowKey,
922                                  WinPriv->next);
923                else
924                    pPrev->next = WinPriv->next;
925                tmp = WinPriv;
926                WinPriv = WinPriv->next;
927                free(tmp);
928                continue;
929            }
930        }
931
932        pPrev = WinPriv;
933        WinPriv = WinPriv->next;
934    }
935
936    if (ScreenPriv->ClipNotify) {
937        pScreen->ClipNotify = ScreenPriv->ClipNotify;
938        (*pScreen->ClipNotify) (pWin, dx, dy);
939        pScreen->ClipNotify = KdXVClipNotify;
940    }
941}
942
943/**** Required XvScreenRec fields ****/
944
945static Bool
946KdXVCloseScreen(ScreenPtr pScreen)
947{
948    XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
949    KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen);
950    XvAdaptorPtr pa;
951    int c;
952
953    if (!ScreenPriv)
954        return TRUE;
955
956    pScreen->DestroyWindow = ScreenPriv->DestroyWindow;
957    pScreen->WindowExposures = ScreenPriv->WindowExposures;
958    pScreen->ClipNotify = ScreenPriv->ClipNotify;
959    pScreen->CloseScreen = ScreenPriv->CloseScreen;
960
961/*   fprintf(stderr,"XV: Unwrapping screen funcs\n"); */
962
963    for (c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) {
964        KdXVFreeAdaptor(pa);
965    }
966
967    free(pxvs->pAdaptors);
968    free(ScreenPriv);
969
970    return pScreen->CloseScreen(pScreen);
971}
972
973static Bool
974KdXVRunning(ScreenPtr pScreen)
975{
976    return (KdXVGeneration == serverGeneration && GET_XV_SCREEN(pScreen) != 0);
977}
978
979Bool
980KdXVEnable(ScreenPtr pScreen)
981{
982    if (!KdXVRunning(pScreen))
983        return TRUE;
984
985    WalkTree(pScreen, KdXVReputAllVideo, 0);
986
987    return TRUE;
988}
989
990void
991KdXVDisable(ScreenPtr pScreen)
992{
993    XvScreenPtr pxvs;
994    XvAdaptorPtr pAdaptor;
995    XvPortPtr pPort;
996    XvPortRecPrivatePtr pPriv;
997    int i, j;
998
999    if (!KdXVRunning(pScreen))
1000        return;
1001
1002    pxvs = GET_XV_SCREEN(pScreen);
1003
1004    for (i = 0; i < pxvs->nAdaptors; i++) {
1005        pAdaptor = &pxvs->pAdaptors[i];
1006        for (j = 0; j < pAdaptor->nPorts; j++) {
1007            pPort = &pAdaptor->pPorts[j];
1008            pPriv = (XvPortRecPrivatePtr) pPort->devPriv.ptr;
1009            if (pPriv->isOn > XV_OFF) {
1010
1011                (*pPriv->AdaptorRec->StopVideo) (pPriv->screen,
1012                                                 pPriv->DevPriv.ptr, TRUE);
1013                pPriv->isOn = XV_OFF;
1014
1015                if (pPriv->pCompositeClip && pPriv->FreeCompositeClip)
1016                    RegionDestroy(pPriv->pCompositeClip);
1017
1018                pPriv->pCompositeClip = NULL;
1019
1020                if (!pPriv->type && pPriv->pDraw) {     /* still */
1021                    KdXVRemovePortFromWindow((WindowPtr) pPriv->pDraw, pPriv);
1022                }
1023            }
1024        }
1025    }
1026}
1027
1028/**** XvAdaptorRec fields ****/
1029
1030static int
1031KdXVPutVideo(DrawablePtr pDraw,
1032             XvPortPtr pPort,
1033             GCPtr pGC,
1034             INT16 vid_x, INT16 vid_y,
1035             CARD16 vid_w, CARD16 vid_h,
1036             INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
1037{
1038    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1039
1040    KdScreenPriv(portPriv->screen->pScreen);
1041    int result;
1042
1043    /* No dumping video to pixmaps... For now anyhow */
1044    if (pDraw->type != DRAWABLE_WINDOW) {
1045        pPort->pDraw = (DrawablePtr) NULL;
1046        return BadAlloc;
1047    }
1048
1049    /* If we are changing windows, unregister our port in the old window */
1050    if (portPriv->pDraw && (portPriv->pDraw != pDraw))
1051        KdXVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1052
1053    /* Register our port with the new window */
1054    result = KdXVEnlistPortInWindow((WindowPtr) pDraw, portPriv);
1055    if (result != Success)
1056        return result;
1057
1058    portPriv->pDraw = pDraw;
1059    portPriv->type = XvInputMask;
1060
1061    /* save a copy of these parameters */
1062    portPriv->vid_x = vid_x;
1063    portPriv->vid_y = vid_y;
1064    portPriv->vid_w = vid_w;
1065    portPriv->vid_h = vid_h;
1066    portPriv->drw_x = drw_x;
1067    portPriv->drw_y = drw_y;
1068    portPriv->drw_w = drw_w;
1069    portPriv->drw_h = drw_h;
1070
1071    /* make sure we have the most recent copy of the clientClip */
1072    KdXVCopyClip(portPriv, pGC);
1073
1074    /* To indicate to the DI layer that we were successful */
1075    pPort->pDraw = pDraw;
1076
1077    if (!pScreenPriv->enabled)
1078        return Success;
1079
1080    return (KdXVReputVideo(portPriv));
1081}
1082
1083static int
1084KdXVPutStill(DrawablePtr pDraw,
1085             XvPortPtr pPort,
1086             GCPtr pGC,
1087             INT16 vid_x, INT16 vid_y,
1088             CARD16 vid_w, CARD16 vid_h,
1089             INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
1090{
1091    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1092    ScreenPtr pScreen = pDraw->pScreen;
1093
1094    KdScreenPriv(pScreen);
1095    KdScreenInfo *screen = pScreenPriv->screen;
1096    RegionRec WinRegion;
1097    RegionRec ClipRegion;
1098    BoxRec WinBox;
1099    int ret = Success;
1100    Bool clippedAway = FALSE;
1101
1102    if (pDraw->type != DRAWABLE_WINDOW)
1103        return BadAlloc;
1104
1105    if (!pScreenPriv->enabled)
1106        return Success;
1107
1108    WinBox.x1 = pDraw->x + drw_x;
1109    WinBox.y1 = pDraw->y + drw_y;
1110    WinBox.x2 = WinBox.x1 + drw_w;
1111    WinBox.y2 = WinBox.y1 + drw_h;
1112
1113    RegionInit(&WinRegion, &WinBox, 1);
1114    RegionInit(&ClipRegion, NullBox, 1);
1115    RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
1116
1117    if (portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
1118        RegionRec VPReg;
1119        BoxRec VPBox;
1120
1121        VPBox.x1 = 0;
1122        VPBox.y1 = 0;
1123        VPBox.x2 = screen->width;
1124        VPBox.y2 = screen->height;
1125
1126        RegionInit(&VPReg, &VPBox, 1);
1127        RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
1128        RegionUninit(&VPReg);
1129    }
1130
1131    if (portPriv->pDraw) {
1132        KdXVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1133    }
1134
1135    if (!RegionNotEmpty(&ClipRegion)) {
1136        clippedAway = TRUE;
1137        goto PUT_STILL_BAILOUT;
1138    }
1139
1140    ret = (*portPriv->AdaptorRec->PutStill) (portPriv->screen, pDraw,
1141                                             vid_x, vid_y, WinBox.x1, WinBox.y1,
1142                                             vid_w, vid_h, drw_w, drw_h,
1143                                             &ClipRegion,
1144                                             portPriv->DevPriv.ptr);
1145
1146    if ((ret == Success) &&
1147        (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) {
1148
1149        KdXVEnlistPortInWindow((WindowPtr) pDraw, portPriv);
1150        portPriv->isOn = XV_ON;
1151        portPriv->pDraw = pDraw;
1152        portPriv->drw_x = drw_x;
1153        portPriv->drw_y = drw_y;
1154        portPriv->drw_w = drw_w;
1155        portPriv->drw_h = drw_h;
1156        portPriv->type = 0;     /* no mask means it's transient and should
1157                                   not be reput once it's removed */
1158        pPort->pDraw = pDraw;   /* make sure we can get stop requests */
1159    }
1160
1161 PUT_STILL_BAILOUT:
1162
1163    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
1164        (*portPriv->AdaptorRec->StopVideo) (portPriv->screen,
1165                                            portPriv->DevPriv.ptr, FALSE);
1166        portPriv->isOn = XV_PENDING;
1167    }
1168
1169    RegionUninit(&WinRegion);
1170    RegionUninit(&ClipRegion);
1171
1172    return ret;
1173}
1174
1175static int
1176KdXVGetVideo(DrawablePtr pDraw,
1177             XvPortPtr pPort,
1178             GCPtr pGC,
1179             INT16 vid_x, INT16 vid_y,
1180             CARD16 vid_w, CARD16 vid_h,
1181             INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
1182{
1183    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1184    int result;
1185
1186    KdScreenPriv(portPriv->screen->pScreen);
1187
1188    /* No pixmaps... For now anyhow */
1189    if (pDraw->type != DRAWABLE_WINDOW) {
1190        pPort->pDraw = (DrawablePtr) NULL;
1191        return BadAlloc;
1192    }
1193
1194    /* If we are changing windows, unregister our port in the old window */
1195    if (portPriv->pDraw && (portPriv->pDraw != pDraw))
1196        KdXVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1197
1198    /* Register our port with the new window */
1199    result = KdXVEnlistPortInWindow((WindowPtr) pDraw, portPriv);
1200    if (result != Success)
1201        return result;
1202
1203    portPriv->pDraw = pDraw;
1204    portPriv->type = XvOutputMask;
1205
1206    /* save a copy of these parameters */
1207    portPriv->vid_x = vid_x;
1208    portPriv->vid_y = vid_y;
1209    portPriv->vid_w = vid_w;
1210    portPriv->vid_h = vid_h;
1211    portPriv->drw_x = drw_x;
1212    portPriv->drw_y = drw_y;
1213    portPriv->drw_w = drw_w;
1214    portPriv->drw_h = drw_h;
1215
1216    /* make sure we have the most recent copy of the clientClip */
1217    KdXVCopyClip(portPriv, pGC);
1218
1219    /* To indicate to the DI layer that we were successful */
1220    pPort->pDraw = pDraw;
1221
1222    if (!pScreenPriv->enabled)
1223        return Success;
1224
1225    return (KdXVRegetVideo(portPriv));
1226}
1227
1228static int
1229KdXVGetStill(DrawablePtr pDraw,
1230             XvPortPtr pPort,
1231             GCPtr pGC,
1232             INT16 vid_x, INT16 vid_y,
1233             CARD16 vid_w, CARD16 vid_h,
1234             INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
1235{
1236    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1237    ScreenPtr pScreen = pDraw->pScreen;
1238
1239    KdScreenPriv(pScreen);
1240    RegionRec WinRegion;
1241    RegionRec ClipRegion;
1242    BoxRec WinBox;
1243    int ret = Success;
1244    Bool clippedAway = FALSE;
1245
1246    if (pDraw->type != DRAWABLE_WINDOW)
1247        return BadAlloc;
1248
1249    if (!pScreenPriv->enabled)
1250        return Success;
1251
1252    WinBox.x1 = pDraw->x + drw_x;
1253    WinBox.y1 = pDraw->y + drw_y;
1254    WinBox.x2 = WinBox.x1 + drw_w;
1255    WinBox.y2 = WinBox.y1 + drw_h;
1256
1257    RegionInit(&WinRegion, &WinBox, 1);
1258    RegionInit(&ClipRegion, NullBox, 1);
1259    RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
1260
1261    if (portPriv->pDraw) {
1262        KdXVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1263    }
1264
1265    if (!RegionNotEmpty(&ClipRegion)) {
1266        clippedAway = TRUE;
1267        goto GET_STILL_BAILOUT;
1268    }
1269
1270    ret = (*portPriv->AdaptorRec->GetStill) (portPriv->screen, pDraw,
1271                                             vid_x, vid_y, WinBox.x1, WinBox.y1,
1272                                             vid_w, vid_h, drw_w, drw_h,
1273                                             &ClipRegion,
1274                                             portPriv->DevPriv.ptr);
1275
1276 GET_STILL_BAILOUT:
1277
1278    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
1279        (*portPriv->AdaptorRec->StopVideo) (portPriv->screen,
1280                                            portPriv->DevPriv.ptr, FALSE);
1281        portPriv->isOn = XV_PENDING;
1282    }
1283
1284    RegionUninit(&WinRegion);
1285    RegionUninit(&ClipRegion);
1286
1287    return ret;
1288}
1289
1290static int
1291KdXVStopVideo(XvPortPtr pPort, DrawablePtr pDraw)
1292{
1293    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1294
1295    KdScreenPriv(portPriv->screen->pScreen);
1296
1297    if (pDraw->type != DRAWABLE_WINDOW)
1298        return BadAlloc;
1299
1300    KdXVRemovePortFromWindow((WindowPtr) pDraw, portPriv);
1301
1302    if (!pScreenPriv->enabled)
1303        return Success;
1304
1305    /* Must free resources. */
1306
1307    if (portPriv->isOn > XV_OFF) {
1308        (*portPriv->AdaptorRec->StopVideo) (portPriv->screen,
1309                                            portPriv->DevPriv.ptr, TRUE);
1310        portPriv->isOn = XV_OFF;
1311    }
1312
1313    return Success;
1314}
1315
1316static int
1317KdXVSetPortAttribute(XvPortPtr pPort, Atom attribute, INT32 value)
1318{
1319    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1320
1321    return ((*portPriv->AdaptorRec->SetPortAttribute) (portPriv->screen,
1322                                                       attribute, value,
1323                                                       portPriv->DevPriv.ptr));
1324}
1325
1326static int
1327KdXVGetPortAttribute(XvPortPtr pPort, Atom attribute, INT32 *p_value)
1328{
1329    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1330
1331    return ((*portPriv->AdaptorRec->GetPortAttribute) (portPriv->screen,
1332                                                       attribute,
1333                                                       (int *) p_value,
1334                                                       portPriv->DevPriv.ptr));
1335}
1336
1337static int
1338KdXVQueryBestSize(XvPortPtr pPort,
1339                  CARD8 motion,
1340                  CARD16 vid_w, CARD16 vid_h,
1341                  CARD16 drw_w, CARD16 drw_h,
1342                  unsigned int *p_w, unsigned int *p_h)
1343{
1344    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1345
1346    (*portPriv->AdaptorRec->QueryBestSize) (portPriv->screen,
1347                                            (Bool) motion, vid_w, vid_h, drw_w,
1348                                            drw_h, p_w, p_h,
1349                                            portPriv->DevPriv.ptr);
1350
1351    return Success;
1352}
1353
1354static int
1355KdXVPutImage(DrawablePtr pDraw,
1356             XvPortPtr pPort,
1357             GCPtr pGC,
1358             INT16 src_x, INT16 src_y,
1359             CARD16 src_w, CARD16 src_h,
1360             INT16 drw_x, INT16 drw_y,
1361             CARD16 drw_w, CARD16 drw_h,
1362             XvImagePtr format,
1363             unsigned char *data, Bool sync, CARD16 width, CARD16 height)
1364{
1365    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1366    ScreenPtr pScreen = pDraw->pScreen;
1367
1368    KdScreenPriv(pScreen);
1369    RegionRec WinRegion;
1370    RegionRec ClipRegion;
1371    BoxRec WinBox;
1372    int ret = Success;
1373    Bool clippedAway = FALSE;
1374
1375    if (pDraw->type != DRAWABLE_WINDOW)
1376        return BadAlloc;
1377
1378    if (!pScreenPriv->enabled)
1379        return Success;
1380
1381    WinBox.x1 = pDraw->x + drw_x;
1382    WinBox.y1 = pDraw->y + drw_y;
1383    WinBox.x2 = WinBox.x1 + drw_w;
1384    WinBox.y2 = WinBox.y1 + drw_h;
1385
1386    RegionInit(&WinRegion, &WinBox, 1);
1387    RegionInit(&ClipRegion, NullBox, 1);
1388    RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
1389
1390    if (portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
1391        RegionRec VPReg;
1392        BoxRec VPBox;
1393
1394        VPBox.x1 = 0;
1395        VPBox.y1 = 0;
1396        VPBox.x2 = pScreen->width;
1397        VPBox.y2 = pScreen->height;
1398
1399        RegionInit(&VPReg, &VPBox, 1);
1400        RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
1401        RegionUninit(&VPReg);
1402    }
1403
1404    if (portPriv->pDraw) {
1405        KdXVRemovePortFromWindow((WindowPtr) (portPriv->pDraw), portPriv);
1406    }
1407
1408    if (!RegionNotEmpty(&ClipRegion)) {
1409        clippedAway = TRUE;
1410        goto PUT_IMAGE_BAILOUT;
1411    }
1412
1413    ret = (*portPriv->AdaptorRec->PutImage) (portPriv->screen, pDraw,
1414                                             src_x, src_y, WinBox.x1, WinBox.y1,
1415                                             src_w, src_h, drw_w, drw_h,
1416                                             format->id, data, width, height,
1417                                             sync, &ClipRegion,
1418                                             portPriv->DevPriv.ptr);
1419
1420    if ((ret == Success) &&
1421        (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) {
1422
1423        KdXVEnlistPortInWindow((WindowPtr) pDraw, portPriv);
1424        portPriv->isOn = XV_ON;
1425        portPriv->pDraw = pDraw;
1426        portPriv->drw_x = drw_x;
1427        portPriv->drw_y = drw_y;
1428        portPriv->drw_w = drw_w;
1429        portPriv->drw_h = drw_h;
1430        portPriv->type = 0;     /* no mask means it's transient and should
1431                                   not be reput once it's removed */
1432        pPort->pDraw = pDraw;   /* make sure we can get stop requests */
1433    }
1434
1435 PUT_IMAGE_BAILOUT:
1436
1437    if ((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
1438        (*portPriv->AdaptorRec->StopVideo) (portPriv->screen,
1439                                            portPriv->DevPriv.ptr, FALSE);
1440        portPriv->isOn = XV_PENDING;
1441    }
1442
1443    RegionUninit(&WinRegion);
1444    RegionUninit(&ClipRegion);
1445
1446    return ret;
1447}
1448
1449static int
1450KdXVQueryImageAttributes(XvPortPtr pPort,
1451                         XvImagePtr format,
1452                         CARD16 *width,
1453                         CARD16 *height, int *pitches, int *offsets)
1454{
1455    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) (pPort->devPriv.ptr);
1456
1457    return (*portPriv->AdaptorRec->QueryImageAttributes) (portPriv->screen,
1458                                                          format->id, width,
1459                                                          height, pitches,
1460                                                          offsets);
1461}
1462
1463/****************  Common video manipulation functions *******************/
1464
1465void
1466KdXVCopyPackedData(KdScreenInfo * screen, CARD8 *src, CARD8 *dst, int randr,
1467                   int srcPitch, int dstPitch, int srcW, int srcH, int top,
1468                   int left, int h, int w)
1469{
1470    int srcDown = srcPitch, srcRight = 2, srcNext;
1471    int p;
1472
1473    switch (randr & RR_Rotate_All) {
1474    case RR_Rotate_0:
1475        srcDown = srcPitch;
1476        srcRight = 2;
1477        break;
1478    case RR_Rotate_90:
1479        src += (srcH - 1) * 2;
1480        srcDown = -2;
1481        srcRight = srcPitch;
1482        break;
1483    case RR_Rotate_180:
1484        src += srcPitch * (srcH - 1) + (srcW - 1) * 2;
1485        srcDown = -srcPitch;
1486        srcRight = -2;
1487        break;
1488    case RR_Rotate_270:
1489        src += srcPitch * (srcW - 1);
1490        srcDown = 2;
1491        srcRight = -srcPitch;
1492        break;
1493    }
1494
1495    src = src + top * srcDown + left * srcRight;
1496
1497    w >>= 1;
1498    /* srcRight >>= 1; */
1499    srcNext = srcRight >> 1;
1500    while (h--) {
1501        CARD16 *s = (CARD16 *) src;
1502        CARD32 *d = (CARD32 *) dst;
1503
1504        p = w;
1505        while (p--) {
1506            *d++ = s[0] | (s[srcNext] << 16);
1507            s += srcRight;
1508        }
1509        src += srcPitch;
1510        dst += dstPitch;
1511    }
1512}
1513
1514void
1515KdXVCopyPlanarData(KdScreenInfo * screen, CARD8 *src, CARD8 *dst, int randr,
1516                   int srcPitch, int srcPitch2, int dstPitch, int srcW,
1517                   int srcH, int height, int top, int left, int h, int w,
1518                   int id)
1519{
1520    int i, j;
1521    CARD8 *src1, *src2, *src3, *dst1;
1522    int srcDown = srcPitch, srcDown2 = srcPitch2;
1523    int srcRight = 2, srcRight2 = 1, srcNext = 1;
1524
1525    /* compute source data pointers */
1526    src1 = src;
1527    src2 = src1 + height * srcPitch;
1528    src3 = src2 + (height >> 1) * srcPitch2;
1529    switch (randr & RR_Rotate_All) {
1530    case RR_Rotate_0:
1531        srcDown = srcPitch;
1532        srcDown2 = srcPitch2;
1533        srcRight = 2;
1534        srcRight2 = 1;
1535        srcNext = 1;
1536        break;
1537    case RR_Rotate_90:
1538        src1 = src1 + srcH - 1;
1539        src2 = src2 + (srcH >> 1) - 1;
1540        src3 = src3 + (srcH >> 1) - 1;
1541        srcDown = -1;
1542        srcDown2 = -1;
1543        srcRight = srcPitch * 2;
1544        srcRight2 = srcPitch2;
1545        srcNext = srcPitch;
1546        break;
1547    case RR_Rotate_180:
1548        src1 = src1 + srcPitch * (srcH - 1) + (srcW - 1);
1549        src2 = src2 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1);
1550        src3 = src3 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1);
1551        srcDown = -srcPitch;
1552        srcDown2 = -srcPitch2;
1553        srcRight = -2;
1554        srcRight2 = -1;
1555        srcNext = -1;
1556        break;
1557    case RR_Rotate_270:
1558        src1 = src1 + srcPitch * (srcW - 1);
1559        src2 = src2 + srcPitch2 * ((srcW >> 1) - 1);
1560        src3 = src3 + srcPitch2 * ((srcW >> 1) - 1);
1561        srcDown = 1;
1562        srcDown2 = 1;
1563        srcRight = -srcPitch * 2;
1564        srcRight2 = -srcPitch2;
1565        srcNext = -srcPitch;
1566        break;
1567    }
1568
1569    /* adjust for origin */
1570    src1 += top * srcDown + left * srcNext;
1571    src2 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2;
1572    src3 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2;
1573
1574    if (id == FOURCC_I420) {
1575        CARD8 *srct = src2;
1576
1577        src2 = src3;
1578        src3 = srct;
1579    }
1580
1581    dst1 = dst;
1582
1583    w >>= 1;
1584    for (j = 0; j < h; j++) {
1585        CARD32 *dst32 = (CARD32 *) dst1;
1586        CARD8 *s1l = src1;
1587        CARD8 *s1r = src1 + srcNext;
1588        CARD8 *s2 = src2;
1589        CARD8 *s3 = src3;
1590
1591        for (i = 0; i < w; i++) {
1592            *dst32++ = *s1l | (*s1r << 16) | (*s3 << 8) | (*s2 << 24);
1593            s1l += srcRight;
1594            s1r += srcRight;
1595            s2 += srcRight2;
1596            s3 += srcRight2;
1597        }
1598        src1 += srcDown;
1599        dst1 += dstPitch;
1600        if (j & 1) {
1601            src2 += srcDown2;
1602            src3 += srcDown2;
1603        }
1604    }
1605}
1606