Xv: fixed wrong fix of big endian NV12 copy, as explained by Daniel Chassot
[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 /**
177  * NVSetPortDefaults
178  * set attributes of port "pPriv" to compiled-in (except for colorKey) defaults
179  * 
180  * @param pScrn screen to get the default colorKey from
181  * @param pPriv port to reset to defaults
182  */
183 static void 
184 NVSetPortDefaults (ScrnInfoPtr pScrn, NVPortPrivPtr pPriv)
185 {
186         NVPtr pNv = NVPTR(pScrn);
187
188         pPriv->brightness               = 0;
189         pPriv->contrast                 = 4096;
190         pPriv->saturation               = 4096;
191         pPriv->hue                      = 0;
192         pPriv->colorKey                 = pNv->videoKey;
193         pPriv->autopaintColorKey        = TRUE;
194         pPriv->doubleBuffer             = TRUE;
195         pPriv->iturbt_709               = FALSE;
196         pPriv->currentHostBuffer        = 0;
197 }
198
199 /**
200  * NVResetVideo
201  * writes the current attributes from the overlay port to the hardware
202  */
203 void 
204 NVResetVideo (ScrnInfoPtr pScrn)
205 {
206         NVPtr          pNv     = NVPTR(pScrn);
207         NVPortPrivPtr  pPriv   = GET_OVERLAY_PRIVATE(pNv);
208         int            satSine, satCosine;
209         double         angle;
210
211         angle = (double)pPriv->hue * 3.1415927 / 180.0;
212
213         satSine = pPriv->saturation * sin(angle);
214         if (satSine < -1024)
215                 satSine = -1024;
216         satCosine = pPriv->saturation * cos(angle);
217         if (satCosine < -1024)
218                 satCosine = -1024;
219
220         nvWriteVIDEO(pNv, NV_PVIDEO_LUMINANCE(0), (pPriv->brightness << 16) |
221                                                    pPriv->contrast);
222         nvWriteVIDEO(pNv, NV_PVIDEO_LUMINANCE(1), (pPriv->brightness << 16) |
223                                                    pPriv->contrast);
224         nvWriteVIDEO(pNv, NV_PVIDEO_CHROMINANCE(0), (satSine << 16) |
225                                                     (satCosine & 0xffff));
226         nvWriteVIDEO(pNv, NV_PVIDEO_CHROMINANCE(1), (satSine << 16) |
227                                                     (satCosine & 0xffff));
228         nvWriteVIDEO(pNv, NV_PVIDEO_COLOR_KEY, pPriv->colorKey);
229 }
230
231 /**
232  * NVStopOverlay
233  * Tell the hardware to stop the overlay
234  */
235 static void 
236 NVStopOverlay (ScrnInfoPtr pScrn)
237 {
238         NVPtr pNv = NVPTR(pScrn);
239
240         nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 1);
241 }
242
243 /**
244  * NVXvDMANotifierAlloc
245  * allocates a notifier from the table of 6 we have
246  *
247  * @return a notifier instance or NULL on error
248  */
249 static struct drm_nouveau_notifierobj_alloc * NVXvDMANotifierAlloc(ScrnInfoPtr pScrn)
250 {
251 int i;
252 for ( i = 0; i < 6; i ++ )
253         {
254         if ( XvDMANotifierStatus[i] == XV_DMA_NOTIFIER_INUSE ) 
255                 continue;
256         
257         if ( XvDMANotifierStatus[i] == XV_DMA_NOTIFIER_FREE )
258                 {
259                 XvDMANotifierStatus[i] = XV_DMA_NOTIFIER_INUSE;
260                 return XvDMANotifiers[i];
261                 }
262         
263         if ( XvDMANotifierStatus[i] == XV_DMA_NOTIFIER_NOALLOC )
264                 {
265                 XvDMANotifiers[i] = NVNotifierAlloc(pScrn, NvDmaXvNotifier0 + i);
266                 if (XvDMANotifiers[i]) 
267                         {
268                         XvDMANotifierStatus[i] = XV_DMA_NOTIFIER_INUSE;
269                         return XvDMANotifiers[i];
270                         }
271                 else return NULL;
272                 }
273         }
274         
275 return NULL;
276 }
277
278 /**
279  * NVXvDMANotifierFree
280  * frees a notifier from the table of 6 we have
281  *
282  * 
283  */
284 static void NVXvDMANotifierFree(ScrnInfoPtr pScrn, struct drm_nouveau_notifierobj_alloc * target)
285 {
286 int i;
287 for ( i = 0; i < 6; i ++ )
288         {
289         if ( XvDMANotifiers[i] == target )
290                 break;
291         }
292 XvDMANotifierStatus[i] = XV_DMA_NOTIFIER_FREE;
293 }
294
295 /**
296  * NVAllocateVideoMemory
297  * allocates video memory for a given port
298  * 
299  * @param pScrn screen which requests the memory
300  * @param mem pointer to previously allocated memory for reallocation
301  * @param size size of requested memory segment
302  * @return pointer to the allocated memory
303  */
304 static NVAllocRec *
305 NVAllocateVideoMemory(ScrnInfoPtr pScrn, NVAllocRec *mem, int size)
306 {
307         NVPtr pNv = NVPTR(pScrn);
308
309
310         if(mem) {
311                 if(mem->size >= size)
312                         return mem;
313                 NVFreeMemory(pNv, mem);
314         }
315
316         return NVAllocateMemory(pNv, NOUVEAU_MEM_FB, size); /* align 32? */
317 }
318
319 /**
320  * NVAllocateTTMemory
321  * allocates TT memory for a given port
322  * 
323  * @param pScrn screen which requests the memory
324  * @param mem pointer to previously allocated memory for reallocation
325  * @param size size of requested memory segment
326  * @return pointer to the allocated memory
327  */
328 static NVAllocRec *
329 NVAllocateTTMemory(ScrnInfoPtr pScrn, NVAllocRec *mem, int size)
330 {
331         NVPtr pNv = NVPTR(pScrn);
332
333
334         if(mem) {
335                 if(mem->size >= size)
336                         return mem;
337                 NVFreeMemory(pNv, mem);
338         }
339         return NVAllocateMemory(pNv, NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI_ACCEPTABLE, size); /* align 32? */
340 }
341
342 /**
343  * NVFreePortMemory
344  * frees memory held by a given port
345  * 
346  * @param pScrn screen whose port wants to free memory
347  * @param pPriv port to free memory of
348  */
349 static void
350 NVFreePortMemory(ScrnInfoPtr pScrn, NVPortPrivPtr pPriv)
351 {
352         NVPtr         pNv   = NVPTR(pScrn);
353
354         //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]);
355         
356         if(pPriv->video_mem) {
357                 NVFreeMemory(pNv, pPriv->video_mem);
358                 pPriv->video_mem = NULL;
359         }
360         
361         if ( pPriv->TT_mem_chunk[ 0 ] && pPriv->DMANotifier [ 0 ] )
362                 {
363                 NVNotifierWaitStatus(pScrn, pPriv->DMANotifier [ 0 ] ,  0, 1000);
364                 }
365         
366         if ( pPriv->TT_mem_chunk[ 1 ] && pPriv->DMANotifier [ 1 ] )
367                 {
368                 NVNotifierWaitStatus(pScrn, pPriv->DMANotifier [ 1 ] , 0, 1000);
369                 }               
370                 
371         if(pPriv->TT_mem_chunk[0]) {
372                 NVFreeMemory(pNv, pPriv->TT_mem_chunk[0]);
373                 pPriv->TT_mem_chunk[0] = NULL;
374         }
375         
376         if(pPriv->TT_mem_chunk[1]) {
377                 NVFreeMemory(pNv, pPriv->TT_mem_chunk[1]);
378                 pPriv->TT_mem_chunk[1] = NULL;
379         }
380         
381         if(pPriv->DMANotifier[0]) {
382                 NVXvDMANotifierFree(pScrn, pPriv->DMANotifier[0]);
383                 pPriv->DMANotifier[0] = NULL;
384         }
385         
386         if(pPriv->DMANotifier[1]) {
387                 NVXvDMANotifierFree(pScrn, pPriv->DMANotifier[1]);
388                 pPriv->DMANotifier[1] = NULL;
389         }
390         
391 }
392
393 /**
394  * NVFreeOverlayMemory
395  * frees memory held by the overlay port
396  * 
397  * @param pScrn screen whose overlay port wants to free memory
398  */
399 static void
400 NVFreeOverlayMemory(ScrnInfoPtr pScrn)
401 {
402         NVPtr   pNv = NVPTR(pScrn);
403         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
404         NVFreePortMemory(pScrn, pPriv);
405 }
406
407 /**
408  * NVFreeBlitMemory
409  * frees memory held by the blit port
410  * 
411  * @param pScrn screen whose blit port wants to free memory
412  */
413 static void
414 NVFreeBlitMemory(ScrnInfoPtr pScrn)
415 {
416         NVPtr   pNv = NVPTR(pScrn);
417         NVPortPrivPtr pPriv = GET_BLIT_PRIVATE(pNv);
418         NVFreePortMemory(pScrn, pPriv);
419 }
420
421 /**
422  * NVVideoTimerCallback
423  * callback function which perform cleanup tasks (stop overlay, free memory).
424  * within the driver it is only called once from NVBlockHandler in nv_driver.c
425  */
426 static void
427 NVVideoTimerCallback(ScrnInfoPtr pScrn, Time currentTime)
428 {
429         NVPtr         pNv = NVPTR(pScrn);
430         NVPortPrivPtr pOverPriv = NULL;
431         NVPortPrivPtr pBlitPriv = NULL;
432         Bool needCallback = FALSE;
433
434         if (!pScrn->vtSema)
435                 return; 
436
437         if (pNv->overlayAdaptor) {
438                 pOverPriv = GET_OVERLAY_PRIVATE(pNv);
439                 if (!pOverPriv->videoStatus)
440                         pOverPriv = NULL;
441         }
442
443         if (pNv->blitAdaptor) {
444                 pBlitPriv = GET_BLIT_PRIVATE(pNv);
445                 if (!pBlitPriv->videoStatus)
446                         pBlitPriv = NULL;
447         }
448
449         if (pOverPriv) {
450                 if (pOverPriv->videoTime < currentTime) {
451                         if (pOverPriv->videoStatus & OFF_TIMER) {
452                                 NVStopOverlay(pScrn);
453                                 pOverPriv->videoStatus = FREE_TIMER;
454                                 pOverPriv->videoTime = currentTime + FREE_DELAY;
455                                 needCallback = TRUE;
456                         } else
457                         if (pOverPriv->videoStatus & FREE_TIMER) {
458                                 NVFreeOverlayMemory(pScrn);
459                                 pOverPriv->videoStatus = 0;
460                         }
461                 } else {
462                         needCallback = TRUE;
463                 }
464         }
465
466         if (pBlitPriv) {
467                 if (pBlitPriv->videoTime < currentTime) {
468                         NVFreeBlitMemory(pScrn);
469                         pBlitPriv->videoStatus = 0;              
470                 } else {
471                         needCallback = TRUE;
472                 }
473         }
474
475         pNv->VideoTimerCallback = needCallback ? NVVideoTimerCallback : NULL;
476 }
477
478 /**
479  * NVPutOverlayImage
480  * program hardware to overlay image into front buffer
481  * 
482  * @param pScrn screen
483  * @param offset card offset to the pixel data
484  * @param id format of image
485  * @param dstPitch pitch of the pixel data in VRAM
486  * @param dstBox destination box
487  * @param x1 first source point - x
488  * @param y1 first source point - y
489  * @param x2 second source point - x
490  * @param y2 second source point - y
491  * @param width width of the source image = x2 - x1
492  * @param height height
493  * @param src_w width of the image data in VRAM
494  * @param src_h height
495  * @param drw_w width of the image to draw to screen
496  * @param drw_h height
497  * @param clipBoxes ???
498  */
499 static void
500 NVPutOverlayImage(ScrnInfoPtr pScrn, int offset, int uvoffset, int id,
501                   int dstPitch, BoxPtr dstBox,
502                   int x1, int y1, int x2, int y2,
503                   short width, short height,
504                   short src_w, short src_h,
505                   short drw_w, short drw_h,
506                   RegionPtr clipBoxes)
507 {
508         NVPtr         pNv    = NVPTR(pScrn);
509         NVPortPrivPtr pPriv  = GET_OVERLAY_PRIVATE(pNv);
510         int           buffer = pPriv->currentBuffer;
511
512         /* paint the color key */
513         if(pPriv->autopaintColorKey && (pPriv->grabbedByV4L ||
514                 !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes))) {
515                 /* we always paint V4L's color key */
516                 if (!pPriv->grabbedByV4L)
517                         REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
518                 {
519                 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
520                 }
521         }
522
523         if(pNv->CurrentLayout.mode->Flags & V_DBLSCAN) {
524                 dstBox->y1 <<= 1;
525                 dstBox->y2 <<= 1;
526                 drw_h <<= 1;
527         }
528         
529         //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));
530
531         nvWriteVIDEO(pNv, NV_PVIDEO_BASE(buffer)     , 0);
532         nvWriteVIDEO(pNv, NV_PVIDEO_OFFSET_BUFF(buffer)     , offset);
533         nvWriteVIDEO(pNv, NV_PVIDEO_SIZE_IN(buffer)  , (height << 16) | width);
534         nvWriteVIDEO(pNv, NV_PVIDEO_POINT_IN(buffer) ,
535                           ((y1 << 4) & 0xffff0000) | (x1 >> 12));
536         nvWriteVIDEO(pNv, NV_PVIDEO_DS_DX(buffer)    , (src_w << 20) / drw_w);
537         nvWriteVIDEO(pNv, NV_PVIDEO_DT_DY(buffer)    , (src_h << 20) / drw_h);
538         nvWriteVIDEO(pNv, NV_PVIDEO_POINT_OUT(buffer),
539                           (dstBox->y1 << 16) | dstBox->x1);
540         nvWriteVIDEO(pNv, NV_PVIDEO_SIZE_OUT(buffer) ,
541                           ((dstBox->y2 - dstBox->y1) << 16) |
542                            (dstBox->x2 - dstBox->x1));
543
544         dstPitch |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;   /* use color key */
545         if(id != FOURCC_UYVY)
546                 dstPitch |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8;
547         if(pPriv->iturbt_709)
548                 dstPitch |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
549         
550         if( id == FOURCC_YV12 || id == FOURCC_I420 )
551                 dstPitch |= NV_PVIDEO_FORMAT_PLANAR;
552
553         /* Those are important only for planar formats (NV12) */
554         if ( uvoffset )
555                 {
556                 nvWriteVIDEO(pNv, NV_PVIDEO_UVPLANE_BASE(buffer), 0); 
557                 nvWriteVIDEO(pNv, NV_PVIDEO_UVPLANE_OFFSET_BUFF(buffer), uvoffset);
558                 }
559         
560         nvWriteVIDEO(pNv, NV_PVIDEO_FORMAT(buffer), dstPitch);
561         nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 0);
562         nvWriteVIDEO(pNv, NV_PVIDEO_BUFFER, buffer ? 0x10 :  0x1);
563
564         pPriv->videoStatus = CLIENT_VIDEO_ON;
565 }
566
567 static void
568 NV04PutOverlayImage(ScrnInfoPtr pScrn, int offset, int uvoffset, int id,
569                   int dstPitch, BoxPtr dstBox,
570                   int x1, int y1, int x2, int y2,
571                   short width, short height,
572                   short src_w, short src_h,
573                   short drw_w, short drw_h,
574                   RegionPtr clipBoxes)
575 {
576         NVPtr         pNv    = NVPTR(pScrn);
577         NVPortPrivPtr pPriv  = GET_OVERLAY_PRIVATE(pNv);
578         int           buffer = pPriv->currentBuffer;
579 /*0x00680000*/
580         /* paint the color key */
581         if(pPriv->autopaintColorKey && (pPriv->grabbedByV4L ||
582                 !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes))) {
583                 /* we always paint V4L's color key */
584                 if (!pPriv->grabbedByV4L)
585                         REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
586                 {
587                 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
588                 }
589         }
590
591         if(pNv->CurrentLayout.mode->Flags & V_DBLSCAN) {
592                 dstBox->y1 <<= 1;
593                 dstBox->y2 <<= 1;
594                 drw_h <<= 1;
595         }
596
597         
598         nvWriteVIDEO(pNv, 0x680000  - 0x8000+ 0x224, 0);
599         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x228, 0);
600         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x22C, 0);
601         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x20C + 4*buffer   , offset);
602         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x21C + 4*buffer   , 0);
603         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x214 + 4*buffer   , dstPitch);
604         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x230   , (dstBox->y1 << 16) | dstBox->x1);
605         nvWriteVIDEO(pNv,  0x680000 - 0x8000+ 0x234/* + 4*buffer UNKNOWN*/, (height << 16) | width);
606         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)));
607         
608         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x280, 0x69);
609         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x284, 0x3e);
610         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x288, 0x89);
611         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x28C, 0x0);
612         
613         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x204, 0x001);
614         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x208, 0x111);
615         
616         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x23C, 0x03);
617         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x238, 0x38);
618         
619         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x240, pPriv->colorKey);
620         
621         /*NV_PVIDEO_OVERLAY (KEY_ON, VIDEO_ON, FORMAT_CCIR) */
622         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x240, 0x111);
623         nvWriteVIDEO(pNv, 0x680000 - 0x8000+ 0x228, 1 << 16);
624
625         /*dstPitch |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;   
626         if(id != FOURCC_UYVY)
627                 dstPitch |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8;
628         if(pPriv->iturbt_709)
629                 dstPitch |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
630         
631         if( id == FOURCC_YV12 || id == FOURCC_I420 )
632                 dstPitch |= NV_PVIDEO_FORMAT_PLANAR;
633         
634         nvWriteVIDEO(pNv, NV_PVIDEO_FORMAT(buffer), dstPitch);
635         nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 0);
636         nvWriteVIDEO(pNv, NV_PVIDEO_BUFFER, buffer ? 0x10 :  0x1);
637         */
638         
639         pPriv->videoStatus = CLIENT_VIDEO_ON;
640 }
641 #ifndef ExaOffscreenMarkUsed
642 extern void ExaOffscreenMarkUsed(PixmapPtr);
643 #endif
644 #ifndef exaGetDrawablePixmap
645 extern PixmapPtr exaGetDrawablePixmap(DrawablePtr);
646 #endif
647 #ifndef exaPixmapIsOffscreen
648 extern Bool exaPixmapIsOffscreen(PixmapPtr p);
649 #endif
650 /* To support EXA 2.0, 2.1 has this in the header */
651 #ifndef exaMoveInPixmap
652 extern void exaMoveInPixmap(PixmapPtr pPixmap);
653 #endif
654
655 /**
656  * NVPutBlitImage
657  * 
658  * @param pScrn screen
659  * @param src_offset
660  * @param id colorspace of image
661  * @param src_pitch
662  * @param dstBox
663  * @param x1
664  * @param y1
665  * @param x2
666  * @param y2
667  * @param width
668  * @param height
669  * @param src_w
670  * @param src_h
671  * @param drw_w
672  * @param drw_h
673  * @param clipBoxes
674  * @param pDraw
675  */
676 static void
677 NVPutBlitImage(ScrnInfoPtr pScrn, int src_offset, int id,
678                int src_pitch, BoxPtr dstBox,
679                int x1, int y1, int x2, int y2,
680                short width, short height,
681                short src_w, short src_h,
682                short drw_w, short drw_h,
683                RegionPtr clipBoxes,
684                DrawablePtr pDraw)
685 {
686         NVPtr          pNv   = NVPTR(pScrn);
687         NVPortPrivPtr  pPriv = GET_BLIT_PRIVATE(pNv);
688         BoxPtr         pbox;
689         int            nbox;
690         CARD32         dsdx, dtdy;
691         CARD32         dst_size, dst_point;
692         CARD32         src_point, src_format;
693
694         if (pNv->useEXA) {
695                 ScreenPtr pScreen = pScrn->pScreen;
696                 PixmapPtr pPix    = exaGetDrawablePixmap(pDraw);
697                 int dst_format;
698
699                 /* Try to get the dest drawable into vram */
700                 if (!exaPixmapIsOffscreen(pPix)) {
701                         exaMoveInPixmap(pPix);
702                         ExaOffscreenMarkUsed(pPix);
703                 }
704
705                 /* If we failed, draw directly onto the screen pixmap.
706                  * Not sure if this is the best approach, maybe failing
707                  * with BadAlloc would be better?
708                  */
709                 if (!exaPixmapIsOffscreen(pPix)) {
710                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
711                                 "XV: couldn't move dst surface into vram\n");
712                         pPix = pScreen->GetScreenPixmap(pScreen);
713                 }
714
715                 NVAccelGetCtxSurf2DFormatFromPixmap(pPix, &dst_format);
716                 NVAccelSetCtxSurf2D(pPix, pPix, dst_format);
717
718 #ifdef COMPOSITE
719                 /* Adjust coordinates if drawing to an offscreen pixmap */
720                 if (pPix->screen_x || pPix->screen_y) {
721                         REGION_TRANSLATE(pScrn->pScreen, clipBoxes,
722                                                              -pPix->screen_x,
723                                                              -pPix->screen_y);
724                         dstBox->x1 -= pPix->screen_x;
725                         dstBox->x2 -= pPix->screen_x;
726                         dstBox->y1 -= pPix->screen_y;
727                         dstBox->y2 -= pPix->screen_y;
728                 }
729
730                 DamageDamageRegion((DrawablePtr)pPix, clipBoxes);
731 #endif
732         } else {
733                 if (pNv->CurrentLayout.depth == 15) {
734                         NVDmaStart(pNv, NvContextSurfaces,
735                                         SURFACE_FORMAT, 1);
736                         NVDmaNext (pNv, SURFACE_FORMAT_X1R5G5B5);
737                 }
738         }
739
740         pbox = REGION_RECTS(clipBoxes);
741         nbox = REGION_NUM_RECTS(clipBoxes);
742
743         dsdx = (src_w << 20) / drw_w;
744         dtdy = (src_h << 20) / drw_h;
745
746         dst_size  = ((dstBox->y2 - dstBox->y1) << 16) |
747                      (dstBox->x2 - dstBox->x1);
748         dst_point = (dstBox->y1 << 16) | dstBox->x1;
749
750         src_pitch |= (STRETCH_BLIT_SRC_FORMAT_ORIGIN_CENTER << 16) |
751                     (STRETCH_BLIT_SRC_FORMAT_FILTER_BILINEAR << 24);
752         src_point = ((y1 << 4) & 0xffff0000) | (x1 >> 12);
753
754         switch(id) {
755         case FOURCC_RGB:
756                 src_format = STRETCH_BLIT_FORMAT_X8R8G8B8;
757                 break;
758         case FOURCC_UYVY:
759                 src_format = STRETCH_BLIT_FORMAT_UYVY;
760                 break;
761         default:
762                 src_format = STRETCH_BLIT_FORMAT_YUYV;
763                 break;
764         }
765
766         if(pPriv->SyncToVBlank) {
767                 NVDmaKickoff(pNv);
768                 NVWaitVSync(pScrn);
769         }
770
771         if(pNv->BlendingPossible) {
772                 NVDmaStart(pNv, NvScaledImage, STRETCH_BLIT_FORMAT, 2);
773                 NVDmaNext (pNv, src_format);
774                 NVDmaNext (pNv, STRETCH_BLIT_OPERATION_COPY);
775         } else {
776                 NVDmaStart(pNv, NvScaledImage, STRETCH_BLIT_FORMAT, 1);
777                 NVDmaNext (pNv, src_format);
778         }
779
780         while(nbox--) {
781                 NVDmaStart(pNv, NvRectangle, RECT_SOLID_COLOR, 1);
782                 NVDmaNext (pNv, 0);
783
784                 NVDmaStart(pNv, NvScaledImage, STRETCH_BLIT_CLIP_POINT, 6);
785                 NVDmaNext (pNv, (pbox->y1 << 16) | pbox->x1); 
786                 NVDmaNext (pNv, ((pbox->y2 - pbox->y1) << 16) |
787                                  (pbox->x2 - pbox->x1));
788                 NVDmaNext (pNv, dst_point);
789                 NVDmaNext (pNv, dst_size);
790                 NVDmaNext (pNv, dsdx);
791                 NVDmaNext (pNv, dtdy);
792
793                 NVDmaStart(pNv, NvScaledImage, STRETCH_BLIT_SRC_SIZE, 4);
794                 NVDmaNext (pNv, (height << 16) | width);
795                 NVDmaNext (pNv, src_pitch);
796                 NVDmaNext (pNv, src_offset);
797                 NVDmaNext (pNv, src_point);
798                 pbox++;
799         }
800
801         if (!pNv->useEXA) {
802                 if(pNv->CurrentLayout.depth == 15) {
803                         NVDmaStart(pNv, NvContextSurfaces,
804                                         SURFACE_FORMAT, 1);
805                         NVDmaNext (pNv, SURFACE_FORMAT_R5G6B5);
806                 }
807         }
808
809         NVDmaKickoff(pNv);
810
811         if (pNv->useEXA)
812                 exaMarkSync(pScrn->pScreen);
813         else
814                 SET_SYNC_FLAG(pNv->AccelInfoRec);
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         XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
2275         XF86VideoAdaptorPtr  overlayAdaptor = NULL;
2276         XF86VideoAdaptorPtr  blitAdaptor = NULL;
2277         int                  num_adaptors;
2278
2279         if (pScrn->bitsPerPixel == 8)
2280                 return;
2281
2282         overlayAdaptor = NVSetupOverlayVideo(pScreen);
2283         blitAdaptor    = NVSetupBlitVideo(pScreen);
2284
2285         num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
2286         if(blitAdaptor || overlayAdaptor) {
2287                 int size = num_adaptors;
2288
2289                 if(overlayAdaptor) size++;
2290                 if(blitAdaptor)    size++;
2291
2292                 newAdaptors = xalloc(size * sizeof(XF86VideoAdaptorPtr *));
2293                 if(newAdaptors) {
2294                         if(num_adaptors) {
2295                                 memcpy(newAdaptors, adaptors, num_adaptors *
2296                                                 sizeof(XF86VideoAdaptorPtr));
2297                         }
2298
2299                         if(overlayAdaptor) {
2300                                 newAdaptors[num_adaptors] = overlayAdaptor;
2301                                 num_adaptors++;
2302                         }
2303
2304                         if(blitAdaptor) {
2305                                 newAdaptors[num_adaptors] = blitAdaptor;
2306                                 num_adaptors++;
2307                         }
2308
2309                         adaptors = newAdaptors;
2310                 }
2311         }
2312
2313         if (num_adaptors)
2314                 xf86XVScreenInit(pScreen, adaptors, num_adaptors);
2315         if (newAdaptors)
2316                 xfree(newAdaptors);
2317 }
2318