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