Fix a thinko from commit 62294d9be8ec6f1159e3c2ad273649f937b7aa7e.
[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 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include "nv_include.h"
49 #include "exa.h"
50
51 #include "nv_dma.h"
52 #include "nv_local.h"
53
54 #include <sys/time.h>
55
56 const int NVCopyROP[16] =
57 {
58    0x00,            /* GXclear */
59    0x88,            /* GXand */
60    0x44,            /* GXandReverse */
61    0xCC,            /* GXcopy */
62    0x22,            /* GXandInverted */
63    0xAA,            /* GXnoop */
64    0x66,            /* GXxor */
65    0xEE,            /* GXor */
66    0x11,            /* GXnor */
67    0x99,            /* GXequiv */
68    0x55,            /* GXinvert*/
69    0xDD,            /* GXorReverse */
70    0x33,            /* GXcopyInverted */
71    0xBB,            /* GXorInverted */
72    0x77,            /* GXnand */
73    0xFF             /* GXset */
74 };
75
76 static void 
77 NVSetPattern(ScrnInfoPtr pScrn, CARD32 clr0, CARD32 clr1,
78                                 CARD32 pat0, CARD32 pat1)
79 {
80         NVPtr pNv = NVPTR(pScrn);
81
82         BEGIN_RING(NvImagePattern, NV04_IMAGE_PATTERN_MONOCHROME_COLOR0, 4);
83         OUT_RING  (clr0);
84         OUT_RING  (clr1);
85         OUT_RING  (pat0);
86         OUT_RING  (pat1);
87 }
88
89 static void 
90 NVSetROP(ScrnInfoPtr pScrn, CARD32 alu, CARD32 planemask)
91 {
92         NVPtr pNv = NVPTR(pScrn);
93         int rop = NVCopyROP[alu] & 0xf0;
94
95         if (planemask != ~0) {
96                 NVSetPattern(pScrn, 0, planemask, ~0, ~0);
97                 if (pNv->currentRop != (alu + 32)) {
98                         BEGIN_RING(NvRop, NV03_CONTEXT_ROP_ROP, 1);
99                         OUT_RING  (rop | 0x0a);
100                         pNv->currentRop = alu + 32;
101                 }
102         } else
103         if (pNv->currentRop != alu) {
104                 if(pNv->currentRop >= 16)
105                         NVSetPattern(pScrn, ~0, ~0, ~0, ~0);
106                 BEGIN_RING(NvRop, NV03_CONTEXT_ROP_ROP, 1);
107                 OUT_RING  (rop | (rop >> 4));
108                 pNv->currentRop = alu;
109         }
110 }
111
112 static void setM2MFDirection(ScrnInfoPtr pScrn, int dir)
113 {
114         NVPtr pNv = NVPTR(pScrn);
115
116         if (pNv->M2MFDirection != dir) {
117
118                 BEGIN_RING(NvMemFormat,
119                            NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
120                 OUT_RING  (dir ? NvDmaTT : NvDmaFB);
121                 OUT_RING  (dir ? NvDmaFB : NvDmaTT);
122                 pNv->M2MFDirection = dir;
123         }
124 }
125
126 static CARD32 rectFormat(DrawablePtr pDrawable)
127 {
128         switch(pDrawable->bitsPerPixel) {
129         case 32:
130         case 24:
131                 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
132                 break;
133         case 16:
134                 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
135                 break;
136         default:
137                 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
138                 break;
139         }
140 }
141
142 /* EXA acceleration hooks */
143 static void NVExaWaitMarker(ScreenPtr pScreen, int marker)
144 {
145         NVSync(xf86Screens[pScreen->myNum]);
146 }
147
148 static Bool NVExaPrepareSolid(PixmapPtr pPixmap,
149                               int   alu,
150                               Pixel planemask,
151                               Pixel fg)
152 {
153         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
154         NVPtr pNv = NVPTR(pScrn);
155         int fmt;
156
157         planemask |= ~0 << pPixmap->drawable.bitsPerPixel;
158         if (planemask != ~0 || alu != GXcopy) {
159                 if (pPixmap->drawable.bitsPerPixel == 32)
160                         return FALSE;
161                 BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
162                 OUT_RING  (1); /* ROP_AND */
163                 NVSetROP(pScrn, alu, planemask);
164         } else {
165                 BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
166                 OUT_RING  (3); /* SRCCOPY */
167         }
168
169         if (!NVAccelGetCtxSurf2DFormatFromPixmap(pPixmap, &fmt))
170                 return FALSE;
171
172         /* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the 
173          * alpha channel gets forced to 0xFF for some reason.  We're using 
174          * SURFACE_FORMAT_Y32 as a workaround
175          */
176         if (fmt == NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8)
177                 fmt = NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
178
179         if (!NVAccelSetCtxSurf2D(pPixmap, pPixmap, fmt))
180                 return FALSE;
181
182         BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
183         OUT_RING  (rectFormat(&pPixmap->drawable));
184         BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
185         OUT_RING  (fg);
186
187         pNv->DMAKickoffCallback = NVDmaKickoffCallback;
188         return TRUE;
189 }
190
191 static void NVExaSolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
192 {
193         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
194         NVPtr pNv = NVPTR(pScrn);
195         int width = x2-x1;
196         int height = y2-y1;
197
198         BEGIN_RING(NvRectangle,
199                    NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
200         OUT_RING  ((x1 << 16) | y1);
201         OUT_RING  ((width << 16) | height);
202
203         if((width * height) >= 512)
204                 FIRE_RING();
205 }
206
207 static void NVExaDoneSolid (PixmapPtr pPixmap)
208 {
209 }
210
211 static Bool NVExaPrepareCopy(PixmapPtr pSrcPixmap,
212                              PixmapPtr pDstPixmap,
213                              int       dx,
214                              int       dy,
215                              int       alu,
216                              Pixel     planemask)
217 {
218         ScrnInfoPtr pScrn = xf86Screens[pSrcPixmap->drawable.pScreen->myNum];
219         NVPtr pNv = NVPTR(pScrn);
220         int fmt;
221
222         if (pSrcPixmap->drawable.bitsPerPixel !=
223                         pDstPixmap->drawable.bitsPerPixel)
224                 return FALSE;
225
226         planemask |= ~0 << pDstPixmap->drawable.bitsPerPixel;
227         if (planemask != ~0 || alu != GXcopy) {
228                 if (pDstPixmap->drawable.bitsPerPixel == 32)
229                         return FALSE;
230                 BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_OPERATION, 1);
231                 OUT_RING  (1); /* ROP_AND */
232                 NVSetROP(pScrn, alu, planemask);
233         } else {
234                 BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_OPERATION, 1);
235                 OUT_RING  (3); /* SRCCOPY */
236         }
237
238         if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDstPixmap, &fmt))
239                 return FALSE;
240         if (!NVAccelSetCtxSurf2D(pSrcPixmap, pDstPixmap, fmt))
241                 return FALSE;
242
243         pNv->DMAKickoffCallback = NVDmaKickoffCallback;
244         return TRUE;
245 }
246
247 static void NVExaCopy(PixmapPtr pDstPixmap,
248                       int       srcX,
249                       int       srcY,
250                       int       dstX,
251                       int       dstY,
252                       int       width,
253                       int       height)
254 {
255         ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
256         NVPtr pNv = NVPTR(pScrn);
257
258         /* We want to catch people who have this bug, to find a decent fix */
259 #if 0
260         /* Now check whether we have the same values for srcY and dstY and
261            whether the used chipset is buggy. Currently we flag all of G70
262            cards as buggy, which is probably much to broad. KoalaBR 
263            16 is an abritrary threshold. It should define the maximum number
264            of lines between dstY and srcY  If the number of lines is below
265            we guess, that the bug won't trigger...
266          */
267         if ( ((abs(srcY - dstY)< 16)||(abs(srcX-dstX)<16)) &&
268                 ((((pNv->Chipset & 0xfff0) == CHIPSET_G70) ||
269                  ((pNv->Chipset & 0xfff0) == CHIPSET_G71) ||
270                  ((pNv->Chipset & 0xfff0) == CHIPSET_G72) ||
271                  ((pNv->Chipset & 0xfff0) == CHIPSET_G73) ||
272                  ((pNv->Chipset & 0xfff0) == CHIPSET_C512))) )
273         {
274                 int dx=abs(srcX - dstX),dy=abs(srcY - dstY);
275                 // Ok, let's do it manually unless someone comes up with a better idea
276                 // 1. If dstY and srcY are really the same, do a copy rowwise
277                 if (dy<dx) {
278                         int i,xpos,inc;
279                         NVDEBUG("ExaCopy: Lines identical:\n");
280                         if (srcX>=dstX) {
281                                 xpos=0;
282                                 inc=1;
283                         } else {
284                                 xpos=width-1;
285                                 inc=-1;
286                         }
287                         for (i = 0; i < width; i++) {
288                                 BEGIN_RING(NvImageBlit,
289                                            NV_IMAGE_BLIT_POINT_IN, 3);
290                                 OUT_RING  ((srcY << 16) | (srcX+xpos));
291                                 OUT_RING  ((dstY << 16) | (dstX+xpos));
292                                 OUT_RING  ((height  << 16) | 1);
293                                 xpos+=inc;
294                         }
295                 } else {
296                         // 2. Otherwise we will try a line by line copy in the hope to avoid
297                         //    the card's bug.
298                         int i,ypos,inc;
299                         NVDEBUG("ExaCopy: Lines nearly the same srcY=%d, dstY=%d:\n", srcY, dstY);
300                         if (srcY>=dstY) {
301                                 ypos=0;
302                                 inc=1;
303                         } else {
304                                 ypos=height-1;
305                                 inc=-1;
306                         }
307                         for (i = 0; i < height; i++) {
308                                 BEGIN_RING(NvImageBlit,
309                                            NV_IMAGE_BLIT_POINT_IN, 3);
310                                 OUT_RING  (((srcY+ypos) << 16) | srcX);
311                                 OUT_RING  (((dstY+ypos) << 16) | dstX);
312                                 OUT_RING  ((1  << 16) | width);
313                                 ypos+=inc;
314                         }
315                 } 
316         } else {
317                 NVDEBUG("ExaCopy: Using default path\n");
318                 BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_POINT_IN, 3);
319                 OUT_RING  ((srcY << 16) | srcX);
320                 OUT_RING  ((dstY << 16) | dstX);
321                 OUT_RING  ((height  << 16) | width);
322         }
323 #endif /* 0 */
324
325         NVDEBUG("ExaCopy: Using default path\n");
326         BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_POINT_IN, 3);
327         OUT_RING  ((srcY << 16) | srcX);
328         OUT_RING  ((dstY << 16) | dstX);
329         OUT_RING  ((height  << 16) | width);
330
331         if((width * height) >= 512)
332                 FIRE_RING(); 
333 }
334
335 static void NVExaDoneCopy (PixmapPtr pDstPixmap) {}
336
337 static inline Bool NVAccelMemcpyRect(char *dst, const char *src, int height,
338                        int dst_pitch, int src_pitch, int line_len)
339 {
340         if ((src_pitch == line_len) && (src_pitch == dst_pitch)) {
341                 memcpy(dst, src, line_len*height);
342         } else {
343                 while (height--) {
344                         memcpy(dst, src, line_len);
345                         src += src_pitch;
346                         dst += dst_pitch;
347                 }
348         }
349
350         return TRUE;
351 }
352
353 static inline Bool
354 NVAccelDownloadM2MF(ScrnInfoPtr pScrn, char *dst, uint64_t src_offset,
355                                      int dst_pitch, int src_pitch,
356                                      int line_len, int line_count)
357 {
358         NVPtr pNv = NVPTR(pScrn);
359
360         setM2MFDirection(pScrn, 0);
361
362         while (line_count) {
363                 char *src = pNv->GARTScratch->map;
364                 int lc, i;
365
366                 if (line_count * line_len <= pNv->GARTScratch->size) {
367                         lc = line_count;
368                 } else {
369                         lc = pNv->GARTScratch->size / line_len;
370                         if (lc > line_count)
371                                 lc = line_count;
372                 }
373
374                 /* HW limitations */
375                 if (lc > 2047)
376                         lc = 2047;
377
378                 if (pNv->Architecture >= NV_ARCH_50) {
379                         BEGIN_RING(NvMemFormat, 0x200, 1);
380                         OUT_RING  (1);
381                         BEGIN_RING(NvMemFormat, 0x21c, 1);
382                         OUT_RING  (1);
383                         /* probably high-order bits of address */
384                         BEGIN_RING(NvMemFormat, 0x238, 2);
385                         OUT_RING  (0);
386                         OUT_RING  (0);
387                 }
388
389                 BEGIN_RING(NvMemFormat,
390                            NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
391                 OUT_RING  ((uint32_t)src_offset);
392                 OUT_RING  ((uint32_t)pNv->GARTScratch->offset);
393                 OUT_RING  (src_pitch);
394                 OUT_RING  (line_len);
395                 OUT_RING  (line_len);
396                 OUT_RING  (lc);
397                 OUT_RING  ((1<<8)|1);
398                 OUT_RING  (0);
399
400                 NVNotifierReset(pScrn, pNv->Notifier0);
401                 BEGIN_RING(NvMemFormat, NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
402                 OUT_RING  (0);
403                 BEGIN_RING(NvMemFormat, 0x100, 1);
404                 OUT_RING  (0);
405                 FIRE_RING();
406                 if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, 2000))
407                         return FALSE;
408
409                 if (dst_pitch == line_len) {
410                         memcpy(dst, src, dst_pitch * lc);
411                         dst += dst_pitch * lc;
412                 } else {
413                         for (i = 0; i < lc; i++) {
414                                 memcpy(dst, src, line_len);
415                                 src += line_len;
416                                 dst += dst_pitch;
417                         }
418                 }
419
420                 line_count -= lc;
421                 src_offset += lc * src_pitch;
422         }
423
424         return TRUE;
425 }
426
427 static inline void *
428 NVExaPixmapMap(PixmapPtr pPix)
429 {
430         ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
431         NVPtr pNv = NVPTR(pScrn);
432         void *map;
433
434         map = pNv->FB->map + exaGetPixmapOffset(pPix);
435         return map;
436 }
437
438 static Bool NVDownloadFromScreen(PixmapPtr pSrc,
439                                  int x,  int y,
440                                  int w,  int h,
441                                  char *dst,  int dst_pitch)
442 {
443         ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
444         NVPtr pNv = NVPTR(pScrn);
445         int src_offset, src_pitch, cpp, offset;
446         const char *src;
447
448         src_offset = NVAccelGetPixmapOffset(pSrc);
449         src_pitch  = exaGetPixmapPitch(pSrc);
450         cpp = pSrc->drawable.bitsPerPixel >> 3;
451         offset = (y * src_pitch) + (x * cpp);
452
453         if (pNv->GARTScratch) {
454                 if (NVAccelDownloadM2MF(pScrn, dst,
455                                         src_offset + offset,
456                                         dst_pitch, src_pitch, w * cpp, h))
457                         return TRUE;
458         }
459
460         src = NVExaPixmapMap(pSrc) + offset;
461         exaWaitSync(pSrc->drawable.pScreen);
462         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
463                 return TRUE;
464
465         return FALSE;
466 }
467
468 static inline Bool
469 NVAccelUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch, 
470                  PixmapPtr pDst, int fmt, int x, int y, int w, int h, int cpp)
471 {
472         NVPtr pNv = NVPTR(pScrn);
473         int line_len = w * cpp;
474         int iw, id, ifc_fmt;
475
476         if (pNv->Architecture >= NV_ARCH_50)
477                 return FALSE;
478
479         if (h > 1024)
480                 return FALSE;
481
482         switch (cpp) {
483         case 2: ifc_fmt = 1; break;
484         case 4: ifc_fmt = 4; break;
485         default:
486                 return FALSE;
487         }
488
489         NVAccelSetCtxSurf2D(pDst, pDst, fmt);
490
491         /* Pad out input width to cover both COLORA() and COLORB() */
492         iw  = (line_len + 7) & ~7;
493         id  = iw / 4; /* line push size */
494         iw /= cpp;
495
496         /* Don't support lines longer than max push size yet.. */
497         if (id > 1792)
498                 return FALSE;
499
500         BEGIN_RING(NvClipRectangle, NV01_CONTEXT_CLIP_RECTANGLE_POINT, 2);
501         OUT_RING  (0x0); 
502         OUT_RING  (0x7FFF7FFF);
503
504         BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_OPERATION, 2);
505         OUT_RING  (NV01_IMAGE_FROM_CPU_OPERATION_SRCCOPY);
506         OUT_RING  (ifc_fmt);
507         BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_POINT, 3);
508         OUT_RING  ((y << 16) | x); /* dst point */
509         OUT_RING  ((h << 16) | w); /* width/height out */
510         OUT_RING  ((h << 16) | iw); /* width/height in */
511
512         while (h--) {
513                 char *dst;
514                 /* send a line */
515                 BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_COLOR(0), id);
516                 dst = (char *)pNv->dmaBase + (pNv->dmaCurrent << 2);
517                 memcpy(dst, src, line_len);
518                 pNv->dmaCurrent += id;
519
520                 src += src_pitch;
521         }
522
523         return TRUE;
524 }
525
526 static inline Bool
527 NVAccelUploadM2MF(ScrnInfoPtr pScrn, uint64_t dst_offset, const char *src,
528                                      int dst_pitch, int src_pitch,
529                                      int line_len, int line_count)
530 {
531         NVPtr pNv = NVPTR(pScrn);
532
533         setM2MFDirection(pScrn, 1);
534
535         while (line_count) {
536                 char *dst = pNv->GARTScratch->map;
537                 int lc, i;
538
539                 /* Determine max amount of data we can DMA at once */
540                 if (line_count * line_len <= pNv->GARTScratch->size) {
541                         lc = line_count;
542                 } else {
543                         lc = pNv->GARTScratch->size / line_len;
544                         if (lc > line_count)
545                                 lc = line_count;
546                 }
547
548                 /* HW limitations */
549                 if (lc > 2047)
550                         lc = 2047;
551
552                 /* Upload to GART */
553                 if (src_pitch == line_len) {
554                         memcpy(dst, src, src_pitch * lc);
555                         src += src_pitch * lc;
556                 } else {
557                         for (i = 0; i < lc; i++) {
558                                 memcpy(dst, src, line_len);
559                                 src += src_pitch;
560                                 dst += line_len;
561                         }
562                 }
563
564                 if (pNv->Architecture >= NV_ARCH_50) {
565                         BEGIN_RING(NvMemFormat, 0x200, 1);
566                         OUT_RING  (1);
567                         BEGIN_RING(NvMemFormat, 0x21c, 1);
568                         OUT_RING  (1);
569                         /* probably high-order bits of address */
570                         BEGIN_RING(NvMemFormat, 0x238, 2);
571                         OUT_RING  (0);
572                         OUT_RING  (0);
573                 }
574
575                 /* DMA to VRAM */
576                 BEGIN_RING(NvMemFormat,
577                            NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
578                 OUT_RING  ((uint32_t)pNv->GARTScratch->offset);
579                 OUT_RING  ((uint32_t)dst_offset);
580                 OUT_RING  (line_len);
581                 OUT_RING  (dst_pitch);
582                 OUT_RING  (line_len);
583                 OUT_RING  (lc);
584                 OUT_RING  ((1<<8)|1);
585                 OUT_RING  (0);
586
587                 NVNotifierReset(pScrn, pNv->Notifier0);
588                 BEGIN_RING(NvMemFormat, NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
589                 OUT_RING  (0);
590                 BEGIN_RING(NvMemFormat, 0x100, 1);
591                 OUT_RING  (0);
592                 FIRE_RING();
593                 if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, 2000))
594                         return FALSE;
595
596                 dst_offset += lc * dst_pitch;
597                 line_count -= lc;
598         }
599
600         return TRUE;
601 }
602
603 static Bool NVUploadToScreen(PixmapPtr pDst,
604                              int x, int y, int w, int h,
605                              char *src, int src_pitch)
606 {
607         ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
608         NVPtr pNv = NVPTR(pScrn);
609         int dst_offset, dst_pitch, cpp;
610         char *dst;
611
612         dst_offset = NVAccelGetPixmapOffset(pDst);
613         dst_pitch  = exaGetPixmapPitch(pDst);
614         cpp = pDst->drawable.bitsPerPixel >> 3;
615
616         /* try hostdata transfer */
617         if (pNv->Architecture < NV_ARCH_50 && w*h*cpp<16*1024) /* heuristic */
618         {
619                 int fmt;
620
621                 if (NVAccelGetCtxSurf2DFormatFromPixmap(pDst, &fmt)) {
622                         if (NVAccelUploadIFC(pScrn, src, src_pitch, pDst, fmt,
623                                                     x, y, w, h, cpp)) {
624                                 exaMarkSync(pDst->drawable.pScreen);
625                                 return TRUE;
626                         }
627                 }
628         }
629
630         /* try gart-based transfer */
631         if (pNv->GARTScratch) {
632                 dst_offset += (y * dst_pitch) + (x * cpp);
633                 if (NVAccelUploadM2MF(pScrn, dst_offset, src, dst_pitch,
634                                         src_pitch, w * cpp, h))
635                         return TRUE;
636         }
637
638         /* fallback to memcpy-based transfer */
639         dst = NVExaPixmapMap(pDst) + (y * dst_pitch) + (x * cpp);
640         exaWaitSync(pDst->drawable.pScreen);
641         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
642                 return TRUE;
643
644         return FALSE;
645 }
646
647 Bool
648 NVExaInit(ScreenPtr pScreen) 
649 {
650         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
651         NVPtr pNv = NVPTR(pScrn);
652
653         if(!(pNv->EXADriverPtr = (ExaDriverPtr) xnfcalloc(sizeof(ExaDriverRec), 1))) {
654                 pNv->NoAccel = TRUE;
655                 return FALSE;
656         }
657
658         pNv->EXADriverPtr->exa_major = EXA_VERSION_MAJOR;
659         pNv->EXADriverPtr->exa_minor = EXA_VERSION_MINOR;
660
661         pNv->EXADriverPtr->memoryBase           = pNv->FB->map;
662         pNv->EXADriverPtr->offScreenBase        =
663                 pScrn->virtualX * pScrn->virtualY*(pScrn->bitsPerPixel/8); 
664         pNv->EXADriverPtr->memorySize           = pNv->FB->size; 
665         pNv->EXADriverPtr->pixmapOffsetAlign    = 256; 
666         pNv->EXADriverPtr->pixmapPitchAlign     = 64; 
667         pNv->EXADriverPtr->flags                = EXA_OFFSCREEN_PIXMAPS;
668         pNv->EXADriverPtr->maxX                 = 32768;
669         pNv->EXADriverPtr->maxY                 = 32768;
670
671         pNv->EXADriverPtr->WaitMarker = NVExaWaitMarker;
672
673         /* Install default hooks */
674         pNv->EXADriverPtr->DownloadFromScreen = NVDownloadFromScreen; 
675         pNv->EXADriverPtr->UploadToScreen = NVUploadToScreen; 
676
677         if (pNv->Architecture < NV_ARCH_50) {
678                 pNv->EXADriverPtr->PrepareCopy = NVExaPrepareCopy;
679                 pNv->EXADriverPtr->Copy = NVExaCopy;
680                 pNv->EXADriverPtr->DoneCopy = NVExaDoneCopy;
681
682                 pNv->EXADriverPtr->PrepareSolid = NVExaPrepareSolid;
683                 pNv->EXADriverPtr->Solid = NVExaSolid;
684                 pNv->EXADriverPtr->DoneSolid = NVExaDoneSolid;
685         } else {
686                 pNv->EXADriverPtr->PrepareCopy = NV50EXAPrepareCopy;
687                 pNv->EXADriverPtr->Copy = NV50EXACopy;
688                 pNv->EXADriverPtr->DoneCopy = NV50EXADoneCopy;
689
690                 pNv->EXADriverPtr->PrepareSolid = NV50EXAPrepareSolid;
691                 pNv->EXADriverPtr->Solid = NV50EXASolid;
692                 pNv->EXADriverPtr->DoneSolid = NV50EXADoneSolid;
693         }
694
695         switch (pNv->Architecture) {
696         
697         case NV_ARCH_10:
698         //case NV_ARCH_20: waiting for confirmation from pq
699                 pNv->EXADriverPtr->CheckComposite   = NV10CheckComposite;
700                 pNv->EXADriverPtr->PrepareComposite = NV10PrepareComposite;
701                 pNv->EXADriverPtr->Composite        = NV10Composite;
702                 pNv->EXADriverPtr->DoneComposite    = NV10DoneComposite;
703                 break;
704                 
705 #if (X_BYTE_ORDER == X_LITTLE_ENDIAN) && defined(ENABLE_NV30EXA)
706         case NV_ARCH_30:
707                 pNv->EXADriverPtr->CheckComposite   = NV30EXACheckComposite;
708                 pNv->EXADriverPtr->PrepareComposite = NV30EXAPrepareComposite;
709                 pNv->EXADriverPtr->Composite        = NV30EXAComposite;
710                 pNv->EXADriverPtr->DoneComposite    = NV30EXADoneComposite;
711                 break;
712 #endif
713         case NV_ARCH_40:
714                 pNv->EXADriverPtr->CheckComposite   = NV40EXACheckComposite;
715                 pNv->EXADriverPtr->PrepareComposite = NV40EXAPrepareComposite;
716                 pNv->EXADriverPtr->Composite        = NV40EXAComposite;
717                 pNv->EXADriverPtr->DoneComposite    = NV40EXADoneComposite;
718                 break;
719         case NV_ARCH_50:
720                 break;
721         default:
722                 break;
723         }
724
725         return exaDriverInit(pScreen, pNv->EXADriverPtr);
726 }
727