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