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