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