randr12: Move away from some of the nv_hw wrappers.
[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 #if X_BYTE_ORDER == X_BIG_ENDIAN
693                         *vud = (vs[0]<<8) | (us[0] << 0);
694 #else
695                         *vud = vs[0] | (us[0]<<8);
696 #endif
697                         }
698                 dst += dstPitch ;
699                 src1 += srcPitch2;
700                 src2 += srcPitch2;
701                 }       
702
703 }
704
705
706 static int NV_set_dimensions(ScrnInfoPtr pScrn, int action_flags, INT32 * xa, INT32 * xb, INT32 * ya, INT32 * yb, 
707                                                         short * src_x, short * src_y, short * src_w, short * src_h,
708                                                         short * drw_x, short * drw_y, short * drw_w, short * drw_h,
709                                                         int * left, int * top, int * right, int * bottom,
710                                                         BoxRec * dstBox, 
711                                                         int * npixels, int * nlines,
712                                                         RegionPtr clipBoxes, short width, short height
713                                                         )
714 {
715     NVPtr pNv = NVPTR(pScrn);
716
717
718     if ( action_flags & USE_OVERLAY ) 
719         { /* overlay hardware scaler limitation - copied from nv, UNCHECKED*/
720         if (*src_w > (*drw_w << 3))
721             *drw_w = *src_w >> 3;
722         if (*src_h > (*drw_h << 3))
723             *drw_h = *src_h >> 3;
724         }
725
726
727     /* Clip */
728     *xa = *src_x;
729     *xb = *src_x + *src_w;
730     *ya = *src_y;
731     *yb = *src_y + *src_h;
732
733     dstBox->x1 = *drw_x;
734     dstBox->x2 = *drw_x + *drw_w;
735     dstBox->y1 = *drw_y;
736     dstBox->y2 = *drw_y + *drw_h;
737
738     if (!xf86XVClipVideoHelper(dstBox, xa, xb, ya, yb, clipBoxes,
739                 width, height))
740         return -1;
741
742     if ( action_flags & USE_OVERLAY )
743         {
744         if ( ! pNv->randr12_enable )
745             {
746             dstBox->x1 -= pScrn->frameX0;
747             dstBox->x2 -= pScrn->frameX0;
748             dstBox->y1 -= pScrn->frameY0;
749             dstBox->y2 -= pScrn->frameY0;
750             }
751         else
752             {
753             xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
754             NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
755             dstBox->x1 -= xf86_config->crtc[pPriv->overlayCRTC]->x;
756             dstBox->x2 -= xf86_config->crtc[pPriv->overlayCRTC]->x;
757             dstBox->y1 -= xf86_config->crtc[pPriv->overlayCRTC]->y;
758             dstBox->y2 -= xf86_config->crtc[pPriv->overlayCRTC]->y;
759             }
760         }
761
762
763
764     /* Convert fixed point to integer, as xf86XVClipVideoHelper probably turns its parameter into fixed point values */
765     *left = (*xa) >> 16;
766     if (*left < 0) *left = 0;
767     *top = (*ya) >> 16;
768     if (*top < 0) *top = 0;
769     *right = (*xb) >> 16;
770     if (*right > width) *right = width;
771     *bottom = (*yb) >> 16;
772     if (*bottom > height) *bottom = height;
773
774     if ( action_flags & IS_YV12 )
775         {
776         *left &= ~1; //even "left", even "top", even number of pixels per line and even number of lines
777         *npixels = ((*right + 1) & ~1) - *left;
778         *top &= ~1;
779         *nlines = ((*bottom + 1) & ~1) - *top;
780         }
781     else if ( action_flags & IS_YUY2 )
782         {
783         *left &= ~1; //even "left"
784         *npixels = ((*right + 1) & ~1) - *left; //even number of pixels per line
785         *nlines = *bottom - *top; 
786         *left <<= 1; //16bpp
787         }
788     else if (action_flags & IS_RGB )
789         {
790         *npixels = *right - *left;
791         *nlines = *bottom - *top;
792         *left <<= 2; //32bpp
793         }
794
795     return 0;
796 }
797
798 static int NV_calculate_pitches_and_mem_size(int action_flags, int * srcPitch, int * srcPitch2, int * dstPitch, 
799                                                                                 int * s2offset, int * s3offset, 
800                                                                                 int * newFBSize, int * newTTSize,
801                                                                                 int * line_len, int npixels, int nlines, int width, int height)
802 {
803         int tmp;
804                 
805         if ( action_flags & IS_YV12 ) 
806                 {       /*YV12 or I420*/
807                 *srcPitch = (width + 3) & ~3;   /* of luma */
808                 *s2offset = *srcPitch * height;
809                 *srcPitch2 = ((width >> 1) + 3) & ~3; /*of chroma*/
810                 *s3offset = (*srcPitch2 * (height >> 1)) + *s2offset;
811                 *dstPitch = (npixels + 63) & ~63; /*luma and chroma pitch*/
812                 *line_len = npixels;
813                 *newFBSize = nlines * *dstPitch + (nlines >> 1) * *dstPitch;
814                 *newTTSize = nlines * *dstPitch + (nlines >> 1) * *dstPitch;
815                 }
816         else if ( action_flags & IS_YUY2 )
817                 {
818                 *srcPitch = width << 1; /* one luma, one chroma per pixel */
819                 *dstPitch = ((npixels << 1) + 63) & ~63;
820                 *line_len = npixels << 1;
821                 *newFBSize = nlines * *dstPitch;
822                 *newTTSize = nlines * *line_len;
823                 }
824         else if ( action_flags & IS_RGB )
825                 {
826                 *srcPitch = width << 2; /* one R, one G, one B, one X per pixel */
827                 *dstPitch = ((npixels << 2) + 63) & ~63;
828                 *line_len = npixels << 2;
829                 *newFBSize = nlines * *dstPitch;
830                 *newTTSize = nlines * *dstPitch;                
831                 }
832         
833         
834         if ( action_flags & CONVERT_TO_YUY2 )
835                 {
836                 *dstPitch = ((npixels << 1) + 63) & ~63;
837                 *line_len = npixels << 1;
838                 *newFBSize = nlines * *dstPitch;
839                 *newTTSize = nlines * *line_len;
840                 }
841         
842         if ( action_flags & SWAP_UV ) 
843                 { //I420 swaps U and V
844                 tmp = *s2offset;
845                 *s2offset = *s3offset;
846                 *s3offset = tmp;
847                 }
848         
849         if ( action_flags & USE_OVERLAY ) // overlay double buffering ...
850                 (*newFBSize) <<= 1; // ... means double the amount of VRAM needed
851         
852         return 0;
853 }
854
855
856 /**
857  * NV_set_action_flags
858  * This function computes the action flags from the input image,
859  * that is, it decides what NVPutImage and its helpers must do.
860  * This eases readability by avoiding lots of switch-case statements in the core NVPutImage
861  */
862 static void NV_set_action_flags(ScrnInfoPtr pScrn, DrawablePtr pDraw, NVPortPrivPtr pPriv, int id, 
863         short drw_x, short drw_y, short drw_w, short drw_h, int * action_flags)
864 {
865 #define USING_OVERLAY (*action_flags & USE_OVERLAY)
866 #define USING_TEXTURE (*action_flags & USE_TEXTURE)
867 #define USING_BLITTER ((!(*action_flags & USE_OVERLAY)) && (!(*action_flags & USE_TEXTURE)))
868
869     NVPtr pNv = NVPTR(pScrn);
870
871     *action_flags = 0;
872
873     /* Pixel format-related bits */
874     if ( id == FOURCC_YUY2 || id == FOURCC_UYVY )
875         *action_flags |= IS_YUY2;
876
877     if ( id == FOURCC_YV12 || id == FOURCC_I420 )
878         *action_flags |= IS_YV12;
879
880     if ( id == FOURCC_RGB ) /*How long will we support it?*/
881         *action_flags |= IS_RGB; 
882
883     if ( id == FOURCC_I420 ) /*I420 is YV12 with swapped UV*/
884         *action_flags |= SWAP_UV;
885
886     /* Desired adapter */
887     if ( !pPriv -> blitter && !pPriv -> texture )
888         *action_flags |= USE_OVERLAY;
889
890     if ( !pPriv -> blitter && pPriv->texture )
891         *action_flags |= USE_TEXTURE;
892
893     /* Adapter fallbacks (when the desired one can't be used)*/
894 #ifdef COMPOSITE
895     WindowPtr pWin = NULL;
896
897     if (!noCompositeExtension && WindowDrawable(pDraw->type)) 
898         {
899         pWin = (WindowPtr)pDraw;
900         }
901
902     if ( pWin )
903         if ( pWin->redirectDraw )
904             *action_flags &= ~USE_OVERLAY;
905
906 #endif
907
908     if ( USING_OVERLAY && pNv->randr12_enable )
909         { /* We need to check the CRTC we're on */
910         char crtc = nv_window_belongs_to_crtc(pScrn, drw_x, drw_y, drw_w, drw_h);
911         
912         /* We're on CRTC 0, or 1, or both.. */
913         if ( ( crtc & (1 << 0)) && (crtc & (1 << 1)) )
914             { /* The overlay cannot be used on two CRTCs at a time, so we need to fallback on the blitter */
915             *action_flags &= ~USE_OVERLAY;
916             }
917         else if ( (crtc & (1 << 0) ) )
918             { /* We need to put the overlay on CRTC0 - if it's not already here */
919             if ( pPriv->overlayCRTC == 1 )
920                 {
921                 NVWriteCRTC(pNv, 0, NV_CRTC_FSEL, NVReadCRTC(pNv, 0, NV_CRTC_FSEL) | NV_CRTC_FSEL_OVERLAY);
922                 NVWriteCRTC(pNv, 1, NV_CRTC_FSEL, NVReadCRTC(pNv, 1, NV_CRTC_FSEL) & ~NV_CRTC_FSEL_OVERLAY);
923                 pPriv->overlayCRTC = 0;
924                 }
925             }
926         else if ( (crtc & (1 << 1) ) )
927             {
928             if ( pPriv->overlayCRTC == 0 )
929                 {
930                 NVWriteCRTC(pNv, 1, NV_CRTC_FSEL, NVReadCRTC(pNv, 1, NV_CRTC_FSEL) | NV_CRTC_FSEL_OVERLAY);
931                 NVWriteCRTC(pNv, 0, NV_CRTC_FSEL, NVReadCRTC(pNv, 0, NV_CRTC_FSEL) & ~NV_CRTC_FSEL_OVERLAY);
932                 pPriv->overlayCRTC = 1;
933                 }
934             }
935         }
936
937     /* At this point the adapter we're going to use is _known_. You cannot change it now. */
938     /* Card/adapter format restrictions */
939     if ( USING_BLITTER )
940         {
941         if ( id == FOURCC_YV12 || id == FOURCC_I420 )
942             { /*The blitter does not handle YV12 natively*/
943             *action_flags |= CONVERT_TO_YUY2;
944             }
945         }
946
947     if ( USING_OVERLAY && (pNv->Architecture == NV_ARCH_04 ))
948         if ( * action_flags & IS_YV12 ) /*NV04-05 don't support native YV12, only YUY2 and ITU-R BT.601*/
949             *action_flags |= CONVERT_TO_YUY2;
950
951     if ( USING_OVERLAY && (pNv->Architecture == NV_ARCH_10 || pNv->Architecture == NV_ARCH_20 ))
952         { /* No YV12 overlay on NV10, 11, 15, 20, NFORCE */
953         switch ( pNv->Chipset & 0xfff0 )
954             {
955             case CHIPSET_NV10:
956             case CHIPSET_NV11:
957             case CHIPSET_NV15:
958             case CHIPSET_NFORCE: /*XXX: unsure about nforce*/
959             case CHIPSET_NV20:
960                 *action_flags |= CONVERT_TO_YUY2; break;
961
962             default : break;
963             }
964         }
965
966 }
967
968
969 /**
970  * NVPutImage
971  * PutImage is "the" important function of the Xv extension.
972  * a client (e.g. video player) calls this function for every
973  * image (of the video) to be displayed. this function then
974  * scales and displays the image.
975  * 
976  * @param pScrn screen which hold the port where the image is put
977  * @param src_x source point in the source image to start displaying from
978  * @param src_y see above
979  * @param src_w width of the source image to display
980  * @param src_h see above
981  * @param drw_x  screen point to display to
982  * @param drw_y
983  * @param drw_w width of the screen drawable
984  * @param drw_h
985  * @param id pixel format of image
986  * @param buf pointer to buffer containing the source image
987  * @param width total width of the source image we are passed
988  * @param height 
989  * @param Sync unused
990  * @param clipBoxes ??
991  * @param data pointer to port 
992  * @param pDraw drawable pointer
993  */
994 static int
995 NVPutImage(ScrnInfoPtr  pScrn, short src_x, short src_y,
996                                    short drw_x, short drw_y,
997                                    short src_w, short src_h, 
998                                    short drw_w, short drw_h,
999                                    int id,
1000                                    unsigned char *buf, 
1001                                    short width, short height, 
1002                                    Bool         Sync, /*FIXME: need to honor the Sync*/
1003                                    RegionPtr    clipBoxes,
1004                                    pointer      data,
1005                                    DrawablePtr  pDraw
1006 )
1007 {
1008         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
1009         NVPtr pNv = NVPTR(pScrn);
1010         INT32 xa = 0, xb = 0, ya = 0, yb = 0; //source box
1011         int newFBSize = 0, newTTSize = 0; //size to allocate in VRAM and in GART respectively
1012         int offset = 0, s2offset = 0, s3offset = 0; //card VRAM offset, source offsets for U and V planes
1013         int srcPitch = 0, srcPitch2 = 0, dstPitch = 0; //source pitch, source pitch of U and V planes in case of YV12, VRAM destination pitch
1014         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
1015         Bool skip = FALSE;
1016         BoxRec dstBox;
1017         CARD32 tmp = 0;
1018         int line_len = 0; //length of a line, like npixels, but in bytes 
1019         struct nouveau_bo *destination_buffer = NULL;
1020         unsigned char * video_mem_destination = NULL;  
1021         int action_flags; //what shall we do?
1022         
1023         
1024         if (pPriv->grabbedByV4L)
1025                 return Success;
1026
1027         
1028         NV_set_action_flags(pScrn, pDraw, pPriv, id, drw_x, drw_y, drw_w, drw_h, &action_flags);
1029         
1030         if ( NV_set_dimensions(pScrn, action_flags, &xa, &xb, &ya, &yb, 
1031                                                         &src_x,  &src_y, &src_w, &src_h,
1032                                                         &drw_x, &drw_y, &drw_w, &drw_h, 
1033                                                         &left, &top, &right, &bottom, &dstBox, 
1034                                                         &npixels, &nlines,
1035                                                         clipBoxes, width, height ) )
1036                 {
1037                 return Success;
1038                 }
1039         
1040
1041         if ( NV_calculate_pitches_and_mem_size(action_flags, &srcPitch, &srcPitch2, &dstPitch, 
1042                                                                                 &s2offset, &s3offset, 
1043                                                                                 & newFBSize, &newTTSize ,&line_len ,
1044                                                                                 npixels, nlines, width, height) )
1045                 {
1046                 return BadImplementation;
1047                 }
1048         
1049         /* There are some cases (tvtime with overscan for example) where the input image is larger (width/height) than 
1050                 the source rectangle for the overlay (src_w, src_h). In those cases, we try to do something optimal by uploading only 
1051                 the necessary data. */
1052         if ( action_flags & IS_YUY2 || action_flags & IS_RGB )
1053                 {
1054                 buf += (top * srcPitch) + left;
1055                 }
1056                 
1057         if ( action_flags & IS_YV12 )
1058                 {
1059                 tmp = ((top >> 1) * srcPitch2) + (left >> 1);
1060                 s2offset += tmp;
1061                 s3offset += tmp;
1062                 }
1063         
1064         pPriv->video_mem = NVAllocateVideoMemory(pScrn, pPriv->video_mem, 
1065                                                               newFBSize);
1066         if (!pPriv->video_mem)
1067                 return BadAlloc;
1068
1069         offset = pPriv->video_mem->offset;
1070
1071         /*The overlay supports hardware double buffering. We handle this here*/
1072         if (pPriv->doubleBuffer) {
1073                 int mask = 1 << (pPriv->currentBuffer << 2);
1074                 /* overwrite the newest buffer if there's not one free */
1075                 if (nvReadVIDEO(pNv, NV_PVIDEO_BUFFER) & mask) {
1076                         if (!pPriv->currentBuffer)
1077                                 offset += newFBSize >> 1;
1078                         skip = TRUE;
1079                 } 
1080                 else 
1081                         if (pPriv->currentBuffer)
1082                                 offset += newFBSize >> 1;
1083                 }
1084
1085         /*Now we take a decision regarding the way we send the data to the card.
1086         Either we use double buffering of "private" TT memory
1087         Either we rely on X's GARTScratch 
1088         Either we fallback on CPU copy
1089         */
1090
1091         /* Try to allocate host-side double buffers, unless we have already failed*/
1092         /* We take only nlines * line_len bytes - that is, only the pixel data we are interested in - because the stuff in the GART is 
1093                  written contiguously */
1094         if ( pPriv -> currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE )
1095                 {
1096                 pPriv->TT_mem_chunk[0] = NVAllocateTTMemory(pScrn, pPriv->TT_mem_chunk[0], 
1097                                                               newTTSize);
1098                 if ( pPriv->TT_mem_chunk[0] )
1099                         {
1100                         pPriv->TT_mem_chunk[1] = NVAllocateTTMemory(pScrn, pPriv->TT_mem_chunk[1], 
1101                                                               newTTSize);
1102                         
1103                         if ( ! pPriv->TT_mem_chunk[1] )
1104                                 {
1105                                 nouveau_bo_del(&pPriv->TT_mem_chunk[0]);
1106                                 pPriv->TT_mem_chunk[0] = NULL;
1107                                 pPriv -> currentHostBuffer = NO_PRIV_HOST_BUFFER_AVAILABLE;
1108                                 //xf86DrvMsg(0, X_INFO, "Alloc 1 failed\n");
1109                                 }
1110                         }
1111                 else 
1112                         {
1113                         pPriv -> currentHostBuffer = NO_PRIV_HOST_BUFFER_AVAILABLE;
1114                         //xf86DrvMsg(0, X_INFO, "Alloc 0 failed\n");
1115                         }
1116                 }
1117         
1118         if ( pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE )
1119                 { //if we have a private buffer
1120                 destination_buffer = pPriv->TT_mem_chunk[pPriv->currentHostBuffer];
1121                 //xf86DrvMsg(0, X_INFO, "Using private mem chunk #%d\n", pPriv->currentHostBuffer);
1122                         
1123                 /* We know where we are going to write, but we are not sure yet whether we can do it directly, because
1124                         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. 
1125                         If we do, then we must wait for it before overwriting the buffer.
1126                         Else we need one, so we call the Xv notifier allocator.*/
1127                 if ( pPriv->DMANotifier [ pPriv->currentHostBuffer ] )
1128                         {
1129                         //xf86DrvMsg(0, X_INFO, "Waiting for notifier %p (%d)\n", pPriv->DMANotifier[pPriv->currentHostBuffer], pPriv->currentHostBuffer);
1130                         if (nouveau_notifier_wait_status(pPriv->DMANotifier[pPriv->currentHostBuffer], 0, 0, 0))
1131                                 return FALSE;
1132                         }
1133                 else 
1134                         {
1135                         //xf86DrvMsg(0, X_INFO, "Allocating notifier...\n");
1136                         pPriv->DMANotifier [ pPriv->currentHostBuffer ] = NVXvDMANotifierAlloc(pScrn);
1137                         if (! pPriv->DMANotifier [ pPriv->currentHostBuffer ] )
1138                                 { /* 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.
1139                                         I know that's a lot of code but I believe it's necessary to properly handle all the cases*/
1140                                 xf86DrvMsg(0, X_ERROR, "Ran out of Xv notifiers!\n");
1141                                 nouveau_bo_del(&pPriv->TT_mem_chunk[0]);
1142                                 pPriv->TT_mem_chunk[0] = NULL;
1143                                 nouveau_bo_del(&pPriv->TT_mem_chunk[1]);
1144                                 pPriv->TT_mem_chunk[1] = NULL;
1145                                 pPriv -> currentHostBuffer = NO_PRIV_HOST_BUFFER_AVAILABLE;
1146                                 }
1147                         //xf86DrvMsg(0, X_INFO, "Got notifier %p\n", pPriv->DMANotifier [ pPriv->currentHostBuffer ]);
1148                         }
1149                 }
1150         
1151         if ( pPriv -> currentHostBuffer == NO_PRIV_HOST_BUFFER_AVAILABLE )
1152                 { //otherwise we fall back on DDX's GARTScratch
1153                 destination_buffer = pNv->GART;
1154                 //xf86DrvMsg(0, X_INFO, "Using global GART memory chunk\n");
1155                 }
1156
1157         if ( !destination_buffer) //if we have no GART at all
1158                 goto CPU_copy;
1159         
1160         if(newTTSize <= destination_buffer->size)
1161                 {
1162                 unsigned char *dst = destination_buffer->map;
1163                 int i = 0;
1164                         
1165                 /* Upload to GART */
1166                 if ( action_flags & IS_YV12)
1167                         {
1168                         if ( action_flags & CONVERT_TO_YUY2 )
1169                                 {
1170                                 NVCopyData420(buf + (top * srcPitch) + left,
1171                                 buf + s2offset, buf + s3offset,
1172                                 dst, srcPitch, srcPitch2,
1173                                 line_len, nlines, npixels);
1174                                 }
1175                         else
1176                                 { /*Native YV12*/
1177                                 unsigned char * tbuf = buf + top * srcPitch + left;
1178                                 unsigned char * tdst = dst;
1179                                 //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);
1180                                 /* luma upload */
1181                                 for ( i=0; i < nlines; i++)
1182                                         {
1183                                         memcpy(tdst, tbuf, line_len);
1184                                         tdst += line_len;
1185                                         tbuf += srcPitch;
1186                                         }
1187                                 dst += line_len * nlines;
1188                                 NVCopyNV12ColorPlanes(buf + s2offset, buf + s3offset, dst, line_len, srcPitch2, nlines, line_len);
1189                                 }
1190                         }
1191                 else 
1192                         {
1193                         for ( i=0; i < nlines; i++)
1194                                 {
1195                                 memcpy(dst, buf, line_len);
1196                                 dst += line_len;
1197                                 buf += srcPitch;
1198                                 }
1199                         }
1200                 
1201                 
1202                 BEGIN_RING(NvMemFormat,
1203                            NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
1204                 OUT_RING  (pNv->chan->gart->handle);
1205                 OUT_RING  (pNv->chan->vram->handle);
1206                 
1207                 /* DMA to VRAM */
1208                 if (action_flags & IS_YV12 && ! (action_flags & CONVERT_TO_YUY2) )
1209                         { /*we start the color plane transfer separately*/
1210                         BEGIN_RING(NvMemFormat,
1211                                    NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
1212                         OUT_RING  ((uint32_t)destination_buffer->offset + line_len * nlines);
1213                         OUT_RING  ((uint32_t)offset + dstPitch * nlines);
1214                         OUT_RING  (line_len);
1215                         OUT_RING  (dstPitch);
1216                         OUT_RING  (line_len);
1217                         OUT_RING  ((nlines >> 1));
1218                         OUT_RING  ((1<<8)|1);
1219                         OUT_RING  (0);
1220                         FIRE_RING();            
1221                         }
1222                                 
1223                 BEGIN_RING(NvMemFormat,
1224                            NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
1225                 OUT_RING  ((uint32_t)destination_buffer->offset);
1226                 OUT_RING  ((uint32_t)offset);
1227                 OUT_RING  (line_len);
1228                 OUT_RING  (dstPitch);
1229                 OUT_RING  (line_len);
1230                 OUT_RING  (nlines);
1231                 OUT_RING  ((1<<8)|1);
1232                 OUT_RING  (0);
1233                         
1234                 if ( destination_buffer == pNv->GART ) 
1235                         {
1236                         nouveau_notifier_reset(pNv->notify0, 0);
1237                         }
1238                 else {
1239                         nouveau_notifier_reset(pPriv->DMANotifier[pPriv->currentHostBuffer], 0);
1240                         BEGIN_RING(NvMemFormat,
1241                                    NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
1242                         OUT_RING  (pPriv->DMANotifier[pPriv->currentHostBuffer]->handle);
1243                         }
1244                         
1245                         
1246                 BEGIN_RING(NvMemFormat, NV04_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
1247                 OUT_RING  (0);
1248                         
1249                 BEGIN_RING(NvMemFormat, 0x100, 1);
1250                 OUT_RING  (0);
1251                                 
1252                 //Put back NvDmaNotifier0 for EXA
1253                 BEGIN_RING(NvMemFormat,
1254                            NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
1255                 OUT_RING  (pNv->notify0->handle);
1256                 
1257                 FIRE_RING();                    
1258
1259                 if ( destination_buffer == pNv->GART ) 
1260                         if (nouveau_notifier_wait_status(pNv->notify0, 0, 0, 0))
1261                                 return FALSE;
1262                 }
1263         else { //GART is too small, we fallback on CPU copy
1264                 CPU_copy:
1265                 video_mem_destination = pPriv->video_mem->map + (offset - (uint32_t)pPriv->video_mem->offset);
1266                 int i = 0;
1267                 if ( action_flags & IS_YV12 )
1268                         {
1269                         if ( action_flags & CONVERT_TO_YUY2 )
1270                                 {
1271                                 NVCopyData420(buf + (top * srcPitch) + left,
1272                                         buf + s2offset, buf + s3offset,
1273                                         video_mem_destination, srcPitch, srcPitch2,
1274                                         dstPitch, nlines, npixels);
1275                                 }
1276                         else {
1277                                 unsigned char * tbuf = buf + left + top * srcPitch;
1278                                 for ( i=0; i < nlines; i++)
1279                                 {
1280                                 int dwords = npixels << 1;
1281                                 while (dwords & ~0x03) 
1282                                         {
1283                                         *video_mem_destination = *tbuf;
1284                                         *(video_mem_destination + 1) = *(tbuf + 1);
1285                                         *(video_mem_destination + 2) = *(tbuf + 2);
1286                                         *(video_mem_destination + 3) = *(tbuf + 3);
1287                                         video_mem_destination += 4;
1288                                         tbuf += 4;
1289                                         dwords -= 4;
1290                                         }
1291                                 switch ( dwords ) 
1292                                         {
1293                                         case 3:
1294                                                 *(video_mem_destination + 2) = *(tbuf + 2);
1295                                         case 2:
1296                                                 *(video_mem_destination + 1) = *(tbuf + 1);
1297                                         case 1:
1298                                                 *video_mem_destination = *tbuf;
1299                                         }
1300                                 
1301                                 video_mem_destination += dstPitch - (npixels << 1);
1302                                 tbuf += srcPitch - (npixels << 1);
1303                                 }
1304                                 
1305                                 NVCopyNV12ColorPlanes(buf + s2offset, buf + s3offset, video_mem_destination, dstPitch, srcPitch2, nlines, line_len);
1306                                 }
1307                         }
1308                 else //YUY2 and RGB
1309                         {
1310                         for ( i=0; i < nlines; i++)
1311                                 {
1312                                 int dwords = npixels << 1;
1313                                 while (dwords & ~0x03) 
1314                                         {
1315                                         *video_mem_destination = *buf;
1316                                         *(video_mem_destination + 1) = *(buf + 1);
1317                                         *(video_mem_destination + 2) = *(buf + 2);
1318                                         *(video_mem_destination + 3) = *(buf + 3);
1319                                         video_mem_destination += 4;
1320                                         buf += 4;
1321                                         dwords -= 4;
1322                                         }
1323                                 switch ( dwords ) 
1324                                         {
1325                                         case 3:
1326                                                 *(video_mem_destination + 2) = *(buf + 2);
1327                                         case 2:
1328                                                 *(video_mem_destination + 1) = *(buf + 1);
1329                                         case 1:
1330                                                 *video_mem_destination = *buf;
1331                                         }
1332                                 
1333                                 video_mem_destination += dstPitch - (npixels << 1);
1334                                 buf += srcPitch - (npixels << 1);
1335                                 }
1336                         }
1337                 } //CPU copy
1338                 
1339
1340         if (!skip) 
1341                 {
1342                 if ( pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE )
1343                         pPriv->currentHostBuffer ^= 1;
1344                 
1345                 if ( action_flags & USE_OVERLAY )
1346                         {
1347                         if ( pNv->Architecture == NV_ARCH_04 )
1348                                 NV04PutOverlayImage(pScrn, offset, id,
1349                                           dstPitch, &dstBox, 
1350                                           0,0, xb, yb,
1351                                           npixels, nlines,
1352                                           src_w, src_h, drw_w, drw_h,
1353                                           clipBoxes);
1354                         else
1355                                 NV10PutOverlayImage(pScrn, offset, ((action_flags & IS_YUY2) || (action_flags & CONVERT_TO_YUY2)) ? 0 : offset + nlines * dstPitch, id,
1356                                           dstPitch, &dstBox, 
1357                                           0,0, xb, yb,
1358                                           npixels, nlines,
1359                                           src_w, src_h, drw_w, drw_h,
1360                                           clipBoxes);
1361                         pPriv->currentBuffer ^= 1;
1362
1363                         }
1364                 else 
1365                         {
1366                                 if (action_flags & USE_TEXTURE) { /* Texture adapter */
1367                                         int rval = NV40PutTextureImage(pScrn, offset, offset + nlines * dstPitch, id,
1368                                                         dstPitch, &dstBox,
1369                                                         0, 0, xb, yb,
1370                                                         npixels, nlines,
1371                                                         src_w, src_h, drw_w, drw_h,
1372                                                         clipBoxes, pDraw);
1373                                         if (rval != Success)
1374                                                 return rval;
1375                                 } else { /* Blit adapter */
1376                                         NVPutBlitImage(pScrn, offset, id,
1377                                                        dstPitch, &dstBox,
1378                                                        0, 0, xb, yb,
1379                                                        npixels, nlines,
1380                                                        src_w, src_h, drw_w, drw_h,
1381                                                        clipBoxes, pDraw);
1382                                 }
1383                         }
1384                 }
1385         return Success;
1386 }
1387
1388 /**
1389  * QueryImageAttributes
1390  * 
1391  * calculates
1392  * - size (memory required to store image),
1393  * - pitches,
1394  * - offsets
1395  * of image
1396  * depending on colorspace (id) and dimensions (w,h) of image
1397  * values of
1398  * - w,
1399  * - h
1400  * may be adjusted as needed
1401  * 
1402  * @param pScrn unused
1403  * @param id colorspace of image
1404  * @param w pointer to width of image
1405  * @param h pointer to height of image
1406  * @param pitches pitches[i] = length of a scanline in plane[i]
1407  * @param offsets offsets[i] = offset of plane i from the beginning of the image
1408  * @return size of the memory required for the XvImage queried
1409  */
1410 static int
1411 NVQueryImageAttributes(ScrnInfoPtr pScrn, int id, 
1412                        unsigned short *w, unsigned short *h, 
1413                        int *pitches, int *offsets)
1414 {
1415         int size, tmp;
1416
1417         if (*w > IMAGE_MAX_W)
1418                 *w = IMAGE_MAX_W;
1419         if (*h > IMAGE_MAX_H)
1420                 *h = IMAGE_MAX_H;
1421
1422         *w = (*w + 1) & ~1; // width rounded up to an even number
1423         if (offsets)
1424                 offsets[0] = 0;
1425
1426         switch (id) {
1427         case FOURCC_YV12:
1428         case FOURCC_I420:
1429                 *h = (*h + 1) & ~1; // height rounded up to an even number
1430                 size = (*w + 3) & ~3; // width rounded up to a multiple of 4
1431                 if (pitches)
1432                         pitches[0] = size; // width rounded up to a multiple of 4
1433                 size *= *h;
1434                 if (offsets)
1435                         offsets[1] = size; // number of pixels in "rounded up" image
1436                 tmp = ((*w >> 1) + 3) & ~3; // width/2 rounded up to a multiple of 4
1437                 if (pitches)
1438                         pitches[1] = pitches[2] = tmp; // width/2 rounded up to a multiple of 4
1439                 tmp *= (*h >> 1); // 1/4*number of pixels in "rounded up" image
1440                 size += tmp; // 5/4*number of pixels in "rounded up" image
1441                 if (offsets)
1442                         offsets[2] = size; // 5/4*number of pixels in "rounded up" image
1443                 size += tmp; // = 3/2*number of pixels in "rounded up" image
1444                 break;
1445         case FOURCC_UYVY:
1446         case FOURCC_YUY2:
1447                 size = *w << 1; // 2*width
1448                 if (pitches)
1449                         pitches[0] = size; // 2*width
1450                 size *= *h; // 2*width*height
1451                 break;
1452         case FOURCC_RGB:
1453                 size = *w << 2; // 4*width (32 bit per pixel)
1454                 if (pitches)
1455                         pitches[0] = size; // 4*width
1456                 size *= *h; // 4*width*height
1457                 break;
1458         default:
1459                 *w = *h = size = 0;
1460                 break;
1461         }
1462
1463         return size;
1464 }
1465
1466 /***** Exported offscreen surface stuff ****/
1467
1468
1469 static int
1470 NVAllocSurface(ScrnInfoPtr pScrn, int id,
1471                unsigned short w, unsigned short h,
1472                XF86SurfacePtr surface)
1473 {
1474         NVPtr pNv = NVPTR(pScrn);
1475         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); 
1476         int size, bpp;
1477
1478         bpp = pScrn->bitsPerPixel >> 3;
1479
1480         if (pPriv->grabbedByV4L)
1481                 return BadAlloc;
1482
1483         if ((w > IMAGE_MAX_W) || (h > IMAGE_MAX_H))
1484                 return BadValue;
1485
1486         w = (w + 1) & ~1;
1487         pPriv->pitch = ((w << 1) + 63) & ~63;
1488         size = h * pPriv->pitch / bpp;
1489
1490         pPriv->video_mem = NVAllocateVideoMemory(pScrn,
1491                                                    pPriv->video_mem,
1492                                                    size);
1493         if (!pPriv->video_mem)
1494                 return BadAlloc;
1495
1496         pPriv->offset = 0;
1497         
1498         surface->width = w;
1499         surface->height = h;
1500         surface->pScrn = pScrn;
1501         surface->pitches = &pPriv->pitch; 
1502         surface->offsets = &pPriv->offset;
1503         surface->devPrivate.ptr = (pointer)pPriv;
1504         surface->id = id;
1505
1506         /* grab the video */
1507         NVStopOverlay(pScrn);
1508         pPriv->videoStatus = 0;
1509         REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1510         pPriv->grabbedByV4L = TRUE;
1511
1512         return Success;
1513 }
1514
1515 static int
1516 NVStopSurface(XF86SurfacePtr surface)
1517 {
1518         NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1519
1520         if (pPriv->grabbedByV4L && pPriv->videoStatus) {
1521                 NV10StopOverlay(surface->pScrn);
1522                 pPriv->videoStatus = 0;
1523         }
1524
1525         return Success;
1526 }
1527
1528 static int 
1529 NVFreeSurface(XF86SurfacePtr surface)
1530 {
1531         NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1532
1533         if (pPriv->grabbedByV4L) {
1534                 NVStopSurface(surface);
1535                 NVFreeOverlayMemory(surface->pScrn);
1536                 pPriv->grabbedByV4L = FALSE;
1537         }
1538
1539         return Success;
1540 }
1541
1542 static int
1543 NVGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value)
1544 {
1545         NVPtr pNv = NVPTR(pScrn);
1546         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1547
1548         return NV10GetOverlayPortAttribute(pScrn, attribute,
1549                                          value, (pointer)pPriv);
1550 }
1551
1552 static int
1553 NVSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value)
1554 {
1555         NVPtr pNv = NVPTR(pScrn);
1556         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1557
1558         return NV10SetOverlayPortAttribute(pScrn, attribute,
1559                                          value, (pointer)pPriv);
1560 }
1561
1562 static int
1563 NVDisplaySurface(XF86SurfacePtr surface,
1564                  short src_x, short src_y, 
1565                  short drw_x, short drw_y,
1566                  short src_w, short src_h, 
1567                  short drw_w, short drw_h,
1568                  RegionPtr clipBoxes)
1569 {
1570         ScrnInfoPtr pScrn = surface->pScrn;
1571         NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1572         INT32 xa, xb, ya, yb;
1573         BoxRec dstBox;
1574
1575         if (!pPriv->grabbedByV4L)
1576                 return Success;
1577
1578         if (src_w > (drw_w << 3))
1579                 drw_w = src_w >> 3;
1580         if (src_h > (drw_h << 3))
1581                 drw_h = src_h >> 3;
1582
1583         /* Clip */
1584         xa = src_x;
1585         xb = src_x + src_w;
1586         ya = src_y;
1587         yb = src_y + src_h;
1588
1589         dstBox.x1 = drw_x;
1590         dstBox.x2 = drw_x + drw_w;
1591         dstBox.y1 = drw_y;
1592         dstBox.y2 = drw_y + drw_h;
1593
1594         if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, 
1595                                   surface->width, surface->height))
1596                 return Success;
1597
1598         dstBox.x1 -= pScrn->frameX0;
1599         dstBox.x2 -= pScrn->frameX0;
1600         dstBox.y1 -= pScrn->frameY0;
1601         dstBox.y2 -= pScrn->frameY0;
1602
1603         pPriv->currentBuffer = 0;
1604
1605         NV10PutOverlayImage(pScrn, surface->offsets[0], 0, surface->id,
1606                           surface->pitches[0], &dstBox, xa, ya, xb, yb,
1607                           surface->width, surface->height, src_w, src_h,
1608                           drw_w, drw_h, clipBoxes);
1609
1610         return Success;
1611 }
1612
1613 /**
1614  * NVSetupBlitVideo
1615  * this function does all the work setting up a blit port
1616  * 
1617  * @return blit port
1618  */
1619 static XF86VideoAdaptorPtr
1620 NVSetupBlitVideo (ScreenPtr pScreen)
1621 {
1622         ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1623         NVPtr               pNv       = NVPTR(pScrn);
1624         XF86VideoAdaptorPtr adapt;
1625         NVPortPrivPtr       pPriv;
1626         int i;
1627
1628         if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
1629                                         sizeof(NVPortPrivRec) +
1630                                         (sizeof(DevUnion) * NUM_BLIT_PORTS)))) {
1631                 return NULL;
1632         }
1633
1634         adapt->type             = XvWindowMask | XvInputMask | XvImageMask;
1635         adapt->flags            = 0;
1636         adapt->name             = "NV Video Blitter";
1637         adapt->nEncodings       = 1;
1638         adapt->pEncodings       = &DummyEncoding;
1639         adapt->nFormats         = NUM_FORMATS_ALL;
1640         adapt->pFormats         = NVFormats;
1641         adapt->nPorts           = NUM_BLIT_PORTS;
1642         adapt->pPortPrivates    = (DevUnion*)(&adapt[1]);
1643
1644         pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_BLIT_PORTS]);
1645         for(i = 0; i < NUM_BLIT_PORTS; i++)
1646                 adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
1647
1648         if(pNv->WaitVSyncPossible) {
1649                 adapt->pAttributes = NVBlitAttributes;
1650                 adapt->nAttributes = NUM_BLIT_ATTRIBUTES;
1651         } else {
1652                 adapt->pAttributes = NULL;
1653                 adapt->nAttributes = 0;
1654         }
1655
1656         adapt->pImages                  = NVImages;
1657         adapt->nImages                  = NUM_IMAGES_ALL;
1658         adapt->PutVideo                 = NULL;
1659         adapt->PutStill                 = NULL;
1660         adapt->GetVideo                 = NULL;
1661         adapt->GetStill                 = NULL;
1662         adapt->StopVideo                = NVStopBlitVideo;
1663         adapt->SetPortAttribute         = NVSetBlitPortAttribute;
1664         adapt->GetPortAttribute         = NVGetBlitPortAttribute;
1665         adapt->QueryBestSize            = NVQueryBestSize;
1666         adapt->PutImage                 = NVPutImage;
1667         adapt->QueryImageAttributes     = NVQueryImageAttributes;
1668
1669         pPriv->videoStatus              = 0;
1670         pPriv->grabbedByV4L             = FALSE;
1671         pPriv->blitter                  = TRUE;
1672         pPriv->texture                  = FALSE;
1673         pPriv->doubleBuffer             = FALSE;
1674         pPriv->SyncToVBlank             = pNv->WaitVSyncPossible;
1675
1676         pNv->blitAdaptor                = adapt;
1677         xvSyncToVBlank                  = MAKE_ATOM("XV_SYNC_TO_VBLANK");
1678
1679         return adapt;
1680 }
1681
1682 /**
1683  * NVSetupOverlayVideo
1684  * this function does all the work setting up an overlay port
1685  * 
1686  * @return overlay port
1687  */
1688 static XF86VideoAdaptorPtr 
1689 NVSetupOverlayVideoAdapter(ScreenPtr pScreen)
1690 {
1691         ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1692         NVPtr               pNv       = NVPTR(pScrn);
1693         XF86VideoAdaptorPtr adapt;
1694         NVPortPrivPtr       pPriv;
1695
1696         if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + 
1697                                         sizeof(NVPortPrivRec) + 
1698                                         sizeof(DevUnion)))) {
1699                 return NULL;
1700         }
1701
1702         adapt->type             = XvWindowMask | XvInputMask | XvImageMask;
1703         adapt->flags            = VIDEO_OVERLAID_IMAGES|VIDEO_CLIP_TO_VIEWPORT;
1704         adapt->name             = "NV Video Overlay";
1705         adapt->nEncodings       = 1;
1706         adapt->pEncodings       = &DummyEncoding;
1707         adapt->nFormats         = NUM_FORMATS_ALL;
1708         adapt->pFormats         = NVFormats;
1709         adapt->nPorts           = 1;
1710         adapt->pPortPrivates    = (DevUnion*)(&adapt[1]);
1711
1712         pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[1]);
1713         adapt->pPortPrivates[0].ptr     = (pointer)(pPriv);
1714
1715         adapt->pAttributes              = (pNv->Architecture != NV_ARCH_04) ? NV10OverlayAttributes : NV04OverlayAttributes;
1716         adapt->nAttributes              = (pNv->Architecture != NV_ARCH_04) ? NUM_NV10_OVERLAY_ATTRIBUTES : NUM_NV04_OVERLAY_ATTRIBUTES;
1717         adapt->pImages                  = NVImages;
1718         adapt->nImages                  = NUM_IMAGES_YUV;
1719         adapt->PutVideo                 = NULL;
1720         adapt->PutStill                 = NULL;
1721         adapt->GetVideo                 = NULL;
1722         adapt->GetStill                 = NULL;
1723         adapt->StopVideo                = NVStopOverlayVideo;
1724         adapt->SetPortAttribute         = (pNv->Architecture != NV_ARCH_04) ? NV10SetOverlayPortAttribute : NV04SetOverlayPortAttribute;
1725         adapt->GetPortAttribute         = (pNv->Architecture != NV_ARCH_04) ? NV10GetOverlayPortAttribute : NV04GetOverlayPortAttribute;
1726         adapt->QueryBestSize            = NVQueryBestSize;
1727         adapt->PutImage                 = NVPutImage;
1728         adapt->QueryImageAttributes     = NVQueryImageAttributes;
1729
1730         pPriv->videoStatus              = 0;
1731         pPriv->currentBuffer            = 0;
1732         pPriv->grabbedByV4L             = FALSE;
1733         pPriv->blitter                  = FALSE;
1734         pPriv->texture                  = FALSE;
1735         if ( pNv->Architecture == NV_ARCH_04 )
1736                 pPriv->doubleBuffer             = 0;
1737         
1738         NVSetPortDefaults (pScrn, pPriv);
1739
1740         /* gotta uninit this someplace */
1741         REGION_NULL(pScreen, &pPriv->clip);
1742
1743         pNv->overlayAdaptor     = adapt;
1744
1745         xvBrightness            = MAKE_ATOM("XV_BRIGHTNESS");
1746         xvColorKey              = MAKE_ATOM("XV_COLORKEY");
1747         xvAutopaintColorKey     = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
1748         xvSetDefaults           = MAKE_ATOM("XV_SET_DEFAULTS");
1749         
1750         if ( pNv->Architecture != NV_ARCH_04 )
1751                 {
1752                 xvDoubleBuffer          = MAKE_ATOM("XV_DOUBLE_BUFFER");
1753                 xvContrast              = MAKE_ATOM("XV_CONTRAST");
1754                 xvSaturation            = MAKE_ATOM("XV_SATURATION");
1755                 xvHue                   = MAKE_ATOM("XV_HUE");
1756                 xvITURBT709             = MAKE_ATOM("XV_ITURBT_709");
1757                 xvOnCRTCNb              = MAKE_ATOM("XV_ON_CRTC_NB");
1758                 NV10WriteOverlayParameters(pScrn);
1759                 }
1760
1761         return adapt;
1762 }
1763
1764
1765 XF86OffscreenImageRec NVOffscreenImages[2] = {
1766         {
1767                 &NVImages[0],
1768                 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1769                 NVAllocSurface,
1770                 NVFreeSurface,
1771                 NVDisplaySurface,
1772                 NVStopSurface,
1773                 NVGetSurfaceAttribute,
1774                 NVSetSurfaceAttribute,
1775                 IMAGE_MAX_W, IMAGE_MAX_H,
1776                 NUM_NV10_OVERLAY_ATTRIBUTES - 1,
1777                 &NV10OverlayAttributes[1]
1778         },
1779         {
1780                 &NVImages[2],
1781                 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1782                 NVAllocSurface,
1783                 NVFreeSurface,
1784                 NVDisplaySurface,
1785                 NVStopSurface,
1786                 NVGetSurfaceAttribute,
1787                 NVSetSurfaceAttribute,
1788                 IMAGE_MAX_W, IMAGE_MAX_H,
1789                 NUM_NV10_OVERLAY_ATTRIBUTES - 1,
1790                 &NV10OverlayAttributes[1]
1791         }
1792 };
1793
1794 static void
1795 NVInitOffscreenImages (ScreenPtr pScreen)
1796 {
1797         xf86XVRegisterOffscreenImages(pScreen, NVOffscreenImages, 2);
1798 }
1799
1800 /**
1801  * NVChipsetHasOverlay
1802  * 
1803  * newer chips don't support overlay anymore.
1804  * overlay feature is emulated via textures.
1805  * 
1806  * @param pNv 
1807  * @return true, if chipset supports overlay
1808  */
1809 static Bool
1810 NVChipsetHasOverlay(NVPtr pNv)
1811 {
1812         switch (pNv->Architecture) {
1813         case NV_ARCH_04: /*NV04 has a different overlay than NV10+*/
1814         case NV_ARCH_10:
1815         case NV_ARCH_20:
1816         case NV_ARCH_30:
1817                 return TRUE;
1818         case NV_ARCH_40:
1819                 if ((pNv->Chipset & 0xfff0) == CHIPSET_NV40)
1820                         return TRUE;
1821                 break;
1822         default:
1823                 break;
1824         }
1825
1826         return FALSE;
1827 }
1828
1829 /**
1830  * NVSetupOverlayVideo
1831  * check if chipset supports Overla
1832  * if so, setup overlay port
1833  * 
1834  * @return overlay port
1835  * @see NVChipsetHasOverlay(NVPtr pNv)
1836  * @see NV10SetupOverlayVideo(ScreenPtr pScreen)
1837  * @see NVInitOffscreenImages(ScreenPtr pScreen)
1838  */
1839 static XF86VideoAdaptorPtr
1840 NVSetupOverlayVideo(ScreenPtr pScreen)
1841 {
1842         ScrnInfoPtr          pScrn = xf86Screens[pScreen->myNum];
1843         XF86VideoAdaptorPtr  overlayAdaptor = NULL;
1844         NVPtr                pNv   = NVPTR(pScrn);
1845
1846         if (!NVChipsetHasOverlay(pNv))
1847                 return NULL;
1848
1849         overlayAdaptor = NVSetupOverlayVideoAdapter(pScreen);
1850         if (overlayAdaptor && pNv->Architecture != NV_ARCH_04 )
1851                 NVInitOffscreenImages(pScreen); //I am not sure what this call does.
1852         
1853         #ifdef COMPOSITE
1854         if (!noCompositeExtension) {
1855                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1856                         "Xv: Composite is enabled, enabling overlay with smart blitter fallback\n");
1857                 overlayAdaptor -> name = "NV Video Overlay with Composite";
1858         }
1859         #endif
1860
1861         if (pNv->randr12_enable) {
1862                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
1863                         "Xv: Randr12 is enabled, using overlay with smart blitter fallback and automatic CRTC switching\n");
1864         }
1865                 
1866
1867         return overlayAdaptor;
1868 }
1869
1870 /**
1871  * NV40 texture adapter.
1872  */
1873
1874 #define NUM_FORMAT_TEXTURED 2
1875
1876 static XF86ImageRec NV40TexturedImages[NUM_FORMAT_TEXTURED] =
1877 {
1878         XVIMAGE_YV12,
1879         XVIMAGE_I420,
1880 };
1881
1882 /**
1883  * NV40SetupTexturedVideo
1884  * this function does all the work setting up textured video port
1885  * 
1886  * @return texture port
1887  */
1888 static XF86VideoAdaptorPtr
1889 NV40SetupTexturedVideo (ScreenPtr pScreen)
1890 {
1891         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1892         NVPtr pNv = NVPTR(pScrn);
1893         XF86VideoAdaptorPtr adapt;
1894         NVPortPrivPtr pPriv;
1895         int i;
1896
1897         if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
1898                                         sizeof(NVPortPrivRec) +
1899                                         (sizeof(DevUnion) * NUM_TEXTURE_PORTS)))) {
1900                 return NULL;
1901         }
1902
1903         adapt->type             = XvWindowMask | XvInputMask | XvImageMask;
1904         adapt->flags            = 0;
1905         adapt->name             = "NV40 Texture adapter";
1906         adapt->nEncodings       = 1;
1907         adapt->pEncodings       = &DummyEncodingTex;
1908         adapt->nFormats         = NUM_FORMATS_ALL;
1909         adapt->pFormats         = NVFormats;
1910         adapt->nPorts           = NUM_TEXTURE_PORTS;
1911         adapt->pPortPrivates    = (DevUnion*)(&adapt[1]);
1912
1913         pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_TEXTURE_PORTS]);
1914         for(i = 0; i < NUM_TEXTURE_PORTS; i++)
1915                 adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
1916
1917         if(pNv->WaitVSyncPossible) {
1918                 adapt->pAttributes = NVTexturedAttributes;
1919                 adapt->nAttributes = NUM_TEXTURED_ATTRIBUTES;
1920         } else {
1921                 adapt->pAttributes = NULL;
1922                 adapt->nAttributes = 0;
1923         }
1924
1925         adapt->pImages                  = NV40TexturedImages;
1926         adapt->nImages                  = NUM_FORMAT_TEXTURED;
1927         adapt->PutVideo                 = NULL;
1928         adapt->PutStill                 = NULL;
1929         adapt->GetVideo                 = NULL;
1930         adapt->GetStill                 = NULL;
1931         adapt->StopVideo                = NV40StopTexturedVideo;
1932         adapt->SetPortAttribute         = NVSetTexturePortAttribute;
1933         adapt->GetPortAttribute         = NVGetTexturePortAttribute;
1934         adapt->QueryBestSize            = NVQueryBestSize;
1935         adapt->PutImage                 = NVPutImage;
1936         adapt->QueryImageAttributes     = NVQueryImageAttributes;
1937
1938         pPriv->videoStatus              = 0;
1939         pPriv->grabbedByV4L     = FALSE;
1940         pPriv->blitter                  = FALSE;
1941         pPriv->texture                  = TRUE;
1942         pPriv->doubleBuffer             = FALSE;
1943         pPriv->SyncToVBlank     = FALSE;
1944
1945         pNv->textureAdaptor     = adapt;
1946
1947         return adapt;
1948 }
1949
1950 /**
1951  * NVInitVideo
1952  * tries to initialize the various supported adapters
1953  * and add them to the list of ports on screen "pScreen".
1954  * 
1955  * @param pScreen
1956  * @see NVSetupOverlayVideo(ScreenPtr pScreen)
1957  * @see NVSetupBlitVideo(ScreenPtr pScreen)
1958  */
1959 void NVInitVideo (ScreenPtr pScreen)
1960 {
1961         ScrnInfoPtr          pScrn = xf86Screens[pScreen->myNum];
1962         NVPtr                pNv = NVPTR(pScrn);
1963         XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
1964         XF86VideoAdaptorPtr  overlayAdaptor = NULL;
1965         XF86VideoAdaptorPtr  blitAdaptor = NULL;
1966         XF86VideoAdaptorPtr  textureAdaptor = NULL;
1967         int                  num_adaptors;
1968
1969         /*
1970          * Driving the blitter requires the DMA FIFO. Using the FIFO
1971          * without accel causes DMA errors. While the overlay might
1972          * might work without accel, we also disable it for now when
1973          * acceleration is disabled:
1974          */
1975         if (pScrn->bitsPerPixel != 8 && pNv->Architecture < NV_ARCH_50 && !pNv->NoAccel) {
1976                 overlayAdaptor = NVSetupOverlayVideo(pScreen);
1977                 blitAdaptor    = NVSetupBlitVideo(pScreen);
1978                 if (pNv->Architecture == NV_ARCH_40)
1979                         textureAdaptor = NV40SetupTexturedVideo(pScreen);
1980         }
1981
1982         num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
1983         if(blitAdaptor || overlayAdaptor) {
1984                 int size = num_adaptors;
1985
1986                 if(overlayAdaptor) size++;
1987                 if(blitAdaptor)    size++;
1988
1989                 newAdaptors = xalloc(size * sizeof(XF86VideoAdaptorPtr *));
1990                 if(newAdaptors) {
1991                         if(num_adaptors) {
1992                                 memcpy(newAdaptors, adaptors, num_adaptors *
1993                                                 sizeof(XF86VideoAdaptorPtr));
1994                         }
1995
1996                         if(overlayAdaptor) {
1997                                 newAdaptors[num_adaptors] = overlayAdaptor;
1998                                 num_adaptors++;
1999                         }
2000
2001                         if (textureAdaptor) {
2002                                 newAdaptors[num_adaptors] = textureAdaptor;
2003                                 num_adaptors++;
2004                         }
2005
2006                         if(blitAdaptor) {
2007                                 newAdaptors[num_adaptors] = blitAdaptor;
2008                                 num_adaptors++;
2009                         }
2010
2011                         adaptors = newAdaptors;
2012                 }
2013         }
2014
2015         if (num_adaptors)
2016                 xf86XVScreenInit(pScreen, adaptors, num_adaptors);
2017         if (newAdaptors)
2018                 xfree(newAdaptors);
2019 }