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