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