Preliminary implementation of "host-side double buffering" to improve performance...
[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 static void setM2MFDirection(ScrnInfoPtr pScrn, int dir)
53 {
54         NVPtr pNv = NVPTR(pScrn);
55
56         if (pNv->M2MFDirection != dir) {
57
58                 NVDmaStart(pNv, NvSubMemFormat, MEMFORMAT_DMA_OBJECT_IN, 2);
59                 NVDmaNext (pNv, dir ? NvDmaTT : NvDmaFB);
60                 NVDmaNext (pNv, dir ? NvDmaFB : NvDmaTT);
61                 pNv->M2MFDirection = dir;
62         }
63 }
64
65 static CARD32 rectFormat(DrawablePtr pDrawable)
66 {
67         switch(pDrawable->bitsPerPixel) {
68         case 32:
69         case 24:
70                 return RECT_FORMAT_DEPTH24;
71                 break;
72         case 16:
73                 return RECT_FORMAT_DEPTH16;
74                 break;
75         default:
76                 return RECT_FORMAT_DEPTH8;
77                 break;
78         }
79 }
80
81 /* EXA acceleration hooks */
82 static void NVExaWaitMarker(ScreenPtr pScreen, int marker)
83 {
84         NVSync(xf86Screens[pScreen->myNum]);
85 }
86
87 static Bool NVExaPrepareSolid(PixmapPtr pPixmap,
88                               int   alu,
89                               Pixel planemask,
90                               Pixel fg)
91 {
92         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
93         NVPtr pNv = NVPTR(pScrn);
94         int fmt;
95
96         planemask |= ~0 << pPixmap->drawable.bitsPerPixel;
97         if (planemask != ~0 || alu != GXcopy) {
98                 if (pPixmap->drawable.bitsPerPixel == 32)
99                         return FALSE;
100                 NVDmaStart(pNv, NvSubRectangle, 0x2fc, 1);
101                 NVDmaNext (pNv, 1 /* ROP_AND */);
102                 NVSetRopSolid(pScrn, alu, planemask);
103         } else {
104                 NVDmaStart(pNv, NvSubRectangle, 0x2fc, 1);
105                 NVDmaNext (pNv, 3 /* SRCCOPY */);
106         }
107
108         if (!NVAccelGetCtxSurf2DFormatFromPixmap(pPixmap, &fmt))
109                 return FALSE;
110
111         /* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the 
112          * alpha channel gets forced to 0xFF for some reason.  We're using 
113          * SURFACE_FORMAT_Y32 as a workaround
114          */
115         if (fmt == SURFACE_FORMAT_A8R8G8B8)
116                 fmt = 0xb;
117
118         if (!NVAccelSetCtxSurf2D(pPixmap, pPixmap, fmt))
119                 return FALSE;
120
121         NVDmaStart(pNv, NvSubRectangle, RECT_FORMAT, 1);
122         NVDmaNext (pNv, rectFormat(&pPixmap->drawable));
123         NVDmaStart(pNv, NvSubRectangle, RECT_SOLID_COLOR, 1);
124         NVDmaNext (pNv, fg);
125
126         pNv->DMAKickoffCallback = NVDmaKickoffCallback;
127         return TRUE;
128 }
129
130 static void NVExaSolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
131 {
132         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
133         NVPtr pNv = NVPTR(pScrn);
134         int width = x2-x1;
135         int height = y2-y1;
136
137         NVDmaStart(pNv, NvSubRectangle, RECT_SOLID_RECTS(0), 2);
138         NVDmaNext (pNv, (x1 << 16) | y1);
139         NVDmaNext (pNv, (width << 16) | height);
140
141         if((width * height) >= 512)
142                 NVDmaKickoff(pNv);
143 }
144
145 static void NVExaDoneSolid (PixmapPtr pPixmap)
146 {
147 }
148
149 static Bool NVExaPrepareCopy(PixmapPtr pSrcPixmap,
150                              PixmapPtr pDstPixmap,
151                              int       dx,
152                              int       dy,
153                              int       alu,
154                              Pixel     planemask)
155 {
156         ScrnInfoPtr pScrn = xf86Screens[pSrcPixmap->drawable.pScreen->myNum];
157         NVPtr pNv = NVPTR(pScrn);
158         int fmt;
159
160         if (pSrcPixmap->drawable.bitsPerPixel !=
161                         pDstPixmap->drawable.bitsPerPixel)
162                 return FALSE;
163
164         planemask |= ~0 << pDstPixmap->drawable.bitsPerPixel;
165         if (planemask != ~0 || alu != GXcopy) {
166                 if (pDstPixmap->drawable.bitsPerPixel == 32)
167                         return FALSE;
168                 NVDmaStart(pNv, NvSubImageBlit, 0x2fc, 1);
169                 NVDmaNext (pNv, 1 /* ROP_AND */);
170                 NVSetRopSolid(pScrn, alu, planemask);
171         } else {
172                 NVDmaStart(pNv, NvSubImageBlit, 0x2fc, 1);
173                 NVDmaNext (pNv, 3 /* SRCCOPY */);
174         }
175
176         if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDstPixmap, &fmt))
177                 return FALSE;
178         if (!NVAccelSetCtxSurf2D(pSrcPixmap, pDstPixmap, fmt))
179                 return FALSE;
180
181         pNv->DMAKickoffCallback = NVDmaKickoffCallback;
182         return TRUE;
183 }
184
185 static void NVExaCopy(PixmapPtr pDstPixmap,
186                       int       srcX,
187                       int       srcY,
188                       int       dstX,
189                       int       dstY,
190                       int       width,
191                       int       height)
192 {
193         ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
194         NVPtr pNv = NVPTR(pScrn);
195
196         /* Now check whether we have the same values for srcY and dstY and
197            whether the used chipset is buggy. Currently we flag all of G70
198            cards as buggy, which is probably much to broad. KoalaBR 
199            16 is an abritrary threshold. It should define the maximum number
200            of lines between dstY and srcY  If the number of lines is below
201            we guess, that the bug won't trigger...
202          */
203         if ( ((abs(srcY - dstY)< 16)||(abs(srcX-dstX)<16)) &&
204                 ((((pNv->Chipset & 0xfff0) == CHIPSET_G70) ||
205                  ((pNv->Chipset & 0xfff0) == CHIPSET_G71) ||
206                  ((pNv->Chipset & 0xfff0) == CHIPSET_G72) ||
207                  ((pNv->Chipset & 0xfff0) == CHIPSET_G73) ||
208                  ((pNv->Chipset & 0xfff0) == CHIPSET_C512))) )
209         {
210                 int dx=abs(srcX - dstX),dy=abs(srcY - dstY);
211                 // Ok, let's do it manually unless someone comes up with a better idea
212                 // 1. If dstY and srcY are really the same, do a copy rowwise
213                 if (dy<dx) {
214                         int i,xpos,inc;
215                         NVDEBUG("ExaCopy: Lines identical:\n");
216                         if (srcX>=dstX) {
217                                 xpos=0;
218                                 inc=1;
219                         } else {
220                                 xpos=width-1;
221                                 inc=-1;
222                         }
223                         for (i = 0; i < width; i++) {
224                                 NVDmaStart(pNv, NvSubImageBlit, BLIT_POINT_SRC, 3);
225                                 NVDmaNext (pNv, (srcY << 16) | (srcX+xpos));
226                                 NVDmaNext (pNv, (dstY << 16) | (dstX+xpos));
227                                 NVDmaNext (pNv, (height  << 16) | 1);
228                                 xpos+=inc;
229                         }
230                 } else {
231                         // 2. Otherwise we will try a line by line copy in the hope to avoid
232                         //    the card's bug.
233                         int i,ypos,inc;
234                         NVDEBUG("ExaCopy: Lines nearly the same srcY=%d, dstY=%d:\n", srcY, dstY);
235                         if (srcY>=dstY) {
236                                 ypos=0;
237                                 inc=1;
238                         } else {
239                                 ypos=height-1;
240                                 inc=-1;
241                         }
242                         for (i = 0; i < height; i++) {
243                                 NVDmaStart(pNv, NvSubImageBlit, BLIT_POINT_SRC, 3);
244                                 NVDmaNext (pNv, ((srcY+ypos) << 16) | srcX);
245                                 NVDmaNext (pNv, ((dstY+ypos) << 16) | dstX);
246                                 NVDmaNext (pNv, (1  << 16) | width);
247                                 ypos+=inc;
248                         }
249                 } 
250         } else {
251                 NVDEBUG("ExaCopy: Using default path\n");
252                 NVDmaStart(pNv, NvSubImageBlit, BLIT_POINT_SRC, 3);
253                 NVDmaNext (pNv, (srcY << 16) | srcX);
254                 NVDmaNext (pNv, (dstY << 16) | dstX);
255                 NVDmaNext (pNv, (height  << 16) | width);
256         }
257
258         if((width * height) >= 512)
259                 NVDmaKickoff(pNv); 
260 }
261
262 static void NVExaDoneCopy (PixmapPtr pDstPixmap) {}
263
264 Bool NVAccelMemcpyRect(char *dst, const char *src, int height,
265                        int dst_pitch, int src_pitch, int line_len)
266 {
267         if ((src_pitch == line_len) && (src_pitch == dst_pitch)) {
268                 memcpy(dst, src, line_len*height);
269         } else {
270                 while (height--) {
271                         memcpy(dst, src, line_len);
272                         src += src_pitch;
273                         dst += dst_pitch;
274                 }
275         }
276
277         return TRUE;
278 }
279
280 Bool
281 NVAccelDownloadM2MF(ScrnInfoPtr pScrn, char *dst, uint64_t src_offset,
282                                      int dst_pitch, int src_pitch,
283                                      int line_len, int line_count)
284 {
285         NVPtr pNv = NVPTR(pScrn);
286
287         setM2MFDirection(pScrn, 0);
288
289         while (line_count) {
290                 char *src = pNv->GARTScratch->map;
291                 int lc, i;
292
293                 if (line_count * line_len <= pNv->GARTScratch->size) {
294                         lc = line_count;
295                 } else {
296                         lc = pNv->GARTScratch->size / line_len;
297                         if (lc > line_count)
298                                 lc = line_count;
299                 }
300                 /*XXX: and hw limitations? */
301
302                 NVDmaStart(pNv, NvSubMemFormat,
303                                 NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
304                 NVDmaNext (pNv, (uint32_t)src_offset);
305                 NVDmaNext (pNv, (uint32_t)pNv->GARTScratch->offset);
306                 NVDmaNext (pNv, src_pitch);
307                 NVDmaNext (pNv, line_len);
308                 NVDmaNext (pNv, line_len);
309                 NVDmaNext (pNv, lc);
310                 NVDmaNext (pNv, (1<<8)|1);
311                 NVDmaNext (pNv, 0);
312
313                 NVNotifierReset(pScrn, pNv->Notifier0);
314                 NVDmaStart(pNv, NvSubMemFormat,
315                                 NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
316                 NVDmaNext (pNv, 0);
317                 NVDmaStart(pNv, NvSubMemFormat, 0x100, 1);
318                 NVDmaNext (pNv, 0);
319                 NVDmaKickoff(pNv);
320                 if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, 0))
321                         return FALSE;
322
323                 if (dst_pitch == line_len) {
324                         memcpy(dst, src, dst_pitch * lc);
325                         dst += dst_pitch * lc;
326                 } else {
327                         for (i = 0; i < lc; i++) {
328                                 memcpy(dst, src, line_len);
329                                 src += line_len;
330                                 dst += dst_pitch;
331                         }
332                 }
333
334                 line_count -= lc;
335         }
336
337         return TRUE;
338 }
339
340 static Bool NVDownloadFromScreen(PixmapPtr pSrc,
341                                  int x,  int y,
342                                  int w,  int h,
343                                  char *dst,  int dst_pitch)
344 {
345         ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
346         NVPtr pNv = NVPTR(pScrn);
347         int src_pitch, cpp, offset;
348         const char *src;
349
350         src_pitch  = exaGetPixmapPitch(pSrc);
351         cpp = pSrc->drawable.bitsPerPixel >> 3;
352         offset = (y * src_pitch) + (x * cpp);
353
354         if (pNv->GARTScratch) {
355                 if (NVAccelDownloadM2MF(pScrn, dst,
356                                         NVAccelGetPixmapOffset(pSrc) + offset,
357                                         dst_pitch, src_pitch, w * cpp, h))
358                         return TRUE;
359         }
360
361         src = pSrc->devPrivate.ptr + offset;
362         exaWaitSync(pSrc->drawable.pScreen);
363         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
364                 return TRUE;
365
366         return FALSE;
367 }
368
369 Bool
370 NVAccelUploadM2MF(ScrnInfoPtr pScrn, uint64_t dst_offset, const char *src,
371                                      int dst_pitch, int src_pitch,
372                                      int line_len, int line_count)
373 {
374         NVPtr pNv = NVPTR(pScrn);
375
376         setM2MFDirection(pScrn, 1);
377
378         while (line_count) {
379                 char *dst = pNv->GARTScratch->map;
380                 int lc, i;
381
382                 /* Determine max amount of data we can DMA at once */
383                 if (line_count * line_len <= pNv->GARTScratch->size) {
384                         lc = line_count;
385                 } else {
386                         lc = pNv->GARTScratch->size / line_len;
387                         if (lc > line_count)
388                                 lc = line_count;
389                 }
390                 /*XXX: and hw limitations? */
391
392                 /* Upload to GART */
393                 if (src_pitch == line_len) {
394                         memcpy(dst, src, src_pitch * lc);
395                         src += src_pitch * lc;
396                 } else {
397                         for (i = 0; i < lc; i++) {
398                                 memcpy(dst, src, line_len);
399                                 src += src_pitch;
400                                 dst += line_len;
401                         }
402                 }
403
404                 /* DMA to VRAM */
405                 NVDmaStart(pNv, NvSubMemFormat,
406                                 NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
407                 NVDmaNext (pNv, (uint32_t)pNv->GARTScratch->offset);
408                 NVDmaNext (pNv, (uint32_t)dst_offset);
409                 NVDmaNext (pNv, line_len);
410                 NVDmaNext (pNv, dst_pitch);
411                 NVDmaNext (pNv, line_len);
412                 NVDmaNext (pNv, lc);
413                 NVDmaNext (pNv, (1<<8)|1);
414                 NVDmaNext (pNv, 0);
415
416                 NVNotifierReset(pScrn, pNv->Notifier0);
417                 NVDmaStart(pNv, NvSubMemFormat,
418                                 NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
419                 NVDmaNext (pNv, 0);
420                 NVDmaStart(pNv, NvSubMemFormat, 0x100, 1);
421                 NVDmaNext (pNv, 0);
422                 NVDmaKickoff(pNv);
423                 if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, 0))
424                         return FALSE;
425
426                 line_count -= lc;
427         }
428
429         return TRUE;
430 }
431
432 static Bool NVUploadToScreen(PixmapPtr pDst,
433                              int x, int y, int w, int h,
434                              char *src, int src_pitch)
435 {
436         ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
437         NVPtr pNv = NVPTR(pScrn);
438         int dst_offset, dst_pitch, cpp;
439         char *dst;
440
441         dst_offset = NVAccelGetPixmapOffset(pDst);
442         dst_pitch  = exaGetPixmapPitch(pDst);
443         cpp = pDst->drawable.bitsPerPixel >> 3;
444
445         if (pNv->GARTScratch) {
446                 dst_offset += (y * dst_pitch) + (x * cpp);
447                 if (NVAccelUploadM2MF(pScrn, dst_offset, src, dst_pitch,
448                                       src_pitch, w * cpp, h))
449                         return TRUE;
450         }
451
452         dst = pDst->devPrivate.ptr + (y * dst_pitch) + (x * cpp);
453         exaWaitSync(pDst->drawable.pScreen);
454         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
455                 return TRUE;
456
457         return FALSE;
458 }
459
460
461 static Bool NVCheckComposite(int        op,
462                              PicturePtr pSrcPicture,
463                              PicturePtr pMaskPicture,
464                              PicturePtr pDstPicture)
465 {
466         CARD32 ret = 0;
467
468         /* PictOpOver doesn't work correctly. The HW command assumes
469          * non premuliplied alpha
470          */
471         if (pMaskPicture)
472                 ret = 0x1;
473         else if (op != PictOpOver && op != PictOpSrc)
474                 ret = 0x2;
475         else if (!pSrcPicture->pDrawable)
476                 ret = 0x4;
477         else if (pSrcPicture->transform || pSrcPicture->repeat)
478                 ret = 0x8;
479         else if (pSrcPicture->alphaMap || pDstPicture->alphaMap)
480                 ret = 0x10;
481         else if (pSrcPicture->format != PICT_a8r8g8b8 &&
482                         pSrcPicture->format != PICT_x8r8g8b8 &&
483                         pSrcPicture->format != PICT_r5g6b5)
484                 ret = 0x20;
485         else if (pDstPicture->format != PICT_a8r8g8b8 &&
486                         pDstPicture->format != PICT_x8r8g8b8 &&
487                         pDstPicture->format != PICT_r5g6b5)
488                 ret = 0x40;
489
490         return ret == 0;
491 }
492
493 static CARD32 src_size, src_pitch, src_offset;
494
495 static Bool NVPrepareComposite(int        op,
496                                PicturePtr pSrcPicture,
497                                PicturePtr pMaskPicture,
498                                PicturePtr pDstPicture,
499                                PixmapPtr  pSrc,
500                                PixmapPtr  pMask,
501                                PixmapPtr  pDst)
502 {
503         ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum];
504         NVPtr pNv = NVPTR(pScrn);
505         int srcFormat, dstFormat;
506
507         if (pSrcPicture->format == PICT_a8r8g8b8)
508                 srcFormat = STRETCH_BLIT_FORMAT_A8R8G8B8;
509         else if (pSrcPicture->format == PICT_x8r8g8b8)
510                 srcFormat = STRETCH_BLIT_FORMAT_X8R8G8B8;
511         else if (pSrcPicture->format == PICT_r5g6b5)
512                 srcFormat = STRETCH_BLIT_FORMAT_DEPTH16;
513         else
514                 return FALSE;
515
516         if (!NVAccelGetCtxSurf2DFormatFromPicture(pDstPicture, &dstFormat))
517                 return FALSE;
518         if (!NVAccelSetCtxSurf2D(pDst, pDst, dstFormat))
519                 return FALSE;
520
521         NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_FORMAT, 2);
522         NVDmaNext (pNv, srcFormat);
523         NVDmaNext (pNv, (op == PictOpSrc) ? STRETCH_BLIT_OPERATION_COPY :
524                         STRETCH_BLIT_OPERATION_BLEND);
525
526         src_size = ((pSrcPicture->pDrawable->width+3)&~3) |
527                 (pSrcPicture->pDrawable->height << 16);
528         src_pitch  = exaGetPixmapPitch(pSrc)
529                 | (STRETCH_BLIT_SRC_FORMAT_ORIGIN_CORNER << 16)
530                 | (STRETCH_BLIT_SRC_FORMAT_FILTER_POINT_SAMPLE << 24);
531         src_offset = NVAccelGetPixmapOffset(pSrc);
532
533         return TRUE;
534 }
535
536 static void NVComposite(PixmapPtr pDst,
537                         int       srcX,
538                         int       srcY,
539                         int       maskX,
540                         int       maskY,
541                         int       dstX,
542                         int       dstY,
543                         int       width,
544                         int       height)
545 {
546         ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
547         NVPtr pNv = NVPTR(pScrn);
548
549         NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_CLIP_POINT, 6);
550         NVDmaNext (pNv, dstX | (dstY << 16));
551         NVDmaNext (pNv, width | (height << 16));
552         NVDmaNext (pNv, dstX | (dstY << 16));
553         NVDmaNext (pNv, width | (height << 16));
554         NVDmaNext (pNv, 1<<20);
555         NVDmaNext (pNv, 1<<20);
556
557         NVDmaStart(pNv, NvSubScaledImage, STRETCH_BLIT_SRC_SIZE, 4);
558         NVDmaNext (pNv, src_size);
559         NVDmaNext (pNv, src_pitch);
560         NVDmaNext (pNv, src_offset);
561         NVDmaNext (pNv, srcX | (srcY<<16));
562
563         NVDmaKickoff(pNv);
564 }
565
566 static void NVDoneComposite (PixmapPtr pDst)
567 {
568         ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
569         NVPtr pNv = NVPTR(pScrn);
570         CARD32 format;
571
572         if (pNv->CurrentLayout.depth == 8)
573                 format = SURFACE_FORMAT_Y8;
574         else if (pNv->CurrentLayout.depth == 16)
575                 format = SURFACE_FORMAT_R5G6B5;
576         else
577                 format = SURFACE_FORMAT_X8R8G8B8;
578
579         NVDmaStart(pNv, NvSubContextSurfaces, SURFACE_FORMAT, 1);
580         NVDmaNext (pNv, format);
581
582         exaMarkSync(pDst->drawable.pScreen);
583 }
584
585 Bool NVExaInit(ScreenPtr pScreen) 
586 {
587         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
588         NVPtr pNv = NVPTR(pScrn);
589
590         if(!(pNv->EXADriverPtr = (ExaDriverPtr) xnfcalloc(sizeof(ExaDriverRec), 1))) {
591                 pNv->NoAccel = TRUE;
592                 return FALSE;
593         }
594
595         pNv->EXADriverPtr->exa_major = EXA_VERSION_MAJOR;
596         pNv->EXADriverPtr->exa_minor = EXA_VERSION_MINOR;
597
598         pNv->EXADriverPtr->memoryBase           = pNv->FB->map;
599         pNv->EXADriverPtr->offScreenBase        =
600                 pScrn->virtualX * pScrn->virtualY*(pScrn->bitsPerPixel/8); 
601         pNv->EXADriverPtr->memorySize           = pNv->FB->size; 
602         pNv->EXADriverPtr->pixmapOffsetAlign    = 256; 
603         pNv->EXADriverPtr->pixmapPitchAlign     = 64; 
604         pNv->EXADriverPtr->flags                = EXA_OFFSCREEN_PIXMAPS;
605         pNv->EXADriverPtr->maxX                 = 32768;
606         pNv->EXADriverPtr->maxY                 = 32768;
607
608         pNv->EXADriverPtr->WaitMarker = NVExaWaitMarker;
609
610         /* Install default hooks */
611         pNv->EXADriverPtr->DownloadFromScreen = NVDownloadFromScreen; 
612         pNv->EXADriverPtr->UploadToScreen = NVUploadToScreen; 
613
614         pNv->EXADriverPtr->PrepareCopy = NVExaPrepareCopy;
615         pNv->EXADriverPtr->Copy = NVExaCopy;
616         pNv->EXADriverPtr->DoneCopy = NVExaDoneCopy;
617
618         pNv->EXADriverPtr->PrepareSolid = NVExaPrepareSolid;
619         pNv->EXADriverPtr->Solid = NVExaSolid;
620         pNv->EXADriverPtr->DoneSolid = NVExaDoneSolid;
621
622         switch (pNv->Architecture) {
623         case NV_ARCH_40:
624                 pNv->EXADriverPtr->CheckComposite   = NV30EXACheckComposite;
625                 pNv->EXADriverPtr->PrepareComposite = NV30EXAPrepareComposite;
626                 pNv->EXADriverPtr->Composite        = NV30EXAComposite;
627                 pNv->EXADriverPtr->DoneComposite    = NV30EXADoneComposite;
628                 break;
629         default:
630                 if (!pNv->BlendingPossible)
631                         break;
632                 pNv->EXADriverPtr->CheckComposite   = NVCheckComposite;
633                 pNv->EXADriverPtr->PrepareComposite = NVPrepareComposite;
634                 pNv->EXADriverPtr->Composite        = NVComposite;
635                 pNv->EXADriverPtr->DoneComposite    = NVDoneComposite;
636                 break;
637         }
638
639         return exaDriverInit(pScreen, pNv->EXADriverPtr);
640 }
641