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