Ported nv_exa.c to work with EXA >=2.0.0
[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 #if (EXA_VERSION_MAJOR < 2)
48 #error You need EXA >=2.0.0
49 #endif
50
51 #include "nv_dma.h"
52 #include "nv_local.h"
53
54 #include <sys/time.h>
55
56 static CARD32 getPitch(DrawablePtr pDrawable)
57 {
58     return (pDrawable->width*(pDrawable->bitsPerPixel >> 3) + 63) & ~63;
59 }
60
61 static CARD32 getOffset(NVPtr pNv, DrawablePtr pDrawable)
62 {
63     PixmapPtr pPixmap;
64     if (pDrawable->type == DRAWABLE_WINDOW)
65         return 0;
66
67     pPixmap = (PixmapPtr)pDrawable;
68     return (CARD32)((unsigned long)pPixmap->devPrivate.ptr - (unsigned long)pNv->FbBase);
69 }
70
71 static CARD32 surfaceFormat(DrawablePtr pDrawable)
72 {
73     switch(pDrawable->bitsPerPixel) {
74     case 32:
75     case 24:
76         return SURFACE_FORMAT_X8R8G8B8;
77         break;
78     case 16:
79         return SURFACE_FORMAT_R5G6B5;
80         break;
81     default:
82         return SURFACE_FORMAT_Y8;
83         break;
84     }
85 }
86
87 static CARD32 rectFormat(DrawablePtr pDrawable)
88 {
89     switch(pDrawable->bitsPerPixel) {
90     case 32:
91     case 24:
92         return RECT_FORMAT_DEPTH24;
93         break;
94     case 16:
95         return RECT_FORMAT_DEPTH16;
96         break;
97     default:
98         return RECT_FORMAT_DEPTH8;
99         break;
100     }
101 }
102
103 /* EXA acceleration hooks */
104
105 static void NVExaWaitMarker(ScreenPtr pScreen, int marker)
106 {
107     NVSync(xf86Screens[pScreen->myNum]);
108 }
109
110 static Bool NVExaPrepareSolid (PixmapPtr      pPixmap,
111                                int            alu,
112                                Pixel          planemask,
113                                Pixel          fg)
114 {
115     ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
116     NVPtr pNv = NVPTR(pScrn);
117     CARD32 pitch;
118
119     planemask |= ~0 << pNv->CurrentLayout.depth;
120
121     NVSetRopSolid(pScrn, alu, planemask);
122
123     NVDmaStart(pNv, NvSubContextSurfaces, SURFACE_FORMAT, 4);
124
125     NVDmaNext (pNv, surfaceFormat(&pPixmap->drawable));
126
127     pitch = getPitch(&pPixmap->drawable);
128     NVDmaNext (pNv, (pitch<<16)|pitch);
129   
130     NVDmaNext (pNv, getOffset(pNv, &pPixmap->drawable));
131     NVDmaNext (pNv, getOffset(pNv, &pPixmap->drawable));
132     
133     NVDmaStart(pNv, NvSubRectangle, RECT_FORMAT, 1);
134     NVDmaNext(pNv, rectFormat(&pPixmap->drawable));
135     NVDmaStart(pNv, NvSubRectangle, RECT_SOLID_COLOR, 1);
136     NVDmaNext (pNv, fg);
137
138     pNv->DMAKickoffCallback = NVDMAKickoffCallback;
139
140     return TRUE;
141 }
142
143 static void NVExaSolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
144 {
145     ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
146     NVPtr pNv = NVPTR(pScrn);
147     int width = x2-x1;
148     int height = y2-y1;
149
150     NVDmaStart(pNv, NvSubRectangle, RECT_SOLID_RECTS(0), 2);
151     NVDmaNext (pNv, (x1 << 16) | y1);
152     NVDmaNext (pNv, (width << 16) | height);
153
154     if((width * height) >= 512)
155         NVDmaKickoff(pNv);
156 }
157
158 static void NVExaDoneSolid (PixmapPtr      pPixmap)
159 {
160 }
161
162 static Bool NVExaPrepareCopy (PixmapPtr       pSrcPixmap,
163                               PixmapPtr       pDstPixmap,
164                               int             dx,
165                               int             dy,
166                               int             alu,
167                               Pixel           planemask)
168 {
169     ScrnInfoPtr pScrn = xf86Screens[pSrcPixmap->drawable.pScreen->myNum];
170     NVPtr pNv = NVPTR(pScrn);
171     CARD32 srcPitch, dstPitch;
172
173     planemask |= ~0 << pNv->CurrentLayout.depth;
174     
175     NVSetRopSolid(pScrn, alu, planemask);
176     
177     dstPitch = getPitch(&pDstPixmap->drawable);
178     srcPitch = getPitch(&pSrcPixmap->drawable);
179     NVDmaStart(pNv, NvSubContextSurfaces, SURFACE_PITCH, 3);
180     NVDmaNext (pNv, (dstPitch<<16)|srcPitch);
181     NVDmaNext (pNv, getOffset(pNv, &pSrcPixmap->drawable));
182     NVDmaNext (pNv, getOffset(pNv, &pDstPixmap->drawable));
183
184     pNv->DMAKickoffCallback = NVDMAKickoffCallback;
185     return TRUE;
186 }
187
188 static void NVExaCopy (PixmapPtr pDstPixmap,
189                        int    srcX,
190                        int    srcY,
191                        int    dstX,
192                        int    dstY,
193                        int    width,
194                        int    height)
195 {
196     ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
197     NVPtr pNv = NVPTR(pScrn);
198
199     NVDmaStart(pNv, NvSubImageBlit, BLIT_POINT_SRC, 3);
200     NVDmaNext (pNv, (srcY << 16) | srcX);
201     NVDmaNext (pNv, (dstY << 16) | dstX);
202     NVDmaNext (pNv, (height  << 16) | width);
203
204     if((width * height) >= 512)
205        NVDmaKickoff(pNv); 
206 }
207
208 static void NVExaDoneCopy (PixmapPtr pDstPixmap) {}
209
210 static Bool NVDownloadFromScreen(PixmapPtr pSrc,
211                                  int x,  int y,
212                                  int w,  int h,
213                                  char *dst,  int dst_pitch)
214 {
215     ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
216     NVPtr pNv = NVPTR(pScrn);
217     CARD32 offset_in, pitch_in, max_lines, line_length;
218     Bool ret = TRUE;
219     
220     pitch_in = getPitch(&pSrc->drawable);
221     offset_in = getOffset(pNv, &pSrc->drawable);
222     offset_in += y*pitch_in;
223     offset_in += x * (pSrc->drawable.bitsPerPixel >> 3);
224     max_lines = 65536/dst_pitch + 1;
225     line_length = w * (pSrc->drawable.bitsPerPixel >> 3);
226
227     NVDmaSetObjectOnSubchannel(pNv, NvSubGraphicsToAGP, NvGraphicsToAGP);
228     
229     NVDEBUG("NVDownloadFromScreen: x=%d, y=%d, w=%d, h=%d\n", x, y, w, h);
230     NVDEBUG("    pitch_in=%x dst_pitch=%x offset_in=%x", pitch_in, dst_pitch, offset_in);
231     while (h > 0) {
232         NVDEBUG("     max_lines=%d, h=%d\n", max_lines, h);
233         int nlines = h > max_lines ? max_lines : h;
234         /* reset the notification object */
235         memset(pNv->agpMemory, 0xff, 0x100);
236         NVDmaStart(pNv, NvSubGraphicsToAGP, MEMFORMAT_NOTIFY, 1);
237         NVDmaNext (pNv, 0);
238         NVDmaStart(pNv, NvSubGraphicsToAGP, MEMFORMAT_OFFSET_IN, 8);
239         NVDmaNext (pNv, offset_in);
240         NVDmaNext (pNv, 0);
241         NVDmaNext (pNv, pitch_in);
242         NVDmaNext (pNv, dst_pitch);
243         NVDmaNext (pNv, line_length);
244         NVDmaNext (pNv, nlines);
245         NVDmaNext (pNv, 0x101);
246         NVDmaNext (pNv, 0);
247         NVDmaKickoff(pNv);
248         if (!NVDmaWaitForNotifier(pNv, NV_DMA_TARGET_AGP, 0)) {
249             ret = FALSE;
250             goto error;
251         }
252 #if 0
253         if (memcmp(pNv->FbBase + offset_in, pNv->agpMemory + 0x10000, nlines*dst_pitch) != 0)
254             ErrorF("DMA transfer wrong!\n");
255 #endif
256         memcpy(dst, pNv->agpMemory + 0x10000, nlines*dst_pitch);
257         h -= nlines;
258         offset_in += nlines*pitch_in;
259         dst += nlines*dst_pitch;
260     }
261
262 error:
263     NVDmaSetObjectOnSubchannel(pNv, NvSubGraphicsToAGP, NvScaledImage);
264     exaMarkSync(pSrc->drawable.pScreen);
265     return ret;
266 }
267
268 static Bool NVUploadToScreen(PixmapPtr pDst,
269                              int x, int y, int w, int h,
270                              char *src, int src_pitch)
271 {
272     ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
273     NVPtr pNv = NVPTR(pScrn);
274     CARD32 offset_out, pitch_out, max_lines, line_length;
275     Bool ret = TRUE;
276 #if 0
277     x = 0;
278     y = 0;
279     w = pDst->drawable.width;
280     h = pDst->drawable.height;
281 #endif
282
283     pitch_out = getPitch(&pDst->drawable);
284     offset_out = getOffset(pNv, &pDst->drawable);
285     offset_out += y*pitch_out;
286     offset_out += x * (pDst->drawable.bitsPerPixel >> 3);
287
288     max_lines = 65536/src_pitch + 1;
289     line_length = w * (pDst->drawable.bitsPerPixel >> 3);
290
291     NVDmaSetObjectOnSubchannel(pNv, NvSubGraphicsToAGP, NvAGPToGraphics);
292     
293     NVDEBUG("NVUploadToScreen: x=%d, y=%d, w=%d, h=%d\n", x, y, w, h);
294     while (h > 0) {
295         NVDEBUG("     max_lines=%d, h=%d\n", max_lines, h);
296         int nlines = h > max_lines ? max_lines : h;
297         /* reset the notification object */
298         memset(pNv->agpMemory, 0xff, 0x100);
299         memcpy(pNv->agpMemory + 0x10000, src, nlines*src_pitch);
300         NVDmaStart(pNv, NvSubGraphicsToAGP, MEMFORMAT_NOTIFY, 1);
301         NVDmaNext (pNv, 0);
302         NVDmaStart(pNv, NvSubGraphicsToAGP, MEMFORMAT_OFFSET_IN, 8);
303         NVDmaNext (pNv, 0);
304         NVDmaNext (pNv, offset_out);
305         NVDmaNext (pNv, src_pitch);
306         NVDmaNext (pNv, pitch_out);
307         NVDmaNext (pNv, line_length);
308         NVDmaNext (pNv, nlines);
309         NVDmaNext (pNv, 0x101);
310         NVDmaNext (pNv, 0);
311         NVDmaKickoff(pNv);
312         if (!NVDmaWaitForNotifier(pNv, NV_DMA_TARGET_AGP, 0)) {
313             ret = FALSE;
314             goto error;
315         }
316         h -= nlines;
317         offset_out += nlines*pitch_out;
318         src += nlines*src_pitch;
319     }
320
321 error:
322     NVDmaSetObjectOnSubchannel(pNv, NvSubGraphicsToAGP, NvScaledImage);
323     exaMarkSync(pDst->drawable.pScreen);
324     return ret;
325 }
326
327
328 static Bool NVCheckComposite (int          op,
329                             PicturePtr   pSrcPicture,
330                             PicturePtr   pMaskPicture,
331                             PicturePtr   pDstPicture)
332 {
333     CARD32 ret = 0;
334     if (pMaskPicture)
335         ret = 0x1;
336     /* PictOpOver doesn't work correctly. The HW command assumes non premuliplied alpha */
337     else if (op != PictOpOver && op != PictOpSrc)
338         ret = 0x2;
339     else if (!pSrcPicture->pDrawable)
340         ret = 0x4;
341     else if (pSrcPicture->transform || pSrcPicture->repeat)
342         ret = 0x8;
343     else if (pSrcPicture->alphaMap || pDstPicture->alphaMap)
344         ret = 0x10;
345     else if (pSrcPicture->format != PICT_a8r8g8b8 &&
346         pSrcPicture->format != PICT_x8r8g8b8 &&
347         pSrcPicture->format != PICT_r5g6b5)
348         ret = 0x20;
349     else if (pDstPicture->format != PICT_a8r8g8b8 &&
350         pDstPicture->format != PICT_x8r8g8b8 &&
351         pDstPicture->format != PICT_r5g6b5)
352         ret = 0x40;
353     return ret == 0;
354 }
355
356 static CARD32 src_size, src_pitch, src_offset;
357
358 static Bool NVPrepareComposite (int                op,
359                                 PicturePtr         pSrcPicture,
360                                 PicturePtr         pMaskPicture,
361                                 PicturePtr         pDstPicture,
362                                 PixmapPtr          pSrc,
363                                 PixmapPtr          pMask,
364                                 PixmapPtr          pDst)
365 {
366     ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum];
367     NVPtr pNv = NVPTR(pScrn);
368
369     int srcFormat, dstFormat;
370     if (pSrcPicture->format == PICT_a8r8g8b8)
371         srcFormat = STRETCH_BLIT_FORMAT_A8R8G8B8;
372     else if (pSrcPicture->format == PICT_x8r8g8b8)
373         srcFormat = STRETCH_BLIT_FORMAT_X8R8G8B8;
374     else
375         srcFormat = STRETCH_BLIT_FORMAT_DEPTH16;
376
377     if (pDstPicture->format == PICT_a8r8g8b8)
378         dstFormat = SURFACE_FORMAT_A8R8G8B8;
379     else if (pDstPicture->format == PICT_x8r8g8b8)
380         dstFormat = SURFACE_FORMAT_X8R8G8B8;
381     else
382         dstFormat = SURFACE_FORMAT_R5G6B5;
383
384 #if 0
385     NVDmaStart(pNv, NvSubContextSurfaces, SURFACE_FORMAT, 1);
386     NVDmaNext (pNv, dstFormat);
387     NVDmaNext (pNv, getPitch(pSrcPicture->pDrawable)|(getPitch(pDstPicture->pDrawable) << 16));
388     NVDmaNext (pNv, getOffset(pNv, pSrcPicture->pDrawable));
389     NVDmaNext (pNv, getOffset(pNv, pDstPicture->pDrawable));
390 #endif
391     NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_FORMAT, 2);
392     NVDmaNext (pNv, srcFormat);
393     NVDmaNext (pNv, (op == PictOpSrc) ? STRETCH_BLIT_OPERATION_COPY : STRETCH_BLIT_OPERATION_BLEND);
394
395     src_size = pSrcPicture->pDrawable->width | (pSrcPicture->pDrawable->height << 16);
396     src_pitch  = getPitch(pSrcPicture->pDrawable)
397                  | (STRETCH_BLIT_SRC_FORMAT_ORIGIN_CORNER << 16)
398                  | (STRETCH_BLIT_SRC_FORMAT_FILTER_POINT_SAMPLE << 24);
399     src_offset = getOffset(pNv, pSrcPicture->pDrawable);
400     return TRUE;
401 }
402
403 static void NVComposite (PixmapPtr         pDst,
404                          int       srcX,
405                          int        srcY,
406                          int        maskX,
407                          int        maskY,
408                          int        dstX,
409                          int        dstY,
410                          int        width,
411                          int        height)
412 {
413     ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
414     NVPtr pNv = NVPTR(pScrn);
415
416     NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_CLIP_POINT, 6);
417     NVDmaNext (pNv, dstX | (dstY << 16));
418     NVDmaNext (pNv, width | (height << 16));
419     NVDmaNext (pNv, dstX | (dstY << 16));
420     NVDmaNext (pNv, width | (height << 16));
421     NVDmaNext (pNv, 1<<20);
422     NVDmaNext (pNv, 1<<20);
423
424     NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_SRC_SIZE, 4);
425     NVDmaNext (pNv, src_size);
426     NVDmaNext (pNv, src_pitch);
427     NVDmaNext (pNv, src_offset);
428     NVDmaNext (pNv, srcX | (srcY<<16));
429
430     NVDmaKickoff(pNv);
431 }
432
433 static void NVDoneComposite (PixmapPtr         pDst)
434 {
435     ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
436     NVPtr pNv = NVPTR(pScrn);
437     CARD32 format;
438     if (pNv->CurrentLayout.depth == 8)
439         format = SURFACE_FORMAT_Y8;
440     else if (pNv->CurrentLayout.depth == 16)
441         format = SURFACE_FORMAT_R5G6B5;
442     else
443         format = SURFACE_FORMAT_X8R8G8B8;
444     NVDmaStart(pNv, NvSubContextSurfaces, SURFACE_FORMAT, 1);
445     NVDmaNext (pNv, format);
446     exaMarkSync(pDst->drawable.pScreen);
447 }
448
449 Bool NVExaInit(ScreenPtr pScreen) 
450 {
451     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
452     NVPtr pNv = NVPTR(pScrn);
453
454     if(!(pNv->EXADriverPtr = (ExaDriverPtr) xnfcalloc(sizeof(ExaDriverRec), 1))) {
455         pNv->NoAccel = TRUE;
456         return FALSE;
457     }
458
459                 pNv->EXADriverPtr->memoryBase         = pNv->FbStart;
460                 pNv->EXADriverPtr->offScreenBase      = pScrn->virtualX*pScrn->virtualY*pScrn->depth; 
461                 pNv->EXADriverPtr->memorySize         = pNv->ScratchBufferStart; 
462                 pNv->EXADriverPtr->pixmapOffsetAlign  = 256; 
463                 pNv->EXADriverPtr->pixmapPitchAlign   = 64; 
464                 pNv->EXADriverPtr->flags              = EXA_OFFSCREEN_PIXMAPS;
465                 pNv->EXADriverPtr->maxX               = 32768;
466                 pNv->EXADriverPtr->maxY               = 32768;
467
468                 pNv->EXADriverPtr->WaitMarker = NVExaWaitMarker;
469
470                 pNv->EXADriverPtr->PrepareCopy = NVExaPrepareCopy;
471                 pNv->EXADriverPtr->Copy = NVExaCopy;
472                 pNv->EXADriverPtr->DoneCopy = NVExaDoneCopy;
473
474                 pNv->EXADriverPtr->PrepareSolid = NVExaPrepareSolid;
475                 pNv->EXADriverPtr->Solid = NVExaSolid;
476     pNv->EXADriverPtr->DoneSolid = NVExaDoneSolid;
477
478     if (pNv->agpMemory) {
479         pNv->EXADriverPtr->DownloadFromScreen = NVDownloadFromScreen; 
480         pNv->EXADriverPtr->UploadToScreen = NVUploadToScreen; 
481     }
482     if (pNv->BlendingPossible) {
483         /* install composite hooks */
484         pNv->EXADriverPtr->CheckComposite = NVCheckComposite;
485         pNv->EXADriverPtr->PrepareComposite = NVPrepareComposite;
486         pNv->EXADriverPtr->Composite = NVComposite;
487         pNv->EXADriverPtr->DoneComposite = NVDoneComposite;
488     }
489
490 #if 0
491     {
492         int i;
493         struct timeval tv, tv2;
494         ErrorF("\nTiming upload:\n");
495         gettimeofday(&tv, 0);
496         NVDmaSetObjectOnSubchannel(pNv, NvSubGraphicsToAGP, NvAGPToGraphics);
497
498         for (i = 0; i < 0x10000; ++i)
499             ((CARD32 *)(pNv->agpMemory+0x10000))[i] = (i<<16) | (0xffff-i);
500         for (i = 0; i < 0x10000; ++i)
501             ((CARD32 *)(pNv->FbBase))[i] = 0;
502             
503         /* reset the notification object */
504         memset(pNv->agpMemory, 0xff, 0x100);
505         NVDmaStart(pNv, NvSubGraphicsToAGP, MEMFORMAT_NOTIFY, 1);
506         NVDmaNext (pNv, 0);
507         NVDmaStart(pNv, NvSubGraphicsToAGP, MEMFORMAT_OFFSET_IN, 8);
508         NVDmaNext (pNv, 0);
509         NVDmaNext (pNv, 0);
510         NVDmaNext (pNv, 1024);
511         NVDmaNext (pNv, 1024);
512         NVDmaNext (pNv, 1024);
513         NVDmaNext (pNv, 1024);
514         NVDmaNext (pNv, 0x101);
515         NVDmaNext (pNv, 0);
516         NVDmaKickoff(pNv);
517         if (!NVDmaWaitForNotifier(pNv, NV_DMA_TARGET_AGP, 0))
518             ErrorF("DMA transfer error!\n");
519
520         NVDmaSetObjectOnSubchannel(pNv, NvSubGraphicsToAGP, NvScaledImage);
521         gettimeofday(&tv2, 0);
522         for (i = 0; i < 0x10000; i += 256)
523             ErrorF("%x %x %x %x\n", ((CARD32 *)(pNv->FbBase))[i], ((CARD32 *)(pNv->FbBase))[i+1],
524                    ((CARD32 *)(pNv->FbBase))[i+2], ((CARD32 *)(pNv->FbBase))[i+3]);
525         ErrorF("Download from Screen %f MB/s\n", 
526                    (1.)*1000000
527                    /((int)tv2.tv_usec- (int)tv.tv_usec + 1000000*(tv2.tv_sec-tv.tv_sec)+1));
528     }
529 #endif
530     
531     return exaDriverInit(pScreen, pNv->EXADriverPtr);
532 }