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