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