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