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