nv_video.c revision d422ce2e
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include "xf86.h"
6#include "xf86_OSproc.h"
7#include "compiler.h"
8#include "pci_ids.h"
9#include "xf86Pci.h"
10#include "xf86fbman.h"
11#include "regionstr.h"
12
13#include "xf86xv.h"
14#include <X11/extensions/Xv.h>
15#include "dixstruct.h"
16#include "fourcc.h"
17
18#include "nv_include.h"
19#include "nv_dma.h"
20
21#define OFF_DELAY 	500  /* milliseconds */
22#define FREE_DELAY 	5000
23
24#define OFF_TIMER 	0x01
25#define FREE_TIMER	0x02
26#define CLIENT_VIDEO_ON	0x04
27
28#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
29
30#define NUM_BLIT_PORTS 32
31
32typedef struct _NVPortPrivRec {
33   short        brightness;
34   short        contrast;
35   short        saturation;
36   short        hue;
37   RegionRec    clip;
38   CARD32       colorKey;
39   Bool         autopaintColorKey;
40   Bool		doubleBuffer;
41   CARD32       videoStatus;
42   int		currentBuffer;
43   Time         videoTime;
44   Bool		grabbedByV4L;
45   Bool         iturbt_709;
46   Bool         blitter;
47   Bool         SyncToVBlank;
48   FBLinearPtr  linear;
49   int pitch;
50   int offset;
51} NVPortPrivRec, *NVPortPrivPtr;
52
53
54static XF86VideoAdaptorPtr NVSetupOverlayVideo(ScreenPtr);
55static XF86VideoAdaptorPtr NVSetupBlitVideo(ScreenPtr);
56
57static void NVStopOverlay (ScrnInfoPtr);
58static void NVPutOverlayImage(ScrnInfoPtr pScrnInfo,
59                              int offset,
60			      int id,
61			      int dstPitch,
62                              BoxPtr dstBox,
63			      int x1, int y1, int x2, int y2,
64                              short width, short height,
65                              short src_w, short src_h,
66                              short dst_w, short dst_h,
67                              RegionPtr cliplist);
68
69static int  NVSetOverlayPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
70static int  NVGetOverlayPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
71static int  NVSetBlitPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
72static int  NVGetBlitPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
73
74
75static void NVStopOverlayVideo(ScrnInfoPtr, pointer, Bool);
76static void NVStopBlitVideo(ScrnInfoPtr, pointer, Bool);
77
78static int  NVPutImage( ScrnInfoPtr, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, Bool, RegionPtr, pointer, DrawablePtr);
79
80static void NVQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, unsigned int *, unsigned int *, pointer);
81static int  NVQueryImageAttributes(ScrnInfoPtr, int, unsigned short *, unsigned short *,  int *, int *);
82
83static void NVVideoTimerCallback(ScrnInfoPtr, Time);
84
85static void NVInitOffscreenImages (ScreenPtr pScreen);
86
87
88#define GET_OVERLAY_PRIVATE(pNv) \
89   (NVPortPrivPtr)((pNv)->overlayAdaptor->pPortPrivates[0].ptr)
90
91#define GET_BLIT_PRIVATE(pNv) \
92   (NVPortPrivPtr)((pNv)->blitAdaptor->pPortPrivates[0].ptr)
93
94#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
95
96static Atom xvBrightness, xvContrast, xvColorKey, xvSaturation,
97            xvHue, xvAutopaintColorKey, xvSetDefaults, xvDoubleBuffer,
98            xvITURBT709, xvSyncToVBlank;
99
100/* client libraries expect an encoding */
101static XF86VideoEncodingRec DummyEncoding =
102{
103   0,
104   "XV_IMAGE",
105   2046, 2046,
106   {1, 1}
107};
108
109#define NUM_FORMATS_ALL 6
110
111XF86VideoFormatRec NVFormats[NUM_FORMATS_ALL] =
112{
113   {15, TrueColor}, {16, TrueColor}, {24, TrueColor},
114   {15, DirectColor}, {16, DirectColor}, {24, DirectColor}
115};
116
117#define NUM_OVERLAY_ATTRIBUTES 9
118XF86AttributeRec NVOverlayAttributes[NUM_OVERLAY_ATTRIBUTES] =
119{
120   {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
121   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
122   {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
123   {XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
124   {XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"},
125   {XvSettable | XvGettable, 0, 8191, "XV_CONTRAST"},
126   {XvSettable | XvGettable, 0, 8191, "XV_SATURATION"},
127   {XvSettable | XvGettable, 0, 360, "XV_HUE"},
128   {XvSettable | XvGettable, 0, 1, "XV_ITURBT_709"}
129};
130
131#define NUM_BLIT_ATTRIBUTES 2
132XF86AttributeRec NVBlitAttributes[NUM_BLIT_ATTRIBUTES] =
133{
134   {XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
135   {XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK"}
136};
137
138
139#define NUM_IMAGES_YUV 4
140#define NUM_IMAGES_ALL 5
141
142#define FOURCC_RGB 0x0000003
143#define XVIMAGE_RGB \
144   { \
145        FOURCC_RGB, \
146        XvRGB, \
147        LSBFirst, \
148        { 0x03, 0x00, 0x00, 0x00, \
149          0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
150        32, \
151        XvPacked, \
152        1, \
153        24, 0x00ff0000, 0x0000ff00, 0x000000ff, \
154        0, 0, 0, \
155        0, 0, 0, \
156        0, 0, 0, \
157        {'B','G','R','X',\
158          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \
159        XvTopToBottom \
160   }
161
162static XF86ImageRec NVImages[NUM_IMAGES_ALL] =
163{
164    XVIMAGE_YUY2,
165    XVIMAGE_YV12,
166    XVIMAGE_UYVY,
167    XVIMAGE_I420,
168    XVIMAGE_RGB
169};
170
171static void
172NVSetPortDefaults (ScrnInfoPtr pScrnInfo, NVPortPrivPtr pPriv)
173{
174    NVPtr pNv = NVPTR(pScrnInfo);
175
176    pPriv->brightness           = 0;
177    pPriv->contrast             = 4096;
178    pPriv->saturation           = 4096;
179    pPriv->hue                  = 0;
180    pPriv->colorKey             = pNv->videoKey;
181    pPriv->autopaintColorKey    = TRUE;
182    pPriv->doubleBuffer		= TRUE;
183    pPriv->iturbt_709           = FALSE;
184}
185
186
187void
188NVResetVideo (ScrnInfoPtr pScrnInfo)
189{
190    NVPtr          pNv     = NVPTR(pScrnInfo);
191    NVPortPrivPtr  pPriv   = GET_OVERLAY_PRIVATE(pNv);
192    int            satSine, satCosine;
193    double         angle;
194
195    angle = (double)pPriv->hue * 3.1415927 / 180.0;
196
197    satSine = pPriv->saturation * sin(angle);
198    if (satSine < -1024)
199        satSine = -1024;
200    satCosine = pPriv->saturation * cos(angle);
201    if (satCosine < -1024)
202        satCosine = -1024;
203
204    pNv->PMC[0x8910/4] = (pPriv->brightness << 16) | pPriv->contrast;
205    pNv->PMC[0x8914/4] = (pPriv->brightness << 16) | pPriv->contrast;
206    pNv->PMC[0x8918/4] = (satSine << 16) | (satCosine & 0xffff);
207    pNv->PMC[0x891C/4] = (satSine << 16) | (satCosine & 0xffff);
208    pNv->PMC[0x8b00/4] = pPriv->colorKey;
209}
210
211
212
213static void
214NVStopOverlay (ScrnInfoPtr pScrnInfo)
215{
216    NVPtr          pNv     = NVPTR(pScrnInfo);
217
218    pNv->PMC[0x00008704/4] = 1;
219}
220
221static FBLinearPtr
222NVAllocateOverlayMemory(
223   ScrnInfoPtr pScrn,
224   FBLinearPtr linear,
225   int size
226){
227   ScreenPtr pScreen;
228   FBLinearPtr new_linear;
229
230   if(linear) {
231        if(linear->size >= size)
232           return linear;
233
234        if(xf86ResizeOffscreenLinear(linear, size))
235           return linear;
236
237        xf86FreeOffscreenLinear(linear);
238   }
239
240   pScreen = xf86ScrnToScreen(pScrn);
241
242   new_linear = xf86AllocateOffscreenLinear(pScreen, size, 32,
243                                                NULL, NULL, NULL);
244
245   if(!new_linear) {
246        int max_size;
247
248        xf86QueryLargestOffscreenLinear(pScreen, &max_size, 32,
249                                                PRIORITY_EXTREME);
250
251        if(max_size < size)
252           return NULL;
253
254        xf86PurgeUnlockedOffscreenAreas(pScreen);
255        new_linear = xf86AllocateOffscreenLinear(pScreen, size, 32,
256                                                NULL, NULL, NULL);
257   }
258
259   return new_linear;
260}
261
262static void NVFreeOverlayMemory(ScrnInfoPtr pScrnInfo)
263{
264    NVPtr               pNv   = NVPTR(pScrnInfo);
265    NVPortPrivPtr  pPriv   = GET_OVERLAY_PRIVATE(pNv);
266
267    if(pPriv->linear) {
268        xf86FreeOffscreenLinear(pPriv->linear);
269	pPriv->linear = NULL;
270    }
271}
272
273
274static void NVFreeBlitMemory(ScrnInfoPtr pScrnInfo)
275{
276    NVPtr               pNv   = NVPTR(pScrnInfo);
277    NVPortPrivPtr  pPriv   = GET_BLIT_PRIVATE(pNv);
278
279    if(pPriv->linear) {
280        xf86FreeOffscreenLinear(pPriv->linear);
281        pPriv->linear = NULL;
282    }
283}
284
285
286void NVInitVideo (ScreenPtr pScreen)
287{
288    ScrnInfoPtr 	pScrn = xf86ScreenToScrn(pScreen);
289    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
290    XF86VideoAdaptorPtr overlayAdaptor = NULL;
291    XF86VideoAdaptorPtr blitAdaptor = NULL;
292    NVPtr         	pNv   = NVPTR(pScrn);
293    int 		num_adaptors;
294
295    if((pScrn->bitsPerPixel != 8) && (pNv->Architecture >= NV_ARCH_10) &&
296         ((pNv->Architecture <= NV_ARCH_30) ||
297            ((pNv->Chipset & 0xfff0) == 0x0040)))
298    {
299	overlayAdaptor = NVSetupOverlayVideo(pScreen);
300
301	if(overlayAdaptor)
302	    NVInitOffscreenImages(pScreen);
303    }
304
305    if((pScrn->bitsPerPixel != 8) && !pNv->NoAccel)
306        blitAdaptor = NVSetupBlitVideo(pScreen);
307
308    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
309
310    if(blitAdaptor || overlayAdaptor) {
311        int size = num_adaptors;
312
313        if(overlayAdaptor) size++;
314        if(blitAdaptor)    size++;
315
316        if((newAdaptors = malloc(size * sizeof(XF86VideoAdaptorPtr*)))) {
317            if(num_adaptors) {
318                 memcpy(newAdaptors, adaptors,
319                        num_adaptors * sizeof(XF86VideoAdaptorPtr));
320            }
321            if(overlayAdaptor) {
322                newAdaptors[num_adaptors] = overlayAdaptor;
323                num_adaptors++;
324	    }
325            if(blitAdaptor) {
326                newAdaptors[num_adaptors] = blitAdaptor;
327                num_adaptors++;
328            }
329	    adaptors = newAdaptors;
330        }
331    }
332
333    if (num_adaptors)
334        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
335
336    if (newAdaptors)
337	free(newAdaptors);
338}
339
340
341static XF86VideoAdaptorPtr
342NVSetupBlitVideo (ScreenPtr pScreen)
343{
344    ScrnInfoPtr pScrnInfo = xf86ScreenToScrn(pScreen);
345    NVPtr       pNv       = NVPTR(pScrnInfo);
346    XF86VideoAdaptorPtr adapt;
347    NVPortPrivPtr       pPriv;
348    int         i;
349
350    if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
351                             sizeof(NVPortPrivRec) +
352                             (sizeof(DevUnion) * NUM_BLIT_PORTS))))
353    {
354        return NULL;
355    }
356
357    adapt->type                 = XvWindowMask | XvInputMask | XvImageMask;
358    adapt->flags                = 0;
359    adapt->name                 = "NV Video Blitter";
360    adapt->nEncodings           = 1;
361    adapt->pEncodings           = &DummyEncoding;
362    adapt->nFormats             = NUM_FORMATS_ALL;
363    adapt->pFormats             = NVFormats;
364    adapt->nPorts               = NUM_BLIT_PORTS;
365    adapt->pPortPrivates        = (DevUnion*)(&adapt[1]);
366
367    pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_BLIT_PORTS]);
368    for(i = 0; i < NUM_BLIT_PORTS; i++)
369       adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
370
371    if(pNv->WaitVSyncPossible) {
372       adapt->pAttributes          = NVBlitAttributes;
373       adapt->nAttributes          = NUM_BLIT_ATTRIBUTES;
374    } else {
375       adapt->pAttributes          = NULL;
376       adapt->nAttributes          = 0;
377    }
378    adapt->pImages              = NVImages;
379    adapt->nImages              = NUM_IMAGES_ALL;
380    adapt->PutVideo             = NULL;
381    adapt->PutStill             = NULL;
382    adapt->GetVideo             = NULL;
383    adapt->GetStill             = NULL;
384    adapt->StopVideo            = NVStopBlitVideo;
385    adapt->SetPortAttribute     = NVSetBlitPortAttribute;
386    adapt->GetPortAttribute     = NVGetBlitPortAttribute;
387    adapt->QueryBestSize        = NVQueryBestSize;
388    adapt->PutImage             = NVPutImage;
389    adapt->QueryImageAttributes = NVQueryImageAttributes;
390
391    pPriv->videoStatus          = 0;
392    pPriv->grabbedByV4L         = FALSE;
393    pPriv->blitter              = TRUE;
394    pPriv->doubleBuffer         = FALSE;
395    pPriv->SyncToVBlank         = pNv->WaitVSyncPossible;
396
397    pNv->blitAdaptor            = adapt;
398
399    xvSyncToVBlank              = MAKE_ATOM("XV_SYNC_TO_VBLANK");
400
401    return adapt;
402}
403
404static XF86VideoAdaptorPtr
405NVSetupOverlayVideo (ScreenPtr pScreen)
406{
407    ScrnInfoPtr pScrnInfo = xf86ScreenToScrn(pScreen);
408    NVPtr       pNv       = NVPTR(pScrnInfo);
409    XF86VideoAdaptorPtr adapt;
410    NVPortPrivPtr       pPriv;
411
412    if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
413                             sizeof(NVPortPrivRec) +
414                             sizeof(DevUnion))))
415    {
416        return NULL;
417    }
418
419    adapt->type                 = XvWindowMask | XvInputMask | XvImageMask;
420    adapt->flags                = VIDEO_OVERLAID_IMAGES|VIDEO_CLIP_TO_VIEWPORT;
421    adapt->name                 = "NV Video Overlay";
422    adapt->nEncodings           = 1;
423    adapt->pEncodings           = &DummyEncoding;
424    adapt->nFormats             = NUM_FORMATS_ALL;
425    adapt->pFormats             = NVFormats;
426    adapt->nPorts               = 1;
427    adapt->pPortPrivates        = (DevUnion*)(&adapt[1]);
428    pPriv                       = (NVPortPrivPtr)(&adapt->pPortPrivates[1]);
429    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
430    adapt->pAttributes          = NVOverlayAttributes;
431    adapt->nAttributes          = NUM_OVERLAY_ATTRIBUTES;
432    adapt->pImages              = NVImages;
433    adapt->nImages              = NUM_IMAGES_YUV;
434    adapt->PutVideo             = NULL;
435    adapt->PutStill             = NULL;
436    adapt->GetVideo             = NULL;
437    adapt->GetStill             = NULL;
438    adapt->StopVideo            = NVStopOverlayVideo;
439    adapt->SetPortAttribute     = NVSetOverlayPortAttribute;
440    adapt->GetPortAttribute     = NVGetOverlayPortAttribute;
441    adapt->QueryBestSize        = NVQueryBestSize;
442    adapt->PutImage             = NVPutImage;
443    adapt->QueryImageAttributes = NVQueryImageAttributes;
444
445    pPriv->videoStatus		= 0;
446    pPriv->currentBuffer	= 0;
447    pPriv->grabbedByV4L		= FALSE;
448    pPriv->blitter              = FALSE;
449
450    NVSetPortDefaults (pScrnInfo, pPriv);
451
452    /* gotta uninit this someplace */
453    REGION_NULL(pScreen, &pPriv->clip);
454
455    pNv->overlayAdaptor		= adapt;
456
457    xvBrightness        = MAKE_ATOM("XV_BRIGHTNESS");
458    xvDoubleBuffer      = MAKE_ATOM("XV_DOUBLE_BUFFER");
459    xvContrast          = MAKE_ATOM("XV_CONTRAST");
460    xvColorKey          = MAKE_ATOM("XV_COLORKEY");
461    xvSaturation        = MAKE_ATOM("XV_SATURATION");
462    xvHue               = MAKE_ATOM("XV_HUE");
463    xvAutopaintColorKey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
464    xvSetDefaults       = MAKE_ATOM("XV_SET_DEFAULTS");
465    xvITURBT709         = MAKE_ATOM("XV_ITURBT_709");
466
467    NVResetVideo(pScrnInfo);
468
469    return adapt;
470}
471
472static void
473NVPutOverlayImage (
474    ScrnInfoPtr pScrnInfo,
475    int         offset,
476    int         id,
477    int         dstPitch,
478    BoxPtr      dstBox,
479    int         x1,
480    int         y1,
481    int		x2,
482    int		y2,
483    short       width,
484    short       height,
485    short       src_w,
486    short       src_h,
487    short       drw_w,
488    short       drw_h,
489    RegionPtr   clipBoxes
490)
491{
492    NVPtr          pNv     = NVPTR(pScrnInfo);
493    NVPortPrivPtr  pPriv   = GET_OVERLAY_PRIVATE(pNv);
494    int buffer = pPriv->currentBuffer;
495
496    /* paint the color key */
497    if(pPriv->autopaintColorKey &&
498       (pPriv->grabbedByV4L ||
499	!REGION_EQUAL(pScrnInfo->pScreen, &pPriv->clip, clipBoxes)))
500    {
501	/* we always paint V4L's color key */
502	if(!pPriv->grabbedByV4L)
503           REGION_COPY(pScrnInfo->pScreen, &pPriv->clip, clipBoxes);
504        xf86XVFillKeyHelper(pScrnInfo->pScreen, pPriv->colorKey, clipBoxes);
505    }
506
507    if(pNv->CurrentLayout.mode->Flags & V_DBLSCAN) {
508        dstBox->y1 <<= 1;
509        dstBox->y2 <<= 1;
510        drw_h <<= 1;
511    }
512
513    pNv->PMC[(0x8900/4) + buffer] = offset;
514    pNv->PMC[(0x8928/4) + buffer] = (height << 16) | width;
515    pNv->PMC[(0x8930/4) + buffer] = ((y1 << 4) & 0xffff0000) | (x1 >> 12);
516    pNv->PMC[(0x8938/4) + buffer] = (src_w << 20) / drw_w;
517    pNv->PMC[(0x8940/4) + buffer] = (src_h << 20) / drw_h;
518    pNv->PMC[(0x8948/4) + buffer] = (dstBox->y1 << 16) | dstBox->x1;
519    pNv->PMC[(0x8950/4) + buffer] = ((dstBox->y2 - dstBox->y1) << 16) |
520                               	       (dstBox->x2 - dstBox->x1);
521
522    dstPitch |= 1 << 20;   /* use color key */
523
524    if(id != FOURCC_UYVY)
525	dstPitch |= 1 << 16;
526    if(pPriv->iturbt_709)
527        dstPitch |= 1 << 24;
528
529    pNv->PMC[(0x8958/4) + buffer] = dstPitch;
530    pNv->PMC[0x00008704/4] = 0;
531    pNv->PMC[0x8700/4] = 1 << (buffer << 2);
532
533    pPriv->videoStatus = CLIENT_VIDEO_ON;
534}
535
536
537
538static void
539NVPutBlitImage (
540    ScrnInfoPtr pScrnInfo,
541    int         offset,
542    int         id,
543    int         dstPitch,
544    BoxPtr      dstBox,
545    int         x1,
546    int         y1,
547    int         x2,
548    int         y2,
549    short       width,
550    short       height,
551    short       src_w,
552    short       src_h,
553    short       drw_w,
554    short       drw_h,
555    RegionPtr   clipBoxes
556)
557{
558    NVPtr          pNv     = NVPTR(pScrnInfo);
559    NVPortPrivPtr  pPriv   = GET_BLIT_PRIVATE(pNv);
560    BoxPtr         pbox    = REGION_RECTS(clipBoxes);
561    int            nbox    = REGION_NUM_RECTS(clipBoxes);
562    CARD32         dsdx, dtdy, size, point, srcpoint, format;
563
564    dsdx = (src_w << 20) / drw_w;
565    dtdy = (src_h << 20) / drw_h;
566
567    size = ((dstBox->y2 - dstBox->y1) << 16) | (dstBox->x2 - dstBox->x1);
568    point = (dstBox->y1 << 16) | dstBox->x1;
569
570    dstPitch |= (STRETCH_BLIT_SRC_FORMAT_ORIGIN_CENTER << 16) |
571                (STRETCH_BLIT_SRC_FORMAT_FILTER_BILINEAR << 24);
572
573    srcpoint = ((y1 << 4) & 0xffff0000) | (x1 >> 12);
574
575    switch(id) {
576    case FOURCC_RGB:
577        format = STRETCH_BLIT_FORMAT_X8R8G8B8;
578        break;
579    case FOURCC_UYVY:
580        format = STRETCH_BLIT_FORMAT_UYVY;
581        break;
582    default:
583        format = STRETCH_BLIT_FORMAT_YUYV;
584        break;
585    }
586
587    if(pNv->CurrentLayout.depth == 15) {
588        NVDmaStart(pNv, SURFACE_FORMAT, 1);
589        NVDmaNext (pNv, SURFACE_FORMAT_DEPTH15);
590    }
591
592    if(pPriv->SyncToVBlank) {
593       NVDmaKickoff(pNv);
594       NVWaitVSync(pNv);
595    }
596
597    if(pNv->BlendingPossible) {
598       NVDmaStart(pNv, STRETCH_BLIT_FORMAT, 2);
599       NVDmaNext (pNv, format);
600       NVDmaNext (pNv, STRETCH_BLIT_OPERATION_COPY);
601    } else {
602       NVDmaStart(pNv, STRETCH_BLIT_FORMAT, 1);
603       NVDmaNext (pNv, format);
604    }
605
606    while(nbox--) {
607       NVDmaStart(pNv, RECT_SOLID_COLOR, 1);
608       NVDmaNext (pNv, 0);
609
610       NVDmaStart(pNv, STRETCH_BLIT_CLIP_POINT, 6);
611       NVDmaNext (pNv, (pbox->y1 << 16) | pbox->x1);
612       NVDmaNext (pNv, ((pbox->y2 - pbox->y1) << 16) | (pbox->x2 - pbox->x1));
613       NVDmaNext (pNv, point);
614       NVDmaNext (pNv, size);
615       NVDmaNext (pNv, dsdx);
616       NVDmaNext (pNv, dtdy);
617
618       NVDmaStart(pNv, STRETCH_BLIT_SRC_SIZE, 4);
619       NVDmaNext (pNv, (height << 16) | width);
620       NVDmaNext (pNv, dstPitch);
621       NVDmaNext (pNv, offset);
622       NVDmaNext (pNv, srcpoint);
623       pbox++;
624    }
625
626    if(pNv->CurrentLayout.depth == 15) {
627        NVDmaStart(pNv, SURFACE_FORMAT, 1);
628        NVDmaNext (pNv, SURFACE_FORMAT_DEPTH16);
629    }
630
631    NVDmaKickoff(pNv);
632#ifdef HAVE_XAA_H
633    SET_SYNC_FLAG(pNv->AccelInfoRec);
634#endif
635    pPriv->videoStatus = FREE_TIMER;
636    pPriv->videoTime = currentTime.milliseconds + FREE_DELAY;
637    pNv->VideoTimerCallback = NVVideoTimerCallback;
638}
639
640/*
641 * StopVideo
642 */
643static void NVStopOverlayVideo
644(
645    ScrnInfoPtr pScrnInfo,
646    pointer     data,
647    Bool        Exit
648)
649{
650    NVPtr pNv = NVPTR(pScrnInfo);
651    NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
652
653    if(pPriv->grabbedByV4L) return;
654
655    REGION_EMPTY(pScrnInfo->pScreen, &pPriv->clip);
656
657    if(Exit) {
658	if(pPriv->videoStatus & CLIENT_VIDEO_ON)
659            NVStopOverlay(pScrnInfo);
660	NVFreeOverlayMemory(pScrnInfo);
661	pPriv->videoStatus = 0;
662    } else {
663	if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
664	    pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
665	    pPriv->videoTime = currentTime.milliseconds + OFF_DELAY;
666	    pNv->VideoTimerCallback = NVVideoTimerCallback;
667	}
668    }
669}
670
671static void NVStopBlitVideo
672(
673    ScrnInfoPtr pScrnInfo,
674    pointer     data,
675    Bool        Exit
676)
677{
678}
679
680static int NVSetOverlayPortAttribute
681(
682    ScrnInfoPtr pScrnInfo,
683    Atom        attribute,
684    INT32       value,
685    pointer     data
686)
687{
688    NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
689
690    if (attribute == xvBrightness)
691    {
692        if ((value < -512) || (value > 512))
693            return BadValue;
694        pPriv->brightness = value;
695    }
696    else if (attribute == xvDoubleBuffer)
697    {
698        if ((value < 0) || (value > 1))
699            return BadValue;
700        pPriv->doubleBuffer = value;
701    }
702    else if (attribute == xvContrast)
703    {
704        if ((value < 0) || (value > 8191))
705            return BadValue;
706        pPriv->contrast = value;
707    }
708    else if (attribute == xvHue)
709    {
710        value %= 360;
711        if (value < 0)
712            value += 360;
713        pPriv->hue = value;
714    }
715    else if (attribute == xvSaturation)
716    {
717        if ((value < 0) || (value > 8191))
718            return BadValue;
719        pPriv->saturation = value;
720    }
721    else if (attribute == xvColorKey)
722    {
723        pPriv->colorKey = value;
724        REGION_EMPTY(pScrnInfo->pScreen, &pPriv->clip);
725    }
726    else if (attribute == xvAutopaintColorKey)
727    {
728        if ((value < 0) || (value > 1))
729            return BadValue;
730        pPriv->autopaintColorKey = value;
731    }
732    else if (attribute == xvITURBT709)
733    {
734        if ((value < 0) || (value > 1))
735            return BadValue;
736        pPriv->iturbt_709 = value;
737    }
738    else if (attribute == xvSetDefaults)
739    {
740        NVSetPortDefaults(pScrnInfo, pPriv);
741    }
742    else
743        return BadMatch;
744
745    NVResetVideo(pScrnInfo);
746    return Success;
747}
748
749
750static int NVGetOverlayPortAttribute
751(
752    ScrnInfoPtr  pScrnInfo,
753    Atom         attribute,
754    INT32       *value,
755    pointer      data
756)
757{
758    NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
759
760    if (attribute == xvBrightness)
761        *value = pPriv->brightness;
762    else if (attribute == xvDoubleBuffer)
763        *value = (pPriv->doubleBuffer) ? 1 : 0;
764    else if (attribute == xvContrast)
765        *value = pPriv->contrast;
766    else if (attribute == xvSaturation)
767        *value = pPriv->saturation;
768    else if (attribute == xvHue)
769        *value = pPriv->hue;
770    else if (attribute == xvColorKey)
771        *value = pPriv->colorKey;
772    else if (attribute == xvAutopaintColorKey)
773        *value = (pPriv->autopaintColorKey) ? 1 : 0;
774    else if (attribute == xvITURBT709)
775        *value = (pPriv->iturbt_709) ? 1 : 0;
776    else
777        return BadMatch;
778
779    return Success;
780}
781
782static int NVSetBlitPortAttribute
783(
784    ScrnInfoPtr pScrnInfo,
785    Atom        attribute,
786    INT32       value,
787    pointer     data
788)
789{
790    NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
791    NVPtr pNv = NVPTR(pScrnInfo);
792
793    if ((attribute == xvSyncToVBlank) && pNv->WaitVSyncPossible) {
794        if ((value < 0) || (value > 1))
795            return BadValue;
796        pPriv->SyncToVBlank = value;
797    } else
798    if (attribute == xvSetDefaults) {
799        pPriv->SyncToVBlank = pNv->WaitVSyncPossible;
800    } else
801       return BadMatch;
802
803    return Success;
804}
805
806static int NVGetBlitPortAttribute
807(
808    ScrnInfoPtr  pScrnInfo,
809    Atom         attribute,
810    INT32       *value,
811    pointer      data
812)
813{
814    NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
815
816    if(attribute == xvSyncToVBlank)
817       *value = (pPriv->SyncToVBlank) ? 1 : 0;
818    else
819       return BadMatch;
820
821    return Success;
822}
823
824
825/*
826 * QueryBestSize
827 */
828static void NVQueryBestSize
829(
830    ScrnInfoPtr   pScrnInfo,
831    Bool          motion,
832    short         vid_w,
833    short         vid_h,
834    short         drw_w,
835    short         drw_h,
836    unsigned int *p_w,
837    unsigned int *p_h,
838    pointer       data
839)
840{
841    if(vid_w > (drw_w << 3))
842	drw_w = vid_w >> 3;
843    if(vid_h > (drw_h << 3))
844	drw_h = vid_h >> 3;
845
846    *p_w = drw_w;
847    *p_h = drw_h;
848}
849
850static void NVCopyData420
851(
852    unsigned char *src1,
853    unsigned char *src2,
854    unsigned char *src3,
855    unsigned char *dst1,
856    int            srcPitch,
857    int            srcPitch2,
858    int            dstPitch,
859    int            h,
860    int            w
861)
862{
863   CARD32 *dst;
864   CARD8 *s1, *s2, *s3;
865   int i, j;
866
867   w >>= 1;
868
869   for(j = 0; j < h; j++) {
870        dst = (CARD32*)dst1;
871        s1 = src1;  s2 = src2;  s3 = src3;
872        i = w;
873        while(i > 4) {
874#if X_BYTE_ORDER == X_BIG_ENDIAN
875           dst[0] = (s1[0] << 24) | (s1[1] << 8) | (s3[0] << 16) | s2[0];
876           dst[1] = (s1[2] << 24) | (s1[3] << 8) | (s3[1] << 16) | s2[1];
877           dst[2] = (s1[4] << 24) | (s1[5] << 8) | (s3[2] << 16) | s2[2];
878           dst[3] = (s1[6] << 24) | (s1[7] << 8) | (s3[3] << 16) | s2[3];
879#else
880           dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
881           dst[1] = s1[2] | (s1[3] << 16) | (s3[1] << 8) | (s2[1] << 24);
882           dst[2] = s1[4] | (s1[5] << 16) | (s3[2] << 8) | (s2[2] << 24);
883           dst[3] = s1[6] | (s1[7] << 16) | (s3[3] << 8) | (s2[3] << 24);
884#endif
885           dst += 4; s2 += 4; s3 += 4; s1 += 8;
886           i -= 4;
887        }
888
889        while(i--) {
890#if X_BYTE_ORDER == X_BIG_ENDIAN
891           dst[0] = (s1[0] << 24) | (s1[1] << 8) | (s3[0] << 16) | s2[0];
892#else
893           dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
894#endif
895           dst++; s2++; s3++;
896           s1 += 2;
897        }
898
899        dst1 += dstPitch;
900        src1 += srcPitch;
901        if(j & 1) {
902            src2 += srcPitch2;
903            src3 += srcPitch2;
904        }
905   }
906}
907
908
909static void NVMoveDWORDS(
910   CARD32* dest,
911   CARD32* src,
912   int dwords )
913{
914     while(dwords & ~0x03) {
915        *dest = *src;
916        *(dest + 1) = *(src + 1);
917        *(dest + 2) = *(src + 2);
918        *(dest + 3) = *(src + 3);
919        src += 4;
920        dest += 4;
921        dwords -= 4;
922     }
923     if(!dwords) return;
924     *dest = *src;
925     if(dwords == 1) return;
926     *(dest + 1) = *(src + 1);
927     if(dwords == 2) return;
928     *(dest + 2) = *(src + 2);
929}
930
931#if X_BYTE_ORDER == X_BIG_ENDIAN
932static void NVMoveDWORDSSwapped(
933   CARD32* dest,
934   CARD8* src,
935   int dwords )
936{
937     while(dwords--) {
938        *dest++ = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
939        src += 4;
940     }
941}
942#endif
943
944static void NVCopyData422
945(
946  unsigned char *src,
947  unsigned char *dst,
948  int            srcPitch,
949  int            dstPitch,
950  int            h,
951  int            w
952)
953{
954    w >>= 1;  /* pixels to DWORDS */
955    while(h--) {
956        NVMoveDWORDS((CARD32*)dst, (CARD32*)src, w);
957        src += srcPitch;
958        dst += dstPitch;
959    }
960}
961
962static void NVCopyDataRGB
963(
964  unsigned char *src,
965  unsigned char *dst,
966  int            srcPitch,
967  int            dstPitch,
968  int            h,
969  int            w
970)
971{
972    while(h--) {
973#if X_BYTE_ORDER == X_BIG_ENDIAN
974        NVMoveDWORDSSwapped((CARD32*)dst, (CARD8*)src, w);
975#else
976        NVMoveDWORDS((CARD32*)dst, (CARD32*)src, w);
977#endif
978        src += srcPitch;
979        dst += dstPitch;
980    }
981}
982
983
984/*
985 * PutImage
986 */
987static int NVPutImage
988(
989    ScrnInfoPtr  pScrnInfo,
990    short        src_x,
991    short        src_y,
992    short        drw_x,
993    short        drw_y,
994    short        src_w,
995    short        src_h,
996    short        drw_w,
997    short        drw_h,
998    int          id,
999    unsigned char *buf,
1000    short        width,
1001    short        height,
1002    Bool         Sync,
1003    RegionPtr    clipBoxes,
1004    pointer      data,
1005    DrawablePtr  pDraw
1006)
1007{
1008    NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
1009    NVPtr pNv = NVPTR(pScrnInfo);
1010    INT32 xa, xb, ya, yb;
1011    unsigned char *dst_start;
1012    int newSize, offset, s2offset, s3offset;
1013    int srcPitch, srcPitch2, dstPitch;
1014    int top, left, right, bottom, npixels, nlines, bpp;
1015    Bool skip = FALSE;
1016    BoxRec dstBox;
1017    CARD32 tmp;
1018
1019   /*
1020    * s2offset, s3offset - byte offsets into U and V plane of the
1021    *                      source where copying starts.  Y plane is
1022    *                      done by editing "buf".
1023    *
1024    * offset - byte offset to the first line of the destination.
1025    *
1026    * dst_start - byte address to the first displayed pel.
1027    *
1028    */
1029
1030    if(pPriv->grabbedByV4L) return Success;
1031
1032    /* make the compiler happy */
1033    s2offset = s3offset = srcPitch2 = 0;
1034
1035    if(!pPriv->blitter) {
1036       if(src_w > (drw_w << 3))
1037          drw_w = src_w >> 3;
1038       if(src_h > (drw_h << 3))
1039          drw_h = src_h >> 3;
1040    }
1041
1042    /* Clip */
1043    xa = src_x;
1044    xb = src_x + src_w;
1045    ya = src_y;
1046    yb = src_y + src_h;
1047
1048    dstBox.x1 = drw_x;
1049    dstBox.x2 = drw_x + drw_w;
1050    dstBox.y1 = drw_y;
1051    dstBox.y2 = drw_y + drw_h;
1052
1053    if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes,
1054                              width, height))
1055    	return Success;
1056
1057    if(!pPriv->blitter) {
1058        dstBox.x1 -= pScrnInfo->frameX0;
1059        dstBox.x2 -= pScrnInfo->frameX0;
1060        dstBox.y1 -= pScrnInfo->frameY0;
1061        dstBox.y2 -= pScrnInfo->frameY0;
1062    }
1063
1064    bpp = pScrnInfo->bitsPerPixel >> 3;
1065
1066    switch(id) {
1067    case FOURCC_YV12:
1068    case FOURCC_I420:
1069        srcPitch = (width + 3) & ~3;	/* of luma */
1070        s2offset = srcPitch * height;
1071        srcPitch2 = ((width >> 1) + 3) & ~3;
1072        s3offset = (srcPitch2 * (height >> 1)) + s2offset;
1073        dstPitch = ((width << 1) + 63) & ~63;
1074        break;
1075    case FOURCC_UYVY:
1076    case FOURCC_YUY2:
1077        srcPitch = width << 1;
1078        dstPitch = ((width << 1) + 63) & ~63;
1079        break;
1080    case FOURCC_RGB:
1081        srcPitch = width << 2;
1082        dstPitch = ((width << 2) + 63) & ~63;
1083        break;
1084    default:
1085        return BadImplementation;
1086    }
1087
1088    newSize = height * dstPitch / bpp;
1089
1090    if(pPriv->doubleBuffer)
1091	newSize <<= 1;
1092
1093    pPriv->linear = NVAllocateOverlayMemory(pScrnInfo,
1094					    pPriv->linear,
1095					    newSize);
1096
1097    if(!pPriv->linear) return BadAlloc;
1098
1099    offset = pPriv->linear->offset * bpp;
1100
1101    if(pPriv->doubleBuffer) {
1102        int mask = 1 << (pPriv->currentBuffer << 2);
1103
1104#if 0
1105        /* burn the CPU until the next buffer is available */
1106        while(pNv->PMC[0x00008700/4] & mask);
1107#else
1108        /* overwrite the newest buffer if there's not one free */
1109        if(pNv->PMC[0x00008700/4] & mask) {
1110           if(!pPriv->currentBuffer)
1111              offset += (newSize * bpp) >> 1;
1112           skip = TRUE;
1113        } else
1114#endif
1115        if(pPriv->currentBuffer)
1116            offset += (newSize * bpp) >> 1;
1117    }
1118
1119    dst_start = pNv->FbStart + offset;
1120
1121    /* We need to enlarge the copied rectangle by a pixel so the HW
1122       filtering doesn't pick up junk laying outside of the source */
1123
1124    left = (xa - 0x00010000) >> 16;
1125    if(left < 0) left = 0;
1126    top = (ya - 0x00010000) >> 16;
1127    if(top < 0) top = 0;
1128    right = (xb + 0x0001ffff) >> 16;
1129    if(right > width) right = width;
1130    bottom = (yb + 0x0001ffff) >> 16;
1131    if(bottom > height) bottom = height;
1132
1133    if(pPriv->blitter) NVSync(pScrnInfo);
1134
1135    switch(id) {
1136    case FOURCC_YV12:
1137    case FOURCC_I420:
1138        left &= ~1;
1139        npixels = ((right + 1) & ~1) - left;
1140        top &= ~1;
1141        nlines = ((bottom + 1) & ~1) - top;
1142
1143        dst_start += (left << 1) + (top * dstPitch);
1144        tmp = ((top >> 1) * srcPitch2) + (left >> 1);
1145        s2offset += tmp;
1146        s3offset += tmp;
1147        if(id == FOURCC_I420) {
1148           tmp = s2offset;
1149           s2offset = s3offset;
1150           s3offset = tmp;
1151        }
1152        NVCopyData420(buf + (top * srcPitch) + left,
1153				buf + s2offset, buf + s3offset,
1154				dst_start, srcPitch, srcPitch2,
1155				dstPitch, nlines, npixels);
1156        break;
1157    case FOURCC_UYVY:
1158    case FOURCC_YUY2:
1159        left &= ~1;
1160        npixels = ((right + 1) & ~1) - left;
1161        nlines = bottom - top;
1162
1163        left <<= 1;
1164        buf += (top * srcPitch) + left;
1165        dst_start += left + (top * dstPitch);
1166
1167        NVCopyData422(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
1168        break;
1169    case FOURCC_RGB:
1170        npixels = right - left;
1171        nlines = bottom - top;
1172
1173        left <<= 2;
1174        buf += (top * srcPitch) + left;
1175        dst_start += left + (top * dstPitch);
1176
1177        NVCopyDataRGB(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
1178        break;
1179    default:
1180        return BadImplementation;
1181    }
1182
1183    if(!skip) {
1184       if(pPriv->blitter) {
1185            NVPutBlitImage(pScrnInfo, offset, id, dstPitch, &dstBox,
1186                           xa, ya, xb, yb,
1187                           width, height, src_w, src_h, drw_w, drw_h,
1188                           clipBoxes);
1189       } else {
1190            NVPutOverlayImage(pScrnInfo, offset, id, dstPitch, &dstBox,
1191                             xa, ya, xb, yb,
1192                             width, height, src_w, src_h, drw_w, drw_h,
1193                             clipBoxes);
1194            pPriv->currentBuffer ^= 1;
1195       }
1196    }
1197
1198    return Success;
1199}
1200/*
1201 * QueryImageAttributes
1202 */
1203static int NVQueryImageAttributes
1204(
1205    ScrnInfoPtr pScrnInfo,
1206    int         id,
1207    unsigned short *w,
1208    unsigned short *h,
1209    int         *pitches,
1210    int         *offsets
1211)
1212{
1213    int size, tmp;
1214
1215    if(*w > 2046)
1216        *w = 2046;
1217    if(*h > 2046)
1218        *h = 2046;
1219
1220    *w = (*w + 1) & ~1;
1221    if (offsets)
1222        offsets[0] = 0;
1223
1224    switch (id)
1225    {
1226        case FOURCC_YV12:
1227        case FOURCC_I420:
1228            *h = (*h + 1) & ~1;
1229            size = (*w + 3) & ~3;
1230            if (pitches)
1231                pitches[0] = size;
1232            size *= *h;
1233            if (offsets)
1234                offsets[1] = size;
1235            tmp = ((*w >> 1) + 3) & ~3;
1236            if (pitches)
1237                pitches[1] = pitches[2] = tmp;
1238            tmp *= (*h >> 1);
1239            size += tmp;
1240            if (offsets)
1241                offsets[2] = size;
1242            size += tmp;
1243            break;
1244        case FOURCC_UYVY:
1245        case FOURCC_YUY2:
1246            size = *w << 1;
1247            if (pitches)
1248                pitches[0] = size;
1249            size *= *h;
1250            break;
1251        case FOURCC_RGB:
1252            size = *w << 2;
1253            if(pitches)
1254               pitches[0] = size;
1255            size *= *h;
1256            break;
1257        default:
1258            *w = *h = size = 0;
1259            break;
1260    }
1261    return size;
1262}
1263
1264static void NVVideoTimerCallback
1265(
1266    ScrnInfoPtr pScrnInfo,
1267    Time currentTime
1268)
1269{
1270    NVPtr         pNv = NVPTR(pScrnInfo);
1271    NVPortPrivPtr pOverPriv = NULL;
1272    NVPortPrivPtr pBlitPriv = NULL;
1273    Bool needCallback = FALSE;
1274
1275    if(!pScrnInfo->vtSema) return;
1276
1277    if(pNv->overlayAdaptor) {
1278	pOverPriv = GET_OVERLAY_PRIVATE(pNv);
1279	if(!pOverPriv->videoStatus)
1280	   pOverPriv = NULL;
1281    }
1282
1283    if(pNv->blitAdaptor) {
1284        pBlitPriv = GET_BLIT_PRIVATE(pNv);
1285        if(!pBlitPriv->videoStatus)
1286           pBlitPriv = NULL;
1287    }
1288
1289    if(pOverPriv) {
1290         if(pOverPriv->videoTime < currentTime) {
1291	    if(pOverPriv->videoStatus & OFF_TIMER) {
1292		NVStopOverlay(pScrnInfo);
1293		pOverPriv->videoStatus = FREE_TIMER;
1294                pOverPriv->videoTime = currentTime + FREE_DELAY;
1295                needCallback = TRUE;
1296	    } else
1297            if(pOverPriv->videoStatus & FREE_TIMER) {
1298		NVFreeOverlayMemory(pScrnInfo);
1299		pOverPriv->videoStatus = 0;
1300	    }
1301	 } else {
1302            needCallback = TRUE;
1303         }
1304    }
1305
1306    if(pBlitPriv) {
1307        if(pBlitPriv->videoTime < currentTime) {
1308            NVFreeBlitMemory(pScrnInfo);
1309            pBlitPriv->videoStatus = 0;
1310        } else {
1311            needCallback = TRUE;
1312        }
1313    }
1314
1315    pNv->VideoTimerCallback = needCallback ? NVVideoTimerCallback : NULL;
1316}
1317
1318
1319/***** Exported offscreen surface stuff ****/
1320
1321
1322static int
1323NVAllocSurface (
1324    ScrnInfoPtr pScrnInfo,
1325    int id,
1326    unsigned short w,
1327    unsigned short h,
1328    XF86SurfacePtr surface
1329)
1330{
1331    NVPtr pNv = NVPTR(pScrnInfo);
1332    NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1333    int size, bpp;
1334
1335    bpp = pScrnInfo->bitsPerPixel >> 3;
1336
1337    if(pPriv->grabbedByV4L) return BadAlloc;
1338
1339    if((w > 2046) || (h > 2046)) return BadValue;
1340
1341    w = (w + 1) & ~1;
1342    pPriv->pitch = ((w << 1) + 63) & ~63;
1343    size = h * pPriv->pitch / bpp;
1344
1345    pPriv->linear = NVAllocateOverlayMemory(pScrnInfo, pPriv->linear,
1346					    size);
1347
1348    if(!pPriv->linear) return BadAlloc;
1349
1350    pPriv->offset = pPriv->linear->offset * bpp;
1351
1352    surface->width = w;
1353    surface->height = h;
1354    surface->pScrn = pScrnInfo;
1355    surface->pitches = &pPriv->pitch;
1356    surface->offsets = &pPriv->offset;
1357    surface->devPrivate.ptr = (pointer)pPriv;
1358    surface->id = id;
1359
1360    /* grab the video */
1361    NVStopOverlay(pScrnInfo);
1362    pPriv->videoStatus = 0;
1363    REGION_EMPTY(pScrnInfo->pScreen, &pPriv->clip);
1364    pPriv->grabbedByV4L = TRUE;
1365
1366    return Success;
1367}
1368
1369static int
1370NVStopSurface (XF86SurfacePtr surface)
1371{
1372    NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1373
1374    if(pPriv->grabbedByV4L && pPriv->videoStatus) {
1375	NVStopOverlay(surface->pScrn);
1376	pPriv->videoStatus = 0;
1377    }
1378
1379    return Success;
1380}
1381
1382static int
1383NVFreeSurface (XF86SurfacePtr surface)
1384{
1385    NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1386
1387    if(pPriv->grabbedByV4L) {
1388	NVStopSurface(surface);
1389	NVFreeOverlayMemory(surface->pScrn);
1390	pPriv->grabbedByV4L = FALSE;
1391    }
1392
1393    return Success;
1394}
1395
1396static int
1397NVGetSurfaceAttribute (
1398    ScrnInfoPtr pScrnInfo,
1399    Atom attribute,
1400    INT32 *value
1401)
1402{
1403    NVPtr pNv = NVPTR(pScrnInfo);
1404    NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1405
1406    return NVGetOverlayPortAttribute(pScrnInfo, attribute, value, (pointer)pPriv);
1407}
1408
1409static int
1410NVSetSurfaceAttribute(
1411    ScrnInfoPtr pScrnInfo,
1412    Atom attribute,
1413    INT32 value
1414)
1415{
1416    NVPtr pNv = NVPTR(pScrnInfo);
1417    NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1418
1419    return NVSetOverlayPortAttribute(pScrnInfo, attribute, value, (pointer)pPriv);
1420}
1421
1422static int
1423NVDisplaySurface (
1424    XF86SurfacePtr surface,
1425    short src_x, short src_y,
1426    short drw_x, short drw_y,
1427    short src_w, short src_h,
1428    short drw_w, short drw_h,
1429    RegionPtr clipBoxes
1430)
1431{
1432    ScrnInfoPtr pScrnInfo = surface->pScrn;
1433    NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1434    INT32 xa, xb, ya, yb;
1435    BoxRec dstBox;
1436
1437    if(!pPriv->grabbedByV4L) return Success;
1438
1439    if(src_w > (drw_w << 3))
1440	drw_w = src_w >> 3;
1441    if(src_h > (drw_h << 3))
1442	drw_h = src_h >> 3;
1443
1444    /* Clip */
1445    xa = src_x;
1446    xb = src_x + src_w;
1447    ya = src_y;
1448    yb = src_y + src_h;
1449
1450    dstBox.x1 = drw_x;
1451    dstBox.x2 = drw_x + drw_w;
1452    dstBox.y1 = drw_y;
1453    dstBox.y2 = drw_y + drw_h;
1454
1455    if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes,
1456		    surface->width, surface->height))
1457    {
1458        return Success;
1459    }
1460
1461    dstBox.x1 -= pScrnInfo->frameX0;
1462    dstBox.x2 -= pScrnInfo->frameX0;
1463    dstBox.y1 -= pScrnInfo->frameY0;
1464    dstBox.y2 -= pScrnInfo->frameY0;
1465
1466    pPriv->currentBuffer = 0;
1467
1468    NVPutOverlayImage (pScrnInfo, surface->offsets[0], surface->id,
1469			surface->pitches[0], &dstBox, xa, ya, xb, yb,
1470			surface->width, surface->height, src_w, src_h,
1471			drw_w, drw_h, clipBoxes);
1472
1473    return Success;
1474}
1475
1476XF86OffscreenImageRec NVOffscreenImages[2] =
1477{
1478 {
1479   &NVImages[0],
1480   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1481   NVAllocSurface,
1482   NVFreeSurface,
1483   NVDisplaySurface,
1484   NVStopSurface,
1485   NVGetSurfaceAttribute,
1486   NVSetSurfaceAttribute,
1487   2046, 2046,
1488   NUM_OVERLAY_ATTRIBUTES - 1,
1489   &NVOverlayAttributes[1]
1490  },
1491 {
1492   &NVImages[2],
1493   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1494   NVAllocSurface,
1495   NVFreeSurface,
1496   NVDisplaySurface,
1497   NVStopSurface,
1498   NVGetSurfaceAttribute,
1499   NVSetSurfaceAttribute,
1500   2046, 2046,
1501   NUM_OVERLAY_ATTRIBUTES - 1,
1502   &NVOverlayAttributes[1]
1503  },
1504};
1505
1506static void
1507NVInitOffscreenImages (ScreenPtr pScreen)
1508{
1509    xf86XVRegisterOffscreenImages(pScreen, NVOffscreenImages, 2);
1510}
1511