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