Disable nv30 exa no big endian until we fix the endianness bugs related to the 3D...
[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 Bool NVDownloadFromScreen(PixmapPtr pSrc,
428                                  int x,  int y,
429                                  int w,  int h,
430                                  char *dst,  int dst_pitch)
431 {
432         ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
433         NVPtr pNv = NVPTR(pScrn);
434         int src_offset, src_pitch, cpp, offset;
435         const char *src;
436
437         src_offset = NVAccelGetPixmapOffset(pSrc);
438         src_pitch  = exaGetPixmapPitch(pSrc);
439         cpp = pSrc->drawable.bitsPerPixel >> 3;
440         offset = (y * src_pitch) + (x * cpp);
441
442         if (pNv->GARTScratch) {
443                 if (NVAccelDownloadM2MF(pScrn, dst,
444                                         src_offset + offset,
445                                         dst_pitch, src_pitch, w * cpp, h))
446                         return TRUE;
447         }
448
449         src = (char *) src_offset + offset;
450         exaWaitSync(pSrc->drawable.pScreen);
451         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
452                 return TRUE;
453
454         return FALSE;
455 }
456
457 static inline Bool
458 NVAccelUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch, 
459                  PixmapPtr pDst, int fmt, int x, int y, int w, int h, int cpp)
460 {
461         NVPtr pNv = NVPTR(pScrn);
462         int line_len = w * cpp;
463         int iw, id, ifc_fmt;
464
465         if (pNv->Architecture >= NV_ARCH_50)
466                 return FALSE;
467
468         if (h > 1024)
469                 return FALSE;
470
471         switch (cpp) {
472         case 2: ifc_fmt = 1; break;
473         case 4: ifc_fmt = 4; break;
474         default:
475                 return FALSE;
476         }
477
478         NVAccelSetCtxSurf2D(pDst, pDst, fmt);
479
480         /* Pad out input width to cover both COLORA() and COLORB() */
481         iw  = (line_len + 7) & ~7;
482         id  = iw / 4; /* line push size */
483         iw /= cpp;
484
485         /* Don't support lines longer than max push size yet.. */
486         if (id > 1792)
487                 return FALSE;
488
489         BEGIN_RING(NvClipRectangle, NV01_CONTEXT_CLIP_RECTANGLE_POINT, 2);
490         OUT_RING  (0x0); 
491         OUT_RING  (0x7FFF7FFF);
492
493         BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_OPERATION, 2);
494         OUT_RING  (NV01_IMAGE_FROM_CPU_OPERATION_SRCCOPY);
495         OUT_RING  (ifc_fmt);
496         BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_POINT, 3);
497         OUT_RING  ((y << 16) | x); /* dst point */
498         OUT_RING  ((h << 16) | w); /* width/height out */
499         OUT_RING  ((h << 16) | iw); /* width/height in */
500
501         while (h--) {
502                 char *dst;
503                 /* send a line */
504                 BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_COLOR(0), id);
505                 dst = (char *)pNv->dmaBase + (pNv->dmaCurrent << 2);
506                 memcpy(dst, src, line_len);
507                 pNv->dmaCurrent += id;
508
509                 src += src_pitch;
510         }
511
512         return TRUE;
513 }
514
515 static inline Bool
516 NVAccelUploadM2MF(ScrnInfoPtr pScrn, uint64_t dst_offset, const char *src,
517                                      int dst_pitch, int src_pitch,
518                                      int line_len, int line_count)
519 {
520         NVPtr pNv = NVPTR(pScrn);
521
522         setM2MFDirection(pScrn, 1);
523
524         while (line_count) {
525                 char *dst = pNv->GARTScratch->map;
526                 int lc, i;
527
528                 /* Determine max amount of data we can DMA at once */
529                 if (line_count * line_len <= pNv->GARTScratch->size) {
530                         lc = line_count;
531                 } else {
532                         lc = pNv->GARTScratch->size / line_len;
533                         if (lc > line_count)
534                                 lc = line_count;
535                 }
536
537                 /* HW limitations */
538                 if (lc > 2047)
539                         lc = 2047;
540
541                 /* Upload to GART */
542                 if (src_pitch == line_len) {
543                         memcpy(dst, src, src_pitch * lc);
544                         src += src_pitch * lc;
545                 } else {
546                         for (i = 0; i < lc; i++) {
547                                 memcpy(dst, src, line_len);
548                                 src += src_pitch;
549                                 dst += line_len;
550                         }
551                 }
552
553                 if (pNv->Architecture >= NV_ARCH_50) {
554                         BEGIN_RING(NvMemFormat, 0x200, 1);
555                         OUT_RING  (1);
556                         BEGIN_RING(NvMemFormat, 0x21c, 1);
557                         OUT_RING  (1);
558                         /* probably high-order bits of address */
559                         BEGIN_RING(NvMemFormat, 0x238, 2);
560                         OUT_RING  (0);
561                         OUT_RING  (0);
562                 }
563
564                 /* DMA to VRAM */
565                 BEGIN_RING(NvMemFormat,
566                            NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
567                 OUT_RING  ((uint32_t)pNv->GARTScratch->offset);
568                 OUT_RING  ((uint32_t)dst_offset);
569                 OUT_RING  (line_len);
570                 OUT_RING  (dst_pitch);
571                 OUT_RING  (line_len);
572                 OUT_RING  (lc);
573                 OUT_RING  ((1<<8)|1);
574                 OUT_RING  (0);
575
576                 NVNotifierReset(pScrn, pNv->Notifier0);
577                 BEGIN_RING(NvMemFormat, NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
578                 OUT_RING  (0);
579                 BEGIN_RING(NvMemFormat, 0x100, 1);
580                 OUT_RING  (0);
581                 FIRE_RING();
582                 if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, 2000))
583                         return FALSE;
584
585                 dst_offset += lc * dst_pitch;
586                 line_count -= lc;
587         }
588
589         return TRUE;
590 }
591
592 static Bool NVUploadToScreen(PixmapPtr pDst,
593                              int x, int y, int w, int h,
594                              char *src, int src_pitch)
595 {
596         ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
597         NVPtr pNv = NVPTR(pScrn);
598         int dst_offset, dst_pitch, cpp;
599         char *dst;
600
601         dst_offset = NVAccelGetPixmapOffset(pDst);
602         dst_pitch  = exaGetPixmapPitch(pDst);
603         cpp = pDst->drawable.bitsPerPixel >> 3;
604
605         /* try hostdata transfer */
606         if (pNv->Architecture < NV_ARCH_50 && w*h*cpp<16*1024) /* heuristic */
607         {
608                 int fmt;
609
610                 if (NVAccelGetCtxSurf2DFormatFromPixmap(pDst, &fmt)) {
611                         if (NVAccelUploadIFC(pScrn, src, src_pitch, pDst, fmt,
612                                                     x, y, w, h, cpp)) {
613                                 exaMarkSync(pDst->drawable.pScreen);
614                                 return TRUE;
615                         }
616                 }
617         }
618
619         /* try gart-based transfer */
620         if (pNv->GARTScratch) {
621                 dst_offset += (y * dst_pitch) + (x * cpp);
622                 if (NVAccelUploadM2MF(pScrn, dst_offset, src, dst_pitch,
623                                         src_pitch, w * cpp, h))
624                         return TRUE;
625         }
626
627         /* fallback to memcpy-based transfer */
628         dst = (char *) dst_offset + (y * dst_pitch) + (x * cpp);
629         exaWaitSync(pDst->drawable.pScreen);
630         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
631                 return TRUE;
632
633         return FALSE;
634 }
635
636 Bool
637 NVExaInit(ScreenPtr pScreen) 
638 {
639         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
640         NVPtr pNv = NVPTR(pScrn);
641
642         if(!(pNv->EXADriverPtr = (ExaDriverPtr) xnfcalloc(sizeof(ExaDriverRec), 1))) {
643                 pNv->NoAccel = TRUE;
644                 return FALSE;
645         }
646
647         pNv->EXADriverPtr->exa_major = EXA_VERSION_MAJOR;
648         pNv->EXADriverPtr->exa_minor = EXA_VERSION_MINOR;
649
650         pNv->EXADriverPtr->memoryBase           = pNv->FB->map;
651         pNv->EXADriverPtr->offScreenBase        =
652                 pScrn->virtualX * pScrn->virtualY*(pScrn->bitsPerPixel/8); 
653         pNv->EXADriverPtr->memorySize           = pNv->FB->size; 
654         pNv->EXADriverPtr->pixmapOffsetAlign    = 256; 
655         pNv->EXADriverPtr->pixmapPitchAlign     = 64; 
656         pNv->EXADriverPtr->flags                = EXA_OFFSCREEN_PIXMAPS;
657         pNv->EXADriverPtr->maxX                 = 32768;
658         pNv->EXADriverPtr->maxY                 = 32768;
659
660         pNv->EXADriverPtr->WaitMarker = NVExaWaitMarker;
661
662         /* Install default hooks */
663         pNv->EXADriverPtr->DownloadFromScreen = NVDownloadFromScreen; 
664         pNv->EXADriverPtr->UploadToScreen = NVUploadToScreen; 
665
666         if (pNv->Architecture < NV_ARCH_50) {
667                 pNv->EXADriverPtr->PrepareCopy = NVExaPrepareCopy;
668                 pNv->EXADriverPtr->Copy = NVExaCopy;
669                 pNv->EXADriverPtr->DoneCopy = NVExaDoneCopy;
670
671                 pNv->EXADriverPtr->PrepareSolid = NVExaPrepareSolid;
672                 pNv->EXADriverPtr->Solid = NVExaSolid;
673                 pNv->EXADriverPtr->DoneSolid = NVExaDoneSolid;
674         } else {
675                 pNv->EXADriverPtr->PrepareCopy = NV50EXAPrepareCopy;
676                 pNv->EXADriverPtr->Copy = NV50EXACopy;
677                 pNv->EXADriverPtr->DoneCopy = NV50EXADoneCopy;
678
679                 pNv->EXADriverPtr->PrepareSolid = NV50EXAPrepareSolid;
680                 pNv->EXADriverPtr->Solid = NV50EXASolid;
681                 pNv->EXADriverPtr->DoneSolid = NV50EXADoneSolid;
682         }
683
684         switch (pNv->Architecture) {
685         
686         case NV_ARCH_10:
687         //case NV_ARCH_20: waiting for confirmation from pq
688                 pNv->EXADriverPtr->CheckComposite   = NV10CheckComposite;
689                 pNv->EXADriverPtr->PrepareComposite = NV10PrepareComposite;
690                 pNv->EXADriverPtr->Composite        = NV10Composite;
691                 pNv->EXADriverPtr->DoneComposite    = NV10DoneComposite;
692                 break;
693                 
694 #if (X_BYTE_ORDER == X_LITTLE_ENDIAN) && defined(ENABLE_NV30EXA)
695         case NV_ARCH_30:
696                 pNv->EXADriverPtr->CheckComposite   = NV30EXACheckComposite;
697                 pNv->EXADriverPtr->PrepareComposite = NV30EXAPrepareComposite;
698                 pNv->EXADriverPtr->Composite        = NV30EXAComposite;
699                 pNv->EXADriverPtr->DoneComposite    = NV30EXADoneComposite;
700                 break;
701         case NV_ARCH_40:
702                 pNv->EXADriverPtr->CheckComposite   = NV40EXACheckComposite;
703                 pNv->EXADriverPtr->PrepareComposite = NV40EXAPrepareComposite;
704                 pNv->EXADriverPtr->Composite        = NV40EXAComposite;
705                 pNv->EXADriverPtr->DoneComposite    = NV40EXADoneComposite;
706                 break;
707 #endif
708         case NV_ARCH_50:
709                 break;
710         default:
711                 break;
712         }
713
714         return exaDriverInit(pScreen, pNv->EXADriverPtr);
715 }
716