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