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