Xv: nforce2 overlay can do yv12
[nouveau] / src / nv_video.c
1 /*
2  * Copyright 2007 Arthur Huillet
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "xf86.h"
29 #include "xf86_OSproc.h"
30 #include "xf86Resources.h"
31 #include "compiler.h"
32 #include "xf86PciInfo.h"
33 #include "xf86Pci.h"
34 #include "xf86fbman.h"
35 #include "regionstr.h"
36
37 #include "xf86xv.h"
38 #include <X11/extensions/Xv.h>
39 #include "exa.h"
40 #include "damage.h"
41 #include "dixstruct.h"
42 #include "fourcc.h"
43
44 #include "nv_include.h"
45 #include "nv_dma.h"
46
47 #define IMAGE_MAX_W 2046
48 #define IMAGE_MAX_H 2046
49
50 #define OFF_DELAY       500  /* milliseconds */
51 #define FREE_DELAY      5000
52
53 #define OFF_TIMER       0x01
54 #define FREE_TIMER      0x02
55 #define CLIENT_VIDEO_ON 0x04
56
57 #define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
58
59 #define NUM_BLIT_PORTS 32
60
61 /* Value taken by pPriv -> currentHostBuffer when we failed to allocate the two private buffers in TT memory, so that we can catch this case
62 and attempt no other allocation afterwards (performance reasons) */
63 #define NO_PRIV_HOST_BUFFER_AVAILABLE 9999 
64
65 typedef struct _NVPortPrivRec {
66         short           brightness;
67         short           contrast;
68         short           saturation;
69         short           hue;
70         RegionRec       clip;
71         CARD32          colorKey;
72         Bool            autopaintColorKey;
73         Bool            doubleBuffer;
74         CARD32          videoStatus;
75         int             currentBuffer;
76         Time            videoTime;
77         int             overlayCRTC;
78         Bool            grabbedByV4L;
79         Bool            iturbt_709;
80         Bool            blitter;
81         Bool            SyncToVBlank;
82         struct nouveau_bo *video_mem;
83         int             pitch;
84         int             offset;
85         struct nouveau_bo *TT_mem_chunk[2];
86         int             currentHostBuffer;
87         struct nouveau_notifier *DMANotifier[2];
88 } NVPortPrivRec, *NVPortPrivPtr;
89
90
91 /* Xv DMA notifiers status tracing */
92
93 enum {
94 XV_DMA_NOTIFIER_NOALLOC=0, //notifier not allocated 
95 XV_DMA_NOTIFIER_INUSE=1,
96 XV_DMA_NOTIFIER_FREE=2, //notifier allocated, ready for use
97 };
98
99 /* We have six notifiers available, they are not allocated at startup */
100 int XvDMANotifierStatus[6]= { XV_DMA_NOTIFIER_NOALLOC , XV_DMA_NOTIFIER_NOALLOC , XV_DMA_NOTIFIER_NOALLOC ,
101                                         XV_DMA_NOTIFIER_NOALLOC , XV_DMA_NOTIFIER_NOALLOC , XV_DMA_NOTIFIER_NOALLOC };
102 struct nouveau_notifier *XvDMANotifiers[6];
103
104 /* NVPutImage action flags */
105 enum {
106                 IS_YV12 = 1,
107                 IS_YUY2 = 2,
108                 CONVERT_TO_YUY2=4,
109                 USE_OVERLAY=8,
110                 SWAP_UV=16,
111                 IS_RGB=32, //I am not sure how long we will support it
112         };
113         
114 #define GET_OVERLAY_PRIVATE(pNv) \
115         (NVPortPrivPtr)((pNv)->overlayAdaptor->pPortPrivates[0].ptr)
116
117 #define GET_BLIT_PRIVATE(pNv) \
118         (NVPortPrivPtr)((pNv)->blitAdaptor->pPortPrivates[0].ptr)
119
120 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
121
122 static Atom xvBrightness, xvContrast, xvColorKey, xvSaturation, 
123             xvHue, xvAutopaintColorKey, xvSetDefaults, xvDoubleBuffer,
124             xvITURBT709, xvSyncToVBlank, xvOnCRTCNb;
125
126 /* client libraries expect an encoding */
127 static XF86VideoEncodingRec DummyEncoding =
128
129         0,
130         "XV_IMAGE",
131         IMAGE_MAX_W, IMAGE_MAX_H,
132         {1, 1}
133 };
134
135 #define NUM_FORMATS_ALL 6
136
137 XF86VideoFormatRec NVFormats[NUM_FORMATS_ALL] = 
138 {
139         {15, TrueColor}, {16, TrueColor}, {24, TrueColor},
140         {15, DirectColor}, {16, DirectColor}, {24, DirectColor}
141 };
142
143 #define NUM_NV04_OVERLAY_ATTRIBUTES 1
144 XF86AttributeRec NV04OverlayAttributes[NUM_NV04_OVERLAY_ATTRIBUTES] =
145 {
146         {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
147 };
148
149
150 #define NUM_OVERLAY_ATTRIBUTES 10
151 XF86AttributeRec NVOverlayAttributes[NUM_OVERLAY_ATTRIBUTES] =
152 {
153         {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
154         {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
155         {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
156         {XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
157         {XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"},
158         {XvSettable | XvGettable, 0, 8191, "XV_CONTRAST"},
159         {XvSettable | XvGettable, 0, 8191, "XV_SATURATION"},
160         {XvSettable | XvGettable, 0, 360, "XV_HUE"},
161         {XvSettable | XvGettable, 0, 1, "XV_ITURBT_709"},
162         {XvSettable | XvGettable, 0, 1, "XV_ON_CRTC_NB"},
163 };
164
165 #define NUM_BLIT_ATTRIBUTES 2
166 XF86AttributeRec NVBlitAttributes[NUM_BLIT_ATTRIBUTES] =
167 {
168         {XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
169         {XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK"}
170 };
171
172
173 #define NUM_IMAGES_YUV 4
174 #define NUM_IMAGES_ALL 5
175
176 #define FOURCC_RGB 0x0000003
177 #define XVIMAGE_RGB \
178    { \
179         FOURCC_RGB, \
180         XvRGB, \
181         LSBFirst, \
182         { 0x03, 0x00, 0x00, 0x00, \
183           0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
184         32, \
185         XvPacked, \
186         1, \
187         24, 0x00ff0000, 0x0000ff00, 0x000000ff, \
188         0, 0, 0, \
189         0, 0, 0, \
190         0, 0, 0, \
191         {'B','G','R','X',\
192           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}, \
193         XvTopToBottom \
194    }
195
196 static XF86ImageRec NVImages[NUM_IMAGES_ALL] =
197 {
198         XVIMAGE_YUY2,
199         XVIMAGE_YV12,
200         XVIMAGE_UYVY,
201         XVIMAGE_I420,
202         XVIMAGE_RGB
203 };
204
205 static void
206 NVWaitVSync(ScrnInfoPtr pScrn)
207 {
208         NVPtr pNv = NVPTR(pScrn);
209
210         BEGIN_RING(NvImageBlit, 0x0000012C, 1);
211         OUT_RING  (0);
212         BEGIN_RING(NvImageBlit, 0x00000134, 1);
213         /* If crtc1 is active, this will produce one, otherwise zero */
214         /* The assumption is that at least one is active */
215         OUT_RING  (pNv->crtc_active[1]);
216         BEGIN_RING(NvImageBlit, 0x00000100, 1);
217         OUT_RING  (0);
218         BEGIN_RING(NvImageBlit, 0x00000130, 1);
219         OUT_RING  (0);
220 }
221
222 /**
223  * NVSetPortDefaults
224  * set attributes of port "pPriv" to compiled-in (except for colorKey) defaults
225  * 
226  * @param pScrn screen to get the default colorKey from
227  * @param pPriv port to reset to defaults
228  */
229 static void 
230 NVSetPortDefaults (ScrnInfoPtr pScrn, NVPortPrivPtr pPriv)
231 {
232         NVPtr pNv = NVPTR(pScrn);
233
234         pPriv->brightness               = 0;
235         pPriv->contrast                 = 4096;
236         pPriv->saturation               = 4096;
237         pPriv->hue                      = 0;
238         pPriv->colorKey                 = pNv->videoKey;
239         pPriv->autopaintColorKey        = TRUE;
240         pPriv->doubleBuffer             = TRUE;
241         pPriv->iturbt_709               = FALSE;
242         pPriv->currentHostBuffer        = 0;
243 }
244
245 /**
246  * NVResetVideo
247  * writes the current attributes from the overlay port to the hardware
248  */
249 void 
250 NVResetVideo (ScrnInfoPtr pScrn)
251 {
252         NVPtr          pNv     = NVPTR(pScrn);
253         NVPortPrivPtr  pPriv   = GET_OVERLAY_PRIVATE(pNv);
254         int            satSine, satCosine;
255         double         angle;
256
257         angle = (double)pPriv->hue * 3.1415927 / 180.0;
258
259         satSine = pPriv->saturation * sin(angle);
260         if (satSine < -1024)
261                 satSine = -1024;
262         satCosine = pPriv->saturation * cos(angle);
263         if (satCosine < -1024)
264                 satCosine = -1024;
265
266         nvWriteVIDEO(pNv, NV_PVIDEO_LUMINANCE(0), (pPriv->brightness << 16) |
267                                                    pPriv->contrast);
268         nvWriteVIDEO(pNv, NV_PVIDEO_LUMINANCE(1), (pPriv->brightness << 16) |
269                                                    pPriv->contrast);
270         nvWriteVIDEO(pNv, NV_PVIDEO_CHROMINANCE(0), (satSine << 16) |
271                                                     (satCosine & 0xffff));
272         nvWriteVIDEO(pNv, NV_PVIDEO_CHROMINANCE(1), (satSine << 16) |
273                                                     (satCosine & 0xffff));
274         nvWriteVIDEO(pNv, NV_PVIDEO_COLOR_KEY, pPriv->colorKey);
275 }
276
277 /**
278  * NVStopOverlay
279  * Tell the hardware to stop the overlay
280  */
281 static void 
282 NVStopOverlay (ScrnInfoPtr pScrn)
283 {
284         NVPtr pNv = NVPTR(pScrn);
285         
286         if ( pNv -> Architecture != NV_ARCH_04 )
287                 nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 1);
288         else
289                 {
290                 nvWriteRAMDAC(pNv, 0, 0x244, nvReadRAMDAC(pNv, 0, 0x244) &~ 0x1);
291                 nvWriteRAMDAC(pNv, 0, 0x224, 0);
292                 nvWriteRAMDAC(pNv, 0, 0x228, 0);
293                 nvWriteRAMDAC(pNv, 0, 0x22c, 0);
294                 }
295 }
296
297 /**
298  * NVXvDMANotifierAlloc
299  * allocates a notifier from the table of 6 we have
300  *
301  * @return a notifier instance or NULL on error
302  */
303 static struct nouveau_notifier *
304 NVXvDMANotifierAlloc(ScrnInfoPtr pScrn)
305 {
306         NVPtr pNv = NVPTR(pScrn);
307         int i;
308
309         for (i = 0; i < 6; i++) {
310                 if (XvDMANotifierStatus[i] == XV_DMA_NOTIFIER_INUSE) 
311                         continue;
312
313                 if (XvDMANotifierStatus[i] == XV_DMA_NOTIFIER_FREE) {
314                         XvDMANotifierStatus[i] = XV_DMA_NOTIFIER_INUSE;
315                         return XvDMANotifiers[i];
316                 }
317
318                 if (XvDMANotifierStatus[i] == XV_DMA_NOTIFIER_NOALLOC) {
319                         if (nouveau_notifier_alloc(pNv->chan,
320                                                    NvDmaXvNotifier0 + i,
321                                                    1, &XvDMANotifiers[i]))
322                                 return NULL;
323                         XvDMANotifierStatus[i] = XV_DMA_NOTIFIER_INUSE;
324                         return XvDMANotifiers[i];
325                 }
326         }
327
328         return NULL;
329 }
330
331 /**
332  * NVXvDMANotifierFree
333  * frees a notifier from the table of 6 we have
334  *
335  * 
336  */
337 static void
338 NVXvDMANotifierFree(ScrnInfoPtr pScrn, struct nouveau_notifier *target)
339 {
340 int i;
341 for ( i = 0; i < 6; i ++ )
342         {
343         if ( XvDMANotifiers[i] == target )
344                 break;
345         }
346 XvDMANotifierStatus[i] = XV_DMA_NOTIFIER_FREE;
347 }
348
349 /**
350  * NVAllocateVideoMemory
351  * allocates video memory for a given port
352  * 
353  * @param pScrn screen which requests the memory
354  * @param mem pointer to previously allocated memory for reallocation
355  * @param size size of requested memory segment
356  * @return pointer to the allocated memory
357  */
358 static struct nouveau_bo *
359 NVAllocateVideoMemory(ScrnInfoPtr pScrn, struct nouveau_bo *mem, int size)
360 {
361         NVPtr pNv = NVPTR(pScrn);
362         struct nouveau_bo *bo = NULL;
363
364         if (mem) {
365                 if(mem->size >= size)
366                         return mem;
367                 nouveau_bo_del(&mem);
368         }
369
370         if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN, 0,
371                            size, &bo))
372                 return NULL;
373
374         if (nouveau_bo_map(bo, NOUVEAU_BO_RDWR)) {
375                 nouveau_bo_del(&bo);
376                 return NULL;
377         }
378
379         return bo;
380 }
381
382 /**
383  * NVAllocateTTMemory
384  * allocates TT memory for a given port
385  * 
386  * @param pScrn screen which requests the memory
387  * @param mem pointer to previously allocated memory for reallocation
388  * @param size size of requested memory segment
389  * @return pointer to the allocated memory
390  */
391 static struct nouveau_bo *
392 NVAllocateTTMemory(ScrnInfoPtr pScrn, struct nouveau_bo *mem, int size)
393 {
394         NVPtr pNv = NVPTR(pScrn);
395         struct nouveau_bo *bo = NULL;
396
397         if(mem) {
398                 if(mem->size >= size)
399                         return mem;
400                 nouveau_bo_del(&mem);
401         }
402
403         if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_GART | NOUVEAU_BO_PIN, 0,
404                            size, &bo))
405                 return NULL;
406
407         if (nouveau_bo_map(bo, NOUVEAU_BO_RDWR)) {
408                 nouveau_bo_del(&bo);
409                 return NULL;
410         }
411
412         return bo;
413 }
414
415 /**
416  * NVFreePortMemory
417  * frees memory held by a given port
418  * 
419  * @param pScrn screen whose port wants to free memory
420  * @param pPriv port to free memory of
421  */
422 static void
423 NVFreePortMemory(ScrnInfoPtr pScrn, NVPortPrivPtr pPriv)
424 {
425         //xf86DrvMsg(0, X_INFO, "Freeing port memory - TTmem chunks %p %p, notifiers %p %p\n", pPriv->TT_mem_chunk[0], pPriv->TT_mem_chunk[1], pPriv->DMANotifier[0], pPriv->DMANotifier[1]);
426         
427         if(pPriv->video_mem) {
428                 nouveau_bo_del(&pPriv->video_mem);
429                 pPriv->video_mem = NULL;
430         }
431         
432         if ( pPriv->TT_mem_chunk[ 0 ] && pPriv->DMANotifier [ 0 ] )
433                 {
434                 nouveau_notifier_wait_status(pPriv->DMANotifier[0], 0, 0, 1000);
435                 }
436         
437         if ( pPriv->TT_mem_chunk[ 1 ] && pPriv->DMANotifier [ 1 ] )
438                 {
439                 nouveau_notifier_wait_status(pPriv->DMANotifier[1], 0, 0, 1000);
440                 }               
441                 
442         if(pPriv->TT_mem_chunk[0]) {
443                 nouveau_bo_del(&pPriv->TT_mem_chunk[0]);
444                 pPriv->TT_mem_chunk[0] = NULL;
445         }
446         
447         if(pPriv->TT_mem_chunk[1]) {
448                 nouveau_bo_del(&pPriv->TT_mem_chunk[1]);
449                 pPriv->TT_mem_chunk[1] = NULL;
450         }
451         
452         if(pPriv->DMANotifier[0]) {
453                 NVXvDMANotifierFree(pScrn, pPriv->DMANotifier[0]);
454                 pPriv->DMANotifier[0] = NULL;
455         }
456         
457         if(pPriv->DMANotifier[1]) {
458                 NVXvDMANotifierFree(pScrn, pPriv->DMANotifier[1]);
459                 pPriv->DMANotifier[1] = NULL;
460         }
461         
462 }
463
464 /**
465  * NVFreeOverlayMemory
466  * frees memory held by the overlay port
467  * 
468  * @param pScrn screen whose overlay port wants to free memory
469  */
470 static void
471 NVFreeOverlayMemory(ScrnInfoPtr pScrn)
472 {
473         NVPtr   pNv = NVPTR(pScrn);
474         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
475         NVFreePortMemory(pScrn, pPriv);
476         nvWriteMC(pNv, 0x200, (nvReadMC(pNv, 0x200) & 0xEFFFFFFF));
477         nvWriteMC(pNv, 0x200, (nvReadMC(pNv, 0x200) | 0x10000000));
478 }
479
480 /**
481  * NVFreeBlitMemory
482  * frees memory held by the blit port
483  * 
484  * @param pScrn screen whose blit port wants to free memory
485  */
486 static void
487 NVFreeBlitMemory(ScrnInfoPtr pScrn)
488 {
489         NVPtr   pNv = NVPTR(pScrn);
490         NVPortPrivPtr pPriv = GET_BLIT_PRIVATE(pNv);
491         NVFreePortMemory(pScrn, pPriv);
492 }
493
494 /**
495  * NVVideoTimerCallback
496  * callback function which perform cleanup tasks (stop overlay, free memory).
497  * within the driver it is only called once from NVBlockHandler in nv_driver.c
498  */
499 static void
500 NVVideoTimerCallback(ScrnInfoPtr pScrn, Time currentTime)
501 {
502         NVPtr         pNv = NVPTR(pScrn);
503         NVPortPrivPtr pOverPriv = NULL;
504         NVPortPrivPtr pBlitPriv = NULL;
505         Bool needCallback = FALSE;
506
507         if (!pScrn->vtSema)
508                 return; 
509
510         if (pNv->overlayAdaptor) {
511                 pOverPriv = GET_OVERLAY_PRIVATE(pNv);
512                 if (!pOverPriv->videoStatus)
513                         pOverPriv = NULL;
514         }
515
516         if (pNv->blitAdaptor) {
517                 pBlitPriv = GET_BLIT_PRIVATE(pNv);
518                 if (!pBlitPriv->videoStatus)
519                         pBlitPriv = NULL;
520         }
521
522         if (pOverPriv) {
523                 if (pOverPriv->videoTime < currentTime) {
524                         if (pOverPriv->videoStatus & OFF_TIMER) {
525                                 NVStopOverlay(pScrn);
526                                 pOverPriv->videoStatus = FREE_TIMER;
527                                 pOverPriv->videoTime = currentTime + FREE_DELAY;
528                                 needCallback = TRUE;
529                         } else
530                         if (pOverPriv->videoStatus & FREE_TIMER) {
531                                 NVFreeOverlayMemory(pScrn);
532                                 pOverPriv->videoStatus = 0;
533                         }
534                 } else {
535                         needCallback = TRUE;
536                 }
537         }
538
539         if (pBlitPriv) {
540                 if (pBlitPriv->videoTime < currentTime) {
541                         NVFreeBlitMemory(pScrn);
542                         pBlitPriv->videoStatus = 0;              
543                 } else {
544                         needCallback = TRUE;
545                 }
546         }
547
548         pNv->VideoTimerCallback = needCallback ? NVVideoTimerCallback : NULL;
549 }
550
551 /**
552  * NVPutOverlayImage
553  * program hardware to overlay image into front buffer
554  * 
555  * @param pScrn screen
556  * @param offset card offset to the pixel data
557  * @param id format of image
558  * @param dstPitch pitch of the pixel data in VRAM
559  * @param dstBox destination box
560  * @param x1 first source point - x
561  * @param y1 first source point - y
562  * @param x2 second source point - x
563  * @param y2 second source point - y
564  * @param width width of the source image = x2 - x1
565  * @param height height
566  * @param src_w width of the image data in VRAM
567  * @param src_h height
568  * @param drw_w width of the image to draw to screen
569  * @param drw_h height
570  * @param clipBoxes ???
571  */
572 static void
573 NVPutOverlayImage(ScrnInfoPtr pScrn, int offset, int uvoffset, int id,
574                   int dstPitch, BoxPtr dstBox,
575                   int x1, int y1, int x2, int y2,
576                   short width, short height,
577                   short src_w, short src_h,
578                   short drw_w, short drw_h,
579                   RegionPtr clipBoxes)
580 {
581         NVPtr         pNv    = NVPTR(pScrn);
582         NVPortPrivPtr pPriv  = GET_OVERLAY_PRIVATE(pNv);
583         int           buffer = pPriv->currentBuffer;
584
585         /* paint the color key */
586         if(pPriv->autopaintColorKey && (pPriv->grabbedByV4L ||
587                 !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes))) {
588                 /* we always paint V4L's color key */
589                 if (!pPriv->grabbedByV4L)
590                         REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
591                 {
592                 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
593                 }
594         }
595
596         if(pNv->CurrentLayout.mode->Flags & V_DBLSCAN) {
597                 dstBox->y1 <<= 1;
598                 dstBox->y2 <<= 1;
599                 drw_h <<= 1;
600         }
601         
602         //xf86DrvMsg(0, X_INFO, "SIZE_IN h %d w %d, POINT_IN x %d y %d, DS_DX %d DT_DY %d, POINT_OUT x %d y %d SIZE_OUT h %d w %d\n", height, width, x1 >> 16,y1>>16, (src_w << 20) / drw_w, (src_h << 20) / drw_h,  (dstBox->x1),(dstBox->y1), (dstBox->y2 - dstBox->y1), (dstBox->x2 - dstBox->x1));
603
604         nvWriteVIDEO(pNv, NV_PVIDEO_BASE(buffer)     , 0);
605         nvWriteVIDEO(pNv, NV_PVIDEO_OFFSET_BUFF(buffer)     , offset);
606         nvWriteVIDEO(pNv, NV_PVIDEO_SIZE_IN(buffer)  , (height << 16) | width);
607         nvWriteVIDEO(pNv, NV_PVIDEO_POINT_IN(buffer) ,
608                           ((y1 << 4) & 0xffff0000) | (x1 >> 12));
609         nvWriteVIDEO(pNv, NV_PVIDEO_DS_DX(buffer)    , (src_w << 20) / drw_w);
610         nvWriteVIDEO(pNv, NV_PVIDEO_DT_DY(buffer)    , (src_h << 20) / drw_h);
611         nvWriteVIDEO(pNv, NV_PVIDEO_POINT_OUT(buffer),
612                           (dstBox->y1 << 16) | dstBox->x1);
613         nvWriteVIDEO(pNv, NV_PVIDEO_SIZE_OUT(buffer) ,
614                           ((dstBox->y2 - dstBox->y1) << 16) |
615                            (dstBox->x2 - dstBox->x1));
616
617         dstPitch |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;   /* use color key */
618         if(id != FOURCC_UYVY)
619                 dstPitch |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8;
620         if(pPriv->iturbt_709)
621                 dstPitch |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
622         
623         if( id == FOURCC_YV12 || id == FOURCC_I420 )
624                 dstPitch |= NV_PVIDEO_FORMAT_PLANAR;
625
626         /* Those are important only for planar formats (NV12) */
627         if ( uvoffset )
628                 {
629                 nvWriteVIDEO(pNv, NV_PVIDEO_UVPLANE_BASE(buffer), 0); 
630                 nvWriteVIDEO(pNv, NV_PVIDEO_UVPLANE_OFFSET_BUFF(buffer), uvoffset);
631                 }
632         
633         nvWriteVIDEO(pNv, NV_PVIDEO_FORMAT(buffer), dstPitch);
634         nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 0);
635         nvWriteVIDEO(pNv, NV_PVIDEO_BUFFER, buffer ? 0x10 :  0x1);
636
637         pPriv->videoStatus = CLIENT_VIDEO_ON;
638 }
639
640 static void
641 NV04PutOverlayImage(ScrnInfoPtr pScrn, int offset, int id,
642                   int dstPitch, BoxPtr dstBox,
643                   int x1, int y1, int x2, int y2,
644                   short width, short height,
645                   short src_w, short src_h,
646                   short drw_w, short drw_h,
647                   RegionPtr clipBoxes)
648 {
649         NVPtr         pNv    = NVPTR(pScrn);
650         NVPortPrivPtr pPriv  = GET_OVERLAY_PRIVATE(pNv);
651
652         /* paint the color key */
653         if(pPriv->autopaintColorKey && (pPriv->grabbedByV4L ||
654                 !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes))) {
655                 /* we always paint V4L's color key */
656                 if (!pPriv->grabbedByV4L)
657                         REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
658                 {
659                 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
660                 }
661         }
662
663         if(pNv->CurrentLayout.mode->Flags & V_DBLSCAN) { /*This may not work with NV04 overlay according to rivatv source*/
664                 dstBox->y1 <<= 1;
665                 dstBox->y2 <<= 1;
666                 drw_h <<= 1;
667         }
668
669         /* NV_PVIDEO_OE_STATE */
670         /* NV_PVIDEO_SU_STATE */
671         /* NV_PVIDEO_RM_STATE */
672         nvWriteRAMDAC(pNv, 0, 0x224, 0);
673         nvWriteRAMDAC(pNv, 0, 0x228, 0);
674         nvWriteRAMDAC(pNv, 0, 0x22c, 0);
675         
676         /* NV_PVIDEO_BUFF0_START_ADDRESS */
677         nvWriteRAMDAC(pNv, 0, 0x20C, offset);
678         nvWriteRAMDAC(pNv, 0, 0x20C + 4, offset);
679         /* NV_PVIDEO_BUFF0_PITCH_LENGTH */
680         nvWriteRAMDAC(pNv, 0, 0x214, dstPitch);
681         nvWriteRAMDAC(pNv, 0, 0x214 + 4, dstPitch);
682         
683         /* NV_PVIDEO_BUFF0_OFFSET */
684         nvWriteRAMDAC(pNv, 0, 0x21C, 0);
685         nvWriteRAMDAC(pNv, 0, 0x21C + 4, 0);
686         
687         /* NV_PVIDEO_WINDOW_START */
688         nvWriteRAMDAC(pNv, 0, 0x230, (dstBox->y1 << 16) | dstBox->x1);
689         /* NV_PVIDEO_WINDOW_SIZE */
690         nvWriteRAMDAC(pNv, 0, 0x234, ((dstBox->y2 - dstBox->y1) << 16) |
691                            (dstBox->x2 - dstBox->x1));
692         /* NV_PVIDEO_STEP_SIZE */
693         nvWriteRAMDAC(pNv,  0,  0x200, (uint32_t)(((src_h - 1) << 11) / (drw_h - 1)) << 16 | (uint32_t)(((src_w - 1) << 11) / (drw_w - 1)));
694         
695         /* NV_PVIDEO_RED_CSC_OFFSET */
696         /* NV_PVIDEO_GREEN_CSC_OFFSET */
697         /* NV_PVIDEO_BLUE_CSC_OFFSET */
698         /* NV_PVIDEO_CSC_ADJUST */
699         nvWriteRAMDAC(pNv, 0, 0x280, 0x69);
700         nvWriteRAMDAC(pNv, 0, 0x284, 0x3e);
701         nvWriteRAMDAC(pNv, 0, 0x288, 0x89);
702         nvWriteRAMDAC(pNv, 0, 0x28C, 0x0);
703
704         /* NV_PVIDEO_CONTROL_Y (BLUR_ON, LINE_HALF) */
705         nvWriteRAMDAC(pNv, 0, 0x204, 0x001);
706         /* NV_PVIDEO_CONTROL_X (WEIGHT_HEAVY, SHARPENING_ON, SMOOTHING_ON) */
707         nvWriteRAMDAC(pNv, 0, 0x208, 0x111);
708         
709         /* NV_PVIDEO_FIFO_BURST_LENGTH */  
710         nvWriteRAMDAC(pNv, 0, 0x23C, 0x03);
711         /* NV_PVIDEO_FIFO_THRES_SIZE */
712         nvWriteRAMDAC(pNv, 0, 0x238, 0x38);
713         
714         /* Color key */
715         nvWriteRAMDAC(pNv, 0, 0x240, pPriv->colorKey);
716         
717         /*NV_PVIDEO_OVERLAY
718                 0x1 Video on
719                 0x10 Use colorkey
720                 0x100 Format YUY2 */
721         nvWriteRAMDAC(pNv, 0, 0x244, 0x111);
722         
723         /* NV_PVIDEO_SU_STATE */
724         nvWriteRAMDAC(pNv, 0, 0x228, (nvReadRAMDAC(pNv, 0, 0x228) ^ (1 << 16)));
725         
726         pPriv->videoStatus = CLIENT_VIDEO_ON;
727 }
728 #ifndef ExaOffscreenMarkUsed
729 extern void ExaOffscreenMarkUsed(PixmapPtr);
730 #endif
731 #ifndef exaGetDrawablePixmap
732 extern PixmapPtr exaGetDrawablePixmap(DrawablePtr);
733 #endif
734 #ifndef exaPixmapIsOffscreen
735 extern Bool exaPixmapIsOffscreen(PixmapPtr p);
736 #endif
737 /* To support EXA 2.0, 2.1 has this in the header */
738 #ifndef exaMoveInPixmap
739 extern void exaMoveInPixmap(PixmapPtr pPixmap);
740 #endif
741
742 /**
743  * NVPutBlitImage
744  * 
745  * @param pScrn screen
746  * @param src_offset
747  * @param id colorspace of image
748  * @param src_pitch
749  * @param dstBox
750  * @param x1
751  * @param y1
752  * @param x2
753  * @param y2
754  * @param width
755  * @param height
756  * @param src_w
757  * @param src_h
758  * @param drw_w
759  * @param drw_h
760  * @param clipBoxes
761  * @param pDraw
762  */
763 static void
764 NVPutBlitImage(ScrnInfoPtr pScrn, int src_offset, int id,
765                int src_pitch, BoxPtr dstBox,
766                int x1, int y1, int x2, int y2,
767                short width, short height,
768                short src_w, short src_h,
769                short drw_w, short drw_h,
770                RegionPtr clipBoxes,
771                DrawablePtr pDraw)
772 {
773         NVPtr          pNv   = NVPTR(pScrn);
774         NVPortPrivPtr  pPriv = GET_BLIT_PRIVATE(pNv);
775         BoxPtr         pbox;
776         int            nbox;
777         CARD32         dsdx, dtdy;
778         CARD32         dst_size, dst_point;
779         CARD32         src_point, src_format;
780
781         ScreenPtr pScreen = pScrn->pScreen;
782         PixmapPtr pPix    = exaGetDrawablePixmap(pDraw);
783         int dst_format;
784
785         /* Try to get the dest drawable into vram */
786         if (!exaPixmapIsOffscreen(pPix)) {
787                 exaMoveInPixmap(pPix);
788                 ExaOffscreenMarkUsed(pPix);
789         }
790
791         /* If we failed, draw directly onto the screen pixmap.
792          * Not sure if this is the best approach, maybe failing
793          * with BadAlloc would be better?
794          */
795         if (!exaPixmapIsOffscreen(pPix)) {
796                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
797                         "XV: couldn't move dst surface into vram\n");
798                 pPix = pScreen->GetScreenPixmap(pScreen);
799         }
800
801         NVAccelGetCtxSurf2DFormatFromPixmap(pPix, &dst_format);
802         BEGIN_RING(NvContextSurfaces, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
803         OUT_RING  (dst_format);
804         OUT_RING  ((exaGetPixmapPitch(pPix) << 16) | exaGetPixmapPitch(pPix));
805         OUT_PIXMAPl(pPix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
806         OUT_PIXMAPl(pPix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
807
808 #ifdef COMPOSITE
809         /* Adjust coordinates if drawing to an offscreen pixmap */
810         if (pPix->screen_x || pPix->screen_y) {
811                 REGION_TRANSLATE(pScrn->pScreen, clipBoxes,
812                                                      -pPix->screen_x,
813                                                      -pPix->screen_y);
814                 dstBox->x1 -= pPix->screen_x;
815                 dstBox->x2 -= pPix->screen_x;
816                 dstBox->y1 -= pPix->screen_y;
817                 dstBox->y2 -= pPix->screen_y;
818         }
819
820         DamageDamageRegion((DrawablePtr)pPix, clipBoxes);
821 #endif
822
823         pbox = REGION_RECTS(clipBoxes);
824         nbox = REGION_NUM_RECTS(clipBoxes);
825
826         dsdx = (src_w << 20) / drw_w;
827         dtdy = (src_h << 20) / drw_h;
828
829         dst_size  = ((dstBox->y2 - dstBox->y1) << 16) |
830                      (dstBox->x2 - dstBox->x1);
831         dst_point = (dstBox->y1 << 16) | dstBox->x1;
832
833         src_pitch |= (NV04_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER |
834                       NV04_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_BILINEAR);
835         src_point = ((y1 << 4) & 0xffff0000) | (x1 >> 12);
836
837         switch(id) {
838         case FOURCC_RGB:
839                 src_format =
840                         NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_X8R8G8B8;
841                 break;
842         case FOURCC_UYVY:
843                 src_format =
844                         NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_YB8V8YA8U8;
845                 break;
846         default:
847                 src_format =
848                         NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_V8YB8U8YA8;
849                 break;
850         }
851
852         if(pPriv->SyncToVBlank) {
853                 FIRE_RING();
854                 NVWaitVSync(pScrn);
855         }
856
857         if(pNv->BlendingPossible) {
858                 BEGIN_RING(NvScaledImage,
859                                 NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT, 2);
860                 OUT_RING  (src_format);
861                 OUT_RING  (NV04_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY);
862         } else {
863                 BEGIN_RING(NvScaledImage,
864                                 NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT, 2);
865                 OUT_RING  (src_format);
866         }
867
868         while(nbox--) {
869                 BEGIN_RING(NvRectangle,
870                                 NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
871                 OUT_RING  (0);
872
873                 BEGIN_RING(NvScaledImage,
874                                 NV04_SCALED_IMAGE_FROM_MEMORY_CLIP_POINT, 6);
875                 OUT_RING  ((pbox->y1 << 16) | pbox->x1); 
876                 OUT_RING  (((pbox->y2 - pbox->y1) << 16) |
877                                  (pbox->x2 - pbox->x1));
878                 OUT_RING  (dst_point);
879                 OUT_RING  (dst_size);
880                 OUT_RING  (dsdx);
881                 OUT_RING  (dtdy);
882
883                 BEGIN_RING(NvScaledImage,
884                                 NV04_SCALED_IMAGE_FROM_MEMORY_SIZE, 4);
885                 OUT_RING  ((height << 16) | width);
886                 OUT_RING  (src_pitch);
887                 OUT_RING  (src_offset);
888                 OUT_RING  (src_point);
889                 pbox++;
890         }
891
892         FIRE_RING();
893
894         exaMarkSync(pScrn->pScreen);
895
896         pPriv->videoStatus = FREE_TIMER;
897         pPriv->videoTime = currentTime.milliseconds + FREE_DELAY;
898         pNv->VideoTimerCallback = NVVideoTimerCallback;
899 }
900
901 /*
902  * StopVideo
903  */
904 static void
905 NVStopOverlayVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit)
906 {
907         NVPtr         pNv   = NVPTR(pScrn);
908         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
909
910         if(pPriv->grabbedByV4L) return;
911
912         REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
913
914         if(Exit) {
915                 if (pPriv->videoStatus & CLIENT_VIDEO_ON)
916                         NVStopOverlay(pScrn);
917                 NVFreeOverlayMemory(pScrn);
918                 pPriv->videoStatus = 0;
919         } else {
920                 if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
921                         pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
922                         pPriv->videoTime = currentTime.milliseconds + OFF_DELAY;
923                         pNv->VideoTimerCallback = NVVideoTimerCallback;
924                 }
925         }
926 }
927
928 /**
929  * NVStopBlitVideo
930  */
931 static void
932 NVStopBlitVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit)
933 {
934 }
935
936 /**
937  * NVSetOverlayPortAttribute
938  * sets the attribute "attribute" of port "data" to value "value"
939  * calls NVResetVideo(pScrn) to apply changes to hardware
940  * 
941  * @param pScrenInfo
942  * @param attribute attribute to set
943  * @param value value to which attribute is to be set
944  * @param data port from which the attribute is to be set
945  * 
946  * @return Success, if setting is successful
947  * BadValue/BadMatch, if value/attribute are invalid
948  * @see NVResetVideo(ScrnInfoPtr pScrn)
949  */
950 static int
951 NVSetOverlayPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
952                           INT32 value, pointer data)
953 {
954         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
955         NVPtr         pNv   = NVPTR(pScrn);
956         
957         if (attribute == xvBrightness) {
958                 if ((value < -512) || (value > 512))
959                         return BadValue;
960                 pPriv->brightness = value;
961         } else
962         if (attribute == xvDoubleBuffer) {
963                 if ((value < 0) || (value > 1))
964                         return BadValue;
965                 pPriv->doubleBuffer = value;
966         } else
967         if (attribute == xvContrast) {
968                 if ((value < 0) || (value > 8191))
969                         return BadValue;
970                 pPriv->contrast = value;
971         } else
972         if (attribute == xvHue) {
973                 value %= 360;
974                 if (value < 0)
975                         value += 360;
976                 pPriv->hue = value;
977         } else
978         if (attribute == xvSaturation) {
979                 if ((value < 0) || (value > 8191))
980                         return BadValue;
981                 pPriv->saturation = value;
982         } else
983         if (attribute == xvColorKey) {
984                 pPriv->colorKey = value;
985                 REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
986         } else
987         if (attribute == xvAutopaintColorKey) {
988                 if ((value < 0) || (value > 1))
989                         return BadValue;
990                 pPriv->autopaintColorKey = value;
991         } else
992         if (attribute == xvITURBT709) {
993                 if ((value < 0) || (value > 1))
994                         return BadValue;
995                 pPriv->iturbt_709 = value;
996         } else
997         if (attribute == xvSetDefaults) {
998                 NVSetPortDefaults(pScrn, pPriv);
999         } else
1000         if ( attribute == xvOnCRTCNb) {
1001                 if ((value < 0) || (value > 1))
1002                         return BadValue;
1003                 pPriv->overlayCRTC = value;
1004                 nvWriteCRTC(pNv, value, NV_CRTC_FSEL, nvReadCRTC(pNv, value, NV_CRTC_FSEL) | NV_CRTC_FSEL_OVERLAY);
1005                 nvWriteCRTC(pNv, !value, NV_CRTC_FSEL, nvReadCRTC(pNv, !value, NV_CRTC_FSEL) & ~NV_CRTC_FSEL_OVERLAY);
1006         } else
1007                 return BadMatch;
1008
1009         NVResetVideo(pScrn);
1010         return Success;
1011 }
1012
1013 /**
1014  * NVGetOverlayPortAttribute
1015  * 
1016  * @param pScrn unused
1017  * @param attribute attribute to be read
1018  * @param value value of attribute will be stored in this pointer
1019  * @param data port from which attribute will be read
1020  * @return Success, if queried attribute exists
1021  */
1022 static int
1023 NVGetOverlayPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
1024                           INT32 *value, pointer data)
1025 {
1026         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
1027
1028         if (attribute == xvBrightness)
1029                 *value = pPriv->brightness;
1030         else if (attribute == xvDoubleBuffer)
1031                 *value = (pPriv->doubleBuffer) ? 1 : 0;
1032         else if (attribute == xvContrast)
1033                 *value = pPriv->contrast;
1034         else if (attribute == xvSaturation)
1035                 *value = pPriv->saturation;
1036         else if (attribute == xvHue)
1037                 *value = pPriv->hue;
1038         else if (attribute == xvColorKey)
1039                 *value = pPriv->colorKey;
1040         else if (attribute == xvAutopaintColorKey)
1041                 *value = (pPriv->autopaintColorKey) ? 1 : 0;
1042         else if (attribute == xvITURBT709)
1043                 *value = (pPriv->iturbt_709) ? 1 : 0;
1044         else if (attribute == xvOnCRTCNb)
1045                 *value = (pPriv->overlayCRTC) ? 1 : 0;
1046         else
1047                 return BadMatch;
1048
1049         return Success;
1050 }
1051
1052 /**
1053  * NVSetBlitPortAttribute
1054  * sets the attribute "attribute" of port "data" to value "value"
1055  * supported attributes:
1056  * - xvSyncToVBlank (values: 0,1)
1057  * - xvSetDefaults (values: NA; SyncToVBlank will be set, if hardware supports it)
1058  * 
1059  * @param pScrenInfo
1060  * @param attribute attribute to set
1061  * @param value value to which attribute is to be set
1062  * @param data port from which the attribute is to be set
1063  * 
1064  * @return Success, if setting is successful
1065  * BadValue/BadMatch, if value/attribute are invalid
1066  */
1067 static int
1068 NVSetBlitPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
1069                        INT32 value, pointer data)
1070 {
1071         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
1072         NVPtr           pNv = NVPTR(pScrn);
1073
1074         if ((attribute == xvSyncToVBlank) && pNv->WaitVSyncPossible) {
1075                 if ((value < 0) || (value > 1))
1076                         return BadValue;
1077                 pPriv->SyncToVBlank = value;
1078         } else
1079         if (attribute == xvSetDefaults) {
1080                 pPriv->SyncToVBlank = pNv->WaitVSyncPossible;
1081         } else
1082                 return BadMatch;
1083
1084         return Success;
1085 }
1086
1087 /**
1088  * NVGetBlitPortAttribute
1089  * reads the value of attribute "attribute" from port "data" into INT32 "*value"
1090  * currently only one attribute supported: xvSyncToVBlank
1091  * 
1092  * @param pScrn unused
1093  * @param attribute attribute to be read
1094  * @param value value of attribute will be stored here
1095  * @param data port from which attribute will be read
1096  * @return Success, if queried attribute exists
1097  */
1098 static int
1099 NVGetBlitPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
1100                        INT32 *value, pointer data)
1101 {
1102         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
1103
1104         if(attribute == xvSyncToVBlank)
1105                 *value = (pPriv->SyncToVBlank) ? 1 : 0;
1106         else
1107                 return BadMatch;
1108
1109         return Success;
1110 }
1111
1112
1113 /**
1114  * QueryBestSize
1115  * used by client applications to ask the driver:
1116  * how would you actually scale a video of dimensions
1117  * vid_w, vid_h, if i wanted you to scale it to dimensions
1118  * drw_w, drw_h?
1119  * function stores actual scaling size in pointers p_w, p_h.
1120  * 
1121  * 
1122  * @param pScrn unused
1123  * @param motion unused
1124  * @param vid_w width of source video
1125  * @param vid_h height of source video
1126  * @param drw_w desired scaled width as requested by client
1127  * @param drw_h desired scaled height as requested by client
1128  * @param p_w actual scaled width as the driver is capable of
1129  * @param p_h actual scaled height as the driver is capable of
1130  * @param data unused
1131  */
1132 static void
1133 NVQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
1134                 short vid_w, short vid_h, 
1135                 short drw_w, short drw_h, 
1136                 unsigned int *p_w, unsigned int *p_h, 
1137                 pointer data)
1138 {
1139         if(vid_w > (drw_w << 3))
1140                 drw_w = vid_w >> 3;
1141         if(vid_h > (drw_h << 3))
1142                 drw_h = vid_h >> 3;
1143
1144         *p_w = drw_w;
1145         *p_h = drw_h; 
1146 }
1147
1148 /**
1149  * NVCopyData420
1150  * used to convert YV12 to YUY2 for the blitter
1151  * 
1152  * @param src1 source buffer of luma
1153  * @param src2 source buffer of chroma1
1154  * @param src3 source buffer of chroma2
1155  * @param dst1 destination buffer
1156  * @param srcPitch pitch of src1
1157  * @param srcPitch2 pitch of src2, src3
1158  * @param dstPitch pitch of dst1
1159  * @param h number of lines to copy
1160  * @param w length of lines to copy
1161  */
1162 static inline void NVCopyData420(unsigned char *src1, unsigned char *src2,
1163                           unsigned char *src3, unsigned char *dst1,
1164                           int srcPitch, int srcPitch2,
1165                           int dstPitch,
1166                           int h, int w)
1167 {
1168         CARD32 *dst;
1169         CARD8 *s1, *s2, *s3;
1170         int i, j;
1171
1172         w >>= 1;
1173
1174         for (j = 0; j < h; j++) {
1175                 dst = (CARD32*)dst1;
1176                 s1 = src1;  s2 = src2;  s3 = src3;
1177                 i = w;
1178
1179                 while (i > 4) {
1180 #if X_BYTE_ORDER == X_BIG_ENDIAN
1181                 dst[0] = (s1[0] << 24) | (s1[1] << 8) | (s3[0] << 16) | s2[0];
1182                 dst[1] = (s1[2] << 24) | (s1[3] << 8) | (s3[1] << 16) | s2[1];
1183                 dst[2] = (s1[4] << 24) | (s1[5] << 8) | (s3[2] << 16) | s2[2];
1184                 dst[3] = (s1[6] << 24) | (s1[7] << 8) | (s3[3] << 16) | s2[3];
1185 #else
1186                 dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
1187                 dst[1] = s1[2] | (s1[3] << 16) | (s3[1] << 8) | (s2[1] << 24);
1188                 dst[2] = s1[4] | (s1[5] << 16) | (s3[2] << 8) | (s2[2] << 24);
1189                 dst[3] = s1[6] | (s1[7] << 16) | (s3[3] << 8) | (s2[3] << 24);
1190 #endif
1191                 dst += 4; s2 += 4; s3 += 4; s1 += 8;
1192                 i -= 4;
1193                 }
1194
1195                 while (i--) {
1196 #if X_BYTE_ORDER == X_BIG_ENDIAN
1197                 dst[0] = (s1[0] << 24) | (s1[1] << 8) | (s3[0] << 16) | s2[0];
1198 #else
1199                 dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
1200 #endif
1201                 dst++; s2++; s3++;
1202                 s1 += 2;
1203                 }
1204
1205                 dst1 += dstPitch;
1206                 src1 += srcPitch;
1207                 if (j & 1) {
1208                         src2 += srcPitch2;
1209                         src3 += srcPitch2;
1210                 }
1211         }
1212 }
1213
1214 /**
1215  * NVCopyNV12ColorPlanes
1216  * Used to convert YV12 color planes to NV12 (interleaved UV) for the overlay
1217  * 
1218  * @param src1 source buffer of chroma1
1219  * @param dst1 destination buffer
1220  * @param h number of lines to copy
1221  * @param w length of lines to copy
1222  * @param id source pixel format (YV12 or I420)
1223  */
1224 static inline void NVCopyNV12ColorPlanes(unsigned char *src1, unsigned char * src2, unsigned char *dst, int dstPitch, int srcPitch2, 
1225                           int h, int w)
1226 {
1227         
1228         int i,j,l,e;
1229         
1230         w >>= 1;
1231         h >>= 1;
1232         l = w >> 1;
1233         e = w & 1;
1234         for ( j = 0; j < h; j++ ) 
1235                 {
1236                 unsigned char * us = src1;
1237                 unsigned char * vs = src2;
1238                 unsigned int * vuvud = (unsigned int *) dst;
1239                 for ( i = 0; i < l; i++ )
1240                         {
1241 #if X_BYTE_ORDER == X_BIG_ENDIAN
1242                         *vuvud++ = (vs[0]<<24) | (us[0]<<16) | (vs[1]<<8) | us[1];
1243 #else
1244                         *vuvud++ = vs[0] | (us[0]<<8) | (vs[1]<<16) | (us[1]<<24);
1245 #endif
1246                         us+=2;
1247                         vs+=2;
1248                         }
1249                 if (e)  {
1250                         unsigned short *vud = (unsigned short *) vuvud;
1251 #if X_BYTE_ORDER == X_BIG_ENDIAN
1252                         *vud = (vs[0]<<8) | (us[0] << 0);
1253 #else
1254                         *vud = vs[0] | (us[0]<<8);
1255 #endif
1256                         }
1257                 dst += dstPitch ;
1258                 src1 += srcPitch2;
1259                 src2 += srcPitch2;
1260                 }       
1261
1262 }
1263
1264
1265 static int NV_set_dimensions(ScrnInfoPtr pScrn, int action_flags, INT32 * xa, INT32 * xb, INT32 * ya, INT32 * yb, 
1266                                                         short * src_x, short * src_y, short * src_w, short * src_h,
1267                                                         short * drw_x, short * drw_y, short * drw_w, short * drw_h,
1268                                                         int * left, int * top, int * right, int * bottom,
1269                                                         BoxRec * dstBox, 
1270                                                         int * npixels, int * nlines,
1271                                                         RegionPtr clipBoxes, short width, short height
1272                                                         )
1273 {
1274         
1275         if ( action_flags & USE_OVERLAY ) 
1276                 { /* overlay hardware scaler limitation - copied from nv, UNCHECKED*/
1277                 if (*src_w > (*drw_w << 3))
1278                         *drw_w = *src_w >> 3;
1279                 if (*src_h > (*drw_h << 3))
1280                         *drw_h = *src_h >> 3;
1281                 }
1282         
1283
1284         /* Clip */
1285         *xa = *src_x;
1286         *xb = *src_x + *src_w;
1287         *ya = *src_y;
1288         *yb = *src_y + *src_h;
1289
1290         dstBox->x1 = *drw_x;
1291         dstBox->x2 = *drw_x + *drw_w;
1292         dstBox->y1 = *drw_y;
1293         dstBox->y2 = *drw_y + *drw_h;
1294
1295         if (!xf86XVClipVideoHelper(dstBox, xa, xb, ya, yb, clipBoxes,
1296                                    width, height))
1297                 return -1;
1298
1299         if ( action_flags & USE_OVERLAY )
1300                 {
1301                 dstBox->x1 -= pScrn->frameX0;
1302                 dstBox->x2 -= pScrn->frameX0;
1303                 dstBox->y1 -= pScrn->frameY0;
1304                 dstBox->y2 -= pScrn->frameY0;
1305                 }
1306                 
1307         
1308         
1309         /* Convert fixed point to integer, as xf86XVClipVideoHelper probably turns its parameter into fixed point values */
1310         *left = (*xa) >> 16;
1311         if (*left < 0) *left = 0;
1312         *top = (*ya) >> 16;
1313         if (*top < 0) *top = 0;
1314         *right = (*xb) >> 16;
1315         if (*right > width) *right = width;
1316         *bottom = (*yb) >> 16;
1317         if (*bottom > height) *bottom = height;
1318         
1319         if ( action_flags & IS_YV12 )
1320                 {
1321                 *left &= ~1; //even "left", even "top", even number of pixels per line and even number of lines
1322                 *npixels = ((*right + 1) & ~1) - *left;
1323                 *top &= ~1;
1324                 *nlines = ((*bottom + 1) & ~1) - *top;
1325                 }
1326         else if ( action_flags & IS_YUY2 )
1327                 {
1328                 *left &= ~1; //even "left"
1329                 *npixels = ((*right + 1) & ~1) - *left; //even number of pixels per line
1330                 *nlines = *bottom - *top; 
1331                 *left <<= 1; //16bpp
1332                 }
1333         else if (action_flags & IS_RGB )
1334                 {
1335                 *npixels = *right - *left;
1336                 *nlines = *bottom - *top;
1337                 *left <<= 2; //32bpp
1338                 }
1339         
1340         return 0;
1341 }
1342
1343 static int NV_calculate_pitches_and_mem_size(int action_flags, int * srcPitch, int * srcPitch2, int * dstPitch, 
1344                                                                                 int * s2offset, int * s3offset, 
1345                                                                                 int * newFBSize, int * newTTSize,
1346                                                                                 int * line_len, int npixels, int nlines, int width, int height)
1347 {
1348         int tmp;
1349                 
1350         if ( action_flags & IS_YV12 ) 
1351                 {       /*YV12 or I420*/
1352                 *srcPitch = (width + 3) & ~3;   /* of luma */
1353                 *s2offset = *srcPitch * height;
1354                 *srcPitch2 = ((width >> 1) + 3) & ~3; /*of chroma*/
1355                 *s3offset = (*srcPitch2 * (height >> 1)) + *s2offset;
1356                 *dstPitch = (npixels + 63) &~ 63; /*luma and chroma pitch*/
1357                 *line_len = npixels;
1358                 *newFBSize = nlines * *dstPitch + (nlines >> 1) * *dstPitch;
1359                 *newTTSize = nlines * *dstPitch + (nlines >> 1) * *dstPitch;
1360                 }
1361         else if ( action_flags & IS_YUY2 )
1362                 {
1363                 *srcPitch = width << 1; /* one luma, one chroma per pixel */
1364                 *dstPitch = ((npixels << 1) + 63) & ~63;
1365                 *line_len = npixels << 1;
1366                 *newFBSize = nlines * *dstPitch;
1367                 *newTTSize = nlines * *line_len;
1368                 }
1369         else if ( action_flags & IS_RGB )
1370                 {
1371                 *srcPitch = width << 2; /* one R, one G, one B, one X per pixel */
1372                 *dstPitch = ((npixels << 2) + 63) & ~63;
1373                 *line_len = npixels << 2;
1374                 *newFBSize = nlines * *dstPitch;
1375                 *newTTSize = nlines * *dstPitch;                
1376                 }
1377         
1378         
1379         if ( action_flags & CONVERT_TO_YUY2 )
1380                 {
1381                 *dstPitch = ((npixels << 1) + 63) & ~63;
1382                 *line_len = npixels << 1;
1383                 *newFBSize = nlines * *dstPitch;
1384                 *newTTSize = nlines * *line_len;
1385                 }
1386         
1387         if ( action_flags & SWAP_UV ) 
1388                 { //I420 swaps U and V
1389                 tmp = *s2offset;
1390                 *s2offset = *s3offset;
1391                 *s3offset = tmp;
1392                 }
1393         
1394         if ( action_flags & USE_OVERLAY ) // overlay double buffering ...
1395                 (*newFBSize) <<= 1; // ... means double the amount of VRAM needed
1396         
1397         return 0;
1398 }
1399
1400
1401 /**
1402  * NV_set_action_flags
1403  * This function computes the action flags from the input image,
1404  * that is, it decides what NVPutImage and its helpers must do.
1405  * This eases readability by avoiding lots of switch-case statements in the core NVPutImage
1406  */
1407 static void NV_set_action_flags(NVPtr pNv, ScrnInfoPtr pScrn, DrawablePtr pDraw, NVPortPrivPtr pPriv, int id, int * action_flags)
1408 {
1409         *action_flags = 0;
1410         if ( id == FOURCC_YUY2 || id == FOURCC_UYVY )
1411                 *action_flags |= IS_YUY2;
1412         
1413         if ( id == FOURCC_YV12 || id == FOURCC_I420 )
1414                 *action_flags |= IS_YV12;
1415         
1416         if ( id == FOURCC_RGB ) /*How long will we support it?*/
1417                 *action_flags |= IS_RGB; 
1418         
1419         if ( id == FOURCC_I420 ) /*I420 is YV12 with swapped UV*/
1420                 *action_flags |= SWAP_UV;
1421         
1422         if ( !pPriv -> blitter )
1423                 *action_flags |= USE_OVERLAY;
1424         
1425         #ifdef COMPOSITE
1426         WindowPtr pWin = NULL;
1427                 
1428         if (!noCompositeExtension && WindowDrawable(pDraw->type)) 
1429                 {
1430                 pWin = (WindowPtr)pDraw;
1431                 }
1432                         
1433         if ( pWin )
1434                 if ( pWin->redirectDraw )
1435                         *action_flags &= ~USE_OVERLAY;
1436                                 
1437         #endif
1438                 
1439         if ( ! ( *action_flags & USE_OVERLAY) )
1440                 {
1441                 if ( id == FOURCC_YV12 || id == FOURCC_I420 )
1442                         { /*The blitter does not handle YV12 natively*/
1443                         *action_flags |= CONVERT_TO_YUY2;
1444                         }
1445                 }
1446
1447         if ( pNv->Architecture == NV_ARCH_04 )
1448                 if ( * action_flags & IS_YV12 ) //NV04-05 don't support native YV12, only YUY2 and ITU-R BT.601)
1449                         *action_flags |= CONVERT_TO_YUY2;
1450                 
1451         if ( pNv->Architecture == NV_ARCH_10 || pNv->Architecture == NV_ARCH_20 )
1452                 {
1453                 switch ( pNv->Chipset & 0xfff0 )
1454                         {
1455                         case CHIPSET_NV10:
1456                         case CHIPSET_NV11:
1457                         case CHIPSET_NV15:
1458                         case CHIPSET_NFORCE: /*XXX: unsure about nforce*/
1459                         case CHIPSET_NV20: /*reported by pq - in fact all cards older than geforce4 ti probably don't have YV12 overlay*/
1460                                         *action_flags |= CONVERT_TO_YUY2; break;
1461                         
1462                         default : break;
1463                         }
1464                 }
1465         
1466 }
1467
1468
1469 /**
1470  * NVPutImage
1471  * PutImage is "the" important function of the Xv extension.
1472  * a client (e.g. video player) calls this function for every
1473  * image (of the video) to be displayed. this function then
1474  * scales and displays the image.
1475  * 
1476  * @param pScrn screen which hold the port where the image is put
1477  * @param src_x source point in the source image to start displaying from
1478  * @param src_y see above
1479  * @param src_w width of the source image to display
1480  * @param src_h see above
1481  * @param drw_x  screen point to display to
1482  * @param drw_y
1483  * @param drw_w width of the screen drawable
1484  * @param drw_h
1485  * @param id pixel format of image
1486  * @param buf pointer to buffer containing the source image
1487  * @param width total width of the source image we are passed
1488  * @param height 
1489  * @param Sync unused
1490  * @param clipBoxes ??
1491  * @param data pointer to port 
1492  * @param pDraw drawable pointer
1493  */
1494 static int
1495 NVPutImage(ScrnInfoPtr  pScrn, short src_x, short src_y,
1496                                    short drw_x, short drw_y,
1497                                    short src_w, short src_h, 
1498                                    short drw_w, short drw_h,
1499                                    int id,
1500                                    unsigned char *buf, 
1501                                    short width, short height, 
1502                                    Bool         Sync, /*FIXME: need to honor the Sync*/
1503                                    RegionPtr    clipBoxes,
1504                                    pointer      data,
1505                                    DrawablePtr  pDraw
1506 )
1507 {
1508         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
1509         NVPtr pNv = NVPTR(pScrn);
1510         INT32 xa = 0, xb = 0, ya = 0, yb = 0; //source box
1511         int newFBSize = 0, newTTSize = 0; //size to allocate in VRAM and in GART respectively
1512         int offset = 0, s2offset = 0, s3offset = 0; //card VRAM offset, source offsets for U and V planes
1513         int srcPitch = 0, srcPitch2 = 0, dstPitch = 0; //source pitch, source pitch of U and V planes in case of YV12, VRAM destination pitch
1514         int top = 0, left = 0, right = 0, bottom = 0, npixels = 0, nlines = 0; //position of the given source data (using src_*), number of pixels and lines we are interested in
1515         Bool skip = FALSE;
1516         BoxRec dstBox;
1517         CARD32 tmp = 0;
1518         int line_len = 0; //length of a line, like npixels, but in bytes 
1519         int DMAoffset = 0; //additional VRAM offset to start the DMA copy to
1520         int UVDMAoffset = 0;
1521         struct nouveau_bo *destination_buffer = NULL;
1522         unsigned char * video_mem_destination = NULL;  
1523         int action_flags; //what shall we do?
1524         
1525         
1526         if (pPriv->grabbedByV4L)
1527                 return Success;
1528
1529         
1530         NV_set_action_flags(pNv, pScrn, pDraw, pPriv, id, &action_flags);
1531         
1532         if ( NV_set_dimensions(pScrn, action_flags, &xa, &xb, &ya, &yb, 
1533                                                         &src_x,  &src_y, &src_w, &src_h,
1534                                                         &drw_x, &drw_y, &drw_w, &drw_h, 
1535                                                         &left, &top, &right, &bottom, &dstBox, 
1536                                                         &npixels, &nlines,
1537                                                         clipBoxes, width, height ) )
1538                 {
1539                 return Success;
1540                 }
1541         
1542
1543         if ( NV_calculate_pitches_and_mem_size(action_flags, &srcPitch, &srcPitch2, &dstPitch, 
1544                                                                                 &s2offset, &s3offset, 
1545                                                                                 & newFBSize, &newTTSize ,&line_len ,
1546                                                                                 npixels, nlines, width, height) )
1547                 {
1548                 return BadImplementation;
1549                 }
1550         
1551         /* There are some cases (tvtime with overscan for example) where the input image is larger (width/height) than 
1552                 the source rectangle for the overlay (src_w, src_h). In those cases, we try to do something optimal by uploading only 
1553                 the necessary data. */
1554         if ( action_flags & IS_YUY2 || action_flags & IS_RGB )
1555                 {
1556                 buf += (top * srcPitch) + left;
1557                 DMAoffset += left + (top * dstPitch);
1558                 }
1559                 
1560         if ( action_flags & IS_YV12 )
1561                 {
1562                 tmp = ((top >> 1) * srcPitch2) + (left >> 1);
1563                 s2offset += tmp;
1564                 s3offset += tmp;
1565                         
1566                 if ( action_flags & CONVERT_TO_YUY2 )
1567                         {
1568                         DMAoffset += (left << 1) + (top * dstPitch);
1569                         }
1570                         
1571                 else
1572                         {
1573                         //real YV12 - we offset only the luma plane, and copy the whole color plane, for easiness
1574                         DMAoffset += left + (top * dstPitch);
1575                         UVDMAoffset += left + (top >> 1) * dstPitch;
1576                         }       
1577                 }
1578         
1579         pPriv->video_mem = NVAllocateVideoMemory(pScrn, pPriv->video_mem, 
1580                                                               newFBSize);
1581         if (!pPriv->video_mem)
1582                 return BadAlloc;
1583
1584         offset = pPriv->video_mem->offset;
1585         
1586         /*The overlay supports hardware double buffering. We handle this here*/
1587         if (pPriv->doubleBuffer) {
1588                 int mask = 1 << (pPriv->currentBuffer << 2);
1589                 /* overwrite the newest buffer if there's not one free */
1590                 if (nvReadVIDEO(pNv, NV_PVIDEO_BUFFER) & mask) {
1591                         if (!pPriv->currentBuffer)
1592                                 offset += newFBSize >> 1;
1593                         skip = TRUE;
1594                 } 
1595                 else 
1596                         if (pPriv->currentBuffer)
1597                                 offset += newFBSize >> 1;
1598                 }
1599
1600         /*Now we take a decision regarding the way we send the data to the card.
1601         Either we use double buffering of "private" TT memory
1602         Either we rely on X's GARTScratch 
1603         Either we fallback on CPU copy
1604         */
1605
1606         /* Try to allocate host-side double buffers, unless we have already failed*/
1607         /* We take only nlines * line_len bytes - that is, only the pixel data we are interested in - because the stuff in the GART is 
1608                  written contiguously */
1609         if ( pPriv -> currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE )
1610                 {
1611                 pPriv->TT_mem_chunk[0] = NVAllocateTTMemory(pScrn, pPriv->TT_mem_chunk[0], 
1612                                                               newTTSize);
1613                 if ( pPriv->TT_mem_chunk[0] )
1614                         {
1615                         pPriv->TT_mem_chunk[1] = NVAllocateTTMemory(pScrn, pPriv->TT_mem_chunk[1], 
1616                                                               newTTSize);
1617                         
1618                         if ( ! pPriv->TT_mem_chunk[1] )
1619                                 {
1620                                 nouveau_bo_del(&pPriv->TT_mem_chunk[0]);
1621                                 pPriv->TT_mem_chunk[0] = NULL;
1622                                 pPriv -> currentHostBuffer = NO_PRIV_HOST_BUFFER_AVAILABLE;
1623                                 //xf86DrvMsg(0, X_INFO, "Alloc 1 failed\n");
1624                                 }
1625                         }
1626                 else 
1627                         {
1628                         pPriv -> currentHostBuffer = NO_PRIV_HOST_BUFFER_AVAILABLE;
1629                         //xf86DrvMsg(0, X_INFO, "Alloc 0 failed\n");
1630                         }
1631                 }
1632         
1633         if ( pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE )
1634                 { //if we have a private buffer
1635                 destination_buffer = pPriv->TT_mem_chunk[pPriv->currentHostBuffer];
1636                 //xf86DrvMsg(0, X_INFO, "Using private mem chunk #%d\n", pPriv->currentHostBuffer);
1637                         
1638                 /* We know where we are going to write, but we are not sure yet whether we can do it directly, because
1639                         the card could be working on the buffer for the last-but-one frame. So we check if we have a notifier ready or not. 
1640                         If we do, then we must wait for it before overwriting the buffer.
1641                         Else we need one, so we call the Xv notifier allocator.*/
1642                 if ( pPriv->DMANotifier [ pPriv->currentHostBuffer ] )
1643                         {
1644                         //xf86DrvMsg(0, X_INFO, "Waiting for notifier %p (%d)\n", pPriv->DMANotifier[pPriv->currentHostBuffer], pPriv->currentHostBuffer);
1645                         if (nouveau_notifier_wait_status(pPriv->DMANotifier[pPriv->currentHostBuffer], 0, 0, 0))
1646                                 return FALSE;
1647                         }
1648                 else 
1649                         {
1650                         //xf86DrvMsg(0, X_INFO, "Allocating notifier...\n");
1651                         pPriv->DMANotifier [ pPriv->currentHostBuffer ] = NVXvDMANotifierAlloc(pScrn);
1652                         if (! pPriv->DMANotifier [ pPriv->currentHostBuffer ] )
1653                                 { /* In case we are out of notifiers (then our guy is watching 3 movies at a time!!), we fallback on global GART, and free the private buffers.
1654                                         I know that's a lot of code but I believe it's necessary to properly handle all the cases*/
1655                                 xf86DrvMsg(0, X_ERROR, "Ran out of Xv notifiers!\n");
1656                                 nouveau_bo_del(&pPriv->TT_mem_chunk[0]);
1657                                 pPriv->TT_mem_chunk[0] = NULL;
1658                                 nouveau_bo_del(&pPriv->TT_mem_chunk[1]);
1659                                 pPriv->TT_mem_chunk[1] = NULL;
1660                                 pPriv -> currentHostBuffer = NO_PRIV_HOST_BUFFER_AVAILABLE;
1661                                 }
1662                         //xf86DrvMsg(0, X_INFO, "Got notifier %p\n", pPriv->DMANotifier [ pPriv->currentHostBuffer ]);
1663                         }
1664                 }
1665         
1666         if ( pPriv -> currentHostBuffer == NO_PRIV_HOST_BUFFER_AVAILABLE )
1667                 { //otherwise we fall back on DDX's GARTScratch
1668                 destination_buffer = pNv->GART;
1669                 //xf86DrvMsg(0, X_INFO, "Using global GART memory chunk\n");
1670                 }
1671
1672         if ( !destination_buffer) //if we have no GART at all
1673                 goto CPU_copy;
1674         
1675         if(newTTSize <= destination_buffer->size)
1676                 {
1677                 unsigned char *dst = destination_buffer->map;
1678                 int i = 0;
1679                         
1680                 /* Upload to GART */
1681                 if ( action_flags & IS_YV12)
1682                         {
1683                         if ( action_flags & CONVERT_TO_YUY2 )
1684                                 {
1685                                 NVCopyData420(buf + (top * srcPitch) + left,
1686                                 buf + s2offset, buf + s3offset,
1687                                 dst, srcPitch, srcPitch2,
1688                                 line_len, nlines, npixels);
1689                                 }
1690                         else
1691                                 { /*Native YV12*/
1692                                 unsigned char * tbuf = buf + top * srcPitch + left;
1693                                 unsigned char * tdst = dst;
1694                                 //xf86DrvMsg(0, X_INFO, "srcPitch %d dstPitch %d srcPitch2 %d nlines %d npixels %d left %d top %d s2offset %d\n", srcPitch, dstPitch, srcPitch2, nlines, npixels, left, top, s2offset);
1695                                 /* luma upload */
1696                                 for ( i=0; i < nlines; i++)
1697                                         {
1698                                         memcpy(tdst, tbuf, line_len);
1699                                         tdst += line_len;
1700                                         tbuf += srcPitch;
1701                                         }
1702                                 dst += line_len * nlines;
1703                                 NVCopyNV12ColorPlanes(buf + s2offset, buf + s3offset, dst, line_len, srcPitch2, nlines, line_len);
1704                                 }
1705                         }
1706                 else 
1707                         {
1708                         for ( i=0; i < nlines; i++)
1709                                 {
1710                                 memcpy(dst, buf, line_len);
1711                                 dst += line_len;
1712                                 buf += srcPitch;
1713                                 }
1714                         }
1715                 
1716                 
1717                 BEGIN_RING(NvMemFormat,
1718                            NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
1719                 OUT_RING  (pNv->chan->gart->handle);
1720                 OUT_RING  (pNv->chan->vram->handle);
1721                 
1722                 /* DMA to VRAM */
1723                 if ( action_flags & IS_YV12 && ! (action_flags & CONVERT_TO_YUY2) )
1724                         { /*we start the color plane transfer separately*/
1725                         BEGIN_RING(NvMemFormat,
1726                                    NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
1727                         OUT_RING  ((uint32_t)destination_buffer->offset + line_len * nlines);
1728                         OUT_RING  ((uint32_t)offset + dstPitch * nlines);
1729                         OUT_RING  (line_len);
1730                         OUT_RING  (dstPitch);
1731                         OUT_RING  (line_len);
1732                         OUT_RING  ((nlines >> 1));
1733                         OUT_RING  ((1<<8)|1);
1734                         OUT_RING  (0);
1735                         FIRE_RING();            
1736                         }
1737                                 
1738                 BEGIN_RING(NvMemFormat,
1739                            NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
1740                 OUT_RING  ((uint32_t)destination_buffer->offset);
1741                 OUT_RING  ((uint32_t)offset /*+ DMAoffset*/);
1742                 OUT_RING  (line_len);
1743                 OUT_RING  (dstPitch);
1744                 OUT_RING  (line_len);
1745                 OUT_RING  (nlines);
1746                 OUT_RING  ((1<<8)|1);
1747                 OUT_RING  (0);
1748                         
1749                 if ( destination_buffer == pNv->GART ) 
1750                         {
1751                         nouveau_notifier_reset(pNv->notify0, 0);
1752                         }
1753                 else {
1754                         nouveau_notifier_reset(pPriv->DMANotifier[pPriv->currentHostBuffer], 0);
1755                         BEGIN_RING(NvMemFormat,
1756                                    NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
1757                         OUT_RING  (pPriv->DMANotifier[pPriv->currentHostBuffer]->handle);
1758                         }
1759                         
1760                         
1761                 BEGIN_RING(NvMemFormat, NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
1762                 OUT_RING  (0);
1763                         
1764                 BEGIN_RING(NvMemFormat, 0x100, 1);
1765                 OUT_RING  (0);
1766                                 
1767                 //Put back NvDmaNotifier0 for EXA
1768                 BEGIN_RING(NvMemFormat,
1769                            NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
1770                 OUT_RING  (pNv->notify0->handle);
1771                 
1772                 FIRE_RING();                    
1773
1774                 if ( destination_buffer == pNv->GART ) 
1775                         if (nouveau_notifier_wait_status(pNv->notify0, 0, 0, 0))
1776                                 return FALSE;
1777                 }
1778         else { //GART is too small, we fallback on CPU copy
1779                 CPU_copy:
1780                 video_mem_destination = pPriv->video_mem->map + (offset - (uint32_t)pPriv->video_mem->offset);
1781                 int i = 0;
1782                 if ( action_flags & IS_YV12 )
1783                         {
1784                         if ( action_flags & CONVERT_TO_YUY2 )
1785                                 {
1786                                 NVCopyData420(buf + (top * srcPitch) + left,
1787                                         buf + s2offset, buf + s3offset,
1788                                         video_mem_destination, srcPitch, srcPitch2,
1789                                         dstPitch, nlines, npixels);
1790                                 }
1791                         else {
1792                                 unsigned char * tbuf = buf + left + top * srcPitch;
1793                                 for ( i=0; i < nlines; i++)
1794                                 {
1795                                 int dwords = npixels << 1;
1796                                 while (dwords & ~0x03) 
1797                                         {
1798                                         *video_mem_destination = *tbuf;
1799                                         *(video_mem_destination + 1) = *(tbuf + 1);
1800                                         *(video_mem_destination + 2) = *(tbuf + 2);
1801                                         *(video_mem_destination + 3) = *(tbuf + 3);
1802                                         video_mem_destination += 4;
1803                                         tbuf += 4;
1804                                         dwords -= 4;
1805                                         }
1806                                 switch ( dwords ) 
1807                                         {
1808                                         case 3:
1809                                                 *(video_mem_destination + 2) = *(tbuf + 2);
1810                                         case 2:
1811                                                 *(video_mem_destination + 1) = *(tbuf + 1);
1812                                         case 1:
1813                                                 *video_mem_destination = *tbuf;
1814                                         }
1815                                 
1816                                 video_mem_destination += dstPitch - (npixels << 1);
1817                                 tbuf += srcPitch - (npixels << 1);
1818                                 }
1819                                 
1820                                 NVCopyNV12ColorPlanes(buf + s2offset, buf + s3offset, video_mem_destination, dstPitch, srcPitch2, nlines, line_len);
1821                                 }
1822                         }
1823                 else //YUY2 and RGB
1824                         {
1825                         for ( i=0; i < nlines; i++)
1826                                 {
1827                                 int dwords = npixels << 1;
1828                                 while (dwords & ~0x03) 
1829                                         {
1830                                         *video_mem_destination = *buf;
1831                                         *(video_mem_destination + 1) = *(buf + 1);
1832                                         *(video_mem_destination + 2) = *(buf + 2);
1833                                         *(video_mem_destination + 3) = *(buf + 3);
1834                                         video_mem_destination += 4;
1835                                         buf += 4;
1836                                         dwords -= 4;
1837                                         }
1838                                 switch ( dwords ) 
1839                                         {
1840                                         case 3:
1841                                                 *(video_mem_destination + 2) = *(buf + 2);
1842                                         case 2:
1843                                                 *(video_mem_destination + 1) = *(buf + 1);
1844                                         case 1:
1845                                                 *video_mem_destination = *buf;
1846                                         }
1847                                 
1848                                 video_mem_destination += dstPitch - (npixels << 1);
1849                                 buf += srcPitch - (npixels << 1);
1850                                 }
1851                         }
1852                 } //CPU copy
1853                 
1854
1855         if (!skip) 
1856                 {
1857                 if ( pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE )
1858                         pPriv->currentHostBuffer ^= 1;
1859                 
1860                 if ( action_flags & USE_OVERLAY )
1861                         {
1862                         if ( pNv->Architecture == NV_ARCH_04 )
1863                                 NV04PutOverlayImage(pScrn, offset, id,
1864                                           dstPitch, &dstBox, 
1865                                           0,0, xb, yb,
1866                                           npixels, nlines,
1867                                           src_w, src_h, drw_w, drw_h,
1868                                           clipBoxes);
1869                         else
1870                                 NVPutOverlayImage(pScrn, offset, ((action_flags & IS_YUY2) || (action_flags & CONVERT_TO_YUY2)) ? 0 : offset + nlines * dstPitch, id,
1871                                           dstPitch, &dstBox, 
1872                                           0,0, xb, yb,
1873                                           npixels, nlines,
1874                                           src_w, src_h, drw_w, drw_h,
1875                                           clipBoxes);
1876                         pPriv->currentBuffer ^= 1;
1877
1878                         }
1879                 else 
1880                         { //Blitter
1881                         NVPutBlitImage(pScrn, offset, id,
1882                                        dstPitch, &dstBox,
1883                                        0, 0, xb, yb,
1884                                        npixels, nlines,
1885                                        src_w, src_h, drw_w, drw_h,
1886                                        clipBoxes, pDraw);
1887                         }
1888                 }
1889         return Success;
1890 }
1891
1892 /**
1893  * QueryImageAttributes
1894  * 
1895  * calculates
1896  * - size (memory required to store image),
1897  * - pitches,
1898  * - offsets
1899  * of image
1900  * depending on colorspace (id) and dimensions (w,h) of image
1901  * values of
1902  * - w,
1903  * - h
1904  * may be adjusted as needed
1905  * 
1906  * @param pScrn unused
1907  * @param id colorspace of image
1908  * @param w pointer to width of image
1909  * @param h pointer to height of image
1910  * @param pitches pitches[i] = length of a scanline in plane[i]
1911  * @param offsets offsets[i] = offset of plane i from the beginning of the image
1912  * @return size of the memory required for the XvImage queried
1913  */
1914 static int
1915 NVQueryImageAttributes(ScrnInfoPtr pScrn, int id, 
1916                        unsigned short *w, unsigned short *h, 
1917                        int *pitches, int *offsets)
1918 {
1919         int size, tmp;
1920
1921         if (*w > IMAGE_MAX_W)
1922                 *w = IMAGE_MAX_W;
1923         if (*h > IMAGE_MAX_H)
1924                 *h = IMAGE_MAX_H;
1925
1926         *w = (*w + 1) & ~1; // width rounded up to an even number
1927         if (offsets)
1928                 offsets[0] = 0;
1929
1930         switch (id) {
1931         case FOURCC_YV12:
1932         case FOURCC_I420:
1933                 *h = (*h + 1) & ~1; // height rounded up to an even number
1934                 size = (*w + 3) & ~3; // width rounded up to a multiple of 4
1935                 if (pitches)
1936                         pitches[0] = size; // width rounded up to a multiple of 4
1937                 size *= *h;
1938                 if (offsets)
1939                         offsets[1] = size; // number of pixels in "rounded up" image
1940                 tmp = ((*w >> 1) + 3) & ~3; // width/2 rounded up to a multiple of 4
1941                 if (pitches)
1942                         pitches[1] = pitches[2] = tmp; // width/2 rounded up to a multiple of 4
1943                 tmp *= (*h >> 1); // 1/4*number of pixels in "rounded up" image
1944                 size += tmp; // 5/4*number of pixels in "rounded up" image
1945                 if (offsets)
1946                         offsets[2] = size; // 5/4*number of pixels in "rounded up" image
1947                 size += tmp; // = 3/2*number of pixels in "rounded up" image
1948                 break;
1949         case FOURCC_UYVY:
1950         case FOURCC_YUY2:
1951                 size = *w << 1; // 2*width
1952                 if (pitches)
1953                         pitches[0] = size; // 2*width
1954                 size *= *h; // 2*width*height
1955                 break;
1956         case FOURCC_RGB:
1957                 size = *w << 2; // 4*width (32 bit per pixel)
1958                 if (pitches)
1959                         pitches[0] = size; // 4*width
1960                 size *= *h; // 4*width*height
1961                 break;
1962         default:
1963                 *w = *h = size = 0;
1964                 break;
1965         }
1966
1967         return size;
1968 }
1969
1970 /***** Exported offscreen surface stuff ****/
1971
1972
1973 static int
1974 NVAllocSurface(ScrnInfoPtr pScrn, int id,
1975                unsigned short w, unsigned short h,
1976                XF86SurfacePtr surface)
1977 {
1978         NVPtr pNv = NVPTR(pScrn);
1979         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); 
1980         int size, bpp;
1981
1982         bpp = pScrn->bitsPerPixel >> 3;
1983
1984         if (pPriv->grabbedByV4L)
1985                 return BadAlloc;
1986
1987         if ((w > IMAGE_MAX_W) || (h > IMAGE_MAX_H))
1988                 return BadValue;
1989
1990         w = (w + 1) & ~1;
1991         pPriv->pitch = ((w << 1) + 63) & ~63;
1992         size = h * pPriv->pitch / bpp;
1993
1994         pPriv->video_mem = NVAllocateVideoMemory(pScrn,
1995                                                    pPriv->video_mem,
1996                                                    size);
1997         if (!pPriv->video_mem)
1998                 return BadAlloc;
1999
2000         pPriv->offset = 0;
2001         
2002         surface->width = w;
2003         surface->height = h;
2004         surface->pScrn = pScrn;
2005         surface->pitches = &pPriv->pitch; 
2006         surface->offsets = &pPriv->offset;
2007         surface->devPrivate.ptr = (pointer)pPriv;
2008         surface->id = id;
2009
2010         /* grab the video */
2011         NVStopOverlay(pScrn);
2012         pPriv->videoStatus = 0;
2013         REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
2014         pPriv->grabbedByV4L = TRUE;
2015
2016         return Success;
2017 }
2018
2019 static int
2020 NVStopSurface(XF86SurfacePtr surface)
2021 {
2022         NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
2023
2024         if (pPriv->grabbedByV4L && pPriv->videoStatus) {
2025                 NVStopOverlay(surface->pScrn);
2026                 pPriv->videoStatus = 0;
2027         }
2028
2029         return Success;
2030 }
2031
2032 static int 
2033 NVFreeSurface(XF86SurfacePtr surface)
2034 {
2035         NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
2036
2037         if (pPriv->grabbedByV4L) {
2038                 NVStopSurface(surface);
2039                 NVFreeOverlayMemory(surface->pScrn);
2040                 pPriv->grabbedByV4L = FALSE;
2041         }
2042
2043         return Success;
2044 }
2045
2046 static int
2047 NVGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value)
2048 {
2049         NVPtr pNv = NVPTR(pScrn);
2050         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
2051
2052         return NVGetOverlayPortAttribute(pScrn, attribute,
2053                                          value, (pointer)pPriv);
2054 }
2055
2056 static int
2057 NVSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value)
2058 {
2059         NVPtr pNv = NVPTR(pScrn);
2060         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
2061
2062         return NVSetOverlayPortAttribute(pScrn, attribute,
2063                                          value, (pointer)pPriv);
2064 }
2065
2066 static int
2067 NVDisplaySurface(XF86SurfacePtr surface,
2068                  short src_x, short src_y, 
2069                  short drw_x, short drw_y,
2070                  short src_w, short src_h, 
2071                  short drw_w, short drw_h,
2072                  RegionPtr clipBoxes)
2073 {
2074         ScrnInfoPtr pScrn = surface->pScrn;
2075         NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
2076         INT32 xa, xb, ya, yb;
2077         BoxRec dstBox;
2078
2079         if (!pPriv->grabbedByV4L)
2080                 return Success;
2081
2082         if (src_w > (drw_w << 3))
2083                 drw_w = src_w >> 3;
2084         if (src_h > (drw_h << 3))
2085                 drw_h = src_h >> 3;
2086
2087         /* Clip */
2088         xa = src_x;
2089         xb = src_x + src_w;
2090         ya = src_y;
2091         yb = src_y + src_h;
2092
2093         dstBox.x1 = drw_x;
2094         dstBox.x2 = drw_x + drw_w;
2095         dstBox.y1 = drw_y;
2096         dstBox.y2 = drw_y + drw_h;
2097
2098         if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, 
2099                                   surface->width, surface->height))
2100                 return Success;
2101
2102         dstBox.x1 -= pScrn->frameX0;
2103         dstBox.x2 -= pScrn->frameX0;
2104         dstBox.y1 -= pScrn->frameY0;
2105         dstBox.y2 -= pScrn->frameY0;
2106
2107         pPriv->currentBuffer = 0;
2108
2109         NVPutOverlayImage(pScrn, surface->offsets[0], 0, surface->id,
2110                           surface->pitches[0], &dstBox, xa, ya, xb, yb,
2111                           surface->width, surface->height, src_w, src_h,
2112                           drw_w, drw_h, clipBoxes);
2113
2114         return Success;
2115 }
2116
2117 /**
2118  * NVSetupBlitVideo
2119  * this function does all the work setting up a blit port
2120  * 
2121  * @return blit port
2122  */
2123 static XF86VideoAdaptorPtr
2124 NVSetupBlitVideo (ScreenPtr pScreen)
2125 {
2126         ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
2127         NVPtr               pNv       = NVPTR(pScrn);
2128         XF86VideoAdaptorPtr adapt;
2129         NVPortPrivPtr       pPriv;
2130         int i;
2131
2132         if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
2133                                         sizeof(NVPortPrivRec) +
2134                                         (sizeof(DevUnion) * NUM_BLIT_PORTS)))) {
2135                 return NULL;
2136         }
2137
2138         adapt->type             = XvWindowMask | XvInputMask | XvImageMask;
2139         adapt->flags            = 0;
2140         adapt->name             = "NV Video Blitter";
2141         adapt->nEncodings       = 1;
2142         adapt->pEncodings       = &DummyEncoding;
2143         adapt->nFormats         = NUM_FORMATS_ALL;
2144         adapt->pFormats         = NVFormats;
2145         adapt->nPorts           = NUM_BLIT_PORTS;
2146         adapt->pPortPrivates    = (DevUnion*)(&adapt[1]);
2147
2148         pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_BLIT_PORTS]);
2149         for(i = 0; i < NUM_BLIT_PORTS; i++)
2150                 adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
2151
2152         if(pNv->WaitVSyncPossible) {
2153                 adapt->pAttributes = NVBlitAttributes;
2154                 adapt->nAttributes = NUM_BLIT_ATTRIBUTES;
2155         } else {
2156                 adapt->pAttributes = NULL;
2157                 adapt->nAttributes = 0;
2158         }
2159
2160         adapt->pImages                  = NVImages;
2161         adapt->nImages                  = NUM_IMAGES_ALL;
2162         adapt->PutVideo                 = NULL;
2163         adapt->PutStill                 = NULL;
2164         adapt->GetVideo                 = NULL;
2165         adapt->GetStill                 = NULL;
2166         adapt->StopVideo                = NVStopBlitVideo;
2167         adapt->SetPortAttribute         = NVSetBlitPortAttribute;
2168         adapt->GetPortAttribute         = NVGetBlitPortAttribute;
2169         adapt->QueryBestSize            = NVQueryBestSize;
2170         adapt->PutImage                 = NVPutImage;
2171         adapt->QueryImageAttributes     = NVQueryImageAttributes;
2172
2173         pPriv->videoStatus              = 0;
2174         pPriv->grabbedByV4L             = FALSE;
2175         pPriv->blitter                  = TRUE;
2176         pPriv->doubleBuffer             = FALSE;
2177         pPriv->SyncToVBlank             = pNv->WaitVSyncPossible;
2178
2179         pNv->blitAdaptor                = adapt;
2180         xvSyncToVBlank                  = MAKE_ATOM("XV_SYNC_TO_VBLANK");
2181
2182         return adapt;
2183 }
2184
2185 /**
2186  * NVSetupOverlayVideo
2187  * this function does all the work setting up an overlay port
2188  * 
2189  * @return overlay port
2190  * @see NVResetVideo(ScrnInfoPtr pScrn)
2191  */
2192 static XF86VideoAdaptorPtr 
2193 NVSetupOverlayVideoAdapter(ScreenPtr pScreen)
2194 {
2195         ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
2196         NVPtr               pNv       = NVPTR(pScrn);
2197         XF86VideoAdaptorPtr adapt;
2198         NVPortPrivPtr       pPriv;
2199
2200         if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + 
2201                                         sizeof(NVPortPrivRec) + 
2202                                         sizeof(DevUnion)))) {
2203                 return NULL;
2204         }
2205
2206         adapt->type             = XvWindowMask | XvInputMask | XvImageMask;
2207         adapt->flags            = VIDEO_OVERLAID_IMAGES|VIDEO_CLIP_TO_VIEWPORT;
2208         adapt->name             = "NV Video Overlay";
2209         adapt->nEncodings       = 1;
2210         adapt->pEncodings       = &DummyEncoding;
2211         adapt->nFormats         = NUM_FORMATS_ALL;
2212         adapt->pFormats         = NVFormats;
2213         adapt->nPorts           = 1;
2214         adapt->pPortPrivates    = (DevUnion*)(&adapt[1]);
2215
2216         pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[1]);
2217         adapt->pPortPrivates[0].ptr     = (pointer)(pPriv);
2218
2219         adapt->pAttributes              = (pNv->Architecture != NV_ARCH_04) ? NVOverlayAttributes : NV04OverlayAttributes;
2220         adapt->nAttributes              = (pNv->Architecture != NV_ARCH_04) ? NUM_OVERLAY_ATTRIBUTES : NUM_NV04_OVERLAY_ATTRIBUTES;
2221         adapt->pImages                  = NVImages;
2222         adapt->nImages                  = NUM_IMAGES_YUV;
2223         adapt->PutVideo                 = NULL;
2224         adapt->PutStill                 = NULL;
2225         adapt->GetVideo                 = NULL;
2226         adapt->GetStill                 = NULL;
2227         adapt->StopVideo                = NVStopOverlayVideo;
2228         adapt->SetPortAttribute         = NVSetOverlayPortAttribute;
2229         adapt->GetPortAttribute         = NVGetOverlayPortAttribute;
2230         adapt->QueryBestSize            = NVQueryBestSize;
2231         adapt->PutImage                 = NVPutImage;
2232         adapt->QueryImageAttributes     = NVQueryImageAttributes;
2233
2234         pPriv->videoStatus              = 0;
2235         pPriv->currentBuffer            = 0;
2236         pPriv->grabbedByV4L             = FALSE;
2237         pPriv->blitter                  = FALSE;
2238         if ( pNv->Architecture == NV_ARCH_04 )
2239                 pPriv->doubleBuffer             = 0;
2240         
2241         NVSetPortDefaults (pScrn, pPriv);
2242
2243         /* gotta uninit this someplace */
2244         REGION_NULL(pScreen, &pPriv->clip);
2245
2246         pNv->overlayAdaptor     = adapt;
2247
2248         xvColorKey              = MAKE_ATOM("XV_COLORKEY");
2249         if ( pNv->Architecture != NV_ARCH_04 )
2250                 {
2251                 xvBrightness            = MAKE_ATOM("XV_BRIGHTNESS");
2252                 xvDoubleBuffer          = MAKE_ATOM("XV_DOUBLE_BUFFER");
2253                 xvContrast              = MAKE_ATOM("XV_CONTRAST");
2254                 xvSaturation            = MAKE_ATOM("XV_SATURATION");
2255                 xvHue                   = MAKE_ATOM("XV_HUE");
2256                 xvAutopaintColorKey     = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
2257                 xvSetDefaults           = MAKE_ATOM("XV_SET_DEFAULTS");
2258                 xvITURBT709             = MAKE_ATOM("XV_ITURBT_709");
2259                 xvOnCRTCNb              = MAKE_ATOM("XV_ON_CRTC_NB");
2260                 }
2261
2262         NVResetVideo(pScrn);
2263
2264         return adapt;
2265 }
2266
2267
2268 XF86OffscreenImageRec NVOffscreenImages[2] = {
2269         {
2270                 &NVImages[0],
2271                 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
2272                 NVAllocSurface,
2273                 NVFreeSurface,
2274                 NVDisplaySurface,
2275                 NVStopSurface,
2276                 NVGetSurfaceAttribute,
2277                 NVSetSurfaceAttribute,
2278                 IMAGE_MAX_W, IMAGE_MAX_H,
2279                 NUM_OVERLAY_ATTRIBUTES - 1,
2280                 &NVOverlayAttributes[1]
2281         },
2282         {
2283                 &NVImages[2],
2284                 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
2285                 NVAllocSurface,
2286                 NVFreeSurface,
2287                 NVDisplaySurface,
2288                 NVStopSurface,
2289                 NVGetSurfaceAttribute,
2290                 NVSetSurfaceAttribute,
2291                 IMAGE_MAX_W, IMAGE_MAX_H,
2292                 NUM_OVERLAY_ATTRIBUTES - 1,
2293                 &NVOverlayAttributes[1]
2294         }
2295 };
2296
2297 static void
2298 NVInitOffscreenImages (ScreenPtr pScreen)
2299 {
2300         xf86XVRegisterOffscreenImages(pScreen, NVOffscreenImages, 2);
2301 }
2302
2303 /**
2304  * NVChipsetHasOverlay
2305  * 
2306  * newer chips don't support overlay anymore.
2307  * overlay feature is emulated via textures.
2308  * 
2309  * @param pNv 
2310  * @return true, if chipset supports overlay
2311  */
2312 static Bool
2313 NVChipsetHasOverlay(NVPtr pNv)
2314 {
2315         switch (pNv->Architecture) {
2316         case NV_ARCH_04: /*NV04 has a different overlay than NV10+*/
2317         case NV_ARCH_10:
2318         case NV_ARCH_20:
2319         case NV_ARCH_30:
2320                 return TRUE;
2321         case NV_ARCH_40:
2322                 if ((pNv->Chipset & 0xfff0) == CHIPSET_NV40)
2323                         return TRUE;
2324                 break;
2325         default:
2326                 break;
2327         }
2328
2329         return FALSE;
2330 }
2331
2332 /**
2333  * NVSetupOverlayVideo
2334  * check if chipset supports Overlay and CompositeExtension is disabled.
2335  * if so, setup overlay port
2336  * 
2337  * @return overlay port
2338  * @see NVChipsetHasOverlay(NVPtr pNv)
2339  * @see NV10SetupOverlayVideo(ScreenPtr pScreen)
2340  * @see NVInitOffscreenImages(ScreenPtr pScreen)
2341  */
2342 static XF86VideoAdaptorPtr
2343 NVSetupOverlayVideo(ScreenPtr pScreen)
2344 {
2345         ScrnInfoPtr          pScrn = xf86Screens[pScreen->myNum];
2346         XF86VideoAdaptorPtr  overlayAdaptor = NULL;
2347         NVPtr                pNv   = NVPTR(pScrn);
2348
2349         if (!NVChipsetHasOverlay(pNv))
2350                 return NULL;
2351
2352         overlayAdaptor = NVSetupOverlayVideoAdapter(pScreen);
2353         if (overlayAdaptor && pNv->Architecture != NV_ARCH_04 )
2354                 NVInitOffscreenImages(pScreen); //I am not sure what this call does.
2355         
2356         #ifdef COMPOSITE
2357         if (!noCompositeExtension) {
2358                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2359                         "XV: Composite is enabled, enabling overlay with smart blitter fallback\n");
2360                 overlayAdaptor -> name = "NV Video Overlay with Composite";
2361         }
2362         #endif
2363
2364         return overlayAdaptor;
2365 }
2366
2367 /**
2368  * NVInitVideo
2369  * tries to initialize one new overlay port and one new blit port
2370  * and add them to the list of ports on screen "pScreen".
2371  * 
2372  * @param pScreen
2373  * @see NVSetupOverlayVideo(ScreenPtr pScreen)
2374  * @see NVSetupBlitVideo(ScreenPtr pScreen)
2375  */
2376 void NVInitVideo (ScreenPtr pScreen)
2377 {
2378         ScrnInfoPtr          pScrn = xf86Screens[pScreen->myNum];
2379         NVPtr                pNv = NVPTR(pScrn);
2380         XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
2381         XF86VideoAdaptorPtr  overlayAdaptor = NULL;
2382         XF86VideoAdaptorPtr  blitAdaptor = NULL;
2383         int                  num_adaptors;
2384
2385         /*
2386          * Driving the blitter requires the DMA FIFO. Using the FIFO
2387          * without accel causes DMA errors. While the overlay might
2388          * might work without accel, we also disable it for now when
2389          * acceleration is disabled:
2390          */
2391         if (pScrn->bitsPerPixel != 8 && pNv->Architecture < NV_ARCH_50 && !pNv->NoAccel) {
2392                 overlayAdaptor = NVSetupOverlayVideo(pScreen);
2393                 blitAdaptor    = NVSetupBlitVideo(pScreen);
2394         }
2395
2396         num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
2397         if(blitAdaptor || overlayAdaptor) {
2398                 int size = num_adaptors;
2399
2400                 if(overlayAdaptor) size++;
2401                 if(blitAdaptor)    size++;
2402
2403                 newAdaptors = xalloc(size * sizeof(XF86VideoAdaptorPtr *));
2404                 if(newAdaptors) {
2405                         if(num_adaptors) {
2406                                 memcpy(newAdaptors, adaptors, num_adaptors *
2407                                                 sizeof(XF86VideoAdaptorPtr));
2408                         }
2409
2410                         if(overlayAdaptor) {
2411                                 newAdaptors[num_adaptors] = overlayAdaptor;
2412                                 num_adaptors++;
2413                         }
2414
2415                         if(blitAdaptor) {
2416                                 newAdaptors[num_adaptors] = blitAdaptor;
2417                                 num_adaptors++;
2418                         }
2419
2420                         adaptors = newAdaptors;
2421                 }
2422         }
2423
2424         if (num_adaptors)
2425                 xf86XVScreenInit(pScreen, adaptors, num_adaptors);
2426         if (newAdaptors)
2427                 xfree(newAdaptors);
2428 }
2429