removed pointless sleep in notifier wait
[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 typedef struct _NVPortPrivRec {
42         short           brightness;
43         short           contrast;
44         short           saturation;
45         short           hue;
46         RegionRec       clip;
47         CARD32          colorKey;
48         Bool            autopaintColorKey;
49         Bool            doubleBuffer;
50         CARD32          videoStatus;
51         int             currentBuffer;
52         Time            videoTime;
53         Bool            grabbedByV4L;
54         Bool            iturbt_709;
55         Bool            blitter;
56         Bool            SyncToVBlank;
57         NVAllocRec *    video_mem;
58         int             pitch;
59         int             offset;
60 } NVPortPrivRec, *NVPortPrivPtr;
61
62 #define GET_OVERLAY_PRIVATE(pNv) \
63         (NVPortPrivPtr)((pNv)->overlayAdaptor->pPortPrivates[0].ptr)
64
65 #define GET_BLIT_PRIVATE(pNv) \
66         (NVPortPrivPtr)((pNv)->blitAdaptor->pPortPrivates[0].ptr)
67
68 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
69
70 static Atom xvBrightness, xvContrast, xvColorKey, xvSaturation, 
71             xvHue, xvAutopaintColorKey, xvSetDefaults, xvDoubleBuffer,
72             xvITURBT709, xvSyncToVBlank;
73
74 /* client libraries expect an encoding */
75 static XF86VideoEncodingRec DummyEncoding =
76
77         0,
78         "XV_IMAGE",
79         IMAGE_MAX_W, IMAGE_MAX_H,
80         {1, 1}
81 };
82
83 #define NUM_FORMATS_ALL 6
84
85 XF86VideoFormatRec NVFormats[NUM_FORMATS_ALL] = 
86 {
87         {15, TrueColor}, {16, TrueColor}, {24, TrueColor},
88         {15, DirectColor}, {16, DirectColor}, {24, DirectColor}
89 };
90
91 #define NUM_OVERLAY_ATTRIBUTES 9
92 XF86AttributeRec NVOverlayAttributes[NUM_OVERLAY_ATTRIBUTES] =
93 {
94         {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
95         {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
96         {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
97         {XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
98         {XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"},
99         {XvSettable | XvGettable, 0, 8191, "XV_CONTRAST"},
100         {XvSettable | XvGettable, 0, 8191, "XV_SATURATION"},
101         {XvSettable | XvGettable, 0, 360, "XV_HUE"},
102         {XvSettable | XvGettable, 0, 1, "XV_ITURBT_709"}
103 };
104
105 #define NUM_BLIT_ATTRIBUTES 2
106 XF86AttributeRec NVBlitAttributes[NUM_BLIT_ATTRIBUTES] =
107 {
108         {XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
109         {XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK"}
110 };
111
112
113 #define NUM_IMAGES_YUV 4
114 #define NUM_IMAGES_ALL 5
115
116 #define FOURCC_RGB 0x0000003
117 #define XVIMAGE_RGB \
118    { \
119         FOURCC_RGB, \
120         XvRGB, \
121         LSBFirst, \
122         { 0x03, 0x00, 0x00, 0x00, \
123           0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
124         32, \
125         XvPacked, \
126         1, \
127         24, 0x00ff0000, 0x0000ff00, 0x000000ff, \
128         0, 0, 0, \
129         0, 0, 0, \
130         0, 0, 0, \
131         {'B','G','R','X',\
132           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}, \
133         XvTopToBottom \
134    }
135
136 static XF86ImageRec NVImages[NUM_IMAGES_ALL] =
137 {
138         XVIMAGE_YUY2,
139         XVIMAGE_YV12,
140         XVIMAGE_UYVY,
141         XVIMAGE_I420,
142         XVIMAGE_RGB
143 };
144
145 /**
146  * NVSetPortDefaults
147  * set attributes of port "pPriv" to compiled-in (except for colorKey) defaults
148  * 
149  * @param pScrn screen to get the default colorKey from
150  * @param pPriv port to reset to defaults
151  */
152 static void 
153 NVSetPortDefaults (ScrnInfoPtr pScrn, NVPortPrivPtr pPriv)
154 {
155         NVPtr pNv = NVPTR(pScrn);
156
157         pPriv->brightness               = 0;
158         pPriv->contrast                 = 4096;
159         pPriv->saturation               = 4096;
160         pPriv->hue                      = 0;
161         pPriv->colorKey                 = pNv->videoKey;
162         pPriv->autopaintColorKey        = TRUE;
163         pPriv->doubleBuffer             = TRUE;
164         pPriv->iturbt_709               = FALSE;
165 }
166
167 /**
168  * NVResetVideo
169  * writes the current attributes from the overlay port to the hardware
170  */
171 void 
172 NVResetVideo (ScrnInfoPtr pScrn)
173 {
174         NVPtr          pNv     = NVPTR(pScrn);
175         NVPortPrivPtr  pPriv   = GET_OVERLAY_PRIVATE(pNv);
176         int            satSine, satCosine;
177         double         angle;
178
179         angle = (double)pPriv->hue * 3.1415927 / 180.0;
180
181         satSine = pPriv->saturation * sin(angle);
182         if (satSine < -1024)
183                 satSine = -1024;
184         satCosine = pPriv->saturation * cos(angle);
185         if (satCosine < -1024)
186                 satCosine = -1024;
187
188         nvWriteVIDEO(pNv, NV_PVIDEO_LUMINANCE(0), (pPriv->brightness << 16) |
189                                                    pPriv->contrast);
190         nvWriteVIDEO(pNv, NV_PVIDEO_LUMINANCE(1), (pPriv->brightness << 16) |
191                                                    pPriv->contrast);
192         nvWriteVIDEO(pNv, NV_PVIDEO_CHROMINANCE(0), (satSine << 16) |
193                                                     (satCosine & 0xffff));
194         nvWriteVIDEO(pNv, NV_PVIDEO_CHROMINANCE(1), (satSine << 16) |
195                                                     (satCosine & 0xffff));
196         nvWriteVIDEO(pNv, NV_PVIDEO_COLOR_KEY, pPriv->colorKey);
197 }
198
199 /**
200  * NVStopOverlay
201  * Tell the hardware to stop the overlay
202  */
203 static void 
204 NVStopOverlay (ScrnInfoPtr pScrn)
205 {
206         NVPtr pNv = NVPTR(pScrn);
207
208         nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 1);
209 }
210
211 /**
212  * NVAllocateOverlayMemory
213  * allocates memory
214  * 
215  * - why does the funciton have "Overlay" in its name? It does not
216  * have anything "Overlay"-specific in its function body and it is called by
217  * non-"Overlay"-specific functions.
218  * TODO: rename to something like NVAllocateVideoMemory or NVAllocateXvMemory
219  * - the function only (re-)allocates memory if it absolutely necessary,
220  * that is, if the requested size is larger than the current size. that means,
221  * that the size of allocated memory never shrinks, even if the requested
222  * does. from a performance point of view this is most likely the best
223  * alternative. but how often does the requested size of memory for video
224  * playback change? whenever video-size/scaling changes? probably not very
225  * often. so maybe sacrifice a tiny bit of performance (whenever the video is
226  * rescaled) and not waste (RAM-)resources?
227  * - the function makes assumptions about the XAA fb manager being used. isn't
228  * there a way to check? what aboaut EXA?
229  * 
230  * @param pScrn screen which requests the memory
231  * @param mem pointer to previously allocated memory for reallocation
232  * @param size size of requested memory segment
233  * @return pointer to the allocated memory
234  */
235 static NVAllocRec *
236 NVAllocateOverlayMemory(ScrnInfoPtr pScrn, NVAllocRec *mem, int size)
237 {
238         NVPtr pNv = NVPTR(pScrn);
239
240         /* The code assumes the XAA fb manager is being used here,
241          * which allocates in pixels.  We allocate in bytes so we
242          * need to adjust the size here.
243          */
244         size *= (pScrn->bitsPerPixel >> 3);
245
246         if(mem) {
247                 if(mem->size >= size) // if(mem->size == size)
248                         return mem;
249                 NVFreeMemory(pNv, mem);
250         }
251
252         return NVAllocateMemory(pNv, NOUVEAU_MEM_FB, size); /* align 32? */
253 }
254
255 /**
256  * NVFreeOverlayMemory
257  * frees memory held by the overlay port
258  * this function (unlike NVAllocateOverlayMemory) is "Overlay"-specific
259  * 
260  * @param pScrn screen whose overlay port wants to free memory
261  */
262 static void
263 NVFreeOverlayMemory(ScrnInfoPtr pScrn)
264 {
265         NVPtr         pNv   = NVPTR(pScrn);
266         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
267
268         if(pPriv->video_mem) {
269                 NVFreeMemory(pNv, pPriv->video_mem);
270                 pPriv->video_mem = NULL;
271         }
272 }
273
274 /**
275  * NVFreeBlitMemory
276  * frees memory held by the blit port
277  * 
278  * @param pScrn screen whose blit port wants to free memory
279  */
280 static void
281 NVFreeBlitMemory(ScrnInfoPtr pScrn)
282 {
283         NVPtr         pNv   = NVPTR(pScrn);
284         NVPortPrivPtr pPriv = GET_BLIT_PRIVATE(pNv);
285
286         if(pPriv->video_mem) {
287                 NVFreeMemory(pNv, pPriv->video_mem);
288                 pPriv->video_mem = NULL;
289         }
290 }
291
292 /**
293  * NVVideoTimerCallback
294  * callback function which perform cleanup tasks (stop overlay, free memory).
295  * within the driver it is only called once from NVBlockHandler in nv_driver.c
296  */
297 static void
298 NVVideoTimerCallback(ScrnInfoPtr pScrn, Time currentTime)
299 {
300         NVPtr         pNv = NVPTR(pScrn);
301         NVPortPrivPtr pOverPriv = NULL;
302         NVPortPrivPtr pBlitPriv = NULL;
303         Bool needCallback = FALSE;
304
305         if (!pScrn->vtSema)
306                 return; 
307
308         if (pNv->overlayAdaptor) {
309                 pOverPriv = GET_OVERLAY_PRIVATE(pNv);
310                 if (!pOverPriv->videoStatus)
311                         pOverPriv = NULL;
312         }
313
314         if (pNv->blitAdaptor) {
315                 pBlitPriv = GET_BLIT_PRIVATE(pNv);
316                 if (!pBlitPriv->videoStatus)
317                         pBlitPriv = NULL;
318         }
319
320         if (pOverPriv) {
321                 if (pOverPriv->videoTime < currentTime) {
322                         if (pOverPriv->videoStatus & OFF_TIMER) {
323                                 NVStopOverlay(pScrn);
324                                 pOverPriv->videoStatus = FREE_TIMER;
325                                 pOverPriv->videoTime = currentTime + FREE_DELAY;
326                                 needCallback = TRUE;
327                         } else
328                         if (pOverPriv->videoStatus & FREE_TIMER) {
329                                 NVFreeOverlayMemory(pScrn);
330                                 pOverPriv->videoStatus = 0;
331                         }
332                 } else {
333                         needCallback = TRUE;
334                 }
335         }
336
337         if (pBlitPriv) {
338                 if (pBlitPriv->videoTime < currentTime) {
339                         NVFreeBlitMemory(pScrn);
340                         pBlitPriv->videoStatus = 0;              
341                 } else {
342                         needCallback = TRUE;
343                 }
344         }
345
346         pNv->VideoTimerCallback = needCallback ? NVVideoTimerCallback : NULL;
347 }
348
349 /**
350  * NVPutOverlayImage
351  * program hardware to overlay image into front buffer
352  * 
353  * @param pScrn screen
354  * @param src_offset
355  * @param id colorspace of image
356  * @param src_pitch
357  * @param dstBox
358  * @param x1
359  * @param y1
360  * @param x2
361  * @param y2
362  * @param width
363  * @param height
364  * @param src_w
365  * @param src_h
366  * @param drw_w
367  * @param drw_h
368  * @param clipBoxes
369  */
370 static void
371 NVPutOverlayImage(ScrnInfoPtr pScrn, int offset, int id,
372                   int dstPitch, BoxPtr dstBox,
373                   int x1, int y1, int x2, int y2,
374                   short width, short height,
375                   short src_w, short src_h,
376                   short drw_w, short drw_h,
377                   RegionPtr clipBoxes)
378 {
379         NVPtr         pNv    = NVPTR(pScrn);
380         NVPortPrivPtr pPriv  = GET_OVERLAY_PRIVATE(pNv);
381         int           buffer = pPriv->currentBuffer;
382
383         /* paint the color key */
384         if(pPriv->autopaintColorKey && (pPriv->grabbedByV4L ||
385                 !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes))) {
386                 /* we always paint V4L's color key */
387                 if (!pPriv->grabbedByV4L)
388                         REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
389                 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
390         }
391
392         if(pNv->CurrentLayout.mode->Flags & V_DBLSCAN) {
393                 dstBox->y1 <<= 1;
394                 dstBox->y2 <<= 1;
395                 drw_h <<= 1;
396         }
397
398         nvWriteVIDEO(pNv, NV_PVIDEO_BASE(buffer)     , offset);
399         nvWriteVIDEO(pNv, NV_PVIDEO_SIZE_IN(buffer)  , (height << 16) | width);
400         nvWriteVIDEO(pNv, NV_PVIDEO_POINT_IN(buffer) ,
401                           ((y1 << 4) & 0xffff0000) | (x1 >> 12));
402         nvWriteVIDEO(pNv, NV_PVIDEO_DS_DX(buffer)    , (src_w << 20) / drw_w);
403         nvWriteVIDEO(pNv, NV_PVIDEO_DT_DY(buffer)    , (src_h << 20) / drw_h);
404         nvWriteVIDEO(pNv, NV_PVIDEO_POINT_OUT(buffer),
405                           (dstBox->y1 << 16) | dstBox->x1);
406         nvWriteVIDEO(pNv, NV_PVIDEO_SIZE_OUT(buffer) ,
407                           ((dstBox->y2 - dstBox->y1) << 16) |
408                            (dstBox->x2 - dstBox->x1));
409
410         dstPitch |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;   /* use color key */
411         if(id != FOURCC_UYVY)
412                 dstPitch |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8;
413         if(pPriv->iturbt_709)
414                 dstPitch |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
415
416         nvWriteVIDEO(pNv, NV_PVIDEO_FORMAT(buffer), dstPitch);
417         nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 0);
418         nvWriteVIDEO(pNv, NV_PVIDEO_BUFFER, buffer ? 0x10 : 0x1);
419
420         pPriv->videoStatus = CLIENT_VIDEO_ON;
421 }
422
423 #ifndef ExaOffscreenMarkUsed
424 extern void ExaOffscreenMarkUsed(PixmapPtr);
425 #endif
426 #ifndef exaGetDrawablePixmap
427 extern PixmapPtr exaGetDrawablePixmap(DrawablePtr);
428 #endif
429 #ifndef exaPixmapIsOffscreen
430 extern Bool exaPixmapIsOffscreen(PixmapPtr p);
431 #endif
432 /* To support EXA 2.0, 2.1 has this in the header */
433 #ifndef exaMoveInPixmap
434 extern void exaMoveInPixmap(PixmapPtr pPixmap);
435 #endif
436
437 /**
438  * NVPutBlitImage
439  * 
440  * @param pScrn screen
441  * @param src_offset
442  * @param id colorspace of image
443  * @param src_pitch
444  * @param dstBox
445  * @param x1
446  * @param y1
447  * @param x2
448  * @param y2
449  * @param width
450  * @param height
451  * @param src_w
452  * @param src_h
453  * @param drw_w
454  * @param drw_h
455  * @param clipBoxes
456  * @param pDraw
457  */
458 static void
459 NVPutBlitImage(ScrnInfoPtr pScrn, int src_offset, int id,
460                int src_pitch, BoxPtr dstBox,
461                int x1, int y1, int x2, int y2,
462                short width, short height,
463                short src_w, short src_h,
464                short drw_w, short drw_h,
465                RegionPtr clipBoxes,
466                DrawablePtr pDraw)
467 {
468         NVPtr          pNv   = NVPTR(pScrn);
469         NVPortPrivPtr  pPriv = GET_BLIT_PRIVATE(pNv);
470         BoxPtr         pbox;
471         int            nbox;
472         CARD32         dsdx, dtdy;
473         CARD32         dst_size, dst_point;
474         CARD32         src_point, src_format;
475
476         if (pNv->useEXA) {
477                 ScreenPtr pScreen = pScrn->pScreen;
478                 PixmapPtr pPix    = exaGetDrawablePixmap(pDraw);
479                 int dst_format;
480
481                 /* Try to get the dest drawable into vram */
482                 if (!exaPixmapIsOffscreen(pPix)) {
483                         exaMoveInPixmap(pPix);
484                         ExaOffscreenMarkUsed(pPix);
485                 }
486
487                 /* If we failed, draw directly onto the screen pixmap.
488                  * Not sure if this is the best approach, maybe failing
489                  * with BadAlloc would be better?
490                  */
491                 if (!exaPixmapIsOffscreen(pPix)) {
492                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
493                                 "XV: couldn't move dst surface into vram\n");
494                         pPix = pScreen->GetScreenPixmap(pScreen);
495                 }
496
497                 NVAccelGetCtxSurf2DFormatFromPixmap(pPix, &dst_format);
498                 NVAccelSetCtxSurf2D(pPix, pPix, dst_format);
499
500 #ifdef COMPOSITE
501                 /* Adjust coordinates if drawing to an offscreen pixmap */
502                 if (pPix->screen_x || pPix->screen_y) {
503                         REGION_TRANSLATE(pScrn->pScreen, clipBoxes,
504                                                              -pPix->screen_x,
505                                                              -pPix->screen_y);
506                         dstBox->x1 -= pPix->screen_x;
507                         dstBox->x2 -= pPix->screen_x;
508                         dstBox->y1 -= pPix->screen_y;
509                         dstBox->y2 -= pPix->screen_y;
510                 }
511
512                 DamageDamageRegion((DrawablePtr)pPix, clipBoxes);
513 #endif
514         } else {
515                 if (pNv->CurrentLayout.depth == 15) {
516                         NVDmaStart(pNv, NvSubContextSurfaces,
517                                         SURFACE_FORMAT, 1);
518                         NVDmaNext (pNv, SURFACE_FORMAT_X1R5G5B5);
519                 }
520         }
521
522         pbox = REGION_RECTS(clipBoxes);
523         nbox = REGION_NUM_RECTS(clipBoxes);
524
525         dsdx = (src_w << 20) / drw_w;
526         dtdy = (src_h << 20) / drw_h;
527
528         dst_size  = ((dstBox->y2 - dstBox->y1) << 16) |
529                      (dstBox->x2 - dstBox->x1);
530         dst_point = (dstBox->y1 << 16) | dstBox->x1;
531
532         src_pitch |= (STRETCH_BLIT_SRC_FORMAT_ORIGIN_CENTER << 16) |
533                     (STRETCH_BLIT_SRC_FORMAT_FILTER_BILINEAR << 24);
534         src_point = ((y1 << 4) & 0xffff0000) | (x1 >> 12);
535
536         switch(id) {
537         case FOURCC_RGB:
538                 src_format = STRETCH_BLIT_FORMAT_X8R8G8B8;
539                 break;
540         case FOURCC_UYVY:
541                 src_format = STRETCH_BLIT_FORMAT_UYVY;
542                 break;
543         default:
544                 src_format = STRETCH_BLIT_FORMAT_YUYV;
545                 break;
546         }
547
548         if(pPriv->SyncToVBlank) {
549                 NVDmaKickoff(pNv);
550                 NVWaitVSync(pScrn);
551         }
552
553         if(pNv->BlendingPossible) {
554                 NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_FORMAT, 2);
555                 NVDmaNext (pNv, src_format);
556                 NVDmaNext (pNv, STRETCH_BLIT_OPERATION_COPY);
557         } else {
558                 NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_FORMAT, 1);
559                 NVDmaNext (pNv, src_format);
560         }
561         
562         NVDmaStart(pNv, NvSubScaledImage,
563                         NV04_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE, 1);
564         NVDmaNext (pNv, NvDmaTT); /* source object */
565
566         while(nbox--) {
567                 NVDmaStart(pNv, NvSubRectangle, RECT_SOLID_COLOR, 1);
568                 NVDmaNext (pNv, 0);
569
570                 NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_CLIP_POINT, 6);
571                 NVDmaNext (pNv, (pbox->y1 << 16) | pbox->x1); 
572                 NVDmaNext (pNv, ((pbox->y2 - pbox->y1) << 16) |
573                                  (pbox->x2 - pbox->x1));
574                 NVDmaNext (pNv, dst_point);
575                 NVDmaNext (pNv, dst_size);
576                 NVDmaNext (pNv, dsdx);
577                 NVDmaNext (pNv, dtdy);
578
579                 NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_SRC_SIZE, 4);
580                 NVDmaNext (pNv, (height << 16) | width);
581                 NVDmaNext (pNv, src_pitch);
582                 NVDmaNext (pNv, src_offset);
583                 NVDmaNext (pNv, src_point);
584                 pbox++;
585         }
586
587         if (!pNv->useEXA) {
588                 if(pNv->CurrentLayout.depth == 15) {
589                         NVDmaStart(pNv, NvSubContextSurfaces,
590                                         SURFACE_FORMAT, 1);
591                         NVDmaNext (pNv, SURFACE_FORMAT_R5G6B5);
592                 }
593         }
594
595         NVDmaKickoff(pNv);
596
597         if (pNv->useEXA)
598                 exaMarkSync(pScrn->pScreen);
599         else
600                 SET_SYNC_FLAG(pNv->AccelInfoRec);
601
602         pPriv->videoStatus = FREE_TIMER;
603         pPriv->videoTime = currentTime.milliseconds + FREE_DELAY;
604         pNv->VideoTimerCallback = NVVideoTimerCallback;
605 }
606
607 /*
608  * StopVideo
609  */
610 static void
611 NVStopOverlayVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit)
612 {
613         NVPtr         pNv   = NVPTR(pScrn);
614         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
615
616         if(pPriv->grabbedByV4L) return;
617
618         REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
619
620         if(Exit) {
621                 if (pPriv->videoStatus & CLIENT_VIDEO_ON)
622                         NVStopOverlay(pScrn);
623                 NVFreeOverlayMemory(pScrn);
624                 pPriv->videoStatus = 0;
625         } else {
626                 if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
627                         pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
628                         pPriv->videoTime = currentTime.milliseconds + OFF_DELAY;
629                         pNv->VideoTimerCallback = NVVideoTimerCallback;
630                 }
631         }
632 }
633
634 /**
635  * NVStopBlitVideo
636  * TODO ?
637  */
638 static void
639 NVStopBlitVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit)
640 {
641 }
642
643 /**
644  * NVSetOverlayPortAttribute
645  * sets the attribute "attribute" of port "data" to value "value"
646  * calls NVResetVideo(pScrn) to apply changes to hardware
647  * 
648  * @param pScrenInfo
649  * @param attribute attribute to set
650  * @param value value to which attribute is to be set
651  * @param data port from which the attribute is to be set
652  * 
653  * @return Success, if setting is successful
654  * BadValue/BadMatch, if value/attribute are invalid
655  * @see NVResetVideo(ScrnInfoPtr pScrn)
656  */
657 static int
658 NVSetOverlayPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
659                           INT32 value, pointer data)
660 {
661         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
662
663         if (attribute == xvBrightness) {
664                 if ((value < -512) || (value > 512))
665                         return BadValue;
666                 pPriv->brightness = value;
667         } else
668         if (attribute == xvDoubleBuffer) {
669                 if ((value < 0) || (value > 1))
670                         return BadValue;
671                 pPriv->doubleBuffer = value;
672         } else
673         if (attribute == xvContrast) {
674                 if ((value < 0) || (value > 8191))
675                         return BadValue;
676                 pPriv->contrast = value;
677         } else
678         if (attribute == xvHue) {
679                 value %= 360;
680                 if (value < 0)
681                         value += 360;
682                 pPriv->hue = value;
683         } else
684         if (attribute == xvSaturation) {
685                 if ((value < 0) || (value > 8191))
686                         return BadValue;
687                 pPriv->saturation = value;
688         } else
689         if (attribute == xvColorKey) {
690                 pPriv->colorKey = value;
691                 REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
692         } else
693         if (attribute == xvAutopaintColorKey) {
694                 if ((value < 0) || (value > 1))
695                         return BadValue;
696                 pPriv->autopaintColorKey = value;
697         } else
698         if (attribute == xvITURBT709) {
699                 if ((value < 0) || (value > 1))
700                         return BadValue;
701                 pPriv->iturbt_709 = value;
702         } else
703         if (attribute == xvSetDefaults) {
704                 NVSetPortDefaults(pScrn, pPriv);
705         } else
706                 return BadMatch;
707
708         NVResetVideo(pScrn);
709         return Success;
710 }
711
712 /**
713  * NVGetOverlayPortAttribute
714  * 
715  * @param pScrn unused
716  * @param attribute attribute to be read
717  * @param value value of attribute will be stored in this pointer
718  * @param data port from which attribute will be read
719  * @return Success, if queried attribute exists
720  */
721 static int
722 NVGetOverlayPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
723                           INT32 *value, pointer data)
724 {
725         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
726
727         if (attribute == xvBrightness)
728                 *value = pPriv->brightness;
729         else if (attribute == xvDoubleBuffer)
730                 *value = (pPriv->doubleBuffer) ? 1 : 0;
731         else if (attribute == xvContrast)
732                 *value = pPriv->contrast;
733         else if (attribute == xvSaturation)
734                 *value = pPriv->saturation;
735         else if (attribute == xvHue)
736                 *value = pPriv->hue;
737         else if (attribute == xvColorKey)
738                 *value = pPriv->colorKey;
739         else if (attribute == xvAutopaintColorKey)
740                 *value = (pPriv->autopaintColorKey) ? 1 : 0;
741         else if (attribute == xvITURBT709)
742                 *value = (pPriv->iturbt_709) ? 1 : 0;
743         else
744                 return BadMatch;
745
746         return Success;
747 }
748
749 /**
750  * NVSetBlitPortAttribute
751  * sets the attribute "attribute" of port "data" to value "value"
752  * supported attributes:
753  * - xvSyncToVBlank (values: 0,1)
754  * - xvSetDefaults (values: NA; SyncToVBlank will be set, if hardware supports it)
755  * 
756  * @param pScrenInfo
757  * @param attribute attribute to set
758  * @param value value to which attribute is to be set
759  * @param data port from which the attribute is to be set
760  * 
761  * @return Success, if setting is successful
762  * BadValue/BadMatch, if value/attribute are invalid
763  */
764 static int
765 NVSetBlitPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
766                        INT32 value, pointer data)
767 {
768         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
769         NVPtr           pNv = NVPTR(pScrn);
770
771         if ((attribute == xvSyncToVBlank) && pNv->WaitVSyncPossible) {
772                 if ((value < 0) || (value > 1))
773                         return BadValue;
774                 pPriv->SyncToVBlank = value;
775         } else
776         if (attribute == xvSetDefaults) {
777                 pPriv->SyncToVBlank = pNv->WaitVSyncPossible;
778         } else
779                 return BadMatch;
780
781         return Success;
782 }
783
784 /**
785  * NVGetBlitPortAttribute
786  * reads the value of attribute "attribute" from port "data" into INT32 "*value"
787  * currently only one attribute supported: xvSyncToVBlank
788  * 
789  * @param pScrn unused
790  * @param attribute attribute to be read
791  * @param value value of attribute will be stored here
792  * @param data port from which attribute will be read
793  * @return Success, if queried attribute exists
794  */
795 static int
796 NVGetBlitPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
797                        INT32 *value, pointer data)
798 {
799         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
800
801         if(attribute == xvSyncToVBlank)
802                 *value = (pPriv->SyncToVBlank) ? 1 : 0;
803         else
804                 return BadMatch;
805
806         return Success;
807 }
808
809
810 /**
811  * QueryBestSize
812  * used by client applications to ask the driver:
813  * how would you actually scale a video of dimensions
814  * vid_w, vid_h, if i wanted you to scale it to dimensions
815  * drw_w, drw_h?
816  * function stores actual scaling size in pointers p_w, p_h.
817  * 
818  * - currently the image cannot be scaled to less than
819  * 1/8th of the original size in either dimension. why?
820  * - what happens if the client requests a scaling to a larger value than
821  * the hardware is capable of (IMAGE_MAX_W, IMAGE_MAX_H)?
822  * 
823  * @param pScrn unused
824  * @param motion unused
825  * @param vid_w width of source video
826  * @param vid_h height of source video
827  * @param drw_w desired scaled width as requested by client
828  * @param drw_h desired scaled height as requested by client
829  * @param p_w actual scaled width as the driver is capable of
830  * @param p_h actual scaled height as the driver is capable of
831  * @param data unused
832  */
833 static void
834 NVQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
835                 short vid_w, short vid_h, 
836                 short drw_w, short drw_h, 
837                 unsigned int *p_w, unsigned int *p_h, 
838                 pointer data)
839 {
840         if(vid_w > (drw_w << 3))
841                 drw_w = vid_w >> 3;
842         if(vid_h > (drw_h << 3))
843                 drw_h = vid_h >> 3;
844
845         *p_w = drw_w;
846         *p_h = drw_h; 
847 }
848
849 /**
850  * NVCopyData420
851  * used by NVPutImage() function to copy (image)data from
852  * system RAM to VRAM and change data order.
853  * 
854  * @param src1 source buffer of luma
855  * @param src2 source buffer of chroma1
856  * @param src3 source buffer of chroma2
857  * @param dst1 destination buffer
858  * @param srcPitch pitch of src1
859  * @param srcPitch2 pitch of src2, src3
860  * @param dstPitch pitch of dst1
861  * @param h number of lines to copy
862  * @param w length of lines to copy
863  */
864 static inline void NVCopyData420(unsigned char *src1, unsigned char *src2,
865                           unsigned char *src3, unsigned char *dst1,
866                           int srcPitch, int srcPitch2,
867                           int dstPitch,
868                           int h, int w)
869 {
870         CARD32 *dst;
871         CARD8 *s1, *s2, *s3;
872         int i, j;
873
874         w >>= 1;
875
876         for (j = 0; j < h; j++) {
877                 dst = (CARD32*)dst1;
878                 s1 = src1;  s2 = src2;  s3 = src3;
879                 i = w;
880
881                 while (i > 4) { // wouldn't it be better to write (i >= 4) ?
882 #if X_BYTE_ORDER == X_BIG_ENDIAN
883                 dst[0] = (s1[0] << 24) | (s1[1] << 8) | (s3[0] << 16) | s2[0];
884                 dst[1] = (s1[2] << 24) | (s1[3] << 8) | (s3[1] << 16) | s2[1];
885                 dst[2] = (s1[4] << 24) | (s1[5] << 8) | (s3[2] << 16) | s2[2];
886                 dst[3] = (s1[6] << 24) | (s1[7] << 8) | (s3[3] << 16) | s2[3];
887 #else
888                 dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
889                 dst[1] = s1[2] | (s1[3] << 16) | (s3[1] << 8) | (s2[1] << 24);
890                 dst[2] = s1[4] | (s1[5] << 16) | (s3[2] << 8) | (s2[2] << 24);
891                 dst[3] = s1[6] | (s1[7] << 16) | (s3[3] << 8) | (s2[3] << 24);
892 #endif
893                 dst += 4; s2 += 4; s3 += 4; s1 += 8;
894                 i -= 4;
895                 }
896
897                 while (i--) {
898 #if X_BYTE_ORDER == X_BIG_ENDIAN
899                 dst[0] = (s1[0] << 24) | (s1[1] << 8) | (s3[0] << 16) | s2[0];
900 #else
901                 dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
902 #endif
903                 dst++; s2++; s3++;
904                 s1 += 2;
905                 }
906
907                 dst1 += dstPitch;
908                 src1 += srcPitch;
909                 if (j & 1) {
910                         src2 += srcPitch2;
911                         src3 += srcPitch2;
912                 }
913         }
914 }
915
916
917 /**
918  * NVPutImage
919  * PutImage is "the" important function of the Xv extention.
920  * a client (e.g. video player) calls this function for every
921  * image (of the video) to be displayed. this function then
922  * scales and displays the image.
923  * 
924  * @param pScrn screen which hold the port where the image is put
925  * @param src_x
926  * @param src_y
927  * @param src_w
928  * @param src_h
929  * @param drw_x
930  * @param drw_y
931  * @param drw_w
932  * @param drw_h
933  * @param id colorspace of image
934  * @param buf pointer to buffer containing the source image
935  * @param width
936  * @param height
937  * @param Sync unused
938  * @param clipBoxes
939  * @param data pointer to port 
940  * @param pDraw
941  */
942 static int
943 NVPutImage(ScrnInfoPtr  pScrn, short src_x, short src_y,
944                                    short drw_x, short drw_y,
945                                    short src_w, short src_h, 
946                                    short drw_w, short drw_h,
947                                    int id,
948                                    unsigned char *buf, 
949                                    short width, short height, 
950                                    Bool         Sync,
951                                    RegionPtr    clipBoxes,
952                                    pointer      data,
953                                    DrawablePtr  pDraw
954 )
955 {
956         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
957         NVPtr pNv = NVPTR(pScrn);
958         INT32 xa, xb, ya, yb;
959         int newSize, offset, s2offset, s3offset;
960         int srcPitch, srcPitch2, dstPitch;
961         int top, left, right, bottom, npixels, nlines, bpp;
962         Bool skip = FALSE;
963         BoxRec dstBox;
964         CARD32 tmp;
965         int line_len;
966         
967         /* s2offset, s3offset - byte offsets into U and V plane of the
968          *                      source where copying starts.  YV12 is indeed one plane of Y and two subsampled planes of U and V
969          * offset - byte offset to the first line of the destination.
970          * dst_start - byte address to the first displayed pel.
971          */
972
973         if (pPriv->grabbedByV4L)
974                 return Success;
975
976         /* make the compiler happy */
977         s2offset = s3offset = srcPitch2 = 0;
978
979         if (!pPriv->blitter) { /* overlay hardware scaler limitation */
980                 if (src_w > (drw_w << 3))
981                         drw_w = src_w >> 3;
982                 if (src_h > (drw_h << 3))
983                         drw_h = src_h >> 3;
984         }
985
986         /* Clip */
987         xa = src_x;
988         xb = src_x + src_w;
989         ya = src_y;
990         yb = src_y + src_h;
991
992         dstBox.x1 = drw_x;
993         dstBox.x2 = drw_x + drw_w;
994         dstBox.y1 = drw_y;
995         dstBox.y2 = drw_y + drw_h;
996
997         if (!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes,
998                                    width, height))
999                 return Success;
1000
1001         if (!pPriv->blitter) {
1002                 dstBox.x1 -= pScrn->frameX0;
1003                 dstBox.x2 -= pScrn->frameX0;
1004                 dstBox.y1 -= pScrn->frameY0;
1005                 dstBox.y2 -= pScrn->frameY0;
1006         }
1007
1008         
1009         /* determine required memory size */
1010         bpp = pScrn->bitsPerPixel >> 3; // bytes per pixel
1011
1012         switch(id) {
1013         case FOURCC_YV12:
1014         case FOURCC_I420:
1015                 srcPitch = (width + 3) & ~3;    /* of luma */
1016                 s2offset = srcPitch * height;
1017                 srcPitch2 = ((width >> 1) + 3) & ~3; /*of chroma*/
1018                 s3offset = (srcPitch2 * (height >> 1)) + s2offset;
1019                 dstPitch = ((width << 1) + 63) & ~63;
1020                 break;
1021         case FOURCC_UYVY:
1022         case FOURCC_YUY2:
1023                 srcPitch = width << 1;
1024                 dstPitch = ((width << 1) + 63) & ~63;
1025                 break;
1026         case FOURCC_RGB:
1027                 srcPitch = width << 2;
1028                 dstPitch = ((width << 2) + 63) & ~63;
1029                 break;
1030         default:
1031                 return BadImplementation;
1032         }
1033         /* dstPitch = number of bytes per row
1034          but the allocation is done is pixel, hence the division to get the real number of bytes */
1035         newSize = height * dstPitch / bpp;
1036         
1037         if (pPriv->doubleBuffer) // double buffering ...
1038                 newSize <<= 1; // ... means double the amount of VRAM needed
1039         
1040         pPriv->video_mem = NVAllocateOverlayMemory(pScrn, pPriv->video_mem, 
1041                                                               newSize);
1042         if (!pPriv->video_mem)
1043                 return BadAlloc;
1044
1045         offset = pPriv->video_mem->offset;
1046         if (pPriv->doubleBuffer) {
1047                 int mask = 1 << (pPriv->currentBuffer << 2);
1048
1049                 /* overwrite the newest buffer if there's not one free */
1050                 if (nvReadVIDEO(pNv, NV_PVIDEO_BUFFER) & mask) {
1051                         if (!pPriv->currentBuffer)
1052                                 offset += (height + 1) * dstPitch;
1053                         skip = TRUE;
1054                 } else
1055
1056                 if (pPriv->currentBuffer)
1057                         offset += (height + 1) * dstPitch;
1058         }
1059
1060
1061         /* We need to enlarge the copied rectangle by a pixel so the HW
1062          * filtering doesn't pick up junk laying outside of the source */
1063         /* fixed point arithmetic */
1064         left = (xa - 0x00010000) >> 16;
1065         if (left < 0) left = 0;
1066         top = (ya - 0x00010000) >> 16;
1067         if (top < 0) top = 0;
1068         right = (xb + 0x0001ffff) >> 16;
1069         if (right > width) right = width;
1070         bottom = (yb + 0x0001ffff) >> 16;
1071         if (bottom > height) bottom = height;
1072
1073         if(pPriv->blitter) NVSync(pScrn);
1074
1075         
1076         switch(id) {
1077         case FOURCC_YV12:
1078         case FOURCC_I420:
1079                 left &= ~1;
1080                 npixels = ((right + 1) & ~1) - left;
1081                 top &= ~1;
1082                 nlines = ((bottom + 1) & ~1) - top;
1083
1084                 offset += (left << 1) + (top * dstPitch);
1085                 tmp = ((top >> 1) * srcPitch2) + (left >> 1);
1086                 s2offset += tmp;
1087                 s3offset += tmp;
1088                 if (id == FOURCC_I420) {
1089                         tmp = s2offset;
1090                         s2offset = s3offset;
1091                         s3offset = tmp;
1092                 }
1093                 line_len = dstPitch;
1094                 break;
1095         case FOURCC_UYVY:
1096         case FOURCC_YUY2:
1097                 left &= ~1;
1098                 npixels = ((right + 1) & ~1) - left;
1099                 nlines = bottom - top;
1100
1101                 left <<= 1;
1102                 buf += (top * srcPitch) + left;
1103                 offset += left + (top * dstPitch);
1104                 line_len = width << 1;
1105                 break;
1106         case FOURCC_RGB:
1107                 npixels = right - left;
1108                 nlines = bottom - top;
1109                 left <<= 2;
1110                 buf += (top * srcPitch) + left;
1111                 offset += left + (top * dstPitch);
1112                 line_len = width << 2;
1113                 break;
1114         default:
1115                 return BadImplementation;
1116         }
1117
1118
1119
1120         /*Below is *almost* a copypaste from NvAccelUploadM2MF, cannot use it directly because of YV12 -> YUY2 conversion */    
1121         if ( nlines * line_len <= pNv->GARTScratch->size)
1122                 {
1123                 char *dst = pNv->GARTScratch->map;
1124                 
1125                 /* Upload to GART */
1126                 switch(id) {
1127                 case FOURCC_YV12:
1128                 case FOURCC_I420:
1129                 
1130                         NVCopyData420(buf + (top * srcPitch) + left,
1131                                 buf + s2offset, buf + s3offset,
1132                                 dst, srcPitch, srcPitch2,
1133                                 dstPitch, nlines, npixels);
1134                         
1135                         break;
1136                 case FOURCC_UYVY:
1137                 case FOURCC_YUY2:
1138                 case FOURCC_RGB:
1139                         memcpy(dst, buf, srcPitch * nlines);
1140                         break;
1141                 default:
1142                         return BadImplementation;
1143                 }
1144                 
1145                 if ( !pPriv -> blitter ) 
1146                         {
1147                         NVDmaStart(pNv, NvSubMemFormat, MEMFORMAT_DMA_OBJECT_IN, 2);
1148                         NVDmaNext (pNv, NvDmaTT);
1149                         NVDmaNext (pNv, NvDmaFB);
1150                         pNv->M2MFDirection = 1;
1151                 
1152                         /* DMA to VRAM */
1153                         
1154                         NVDmaStart(pNv, NvSubMemFormat,
1155                                 NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
1156                         NVDmaNext (pNv, (uint32_t)pNv->GARTScratch->offset);
1157                         NVDmaNext (pNv, (uint32_t)offset);
1158                         NVDmaNext (pNv, line_len);
1159                         NVDmaNext (pNv, dstPitch);
1160                         NVDmaNext (pNv, line_len);
1161                         NVDmaNext (pNv, nlines);
1162                         NVDmaNext (pNv, (1<<8)|1);
1163                         NVDmaNext (pNv, 0);
1164
1165                         NVNotifierReset(pScrn, pNv->Notifier0);
1166                         NVDmaStart(pNv, NvSubMemFormat,
1167                                 NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
1168                         NVDmaNext (pNv, 0);
1169                         NVDmaStart(pNv, NvSubMemFormat, 0x100, 1);
1170                         NVDmaNext (pNv, 0);
1171                         NVDmaKickoff(pNv);
1172
1173                         if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, 0))
1174                                 return FALSE;
1175                         }
1176                 else 
1177                         {
1178                         NVDmaStart(pNv, NvSubScaledImage, NV04_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE, 1);
1179                         NVDmaNext (pNv, NvDmaTT); /* source object */
1180                         
1181                         NVPutBlitImage(pScrn, pNv->GARTScratch->offset, id,
1182                                        dstPitch, &dstBox,
1183                                        xa, ya, xb, yb,
1184                                        width, height,
1185                                        src_w, src_h, drw_w, drw_h,
1186                                        clipBoxes, pDraw);
1187                         
1188                         NVNotifierReset(pScrn, pNv->Notifier0);
1189                         NVDmaStart(pNv, NvSubScaledImage,
1190                                 NV10_IMAGE_BLIT_NOTIFY, 1);
1191                         NVDmaNext (pNv, 0);
1192                         NVDmaStart(pNv, NvSubScaledImage, 0x100, 1);
1193                         NVDmaNext (pNv, 106);
1194                                 
1195                         NVDmaStart(pNv, NvSubScaledImage, NV04_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE, 1);
1196                         NVDmaNext (pNv, NvDmaFB); /* source object */
1197                         NVDmaKickoff(pNv);
1198                         if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, 0))
1199                                 return FALSE;
1200                         return Success;
1201                         }
1202                 }
1203         else //GART is too small, we fallback on CPU copy for simplicity
1204                 {
1205                 }
1206                 
1207         
1208
1209         if (!skip) {
1210                 if (pPriv->blitter) {
1211                         NVPutBlitImage(pScrn, offset, id,
1212                                        dstPitch, &dstBox,
1213                                        xa, ya, xb, yb,
1214                                        width, height,
1215                                        src_w, src_h, drw_w, drw_h,
1216                                        clipBoxes, pDraw);
1217                 } else {
1218                         NVPutOverlayImage(pScrn, offset, id,
1219                                           dstPitch, &dstBox, 
1220                                           xa, ya, xb, yb,
1221                                           width, height,
1222                                           src_w, src_h, drw_w, drw_h,
1223                                           clipBoxes);
1224                         pPriv->currentBuffer ^= 1;
1225                 }
1226         }
1227         
1228         
1229         return Success;
1230 }
1231
1232 /**
1233  * QueryImageAttributes
1234  * 
1235  * calculates
1236  * - size (memory required to store image),
1237  * - pitches,
1238  * - offsets
1239  * of image
1240  * depending on colorspace (id) and dimensions (w,h) of image
1241  * values of
1242  * - w,
1243  * - h
1244  * may be adjusted as needed
1245  * 
1246  * @param pScrn unused
1247  * @param id colorspace of image
1248  * @param w pointer to width of image
1249  * @param h pointer to height of image
1250  * @param pitches pitches[i] = length of a scanline in plane[i]
1251  * @param offsets offsets[i] = offset of plane i from the beginning of the image
1252  * @return size of the memory required for the XvImage queried
1253  */
1254 static int
1255 NVQueryImageAttributes(ScrnInfoPtr pScrn, int id, 
1256                        unsigned short *w, unsigned short *h, 
1257                        int *pitches, int *offsets)
1258 {
1259         int size, tmp;
1260
1261         if (*w > IMAGE_MAX_W)
1262                 *w = IMAGE_MAX_W;
1263         if (*h > IMAGE_MAX_H)
1264                 *h = IMAGE_MAX_H;
1265
1266         *w = (*w + 1) & ~1; // width rounded up to an even number
1267         if (offsets)
1268                 offsets[0] = 0;
1269
1270         switch (id) {
1271         case FOURCC_YV12:
1272         case FOURCC_I420:
1273                 *h = (*h + 1) & ~1; // height rounded up to an even number
1274                 size = (*w + 3) & ~3; // width rounded up to a multiple of 4
1275                 if (pitches)
1276                         pitches[0] = size; // width rounded up to a multiple of 4
1277                 size *= *h;
1278                 if (offsets)
1279                         offsets[1] = size; // number of pixels in "rounded up" image
1280                 tmp = ((*w >> 1) + 3) & ~3; // width/2 rounded up to a multiple of 4
1281                 if (pitches)
1282                         pitches[1] = pitches[2] = tmp; // width/2 rounded up to a multiple of 4
1283                 tmp *= (*h >> 1); // 1/4*number of pixels in "rounded up" image
1284                 size += tmp; // 5/4*number of pixels in "rounded up" image
1285                 if (offsets)
1286                         offsets[2] = size; // 5/4*number of pixels in "rounded up" image
1287                 size += tmp; // = 3/2*number of pixels in "rounded up" image
1288                 break;
1289         case FOURCC_UYVY:
1290         case FOURCC_YUY2:
1291                 size = *w << 1; // 2*width
1292                 if (pitches)
1293                         pitches[0] = size; // 2*width
1294                 size *= *h; // 2*width*height
1295                 break;
1296         case FOURCC_RGB:
1297                 size = *w << 2; // 4*width (32 bit per pixel)
1298                 if (pitches)
1299                         pitches[0] = size; // 4*width
1300                 size *= *h; // 4*width*height
1301                 break;
1302         default:
1303                 *w = *h = size = 0;
1304                 break;
1305         }
1306
1307         return size;
1308 }
1309
1310 /***** Exported offscreen surface stuff ****/
1311
1312
1313 static int
1314 NVAllocSurface(ScrnInfoPtr pScrn, int id,
1315                unsigned short w, unsigned short h,
1316                XF86SurfacePtr surface)
1317 {
1318         NVPtr pNv = NVPTR(pScrn);
1319         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); 
1320         int size, bpp;
1321
1322         bpp = pScrn->bitsPerPixel >> 3;
1323
1324         if (pPriv->grabbedByV4L)
1325                 return BadAlloc;
1326
1327         if ((w > IMAGE_MAX_W) || (h > IMAGE_MAX_H))
1328                 return BadValue;
1329
1330         w = (w + 1) & ~1;
1331         pPriv->pitch = ((w << 1) + 63) & ~63;
1332         size = h * pPriv->pitch / bpp;
1333
1334         pPriv->video_mem = NVAllocateOverlayMemory(pScrn,
1335                                                    pPriv->video_mem,
1336                                                    size);
1337         if (!pPriv->video_mem)
1338                 return BadAlloc;
1339
1340         pPriv->offset = 0;
1341         
1342         surface->width = w;
1343         surface->height = h;
1344         surface->pScrn = pScrn;
1345         surface->pitches = &pPriv->pitch; 
1346         surface->offsets = &pPriv->offset;
1347         surface->devPrivate.ptr = (pointer)pPriv;
1348         surface->id = id;
1349
1350         /* grab the video */
1351         NVStopOverlay(pScrn);
1352         pPriv->videoStatus = 0;
1353         REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1354         pPriv->grabbedByV4L = TRUE;
1355
1356         return Success;
1357 }
1358
1359 static int
1360 NVStopSurface(XF86SurfacePtr surface)
1361 {
1362         NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1363
1364         if (pPriv->grabbedByV4L && pPriv->videoStatus) {
1365                 NVStopOverlay(surface->pScrn);
1366                 pPriv->videoStatus = 0;
1367         }
1368
1369         return Success;
1370 }
1371
1372 static int 
1373 NVFreeSurface(XF86SurfacePtr surface)
1374 {
1375         NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1376
1377         if (pPriv->grabbedByV4L) {
1378                 NVStopSurface(surface);
1379                 NVFreeOverlayMemory(surface->pScrn);
1380                 pPriv->grabbedByV4L = FALSE;
1381         }
1382
1383         return Success;
1384 }
1385
1386 static int
1387 NVGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value)
1388 {
1389         NVPtr pNv = NVPTR(pScrn);
1390         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1391
1392         return NVGetOverlayPortAttribute(pScrn, attribute,
1393                                          value, (pointer)pPriv);
1394 }
1395
1396 static int
1397 NVSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value)
1398 {
1399         NVPtr pNv = NVPTR(pScrn);
1400         NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1401
1402         return NVSetOverlayPortAttribute(pScrn, attribute,
1403                                          value, (pointer)pPriv);
1404 }
1405
1406 static int
1407 NVDisplaySurface(XF86SurfacePtr surface,
1408                  short src_x, short src_y, 
1409                  short drw_x, short drw_y,
1410                  short src_w, short src_h, 
1411                  short drw_w, short drw_h,
1412                  RegionPtr clipBoxes)
1413 {
1414         ScrnInfoPtr pScrn = surface->pScrn;
1415         NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1416         INT32 xa, xb, ya, yb;
1417         BoxRec dstBox;
1418
1419         if (!pPriv->grabbedByV4L)
1420                 return Success;
1421
1422         if (src_w > (drw_w << 3))
1423                 drw_w = src_w >> 3;
1424         if (src_h > (drw_h << 3))
1425                 drw_h = src_h >> 3;
1426
1427         /* Clip */
1428         xa = src_x;
1429         xb = src_x + src_w;
1430         ya = src_y;
1431         yb = src_y + src_h;
1432
1433         dstBox.x1 = drw_x;
1434         dstBox.x2 = drw_x + drw_w;
1435         dstBox.y1 = drw_y;
1436         dstBox.y2 = drw_y + drw_h;
1437
1438         if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, 
1439                                   surface->width, surface->height))
1440                 return Success;
1441
1442         dstBox.x1 -= pScrn->frameX0;
1443         dstBox.x2 -= pScrn->frameX0;
1444         dstBox.y1 -= pScrn->frameY0;
1445         dstBox.y2 -= pScrn->frameY0;
1446
1447         pPriv->currentBuffer = 0;
1448
1449         NVPutOverlayImage(pScrn, surface->offsets[0], surface->id,
1450                           surface->pitches[0], &dstBox, xa, ya, xb, yb,
1451                           surface->width, surface->height, src_w, src_h,
1452                           drw_w, drw_h, clipBoxes);
1453
1454         return Success;
1455 }
1456
1457 /**
1458  * NVSetupBlitVideo
1459  * this function does all the work setting up a blit port
1460  * 
1461  * @return blit port
1462  */
1463 static XF86VideoAdaptorPtr
1464 NVSetupBlitVideo (ScreenPtr pScreen)
1465 {
1466         ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1467         NVPtr               pNv       = NVPTR(pScrn);
1468         XF86VideoAdaptorPtr adapt;
1469         NVPortPrivPtr       pPriv;
1470         int i;
1471
1472         if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
1473                                         sizeof(NVPortPrivRec) +
1474                                         (sizeof(DevUnion) * NUM_BLIT_PORTS)))) {
1475                 return NULL;
1476         }
1477
1478         adapt->type             = XvWindowMask | XvInputMask | XvImageMask;
1479         adapt->flags            = 0;
1480         adapt->name             = "NV Video Blitter";
1481         adapt->nEncodings       = 1;
1482         adapt->pEncodings       = &DummyEncoding;
1483         adapt->nFormats         = NUM_FORMATS_ALL;
1484         adapt->pFormats         = NVFormats;
1485         adapt->nPorts           = NUM_BLIT_PORTS;
1486         adapt->pPortPrivates    = (DevUnion*)(&adapt[1]);
1487
1488         pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_BLIT_PORTS]);
1489         for(i = 0; i < NUM_BLIT_PORTS; i++)
1490                 adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
1491
1492         if(pNv->WaitVSyncPossible) {
1493                 adapt->pAttributes = NVBlitAttributes;
1494                 adapt->nAttributes = NUM_BLIT_ATTRIBUTES;
1495         } else {
1496                 adapt->pAttributes = NULL;
1497                 adapt->nAttributes = 0;
1498         }
1499
1500         adapt->pImages                  = NVImages;
1501         adapt->nImages                  = NUM_IMAGES_ALL;
1502         adapt->PutVideo                 = NULL;
1503         adapt->PutStill                 = NULL;
1504         adapt->GetVideo                 = NULL;
1505         adapt->GetStill                 = NULL;
1506         adapt->StopVideo                = NVStopBlitVideo;
1507         adapt->SetPortAttribute         = NVSetBlitPortAttribute;
1508         adapt->GetPortAttribute         = NVGetBlitPortAttribute;
1509         adapt->QueryBestSize            = NVQueryBestSize;
1510         adapt->PutImage                 = NVPutImage;
1511         adapt->QueryImageAttributes     = NVQueryImageAttributes;
1512
1513         pPriv->videoStatus              = 0;
1514         pPriv->grabbedByV4L             = FALSE;
1515         pPriv->blitter                  = TRUE;
1516         pPriv->doubleBuffer             = FALSE;
1517         pPriv->SyncToVBlank             = pNv->WaitVSyncPossible;
1518
1519         pNv->blitAdaptor                = adapt;
1520         xvSyncToVBlank                  = MAKE_ATOM("XV_SYNC_TO_VBLANK");
1521
1522         return adapt;
1523 }
1524
1525 /**
1526  * NV10SetupOverlayVideo
1527  * this function does all the work setting up an overlay port
1528  * 
1529  * @return overlay port
1530  * @see NVResetVideo(ScrnInfoPtr pScrn)
1531  */
1532 static XF86VideoAdaptorPtr 
1533 NV10SetupOverlayVideo(ScreenPtr pScreen)
1534 {
1535         ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1536         NVPtr               pNv       = NVPTR(pScrn);
1537         XF86VideoAdaptorPtr adapt;
1538         NVPortPrivPtr       pPriv;
1539
1540         if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + 
1541                                         sizeof(NVPortPrivRec) + 
1542                                         sizeof(DevUnion)))) {
1543                 return NULL;
1544         }
1545
1546         adapt->type             = XvWindowMask | XvInputMask | XvImageMask;
1547         adapt->flags            = VIDEO_OVERLAID_IMAGES|VIDEO_CLIP_TO_VIEWPORT;
1548         adapt->name             = "NV Video Overlay";
1549         adapt->nEncodings       = 1;
1550         adapt->pEncodings       = &DummyEncoding;
1551         adapt->nFormats         = NUM_FORMATS_ALL;
1552         adapt->pFormats         = NVFormats;
1553         adapt->nPorts           = 1;
1554         adapt->pPortPrivates    = (DevUnion*)(&adapt[1]);
1555
1556         pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[1]);
1557         adapt->pPortPrivates[0].ptr     = (pointer)(pPriv);
1558
1559         adapt->pAttributes              = NVOverlayAttributes;
1560         adapt->nAttributes              = NUM_OVERLAY_ATTRIBUTES;
1561         adapt->pImages                  = NVImages;
1562         adapt->nImages                  = NUM_IMAGES_YUV;
1563         adapt->PutVideo                 = NULL;
1564         adapt->PutStill                 = NULL;
1565         adapt->GetVideo                 = NULL;
1566         adapt->GetStill                 = NULL;
1567         adapt->StopVideo                = NVStopOverlayVideo;
1568         adapt->SetPortAttribute         = NVSetOverlayPortAttribute;
1569         adapt->GetPortAttribute         = NVGetOverlayPortAttribute;
1570         adapt->QueryBestSize            = NVQueryBestSize;
1571         adapt->PutImage                 = NVPutImage;
1572         adapt->QueryImageAttributes     = NVQueryImageAttributes;
1573
1574         pPriv->videoStatus              = 0;
1575         pPriv->currentBuffer            = 0;
1576         pPriv->grabbedByV4L             = FALSE;
1577         pPriv->blitter                  = FALSE;
1578
1579         NVSetPortDefaults (pScrn, pPriv);
1580
1581         /* gotta uninit this someplace */
1582         REGION_NULL(pScreen, &pPriv->clip);
1583
1584         pNv->overlayAdaptor     = adapt;
1585
1586         xvBrightness            = MAKE_ATOM("XV_BRIGHTNESS");
1587         xvDoubleBuffer          = MAKE_ATOM("XV_DOUBLE_BUFFER");
1588         xvContrast              = MAKE_ATOM("XV_CONTRAST");
1589         xvColorKey              = MAKE_ATOM("XV_COLORKEY");
1590         xvSaturation            = MAKE_ATOM("XV_SATURATION");
1591         xvHue                   = MAKE_ATOM("XV_HUE");
1592         xvAutopaintColorKey     = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
1593         xvSetDefaults           = MAKE_ATOM("XV_SET_DEFAULTS");
1594         xvITURBT709             = MAKE_ATOM("XV_ITURBT_709");
1595
1596         NVResetVideo(pScrn);
1597
1598         return adapt;
1599 }
1600
1601 XF86OffscreenImageRec NVOffscreenImages[2] = {
1602         {
1603                 &NVImages[0],
1604                 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1605                 NVAllocSurface,
1606                 NVFreeSurface,
1607                 NVDisplaySurface,
1608                 NVStopSurface,
1609                 NVGetSurfaceAttribute,
1610                 NVSetSurfaceAttribute,
1611                 IMAGE_MAX_W, IMAGE_MAX_H,
1612                 NUM_OVERLAY_ATTRIBUTES - 1,
1613                 &NVOverlayAttributes[1]
1614         },
1615         {
1616                 &NVImages[2],
1617                 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1618                 NVAllocSurface,
1619                 NVFreeSurface,
1620                 NVDisplaySurface,
1621                 NVStopSurface,
1622                 NVGetSurfaceAttribute,
1623                 NVSetSurfaceAttribute,
1624                 IMAGE_MAX_W, IMAGE_MAX_H,
1625                 NUM_OVERLAY_ATTRIBUTES - 1,
1626                 &NVOverlayAttributes[1]
1627         }
1628 };
1629
1630 static void
1631 NVInitOffscreenImages (ScreenPtr pScreen)
1632 {
1633         xf86XVRegisterOffscreenImages(pScreen, NVOffscreenImages, 2);
1634 }
1635
1636 /**
1637  * NVChipsetHasOverlay
1638  * 
1639  * newer chips don't support overlay anymore.
1640  * overlay feature is emulated via textures.
1641  * 
1642  * @param pNv 
1643  * @return true, if chipset supports overlay
1644  */
1645 static Bool
1646 NVChipsetHasOverlay(NVPtr pNv)
1647 {
1648         switch (pNv->Architecture) {
1649         case NV_ARCH_10:
1650         case NV_ARCH_20:
1651         case NV_ARCH_30:
1652                 return TRUE;
1653         case NV_ARCH_40:
1654                 if ((pNv->Chipset & 0xfff0) == CHIPSET_NV40)
1655                         return TRUE;
1656                 break;
1657         default:
1658                 break;
1659         }
1660
1661         return FALSE;
1662 }
1663
1664 /**
1665  * NVSetupOverlayVideo
1666  * check if chipset supports Overlay and CompositeExtension is disabled.
1667  * if so, setup overlay port
1668  * 
1669  * @return overlay port
1670  * @see NVChipsetHasOverlay(NVPtr pNv)
1671  * @see NV10SetupOverlayVideo(ScreenPtr pScreen)
1672  * @see NVInitOffscreenImages(ScreenPtr pScreen)
1673  */
1674 static XF86VideoAdaptorPtr
1675 NVSetupOverlayVideo(ScreenPtr pScreen)
1676 {
1677         ScrnInfoPtr          pScrn = xf86Screens[pScreen->myNum];
1678         XF86VideoAdaptorPtr  overlayAdaptor = NULL;
1679         NVPtr                pNv   = NVPTR(pScrn);
1680
1681         if (!NVChipsetHasOverlay(pNv))
1682                 return NULL;
1683
1684         /*XXX: Do we still want to provide the overlay anyway, but make the
1685          *     blit adaptor the default if composite is enabled?
1686          */
1687 #ifdef COMPOSITE
1688 /*      if (!noCompositeExtension) {
1689                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1690                         "XV: Video overlay not available, composite enabled\n");
1691                 return NULL;
1692         }*/
1693 #endif
1694         overlayAdaptor = NV10SetupOverlayVideo(pScreen);
1695         if (overlayAdaptor)
1696                 NVInitOffscreenImages(pScreen);
1697
1698         return overlayAdaptor;
1699 }
1700
1701 /**
1702  * NVInitVideo
1703  * tries to initialize one new overlay port and one new blit port
1704  * and add them to the list of ports on screen "pScreen".
1705  * 
1706  * @param pScreen
1707  * @see NVSetupOverlayVideo(ScreenPtr pScreen)
1708  * @see NVSetupBlitVideo(ScreenPtr pScreen)
1709  */
1710 void NVInitVideo (ScreenPtr pScreen)
1711 {
1712         ScrnInfoPtr          pScrn = xf86Screens[pScreen->myNum];
1713         XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
1714         XF86VideoAdaptorPtr  overlayAdaptor = NULL;
1715         XF86VideoAdaptorPtr  blitAdaptor = NULL;
1716         int                  num_adaptors;
1717
1718         if (pScrn->bitsPerPixel == 8)
1719                 return;
1720
1721         overlayAdaptor = NVSetupOverlayVideo(pScreen);
1722         blitAdaptor    = NVSetupBlitVideo(pScreen);
1723
1724         num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
1725         if(blitAdaptor || overlayAdaptor) {
1726                 int size = num_adaptors;
1727
1728                 if(overlayAdaptor) size++;
1729                 if(blitAdaptor)    size++;
1730
1731                 newAdaptors = xalloc(size * sizeof(XF86VideoAdaptorPtr *));
1732                 if(newAdaptors) {
1733                         if(num_adaptors) {
1734                                 memcpy(newAdaptors, adaptors, num_adaptors *
1735                                                 sizeof(XF86VideoAdaptorPtr));
1736                         }
1737
1738                         if(overlayAdaptor) {
1739                                 newAdaptors[num_adaptors] = overlayAdaptor;
1740                                 num_adaptors++;
1741                         }
1742
1743                         if(blitAdaptor) {
1744                                 newAdaptors[num_adaptors] = blitAdaptor;
1745                                 num_adaptors++;
1746                         }
1747
1748                         adaptors = newAdaptors;
1749                 }
1750         }
1751
1752         if (num_adaptors)
1753                 xf86XVScreenInit(pScreen, adaptors, num_adaptors);
1754         if (newAdaptors)
1755                 xfree(newAdaptors);
1756 }
1757