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