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