randr12: Misc fix.
[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         NVDmaStart(pNv, NvImagePattern, PATTERN_COLOR_0, 4);
83         NVDmaNext (pNv, clr0);
84         NVDmaNext (pNv, clr1);
85         NVDmaNext (pNv, pat0);
86         NVDmaNext (pNv, 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                         NVDmaStart(pNv, NvRop, ROP_SET, 1);
99                         NVDmaNext (pNv, 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                 NVDmaStart(pNv, NvRop, ROP_SET, 1);
107                 NVDmaNext (pNv, 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                 NVDmaStart(pNv, NvMemFormat, MEMFORMAT_DMA_OBJECT_IN, 2);
119                 NVDmaNext (pNv, dir ? NvDmaTT : NvDmaFB);
120                 NVDmaNext (pNv, dir ? NvDmaFB : NvDmaTT);
121                 pNv->M2MFDirection = dir;
122         }
123 }
124
125 static CARD32 rectFormat(DrawablePtr pDrawable)
126 {
127         switch(pDrawable->bitsPerPixel) {
128         case 32:
129         case 24:
130                 return RECT_FORMAT_DEPTH24;
131                 break;
132         case 16:
133                 return RECT_FORMAT_DEPTH16;
134                 break;
135         default:
136                 return RECT_FORMAT_DEPTH8;
137                 break;
138         }
139 }
140
141 /* EXA acceleration hooks */
142 static void NVExaWaitMarker(ScreenPtr pScreen, int marker)
143 {
144         NVSync(xf86Screens[pScreen->myNum]);
145 }
146
147 static Bool NVExaPrepareSolid(PixmapPtr pPixmap,
148                               int   alu,
149                               Pixel planemask,
150                               Pixel fg)
151 {
152         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
153         NVPtr pNv = NVPTR(pScrn);
154         int fmt;
155
156         planemask |= ~0 << pPixmap->drawable.bitsPerPixel;
157         if (planemask != ~0 || alu != GXcopy) {
158                 if (pPixmap->drawable.bitsPerPixel == 32)
159                         return FALSE;
160                 NVDmaStart(pNv, NvRectangle, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
161                 NVDmaNext (pNv, 1 /* ROP_AND */);
162                 NVSetROP(pScrn, alu, planemask);
163         } else {
164                 NVDmaStart(pNv, NvRectangle, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
165                 NVDmaNext (pNv, 3 /* SRCCOPY */);
166         }
167
168         if (!NVAccelGetCtxSurf2DFormatFromPixmap(pPixmap, &fmt))
169                 return FALSE;
170
171         /* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the 
172          * alpha channel gets forced to 0xFF for some reason.  We're using 
173          * SURFACE_FORMAT_Y32 as a workaround
174          */
175         if (fmt == SURFACE_FORMAT_A8R8G8B8)
176                 fmt = 0xb;
177
178         if (!NVAccelSetCtxSurf2D(pPixmap, pPixmap, fmt))
179                 return FALSE;
180
181         NVDmaStart(pNv, NvRectangle, RECT_FORMAT, 1);
182         NVDmaNext (pNv, rectFormat(&pPixmap->drawable));
183         NVDmaStart(pNv, NvRectangle, RECT_SOLID_COLOR, 1);
184         NVDmaNext (pNv, fg);
185
186         pNv->DMAKickoffCallback = NVDmaKickoffCallback;
187         return TRUE;
188 }
189
190 static void NVExaSolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
191 {
192         ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
193         NVPtr pNv = NVPTR(pScrn);
194         int width = x2-x1;
195         int height = y2-y1;
196
197         NVDmaStart(pNv, NvRectangle, RECT_SOLID_RECTS(0), 2);
198         NVDmaNext (pNv, (x1 << 16) | y1);
199         NVDmaNext (pNv, (width << 16) | height);
200
201         if((width * height) >= 512)
202                 NVDmaKickoff(pNv);
203 }
204
205 static void NVExaDoneSolid (PixmapPtr pPixmap)
206 {
207 }
208
209 static Bool NVExaPrepareCopy(PixmapPtr pSrcPixmap,
210                              PixmapPtr pDstPixmap,
211                              int       dx,
212                              int       dy,
213                              int       alu,
214                              Pixel     planemask)
215 {
216         ScrnInfoPtr pScrn = xf86Screens[pSrcPixmap->drawable.pScreen->myNum];
217         NVPtr pNv = NVPTR(pScrn);
218         int fmt;
219
220         if (pSrcPixmap->drawable.bitsPerPixel !=
221                         pDstPixmap->drawable.bitsPerPixel)
222                 return FALSE;
223
224         planemask |= ~0 << pDstPixmap->drawable.bitsPerPixel;
225         if (planemask != ~0 || alu != GXcopy) {
226                 if (pDstPixmap->drawable.bitsPerPixel == 32)
227                         return FALSE;
228                 NVDmaStart(pNv, NvImageBlit, NV_IMAGE_BLIT_OPERATION, 1);
229                 NVDmaNext (pNv, 1 /* ROP_AND */);
230                 NVSetROP(pScrn, alu, planemask);
231         } else {
232                 NVDmaStart(pNv, NvImageBlit, NV_IMAGE_BLIT_OPERATION, 1);
233                 NVDmaNext (pNv, 3 /* SRCCOPY */);
234         }
235
236         if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDstPixmap, &fmt))
237                 return FALSE;
238         if (!NVAccelSetCtxSurf2D(pSrcPixmap, pDstPixmap, fmt))
239                 return FALSE;
240
241         pNv->DMAKickoffCallback = NVDmaKickoffCallback;
242         return TRUE;
243 }
244
245 static void NVExaCopy(PixmapPtr pDstPixmap,
246                       int       srcX,
247                       int       srcY,
248                       int       dstX,
249                       int       dstY,
250                       int       width,
251                       int       height)
252 {
253         ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
254         NVPtr pNv = NVPTR(pScrn);
255
256         /* Now check whether we have the same values for srcY and dstY and
257            whether the used chipset is buggy. Currently we flag all of G70
258            cards as buggy, which is probably much to broad. KoalaBR 
259            16 is an abritrary threshold. It should define the maximum number
260            of lines between dstY and srcY  If the number of lines is below
261            we guess, that the bug won't trigger...
262          */
263         if ( ((abs(srcY - dstY)< 16)||(abs(srcX-dstX)<16)) &&
264                 ((((pNv->Chipset & 0xfff0) == CHIPSET_G70) ||
265                  ((pNv->Chipset & 0xfff0) == CHIPSET_G71) ||
266                  ((pNv->Chipset & 0xfff0) == CHIPSET_G72) ||
267                  ((pNv->Chipset & 0xfff0) == CHIPSET_G73) ||
268                  ((pNv->Chipset & 0xfff0) == CHIPSET_C512))) )
269         {
270                 int dx=abs(srcX - dstX),dy=abs(srcY - dstY);
271                 // Ok, let's do it manually unless someone comes up with a better idea
272                 // 1. If dstY and srcY are really the same, do a copy rowwise
273                 if (dy<dx) {
274                         int i,xpos,inc;
275                         NVDEBUG("ExaCopy: Lines identical:\n");
276                         if (srcX>=dstX) {
277                                 xpos=0;
278                                 inc=1;
279                         } else {
280                                 xpos=width-1;
281                                 inc=-1;
282                         }
283                         for (i = 0; i < width; i++) {
284                                 NVDmaStart(pNv, NvImageBlit, BLIT_POINT_SRC, 3);
285                                 NVDmaNext (pNv, (srcY << 16) | (srcX+xpos));
286                                 NVDmaNext (pNv, (dstY << 16) | (dstX+xpos));
287                                 NVDmaNext (pNv, (height  << 16) | 1);
288                                 xpos+=inc;
289                         }
290                 } else {
291                         // 2. Otherwise we will try a line by line copy in the hope to avoid
292                         //    the card's bug.
293                         int i,ypos,inc;
294                         NVDEBUG("ExaCopy: Lines nearly the same srcY=%d, dstY=%d:\n", srcY, dstY);
295                         if (srcY>=dstY) {
296                                 ypos=0;
297                                 inc=1;
298                         } else {
299                                 ypos=height-1;
300                                 inc=-1;
301                         }
302                         for (i = 0; i < height; i++) {
303                                 NVDmaStart(pNv, NvImageBlit, BLIT_POINT_SRC, 3);
304                                 NVDmaNext (pNv, ((srcY+ypos) << 16) | srcX);
305                                 NVDmaNext (pNv, ((dstY+ypos) << 16) | dstX);
306                                 NVDmaNext (pNv, (1  << 16) | width);
307                                 ypos+=inc;
308                         }
309                 } 
310         } else {
311                 NVDEBUG("ExaCopy: Using default path\n");
312                 NVDmaStart(pNv, NvImageBlit, BLIT_POINT_SRC, 3);
313                 NVDmaNext (pNv, (srcY << 16) | srcX);
314                 NVDmaNext (pNv, (dstY << 16) | dstX);
315                 NVDmaNext (pNv, (height  << 16) | width);
316         }
317
318         if((width * height) >= 512)
319                 NVDmaKickoff(pNv); 
320 }
321
322 static void NVExaDoneCopy (PixmapPtr pDstPixmap) {}
323
324 static inline Bool NVAccelMemcpyRect(char *dst, const char *src, int height,
325                        int dst_pitch, int src_pitch, int line_len)
326 {
327         if ((src_pitch == line_len) && (src_pitch == dst_pitch)) {
328                 memcpy(dst, src, line_len*height);
329         } else {
330                 while (height--) {
331                         memcpy(dst, src, line_len);
332                         src += src_pitch;
333                         dst += dst_pitch;
334                 }
335         }
336
337         return TRUE;
338 }
339
340 static inline Bool
341 NVAccelDownloadM2MF(ScrnInfoPtr pScrn, char *dst, uint64_t src_offset,
342                                      int dst_pitch, int src_pitch,
343                                      int line_len, int line_count)
344 {
345         NVPtr pNv = NVPTR(pScrn);
346
347         setM2MFDirection(pScrn, 0);
348
349         while (line_count) {
350                 char *src = pNv->GARTScratch->map;
351                 int lc, i;
352
353                 if (line_count * line_len <= pNv->GARTScratch->size) {
354                         lc = line_count;
355                 } else {
356                         lc = pNv->GARTScratch->size / line_len;
357                         if (lc > line_count)
358                                 lc = line_count;
359                 }
360
361                 /* HW limitations */
362                 if (lc > 2047)
363                         lc = 2047;
364
365                 if (pNv->Architecture >= NV_ARCH_50) {
366                         NVDmaStart(pNv, NvMemFormat, 0x200, 1);
367                         NVDmaNext (pNv, 1);
368                         NVDmaStart(pNv, NvMemFormat, 0x21c, 1);
369                         NVDmaNext (pNv, 1);
370                         /* probably high-order bits of address */
371                         NVDmaStart(pNv, NvMemFormat, 0x238, 2);
372                         NVDmaNext (pNv, 0);
373                         NVDmaNext (pNv, 0);
374                 }
375
376                 NVDmaStart(pNv, NvMemFormat,
377                                 NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
378                 NVDmaNext (pNv, (uint32_t)src_offset);
379                 NVDmaNext (pNv, (uint32_t)pNv->GARTScratch->offset);
380                 NVDmaNext (pNv, src_pitch);
381                 NVDmaNext (pNv, line_len);
382                 NVDmaNext (pNv, line_len);
383                 NVDmaNext (pNv, lc);
384                 NVDmaNext (pNv, (1<<8)|1);
385                 NVDmaNext (pNv, 0);
386
387                 NVNotifierReset(pScrn, pNv->Notifier0);
388                 NVDmaStart(pNv, NvMemFormat,
389                                 NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
390                 NVDmaNext (pNv, 0);
391                 NVDmaStart(pNv, NvMemFormat, 0x100, 1);
392                 NVDmaNext (pNv, 0);
393                 NVDmaKickoff(pNv);
394                 if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, 2000))
395                         return FALSE;
396
397                 if (dst_pitch == line_len) {
398                         memcpy(dst, src, dst_pitch * lc);
399                         dst += dst_pitch * lc;
400                 } else {
401                         for (i = 0; i < lc; i++) {
402                                 memcpy(dst, src, line_len);
403                                 src += line_len;
404                                 dst += dst_pitch;
405                         }
406                 }
407
408                 line_count -= lc;
409                 src_offset += lc * src_pitch;
410         }
411
412         return TRUE;
413 }
414
415 static Bool NVDownloadFromScreen(PixmapPtr pSrc,
416                                  int x,  int y,
417                                  int w,  int h,
418                                  char *dst,  int dst_pitch)
419 {
420         ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
421         NVPtr pNv = NVPTR(pScrn);
422         int src_offset, src_pitch, cpp, offset;
423         const char *src;
424
425         src_offset = NVAccelGetPixmapOffset(pSrc);
426         src_pitch  = exaGetPixmapPitch(pSrc);
427         cpp = pSrc->drawable.bitsPerPixel >> 3;
428         offset = (y * src_pitch) + (x * cpp);
429
430         if (pNv->GARTScratch) {
431                 if (NVAccelDownloadM2MF(pScrn, dst,
432                                         src_offset + offset,
433                                         dst_pitch, src_pitch, w * cpp, h))
434                         return TRUE;
435         }
436
437         src = (char *) src_offset + offset;
438         exaWaitSync(pSrc->drawable.pScreen);
439         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
440                 return TRUE;
441
442         return FALSE;
443 }
444
445 static inline Bool
446 NVAccelUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch, 
447                  PixmapPtr pDst, int fmt, int x, int y, int w, int h, int cpp)
448 {
449         NVPtr pNv = NVPTR(pScrn);
450         int line_len = w * cpp;
451         int iw, id, ifc_fmt;
452
453         if (pNv->Architecture >= NV_ARCH_50)
454                 return FALSE;
455
456         if (h > 1024)
457                 return FALSE;
458
459         switch (cpp) {
460         case 2: ifc_fmt = 1; break;
461         case 4: ifc_fmt = 4; break;
462         default:
463                 return FALSE;
464         }
465
466         NVAccelSetCtxSurf2D(pDst, pDst, fmt);
467
468         /* Pad out input width to cover both COLORA() and COLORB() */
469         iw  = (line_len + 7) & ~7;
470         id  = iw / 4; /* line push size */
471         iw /= cpp;
472
473         /* Don't support lines longer than max push size yet.. */
474         if (id > 1792)
475                 return FALSE;
476
477         NVDmaStart(pNv, NvClipRectangle, CLIP_POINT, 2);
478         NVDmaNext (pNv, 0x0); 
479         NVDmaNext (pNv, 0x7FFF7FFF);
480
481         NVDmaStart(pNv, NvImageFromCpu, NV05_IMAGE_FROM_CPU_OPERATION, 2);
482         NVDmaNext (pNv, 0x3 /* SRCCOPY */);
483         NVDmaNext (pNv, ifc_fmt);
484         NVDmaStart(pNv, NvImageFromCpu, NV05_IMAGE_FROM_CPU_POINT, 3);
485         NVDmaNext (pNv, (y << 16) | x); /* dst point */
486         NVDmaNext (pNv, (h << 16) | w); /* width/height out */
487         NVDmaNext (pNv, (h << 16) | iw); /* width/height in */
488
489         while (h--) {
490                 char *dst;
491                 /* send a line */
492                 NVDmaStart(pNv, NvImageFromCpu,
493                                 NV10_IMAGE_FROM_CPU_HLINE, id);
494                 dst = (char *)pNv->dmaBase + (pNv->dmaCurrent << 2);
495                 memcpy(dst, src, line_len);
496                 pNv->dmaCurrent += id;
497
498                 src += src_pitch;
499         }
500
501         return TRUE;
502 }
503
504 static inline Bool
505 NVAccelUploadM2MF(ScrnInfoPtr pScrn, uint64_t dst_offset, const char *src,
506                                      int dst_pitch, int src_pitch,
507                                      int line_len, int line_count)
508 {
509         NVPtr pNv = NVPTR(pScrn);
510
511         setM2MFDirection(pScrn, 1);
512
513         while (line_count) {
514                 char *dst = pNv->GARTScratch->map;
515                 int lc, i;
516
517                 /* Determine max amount of data we can DMA at once */
518                 if (line_count * line_len <= pNv->GARTScratch->size) {
519                         lc = line_count;
520                 } else {
521                         lc = pNv->GARTScratch->size / line_len;
522                         if (lc > line_count)
523                                 lc = line_count;
524                 }
525
526                 /* HW limitations */
527                 if (lc > 2047)
528                         lc = 2047;
529
530                 /* Upload to GART */
531                 if (src_pitch == line_len) {
532                         memcpy(dst, src, src_pitch * lc);
533                         src += src_pitch * lc;
534                 } else {
535                         for (i = 0; i < lc; i++) {
536                                 memcpy(dst, src, line_len);
537                                 src += src_pitch;
538                                 dst += line_len;
539                         }
540                 }
541
542                 if (pNv->Architecture >= NV_ARCH_50) {
543                         NVDmaStart(pNv, NvMemFormat, 0x200, 1);
544                         NVDmaNext (pNv, 1);
545                         NVDmaStart(pNv, NvMemFormat, 0x21c, 1);
546                         NVDmaNext (pNv, 1);
547                         /* probably high-order bits of address */
548                         NVDmaStart(pNv, NvMemFormat, 0x238, 2);
549                         NVDmaNext (pNv, 0);
550                         NVDmaNext (pNv, 0);
551                 }
552
553                 /* DMA to VRAM */
554                 NVDmaStart(pNv, NvMemFormat,
555                                 NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
556                 NVDmaNext (pNv, (uint32_t)pNv->GARTScratch->offset);
557                 NVDmaNext (pNv, (uint32_t)dst_offset);
558                 NVDmaNext (pNv, line_len);
559                 NVDmaNext (pNv, dst_pitch);
560                 NVDmaNext (pNv, line_len);
561                 NVDmaNext (pNv, lc);
562                 NVDmaNext (pNv, (1<<8)|1);
563                 NVDmaNext (pNv, 0);
564
565                 NVNotifierReset(pScrn, pNv->Notifier0);
566                 NVDmaStart(pNv, NvMemFormat,
567                                 NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
568                 NVDmaNext (pNv, 0);
569                 NVDmaStart(pNv, NvMemFormat, 0x100, 1);
570                 NVDmaNext (pNv, 0);
571                 NVDmaKickoff(pNv);
572                 if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, 2000))
573                         return FALSE;
574
575                 dst_offset += lc * dst_pitch;
576                 line_count -= lc;
577         }
578
579         return TRUE;
580 }
581
582 static Bool NVUploadToScreen(PixmapPtr pDst,
583                              int x, int y, int w, int h,
584                              char *src, int src_pitch)
585 {
586         ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
587         NVPtr pNv = NVPTR(pScrn);
588         int dst_offset, dst_pitch, cpp;
589         char *dst;
590
591         dst_offset = NVAccelGetPixmapOffset(pDst);
592         dst_pitch  = exaGetPixmapPitch(pDst);
593         cpp = pDst->drawable.bitsPerPixel >> 3;
594
595         /* try hostdata transfer */
596         if (pNv->Architecture < NV_ARCH_50 && w*h*cpp<16*1024) /* heuristic */
597         {
598                 int fmt;
599
600                 if (NVAccelGetCtxSurf2DFormatFromPixmap(pDst, &fmt)) {
601                         if (NVAccelUploadIFC(pScrn, src, src_pitch, pDst, fmt,
602                                                     x, y, w, h, cpp)) {
603                                 exaMarkSync(pDst->drawable.pScreen);
604                                 return TRUE;
605                         }
606                 }
607         }
608
609         /* try gart-based transfer */
610         if (pNv->GARTScratch) {
611                 dst_offset += (y * dst_pitch) + (x * cpp);
612                 if (NVAccelUploadM2MF(pScrn, dst_offset, src, dst_pitch,
613                                         src_pitch, w * cpp, h))
614                         return TRUE;
615         }
616
617         /* fallback to memcpy-based transfer */
618         dst = (char *) dst_offset + (y * dst_pitch) + (x * cpp);
619         exaWaitSync(pDst->drawable.pScreen);
620         if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
621                 return TRUE;
622
623         return FALSE;
624 }
625
626
627 static Bool NVCheckComposite(int        op,
628                              PicturePtr pSrcPicture,
629                              PicturePtr pMaskPicture,
630                              PicturePtr pDstPicture)
631 {
632         CARD32 ret = 0;
633
634         /* PictOpOver doesn't work correctly. The HW command assumes
635          * non premuliplied alpha
636          */
637         if (pMaskPicture)
638                 ret = 0x1;
639         else if (op != PictOpOver &&  op != PictOpSrc)
640                 ret = 0x2;
641         else if (!pSrcPicture->pDrawable)
642                 ret = 0x4;
643         else if (pSrcPicture->transform || pSrcPicture->repeat)
644                 ret = 0x8;
645         else if (pSrcPicture->alphaMap || pDstPicture->alphaMap)
646                 ret = 0x10;
647         else if (pSrcPicture->format != PICT_a8r8g8b8 &&
648                         pSrcPicture->format != PICT_x8r8g8b8 &&
649                         pSrcPicture->format != PICT_r5g6b5)
650                 ret = 0x20;
651         else if (pDstPicture->format != PICT_a8r8g8b8 &&
652                         pDstPicture->format != PICT_x8r8g8b8 &&
653                         pDstPicture->format != PICT_r5g6b5)
654                 ret = 0x40;
655
656         return ret == 0;
657 }
658
659 static CARD32 src_size, src_pitch, src_offset;
660
661 static Bool NVPrepareComposite(int        op,
662                                PicturePtr pSrcPicture,
663                                PicturePtr pMaskPicture,
664                                PicturePtr pDstPicture,
665                                PixmapPtr  pSrc,
666                                PixmapPtr  pMask,
667                                PixmapPtr  pDst)
668 {
669         ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum];
670         NVPtr pNv = NVPTR(pScrn);
671         int srcFormat, dstFormat;
672
673         if (pSrcPicture->format == PICT_a8r8g8b8)
674                 srcFormat = STRETCH_BLIT_FORMAT_A8R8G8B8;
675         else if (pSrcPicture->format == PICT_x8r8g8b8)
676                 srcFormat = STRETCH_BLIT_FORMAT_X8R8G8B8;
677         else if (pSrcPicture->format == PICT_r5g6b5)
678                 srcFormat = STRETCH_BLIT_FORMAT_DEPTH16;
679         else
680                 return FALSE;
681
682         if (!NVAccelGetCtxSurf2DFormatFromPicture(pDstPicture, &dstFormat))
683                 return FALSE;
684         if (!NVAccelSetCtxSurf2D(pDst, pDst, dstFormat))
685                 return FALSE;
686
687         NVDmaStart(pNv, NvScaledImage, STRETCH_BLIT_FORMAT, 2);
688         NVDmaNext (pNv, srcFormat);
689         NVDmaNext (pNv, (op == PictOpSrc) ? STRETCH_BLIT_OPERATION_COPY : STRETCH_BLIT_OPERATION_BLEND);
690
691         src_size = ((pSrcPicture->pDrawable->width+3)&~3) |
692                 (pSrcPicture->pDrawable->height << 16);
693         src_pitch  = exaGetPixmapPitch(pSrc)
694                 | (STRETCH_BLIT_SRC_FORMAT_ORIGIN_CORNER << 16)
695                 | (STRETCH_BLIT_SRC_FORMAT_FILTER_POINT_SAMPLE << 24);
696         src_offset = NVAccelGetPixmapOffset(pSrc);
697
698         return TRUE;
699 }
700
701 static void NVComposite(PixmapPtr pDst,
702                         int       srcX,
703                         int       srcY,
704                         int       maskX,
705                         int       maskY,
706                         int       dstX,
707                         int       dstY,
708                         int       width,
709                         int       height)
710 {
711         ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
712         NVPtr pNv = NVPTR(pScrn);
713
714         NVDmaStart(pNv, NvScaledImage, STRETCH_BLIT_CLIP_POINT, 6);
715         NVDmaNext (pNv, dstX | (dstY << 16));
716         NVDmaNext (pNv, width | (height << 16));
717         NVDmaNext (pNv, dstX | (dstY << 16));
718         NVDmaNext (pNv, width | (height << 16));
719         NVDmaNext (pNv, 1<<20);
720         NVDmaNext (pNv, 1<<20);
721
722         NVDmaStart(pNv, NvScaledImage, STRETCH_BLIT_SRC_SIZE, 4);
723         NVDmaNext (pNv, src_size);
724         NVDmaNext (pNv, src_pitch);
725         NVDmaNext (pNv, src_offset);
726         NVDmaNext (pNv, srcX | (srcY<<16));
727
728         NVDmaKickoff(pNv);
729 }
730
731 static void NVDoneComposite (PixmapPtr pDst)
732 {
733         ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
734         NVPtr pNv = NVPTR(pScrn);
735         CARD32 format;
736
737         if (pNv->CurrentLayout.depth == 8)
738                 format = SURFACE_FORMAT_Y8;
739         else if (pNv->CurrentLayout.depth == 16)
740                 format = SURFACE_FORMAT_R5G6B5;
741         else
742                 format = SURFACE_FORMAT_X8R8G8B8;
743
744         NVDmaStart(pNv, NvContextSurfaces, SURFACE_FORMAT, 1);
745         NVDmaNext (pNv, format);
746
747         exaMarkSync(pDst->drawable.pScreen);
748 }
749
750 Bool NVExaInit(ScreenPtr pScreen) 
751 {
752         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
753         NVPtr pNv = NVPTR(pScrn);
754
755         if(!(pNv->EXADriverPtr = (ExaDriverPtr) xnfcalloc(sizeof(ExaDriverRec), 1))) {
756                 pNv->NoAccel = TRUE;
757                 return FALSE;
758         }
759
760         pNv->EXADriverPtr->exa_major = EXA_VERSION_MAJOR;
761         pNv->EXADriverPtr->exa_minor = EXA_VERSION_MINOR;
762
763         pNv->EXADriverPtr->memoryBase           = pNv->FB->map;
764         pNv->EXADriverPtr->offScreenBase        =
765                 pScrn->virtualX * pScrn->virtualY*(pScrn->bitsPerPixel/8); 
766         pNv->EXADriverPtr->memorySize           = pNv->FB->size; 
767         pNv->EXADriverPtr->pixmapOffsetAlign    = 256; 
768         pNv->EXADriverPtr->pixmapPitchAlign     = 64; 
769         pNv->EXADriverPtr->flags                = EXA_OFFSCREEN_PIXMAPS;
770         pNv->EXADriverPtr->maxX                 = 32768;
771         pNv->EXADriverPtr->maxY                 = 32768;
772
773         pNv->EXADriverPtr->WaitMarker = NVExaWaitMarker;
774
775         /* Install default hooks */
776         pNv->EXADriverPtr->DownloadFromScreen = NVDownloadFromScreen; 
777         pNv->EXADriverPtr->UploadToScreen = NVUploadToScreen; 
778
779         if (pNv->Architecture < NV_ARCH_50) {
780                 pNv->EXADriverPtr->PrepareCopy = NVExaPrepareCopy;
781                 pNv->EXADriverPtr->Copy = NVExaCopy;
782                 pNv->EXADriverPtr->DoneCopy = NVExaDoneCopy;
783
784                 pNv->EXADriverPtr->PrepareSolid = NVExaPrepareSolid;
785                 pNv->EXADriverPtr->Solid = NVExaSolid;
786                 pNv->EXADriverPtr->DoneSolid = NVExaDoneSolid;
787         } else {
788                 pNv->EXADriverPtr->PrepareCopy = NV50EXAPrepareCopy;
789                 pNv->EXADriverPtr->Copy = NV50EXACopy;
790                 pNv->EXADriverPtr->DoneCopy = NV50EXADoneCopy;
791
792                 pNv->EXADriverPtr->PrepareSolid = NV50EXAPrepareSolid;
793                 pNv->EXADriverPtr->Solid = NV50EXASolid;
794                 pNv->EXADriverPtr->DoneSolid = NV50EXADoneSolid;
795         }
796
797         switch (pNv->Architecture) {
798 #if defined(ENABLE_NV30EXA)
799 //      not working yet
800 /*
801         case NV_ARCH_30:
802                 pNv->EXADriverPtr->CheckComposite   = NV30EXACheckComposite;
803                 pNv->EXADriverPtr->PrepareComposite = NV30EXAPrepareComposite;
804                 pNv->EXADriverPtr->Composite        = NV30EXAComposite;
805                 pNv->EXADriverPtr->DoneComposite    = NV30EXADoneComposite;
806                 break;
807 */
808 #endif
809 #if (X_BYTE_ORDER == X_LITTLE_ENDIAN) && defined(ENABLE_NV30EXA)
810         case NV_ARCH_40:
811                 pNv->EXADriverPtr->CheckComposite   = NV40EXACheckComposite;
812                 pNv->EXADriverPtr->PrepareComposite = NV40EXAPrepareComposite;
813                 pNv->EXADriverPtr->Composite        = NV40EXAComposite;
814                 pNv->EXADriverPtr->DoneComposite    = NV40EXADoneComposite;
815                 break;
816 #endif
817         case NV_ARCH_50:
818                 break;
819         default:
820                 if (!pNv->BlendingPossible)
821                         break;
822                 pNv->EXADriverPtr->CheckComposite   = NVCheckComposite;
823                 pNv->EXADriverPtr->PrepareComposite = NVPrepareComposite;
824                 pNv->EXADriverPtr->Composite        = NVComposite;
825                 pNv->EXADriverPtr->DoneComposite    = NVDoneComposite;
826                 break;
827         }
828
829         return exaDriverInit(pScreen, pNv->EXADriverPtr);
830 }
831