randr12: common tmds access functions
[nouveau] / src / nv_exa.c
1  /***************************************************************************\
2 |*                                                                           *|
3 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
4 |*                                                                           *|
5 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
6 |*     international laws.  Users and possessors of this source code are     *|
7 |*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
8 |*     use this code in individual and commercial software.                  *|
9 |*                                                                           *|
10 |*     Any use of this source code must include,  in the user documenta-     *|
11 |*     tion and  internal comments to the code,  notices to the end user     *|
12 |*     as follows:                                                           *|
13 |*                                                                           *|
14 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
15 |*                                                                           *|
16 |*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
17 |*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
18 |*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
19 |*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
20 |*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
21 |*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
22 |*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
23 |*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
24 |*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
25 |*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
26 |*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
27 |*                                                                           *|
28 |*     U.S. Government  End  Users.   This source code  is a "commercial     *|
29 |*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
30 |*     consisting  of "commercial  computer  software"  and  "commercial     *|
31 |*     computer  software  documentation,"  as such  terms  are  used in     *|
32 |*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
33 |*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
34 |*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
35 |*     all U.S. Government End Users  acquire the source code  with only     *|
36 |*     those rights set forth herein.                                        *|
37 |*                                                                           *|
38  \***************************************************************************/
39
40 /*
41   Exa Modifications (c) Lars Knoll (lars@trolltech.com)
42  */
43
44 #include "nv_include.h"
45 #include "exa.h"
46
47 #include "nv_dma.h"
48 #include "nv_local.h"
49
50 #include <sys/time.h>
51
52 const int NVCopyROP[16] =
53 {
54    0x00,            /* GXclear */
55    0x88,            /* GXand */
56    0x44,            /* GXandReverse */
57    0xCC,            /* GXcopy */
58    0x22,            /* GXandInverted */
59    0xAA,            /* GXnoop */
60    0x66,            /* GXxor */
61    0xEE,            /* GXor */
62    0x11,            /* GXnor */
63    0x99,            /* GXequiv */
64    0x55,            /* GXinvert*/
65    0xDD,            /* GXorReverse */
66    0x33,            /* GXcopyInverted */
67    0xBB,            /* GXorInverted */
68    0x77,            /* GXnand */
69    0xFF             /* GXset */
70 };
71
72 static void 
73 NVSetPattern(ScrnInfoPtr pScrn, CARD32 clr0, CARD32 clr1,
74                                 CARD32 pat0, CARD32 pat1)
75 {
76         NVPtr pNv = NVPTR(pScrn);
77
78         BEGIN_RING(NvImagePattern, NV04_IMAGE_PATTERN_MONOCHROME_COLOR0, 4);
79         OUT_RING  (clr0);
80         OUT_RING  (clr1);
81         OUT_RING  (pat0);
82         OUT_RING  (pat1);
83 }
84
85 static void 
86 NVSetROP(ScrnInfoPtr pScrn, CARD32 alu, CARD32 planemask)
87 {
88         NVPtr pNv = NVPTR(pScrn);
89         int rop = NVCopyROP[alu] & 0xf0;
90
91         if (planemask != ~0) {
92                 NVSetPattern(pScrn, 0, planemask, ~0, ~0);
93                 if (pNv->currentRop != (alu + 32)) {
94                         BEGIN_RING(NvRop, NV03_CONTEXT_ROP_ROP, 1);
95                         OUT_RING  (rop | 0x0a);
96                         pNv->currentRop = alu + 32;
97                 }
98         } else
99         if (pNv->currentRop != alu) {
100                 if(pNv->currentRop >= 16)
101                         NVSetPattern(pScrn, ~0, ~0, ~0, ~0);
102                 BEGIN_RING(NvRop, NV03_CONTEXT_ROP_ROP, 1);
103                 OUT_RING  (rop | (rop >> 4));
104                 pNv->currentRop = alu;
105         }
106 }
107
108 static CARD32 rectFormat(DrawablePtr pDrawable)
109 {
110         switch(pDrawable->bitsPerPixel) {
111         case 32:
112         case 24:
113                 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
114                 break;
115         case 16:
116                 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
117                 break;
118         default:
119                 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
120                 break;
121         }
122 }
123
124 /* EXA acceleration hooks */
125 static void NVExaWaitMarker(ScreenPtr pScreen, int marker)
126 {
127         NVSync(xf86Screens[pScreen->myNum]);
128 }
129
130 static Bool NVExaPrepareSolid(PixmapPtr pPixmap,
131                               int   alu,
132                               Pixel planemask,
133                               Pixel fg)
134 {
135         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
136         NVPtr pNv = NVPTR(pScrn);
137         unsigned int fmt, pitch;
138
139         planemask |= ~0 << pPixmap->drawable.bitsPerPixel;
140         if (planemask != ~0 || alu != GXcopy) {
141                 if (pPixmap->drawable.bitsPerPixel == 32)
142                         return FALSE;
143                 BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
144                 OUT_RING  (1); /* ROP_AND */
145                 NVSetROP(pScrn, alu, planemask);
146         } else {
147                 BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
148                 OUT_RING  (3); /* SRCCOPY */
149         }
150
151         if (!NVAccelGetCtxSurf2DFormatFromPixmap(pPixmap, (int*)&fmt))
152                 return FALSE;
153         pitch = exaGetPixmapPitch(pPixmap);
154
155         /* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the 
156          * alpha channel gets forced to 0xFF for some reason.  We're using 
157          * SURFACE_FORMAT_Y32 as a workaround
158          */
159         if (fmt == NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8)
160                 fmt = NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
161
162         BEGIN_RING(NvContextSurfaces, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
163         OUT_RING  (fmt);
164         OUT_RING  ((pitch << 16) | pitch);
165         OUT_PIXMAPl(pPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
166         OUT_PIXMAPl(pPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
167
168         BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
169         OUT_RING  (rectFormat(&pPixmap->drawable));
170         BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
171         OUT_RING  (fg);
172
173         return TRUE;
174 }
175
176 static void NVExaSolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
177 {
178         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
179         NVPtr pNv = NVPTR(pScrn);
180         int width = x2-x1;
181         int height = y2-y1;
182
183         BEGIN_RING(NvRectangle,
184                    NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
185         OUT_RING  ((x1 << 16) | y1);
186         OUT_RING  ((width << 16) | height);
187
188         if((width * height) >= 512)
189                 FIRE_RING();
190 }
191
192 static void NVExaDoneSolid (PixmapPtr pPixmap)
193 {
194 }
195
196 static Bool NVExaPrepareCopy(PixmapPtr pSrcPixmap,
197                              PixmapPtr pDstPixmap,
198                              int       dx,
199                              int       dy,
200                              int       alu,
201                              Pixel     planemask)
202 {
203         ScrnInfoPtr pScrn = xf86Screens[pSrcPixmap->drawable.pScreen->myNum];
204         NVPtr pNv = NVPTR(pScrn);
205         int fmt;
206
207         if (pSrcPixmap->drawable.bitsPerPixel !=
208                         pDstPixmap->drawable.bitsPerPixel)
209                 return FALSE;
210
211         planemask |= ~0 << pDstPixmap->drawable.bitsPerPixel;
212         if (planemask != ~0 || alu != GXcopy) {
213                 if (pDstPixmap->drawable.bitsPerPixel == 32)
214                         return FALSE;
215                 BEGIN_RING(NvImageBlit, NV04_IMAGE_BLIT_OPERATION, 1);
216                 OUT_RING  (1); /* ROP_AND */
217                 NVSetROP(pScrn, alu, planemask);
218         } else {
219                 BEGIN_RING(NvImageBlit, NV04_IMAGE_BLIT_OPERATION, 1);
220                 OUT_RING  (3); /* SRCCOPY */
221         }
222
223         if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDstPixmap, &fmt))
224                 return FALSE;
225
226         BEGIN_RING(NvContextSurfaces, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
227         OUT_RING  (fmt);
228         OUT_RING  ((exaGetPixmapPitch(pDstPixmap) << 16) |
229                    (exaGetPixmapPitch(pSrcPixmap)));
230         OUT_PIXMAPl(pSrcPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
231         OUT_PIXMAPl(pDstPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
232
233         return TRUE;
234 }
235
236 static void NVExaCopy(PixmapPtr pDstPixmap,
237                       int       srcX,
238                       int       srcY,
239                       int       dstX,
240                       int       dstY,
241                       int       width,
242                       int       height)
243 {
244         ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
245         NVPtr pNv = NVPTR(pScrn);
246
247         /* We want to catch people who have this bug, to find a decent fix */
248 #if 0
249         /* Now check whether we have the same values for srcY and dstY and
250            whether the used chipset is buggy. Currently we flag all of G70
251            cards as buggy, which is probably much to broad. KoalaBR 
252            16 is an abritrary threshold. It should define the maximum number
253            of lines between dstY and srcY  If the number of lines is below
254            we guess, that the bug won't trigger...
255          */
256         if ( ((abs(srcY - dstY)< 16)||(abs(srcX-dstX)<16)) &&
257                 ((((pNv->Chipset & 0xfff0) == CHIPSET_G70) ||
258                  ((pNv->Chipset & 0xfff0) == CHIPSET_G71) ||
259                  ((pNv->Chipset & 0xfff0) == CHIPSET_G72) ||
260                  ((pNv->Chipset & 0xfff0) == CHIPSET_G73) ||
261                  ((pNv->Chipset & 0xfff0) == CHIPSET_C512))) )
262         {
263                 int dx=abs(srcX - dstX),dy=abs(srcY - dstY);
264                 // Ok, let's do it manually unless someone comes up with a better idea
265                 // 1. If dstY and srcY are really the same, do a copy rowwise
266                 if (dy<dx) {
267                         int i,xpos,inc;
268                         NVDEBUG("ExaCopy: Lines identical:\n");
269                         if (srcX>=dstX) {
270                                 xpos=0;
271                                 inc=1;
272                         } else {
273                                 xpos=width-1;
274                                 inc=-1;
275                         }
276                         for (i = 0; i < width; i++) {
277                                 BEGIN_RING(NvImageBlit,
278                                            NV_IMAGE_BLIT_POINT_IN, 3);
279                                 OUT_RING  ((srcY << 16) | (srcX+xpos));
280                                 OUT_RING  ((dstY << 16) | (dstX+xpos));
281                                 OUT_RING  ((height  << 16) | 1);
282                                 xpos+=inc;
283                         }
284                 } else {
285                         // 2. Otherwise we will try a line by line copy in the hope to avoid
286                         //    the card's bug.
287                         int i,ypos,inc;
288                         NVDEBUG("ExaCopy: Lines nearly the same srcY=%d, dstY=%d:\n", srcY, dstY);
289                         if (srcY>=dstY) {
290                                 ypos=0;
291                                 inc=1;
292                         } else {
293                                 ypos=height-1;
294                                 inc=-1;
295                         }
296                         for (i = 0; i < height; i++) {
297                                 BEGIN_RING(NvImageBlit,
298                                            NV_IMAGE_BLIT_POINT_IN, 3);
299                                 OUT_RING  (((srcY+ypos) << 16) | srcX);
300                                 OUT_RING  (((dstY+ypos) << 16) | dstX);
301                                 OUT_RING  ((1  << 16) | width);
302                                 ypos+=inc;
303                         }
304                 } 
305         } else {
306                 NVDEBUG("ExaCopy: Using default path\n");
307                 BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_POINT_IN, 3);
308                 OUT_RING  ((srcY << 16) | srcX);
309                 OUT_RING  ((dstY << 16) | dstX);
310                 OUT_RING  ((height  << 16) | width);
311         }
312 #endif /* 0 */
313
314         NVDEBUG("ExaCopy: Using default path\n");
315         BEGIN_RING(NvImageBlit, NV01_IMAGE_BLIT_POINT_IN, 3);
316         OUT_RING  ((srcY << 16) | srcX);
317         OUT_RING  ((dstY << 16) | dstX);
318         OUT_RING  ((height  << 16) | width);
319
320         if((width * height) >= 512)
321                 FIRE_RING(); 
322 }
323
324 static void NVExaDoneCopy (PixmapPtr pDstPixmap) {}
325
326 static inline Bool NVAccelMemcpyRect(char *dst, const char *src, int height,
327                        int dst_pitch, int src_pitch, int line_len)
328 {
329         if ((src_pitch == line_len) && (src_pitch == dst_pitch)) {
330                 memcpy(dst, src, line_len*height);
331         } else {
332                 while (height--) {
333                         memcpy(dst, src, line_len);
334                         src += src_pitch;
335                         dst += dst_pitch;
336                 }
337         }
338
339         return TRUE;
340 }
341
342 static inline Bool
343 NVAccelDownloadM2MF(ScrnInfoPtr pScrn, char *dst, PixmapPtr pspix,
344                     uint32_t src_offset, int dst_pitch, int src_pitch,
345                     int line_len, int line_count)
346 {
347         NVPtr pNv = NVPTR(pScrn);
348
349         BEGIN_RING(NvMemFormat, 0x184, 2);
350         OUT_PIXMAPo(pspix, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
351         OUT_RELOCo(pNv->GART, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
352
353         while (line_count) {
354                 char *src = pNv->GART->map;
355                 int lc, i;
356
357                 if (line_count * line_len <= pNv->GART->size) {
358                         lc = line_count;
359                 } else {
360                         lc = pNv->GART->size / line_len;
361                         if (lc > line_count)
362                                 lc = line_count;
363                 }
364
365                 /* HW limitations */
366                 if (lc > 2047)
367                         lc = 2047;
368
369                 if (pNv->Architecture >= NV_ARCH_50) {
370                         BEGIN_RING(NvMemFormat, 0x200, 1);
371                         OUT_RING  (1);
372                         BEGIN_RING(NvMemFormat, 0x21c, 1);
373                         OUT_RING  (1);
374                         /* probably high-order bits of address */
375                         BEGIN_RING(NvMemFormat, 0x238, 2);
376                         OUT_PIXMAPh(pspix, src_offset, NOUVEAU_BO_GART |
377                                     NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
378                         OUT_RELOCh(pNv->GART, 0, NOUVEAU_BO_GART |
379                                    NOUVEAU_BO_WR);
380                 }
381
382                 BEGIN_RING(NvMemFormat,
383                            NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
384                 OUT_PIXMAPl(pspix, src_offset, NOUVEAU_BO_GART |
385                             NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
386                 OUT_RELOCl(pNv->GART, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
387                 OUT_RING  (src_pitch);
388                 OUT_RING  (line_len);
389                 OUT_RING  (line_len);
390                 OUT_RING  (lc);
391                 OUT_RING  ((1<<8)|1);
392                 OUT_RING  (0);
393
394                 nouveau_notifier_reset(pNv->notify0, 0);
395                 BEGIN_RING(NvMemFormat, NV04_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
396                 OUT_RING  (0);
397                 BEGIN_RING(NvMemFormat, 0x100, 1);
398                 OUT_RING  (0);
399                 FIRE_RING();
400                 if (nouveau_notifier_wait_status(pNv->notify0, 0, 0,
401                                                  2000))
402                         return FALSE;
403
404                 if (dst_pitch == line_len) {
405                         memcpy(dst, src, dst_pitch * lc);
406                         dst += dst_pitch * lc;
407                 } else {
408                         for (i = 0; i < lc; i++) {
409                                 memcpy(dst, src, line_len);
410                                 src += line_len;
411                                 dst += dst_pitch;
412                         }
413                 }
414
415                 line_count -= lc;
416                 src_offset += lc * src_pitch;
417         }
418
419         return TRUE;
420 }
421
422 static inline void *
423 NVExaPixmapMap(PixmapPtr pPix)
424 {
425         void *map;
426 #if NOUVEAU_EXA_PIXMAPS
427         struct nouveau_pixmap *nvpix;
428
429         nvpix = exaGetPixmapDriverPrivate(pPix);
430         if (!nvpix || !nvpix->bo)
431                 return NULL;
432
433         map = nvpix->bo->map;
434 #else
435         ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
436         NVPtr pNv = NVPTR(pScrn);
437         map = pNv->FB->map + exaGetPixmapOffset(pPix);
438 #endif /* NOUVEAU_EXA_PIXMAPS */
439         return map;
440 }
441
442 static Bool NVDownloadFromScreen(PixmapPtr pSrc,
443                                  int x,  int y,
444                                  int w,  int h,
445                                  char *dst,  int dst_pitch)
446 {
447         ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
448         NVPtr pNv = NVPTR(pScrn);
449         int src_pitch, cpp, offset;
450         const char *src;
451
452         src_pitch  = exaGetPixmapPitch(pSrc);
453         cpp = pSrc->drawable.bitsPerPixel >> 3;
454         offset = (y * src_pitch) + (x * cpp);
455
456         if (pNv->GART) {
457                 if (NVAccelDownloadM2MF(pScrn, dst, pSrc, offset,
458                                         dst_pitch, src_pitch, w * cpp, h))
459                         return TRUE;
460         }
461
462         src = NVExaPixmapMap(pSrc);
463         if (!src)
464                 return FALSE;
465         src += offset;
466         exaWaitSync(pSrc->drawable.pScreen);
467         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
468                 return TRUE;
469
470         return FALSE;
471 }
472
473 static inline Bool
474 NVAccelUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch, 
475                  PixmapPtr pDst, int x, int y, int w, int h, int cpp)
476 {
477         NVPtr pNv = NVPTR(pScrn);
478         int line_len = w * cpp;
479         int iw, id, surf_fmt, ifc_fmt;
480         int padbytes;
481
482         if (pNv->Architecture >= NV_ARCH_50)
483                 return FALSE;
484
485         if (h > 1024)
486                 return FALSE;
487
488         switch (cpp) {
489         case 2: ifc_fmt = 1; break;
490         case 4: ifc_fmt = 4; break;
491         default:
492                 return FALSE;
493         }
494
495         if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDst, &surf_fmt))
496                 return FALSE;
497
498         BEGIN_RING(NvContextSurfaces, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
499         OUT_RING  (surf_fmt);
500         OUT_RING  ((exaGetPixmapPitch(pDst) << 16) | exaGetPixmapPitch(pDst));
501         OUT_PIXMAPl(pDst, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
502         OUT_PIXMAPl(pDst, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
503
504         /* Pad out input width to cover both COLORA() and COLORB() */
505         iw  = (line_len + 7) & ~7;
506         padbytes = iw - line_len;
507         id  = iw / 4; /* line push size */
508         iw /= cpp;
509
510         /* Don't support lines longer than max push size yet.. */
511         if (id > 1792)
512                 return FALSE;
513
514         BEGIN_RING(NvClipRectangle, NV01_CONTEXT_CLIP_RECTANGLE_POINT, 2);
515         OUT_RING  (0x0); 
516         OUT_RING  (0x7FFF7FFF);
517
518         BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_OPERATION, 2);
519         OUT_RING  (NV01_IMAGE_FROM_CPU_OPERATION_SRCCOPY);
520         OUT_RING  (ifc_fmt);
521         BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_POINT, 3);
522         OUT_RING  ((y << 16) | x); /* dst point */
523         OUT_RING  ((h << 16) | w); /* width/height out */
524         OUT_RING  ((h << 16) | iw); /* width/height in */
525
526         if (padbytes)
527                 h--;
528         while (h--) {
529                 /* send a line */
530                 BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_COLOR(0), id);
531                 OUT_RINGp (src, id);
532
533                 src += src_pitch;
534         }
535         if (padbytes) {
536                 char padding[8];
537                 int aux = (padbytes + 7) >> 2;
538                 BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_COLOR(0), id);
539                 OUT_RINGp (src, id - aux);
540                 memcpy(padding, src + (id - aux) * 4, padbytes);
541                 OUT_RINGp (padding, aux);
542         }
543
544         return TRUE;
545 }
546
547 static inline Bool
548 NVAccelUploadM2MF(ScrnInfoPtr pScrn, PixmapPtr pdpix, uint32_t dst_offset,
549                   const char *src, int dst_pitch, int src_pitch,
550                   int line_len, int line_count)
551 {
552         NVPtr pNv = NVPTR(pScrn);
553
554         BEGIN_RING(NvMemFormat, 0x184, 2);
555         OUT_RELOCo(pNv->GART, NOUVEAU_BO_GART | NOUVEAU_BO_RD);
556         OUT_PIXMAPo(pdpix, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_WR);
557
558         while (line_count) {
559                 char *dst = pNv->GART->map;
560                 int lc, i;
561
562                 /* Determine max amount of data we can DMA at once */
563                 if (line_count * line_len <= pNv->GART->size) {
564                         lc = line_count;
565                 } else {
566                         lc = pNv->GART->size / line_len;
567                         if (lc > line_count)
568                                 lc = line_count;
569                 }
570
571                 /* HW limitations */
572                 if (lc > 2047)
573                         lc = 2047;
574
575                 /* Upload to GART */
576                 if (src_pitch == line_len) {
577                         memcpy(dst, src, src_pitch * lc);
578                         src += src_pitch * lc;
579                 } else {
580                         for (i = 0; i < lc; i++) {
581                                 memcpy(dst, src, line_len);
582                                 src += src_pitch;
583                                 dst += line_len;
584                         }
585                 }
586
587                 if (pNv->Architecture >= NV_ARCH_50) {
588                         BEGIN_RING(NvMemFormat, 0x200, 1);
589                         OUT_RING  (1);
590                         BEGIN_RING(NvMemFormat, 0x21c, 1);
591                         OUT_RING  (1);
592                         /* probably high-order bits of address */
593                         BEGIN_RING(NvMemFormat, 0x238, 2);
594                         OUT_RELOCh(pNv->GART, 0, NOUVEAU_BO_GART |
595                                    NOUVEAU_BO_RD);
596                         OUT_PIXMAPh(pdpix, 0, NOUVEAU_BO_VRAM | 
597                                     NOUVEAU_BO_GART | NOUVEAU_BO_WR);
598                 }
599
600                 /* DMA to VRAM */
601                 BEGIN_RING(NvMemFormat,
602                            NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
603                 OUT_RELOCl(pNv->GART, 0, NOUVEAU_BO_GART | NOUVEAU_BO_RD);
604                 OUT_PIXMAPl(pdpix, dst_offset, NOUVEAU_BO_VRAM |
605                             NOUVEAU_BO_GART | NOUVEAU_BO_WR);
606                 OUT_RING  (line_len);
607                 OUT_RING  (dst_pitch);
608                 OUT_RING  (line_len);
609                 OUT_RING  (lc);
610                 OUT_RING  ((1<<8)|1);
611                 OUT_RING  (0);
612
613                 nouveau_notifier_reset(pNv->notify0, 0);
614                 BEGIN_RING(NvMemFormat, NV04_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
615                 OUT_RING  (0);
616                 BEGIN_RING(NvMemFormat, 0x100, 1);
617                 OUT_RING  (0);
618                 FIRE_RING();
619                 if (nouveau_notifier_wait_status(pNv->notify0, 0, 0, 2000))
620                         return FALSE;
621
622                 dst_offset += lc * dst_pitch;
623                 line_count -= lc;
624         }
625
626         return TRUE;
627 }
628
629 static Bool NVUploadToScreen(PixmapPtr pDst,
630                              int x, int y, int w, int h,
631                              char *src, int src_pitch)
632 {
633         ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
634         NVPtr pNv = NVPTR(pScrn);
635         int dst_pitch, cpp;
636         char *dst;
637
638         dst_pitch  = exaGetPixmapPitch(pDst);
639         cpp = pDst->drawable.bitsPerPixel >> 3;
640
641         /* try hostdata transfer */
642         if (w * h * cpp < 16*1024) /* heuristic */
643         {
644                 if (pNv->Architecture < NV_ARCH_50) {
645                         if (NVAccelUploadIFC(pScrn, src, src_pitch, pDst,
646                                              x, y, w, h, cpp)) {
647                                 exaMarkSync(pDst->drawable.pScreen);
648                                 return TRUE;
649                         }
650                 } else {
651                         if (NV50EXAUploadSIFC(pScrn, src, src_pitch, pDst,
652                                               x, y, w, h, cpp)) {
653                                 exaMarkSync(pDst->drawable.pScreen);
654                                 return TRUE;
655                         }
656                 }
657         }
658
659         /* try gart-based transfer */
660         if (pNv->GART) {
661                 if (NVAccelUploadM2MF(pScrn, pDst, (y * dst_pitch) + (x * cpp),
662                                       src, dst_pitch, src_pitch, w * cpp, h))
663                         return TRUE;
664         }
665
666         /* fallback to memcpy-based transfer */
667         dst = NVExaPixmapMap(pDst);
668         if (!dst)
669                 return FALSE;
670         dst += (y * dst_pitch) + (x * cpp);
671         exaWaitSync(pDst->drawable.pScreen);
672         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
673                 return TRUE;
674
675         return FALSE;
676 }
677
678 #ifdef NOUVEAU_EXA_PIXMAPS
679 static Bool
680 NVExaPrepareAccess(PixmapPtr pPix, int index)
681 {
682         ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
683         NVPtr pNv = NVPTR(pScrn);
684         struct nouveau_pixmap *nvpix;
685         (void)pNv;
686
687         nvpix = exaGetPixmapDriverPrivate(pPix);
688         if (!nvpix || !nvpix->bo)
689                 return FALSE;
690
691         /*XXX: ho hum.. sync if needed */
692
693         if (nvpix->mapped)
694                 return TRUE;
695
696         if (nouveau_bo_map(nvpix->bo, NOUVEAU_BO_RDWR))
697                 return FALSE;
698         pPix->devPrivate.ptr = nvpix->bo->map;
699         nvpix->mapped = TRUE;
700         return TRUE;
701 }
702
703 static void
704 NVExaFinishAccess(PixmapPtr pPix, int index)
705 {
706         ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
707         NVPtr pNv = NVPTR(pScrn);
708         struct nouveau_pixmap *nvpix;
709         (void)pNv;
710
711         nvpix = exaGetPixmapDriverPrivate(pPix);
712         if (!nvpix || !nvpix->bo || !nvpix->mapped)
713                 return;
714
715         nouveau_bo_unmap(nvpix->bo);
716         pPix->devPrivate.ptr = NULL;
717         nvpix->mapped = FALSE;
718 }
719
720 static Bool
721 NVExaPixmapIsOffscreen(PixmapPtr pPix)
722 {
723         ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
724         NVPtr pNv = NVPTR(pScrn);
725         struct nouveau_pixmap *nvpix;
726         (void)pNv;
727
728         nvpix = exaGetPixmapDriverPrivate(pPix);
729         if (!nvpix || !nvpix->bo)
730                 return FALSE;
731
732         return TRUE;
733 }
734
735 static void *
736 NVExaCreatePixmap(ScreenPtr pScreen, int size, int align)
737 {
738         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
739         NVPtr pNv = NVPTR(pScrn);
740         struct nouveau_pixmap *nvpix;
741
742         nvpix = xcalloc(1, sizeof(struct nouveau_pixmap));
743         if (!nvpix)
744                 return NULL;
745
746         if (size) {
747                 if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM, 0, size,
748                                    &nvpix->bo)) {
749                         xfree(nvpix);
750                         return NULL;
751                 }
752         }
753
754         return nvpix;
755 }
756
757 static void
758 NVExaDestroyPixmap(ScreenPtr pScreen, void *driverPriv)
759 {
760         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
761         NVPtr pNv = NVPTR(pScrn);
762         struct nouveau_pixmap *nvpix = driverPriv;
763
764         if (!driverPriv)
765                 return;
766
767         /*XXX: only if pending relocs reference this buffer..*/
768         FIRE_RING();
769
770         nouveau_bo_del(&nvpix->bo);
771         xfree(nvpix);
772 }
773
774 static Bool
775 NVExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth,
776                         int bitsPerPixel, int devKind, pointer pPixData)
777 {
778         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
779         NVPtr pNv = NVPTR(pScrn);
780         struct nouveau_pixmap *nvpix;
781
782         if (pPixData == pNv->FB->map) {
783                 nvpix = exaGetPixmapDriverPrivate(pPixmap);
784                 if (!nvpix)
785                         return FALSE;
786
787                 if (nouveau_bo_ref(pNv->dev, pNv->FB->handle, &nvpix->bo))
788                         return FALSE;
789
790                 miModifyPixmapHeader(pPixmap, width, height, depth,
791                                      bitsPerPixel, devKind, NULL);
792                 return TRUE;
793         }
794
795         return FALSE;
796 }
797 #endif
798
799 Bool
800 NVExaPixmapIsOnscreen(PixmapPtr pPixmap)
801 {
802         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
803         NVPtr pNv = NVPTR(pScrn);
804
805 #if NOUVEAU_EXA_PIXMAPS
806         struct nouveau_pixmap *nvpix;
807         nvpix = exaGetPixmapDriverPrivate(pPixmap);
808
809         if (nvpix && nvpix->bo == pNv->FB)
810                 return TRUE;
811
812 #else
813         unsigned long offset = exaGetPixmapOffset(pPixmap);
814
815         if (offset < pNv->EXADriverPtr->offScreenBase)
816                 return TRUE;
817 #endif /* NOUVEAU_EXA_PIXMAPS */
818
819         return FALSE;
820 }
821
822 Bool
823 NVExaInit(ScreenPtr pScreen) 
824 {
825         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
826         NVPtr pNv = NVPTR(pScrn);
827
828         if(!(pNv->EXADriverPtr = (ExaDriverPtr) xnfcalloc(sizeof(ExaDriverRec), 1))) {
829                 pNv->NoAccel = TRUE;
830                 return FALSE;
831         }
832
833         pNv->EXADriverPtr->exa_major = EXA_VERSION_MAJOR;
834         pNv->EXADriverPtr->exa_minor = EXA_VERSION_MINOR;
835
836 #ifdef NOUVEAU_EXA_PIXMAPS
837         if (NOUVEAU_EXA_PIXMAPS) {
838                 pNv->EXADriverPtr->flags = EXA_OFFSCREEN_PIXMAPS |
839                                            EXA_HANDLES_PIXMAPS;
840                 pNv->EXADriverPtr->PrepareAccess = NVExaPrepareAccess;
841                 pNv->EXADriverPtr->FinishAccess = NVExaFinishAccess;
842                 pNv->EXADriverPtr->PixmapIsOffscreen = NVExaPixmapIsOffscreen;
843                 pNv->EXADriverPtr->CreatePixmap = NVExaCreatePixmap;
844                 pNv->EXADriverPtr->DestroyPixmap = NVExaDestroyPixmap;
845                 pNv->EXADriverPtr->ModifyPixmapHeader = NVExaModifyPixmapHeader;
846         } else
847 #endif
848         {
849                 pNv->EXADriverPtr->flags = EXA_OFFSCREEN_PIXMAPS;
850                 pNv->EXADriverPtr->memoryBase = pNv->FB->map;
851                 pNv->EXADriverPtr->offScreenBase =
852                         NOUVEAU_ALIGN(pScrn->virtualX, 64) * NOUVEAU_ALIGN(pScrn->virtualY,64) * 
853                         (pScrn->bitsPerPixel / 8); 
854                 pNv->EXADriverPtr->memorySize           = pNv->FB->size; 
855         }
856         pNv->EXADriverPtr->pixmapOffsetAlign    = 256; 
857         pNv->EXADriverPtr->pixmapPitchAlign     = 64; 
858
859         if (pNv->Architecture >= NV_ARCH_50) {
860                 pNv->EXADriverPtr->maxX = 8192;
861                 pNv->EXADriverPtr->maxY = 8192;
862         } else
863         if (pNv->Architecture >= NV_ARCH_20) {
864                 pNv->EXADriverPtr->maxX = 4096;
865                 pNv->EXADriverPtr->maxY = 4096;
866         } else {
867                 pNv->EXADriverPtr->maxX = 2048;
868                 pNv->EXADriverPtr->maxY = 2048;
869         }
870
871         pNv->EXADriverPtr->WaitMarker = NVExaWaitMarker;
872
873         /* Install default hooks */
874         pNv->EXADriverPtr->DownloadFromScreen = NVDownloadFromScreen; 
875         pNv->EXADriverPtr->UploadToScreen = NVUploadToScreen; 
876
877         if (pNv->Architecture < NV_ARCH_50) {
878                 pNv->EXADriverPtr->PrepareCopy = NVExaPrepareCopy;
879                 pNv->EXADriverPtr->Copy = NVExaCopy;
880                 pNv->EXADriverPtr->DoneCopy = NVExaDoneCopy;
881
882                 pNv->EXADriverPtr->PrepareSolid = NVExaPrepareSolid;
883                 pNv->EXADriverPtr->Solid = NVExaSolid;
884                 pNv->EXADriverPtr->DoneSolid = NVExaDoneSolid;
885         } else {
886                 pNv->EXADriverPtr->PrepareCopy = NV50EXAPrepareCopy;
887                 pNv->EXADriverPtr->Copy = NV50EXACopy;
888                 pNv->EXADriverPtr->DoneCopy = NV50EXADoneCopy;
889
890                 pNv->EXADriverPtr->PrepareSolid = NV50EXAPrepareSolid;
891                 pNv->EXADriverPtr->Solid = NV50EXASolid;
892                 pNv->EXADriverPtr->DoneSolid = NV50EXADoneSolid;
893         }
894
895         switch (pNv->Architecture) {
896         
897         case NV_ARCH_10:
898         case NV_ARCH_20:
899                 pNv->EXADriverPtr->CheckComposite   = NV10CheckComposite;
900                 pNv->EXADriverPtr->PrepareComposite = NV10PrepareComposite;
901                 pNv->EXADriverPtr->Composite        = NV10Composite;
902                 pNv->EXADriverPtr->DoneComposite    = NV10DoneComposite;
903                 break;
904         case NV_ARCH_30:
905                 pNv->EXADriverPtr->CheckComposite   = NV30EXACheckComposite;
906                 pNv->EXADriverPtr->PrepareComposite = NV30EXAPrepareComposite;
907                 pNv->EXADriverPtr->Composite        = NV30EXAComposite;
908                 pNv->EXADriverPtr->DoneComposite    = NV30EXADoneComposite;
909                 break;
910         case NV_ARCH_40:
911                 pNv->EXADriverPtr->CheckComposite   = NV40EXACheckComposite;
912                 pNv->EXADriverPtr->PrepareComposite = NV40EXAPrepareComposite;
913                 pNv->EXADriverPtr->Composite        = NV40EXAComposite;
914                 pNv->EXADriverPtr->DoneComposite    = NV40EXADoneComposite;
915                 break;
916         case NV_ARCH_50:
917                 break;
918         default:
919                 break;
920         }
921
922         if (!exaDriverInit(pScreen, pNv->EXADriverPtr))
923                 return FALSE;
924         else
925                 /* EXA init catches this, but only for xserver >= 1.4 */
926                 if (pNv->VRAMPhysicalSize / 2 < NOUVEAU_ALIGN(pScrn->virtualX, 64) * NOUVEAU_ALIGN(pScrn->virtualY, 64) * (pScrn->bitsPerPixel >> 3)) {
927                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "The virtual screen size's resolution is too big for the video RAM framebuffer at this colour depth.\n");
928                         return FALSE;
929                 }
930
931         return TRUE;
932 }