~ubuntu-branches/ubuntu/karmic/xserver-xorg-video-nouveau/karmic

« back to all changes in this revision

Viewing changes to src/nv_exa.c

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2008-07-06 20:26:53 UTC
  • Revision ID: james.westby@ubuntu.com-20080706202653-e99oiii765j3a0qn
Tags: upstream-0.0.10~git+20080706+b1f3169
ImportĀ upstreamĀ versionĀ 0.0.10~git+20080706+b1f3169

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2003 NVIDIA, Corporation
 
3
 *
 
4
 * Permission is hereby granted, free of charge, to any person obtaining a
 
5
 * copy of this software and associated documentation files (the "Software"),
 
6
 * to deal in the Software without restriction, including without limitation
 
7
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
8
 * and/or sell copies of the Software, and to permit persons to whom the
 
9
 * Software is furnished to do so, subject to the following conditions:
 
10
 *
 
11
 * The above copyright notice and this permission notice shall be included in
 
12
 * all copies or substantial portions of the Software.
 
13
 *
 
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
17
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
18
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 
19
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
20
 * SOFTWARE.
 
21
 */
 
22
 
 
23
#include "nv_include.h"
 
24
#include "exa.h"
 
25
 
 
26
#include "nv_dma.h"
 
27
#include "nv_local.h"
 
28
 
 
29
#include <sys/time.h>
 
30
 
 
31
const int NVCopyROP[16] =
 
32
{
 
33
   0x00,            /* GXclear */
 
34
   0x88,            /* GXand */
 
35
   0x44,            /* GXandReverse */
 
36
   0xCC,            /* GXcopy */
 
37
   0x22,            /* GXandInverted */
 
38
   0xAA,            /* GXnoop */
 
39
   0x66,            /* GXxor */
 
40
   0xEE,            /* GXor */
 
41
   0x11,            /* GXnor */
 
42
   0x99,            /* GXequiv */
 
43
   0x55,            /* GXinvert*/
 
44
   0xDD,            /* GXorReverse */
 
45
   0x33,            /* GXcopyInverted */
 
46
   0xBB,            /* GXorInverted */
 
47
   0x77,            /* GXnand */
 
48
   0xFF             /* GXset */
 
49
};
 
50
 
 
51
static void 
 
52
NVSetPattern(ScrnInfoPtr pScrn, CARD32 clr0, CARD32 clr1,
 
53
                                CARD32 pat0, CARD32 pat1)
 
54
{
 
55
        NVPtr pNv = NVPTR(pScrn);
 
56
 
 
57
        BEGIN_RING(NvImagePattern, NV04_IMAGE_PATTERN_MONOCHROME_COLOR0, 4);
 
58
        OUT_RING  (clr0);
 
59
        OUT_RING  (clr1);
 
60
        OUT_RING  (pat0);
 
61
        OUT_RING  (pat1);
 
62
}
 
63
 
 
64
static void 
 
65
NVSetROP(ScrnInfoPtr pScrn, CARD32 alu, CARD32 planemask)
 
66
{
 
67
        NVPtr pNv = NVPTR(pScrn);
 
68
        int rop = NVCopyROP[alu] & 0xf0;
 
69
 
 
70
        if (planemask != ~0) {
 
71
                NVSetPattern(pScrn, 0, planemask, ~0, ~0);
 
72
                if (pNv->currentRop != (alu + 32)) {
 
73
                        BEGIN_RING(NvRop, NV03_CONTEXT_ROP_ROP, 1);
 
74
                        OUT_RING  (rop | 0x0a);
 
75
                        pNv->currentRop = alu + 32;
 
76
                }
 
77
        } else
 
78
        if (pNv->currentRop != alu) {
 
79
                if(pNv->currentRop >= 16)
 
80
                        NVSetPattern(pScrn, ~0, ~0, ~0, ~0);
 
81
                BEGIN_RING(NvRop, NV03_CONTEXT_ROP_ROP, 1);
 
82
                OUT_RING  (rop | (rop >> 4));
 
83
                pNv->currentRop = alu;
 
84
        }
 
85
}
 
86
 
 
87
static CARD32 rectFormat(DrawablePtr pDrawable)
 
88
{
 
89
        switch(pDrawable->bitsPerPixel) {
 
90
        case 32:
 
91
        case 24:
 
92
                return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
 
93
                break;
 
94
        case 16:
 
95
                return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
 
96
                break;
 
97
        default:
 
98
                return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
 
99
                break;
 
100
        }
 
101
}
 
102
 
 
103
/* EXA acceleration hooks */
 
104
static void NVExaWaitMarker(ScreenPtr pScreen, int marker)
 
105
{
 
106
        NVSync(xf86Screens[pScreen->myNum]);
 
107
}
 
108
 
 
109
static Bool NVExaPrepareSolid(PixmapPtr pPixmap,
 
110
                              int   alu,
 
111
                              Pixel planemask,
 
112
                              Pixel fg)
 
113
{
 
114
        ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
 
115
        NVPtr pNv = NVPTR(pScrn);
 
116
        unsigned int fmt, pitch;
 
117
 
 
118
        planemask |= ~0 << pPixmap->drawable.bitsPerPixel;
 
119
        if (planemask != ~0 || alu != GXcopy) {
 
120
                if (pPixmap->drawable.bitsPerPixel == 32)
 
121
                        return FALSE;
 
122
                BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
 
123
                OUT_RING  (1); /* ROP_AND */
 
124
                NVSetROP(pScrn, alu, planemask);
 
125
        } else {
 
126
                BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
 
127
                OUT_RING  (3); /* SRCCOPY */
 
128
        }
 
129
 
 
130
        if (!NVAccelGetCtxSurf2DFormatFromPixmap(pPixmap, (int*)&fmt))
 
131
                return FALSE;
 
132
        pitch = exaGetPixmapPitch(pPixmap);
 
133
 
 
134
        /* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the 
 
135
         * alpha channel gets forced to 0xFF for some reason.  We're using 
 
136
         * SURFACE_FORMAT_Y32 as a workaround
 
137
         */
 
138
        if (fmt == NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8)
 
139
                fmt = NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
 
140
 
 
141
        BEGIN_RING(NvContextSurfaces, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
 
142
        OUT_RING  (fmt);
 
143
        OUT_RING  ((pitch << 16) | pitch);
 
144
        OUT_PIXMAPl(pPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
 
145
        OUT_PIXMAPl(pPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
 
146
 
 
147
        BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
 
148
        OUT_RING  (rectFormat(&pPixmap->drawable));
 
149
        BEGIN_RING(NvRectangle, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
 
150
        OUT_RING  (fg);
 
151
 
 
152
        return TRUE;
 
153
}
 
154
 
 
155
static void NVExaSolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
 
156
{
 
157
        ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
 
158
        NVPtr pNv = NVPTR(pScrn);
 
159
        int width = x2-x1;
 
160
        int height = y2-y1;
 
161
 
 
162
        BEGIN_RING(NvRectangle,
 
163
                   NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
 
164
        OUT_RING  ((x1 << 16) | y1);
 
165
        OUT_RING  ((width << 16) | height);
 
166
 
 
167
        if((width * height) >= 512)
 
168
                FIRE_RING();
 
169
}
 
170
 
 
171
static void NVExaDoneSolid (PixmapPtr pPixmap)
 
172
{
 
173
}
 
174
 
 
175
static Bool NVExaPrepareCopy(PixmapPtr pSrcPixmap,
 
176
                             PixmapPtr pDstPixmap,
 
177
                             int       dx,
 
178
                             int       dy,
 
179
                             int       alu,
 
180
                             Pixel     planemask)
 
181
{
 
182
        ScrnInfoPtr pScrn = xf86Screens[pSrcPixmap->drawable.pScreen->myNum];
 
183
        NVPtr pNv = NVPTR(pScrn);
 
184
        int fmt;
 
185
 
 
186
        if (pSrcPixmap->drawable.bitsPerPixel !=
 
187
                        pDstPixmap->drawable.bitsPerPixel)
 
188
                return FALSE;
 
189
 
 
190
        planemask |= ~0 << pDstPixmap->drawable.bitsPerPixel;
 
191
        if (planemask != ~0 || alu != GXcopy) {
 
192
                if (pDstPixmap->drawable.bitsPerPixel == 32)
 
193
                        return FALSE;
 
194
                BEGIN_RING(NvImageBlit, NV04_IMAGE_BLIT_OPERATION, 1);
 
195
                OUT_RING  (1); /* ROP_AND */
 
196
                NVSetROP(pScrn, alu, planemask);
 
197
        } else {
 
198
                BEGIN_RING(NvImageBlit, NV04_IMAGE_BLIT_OPERATION, 1);
 
199
                OUT_RING  (3); /* SRCCOPY */
 
200
        }
 
201
 
 
202
        if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDstPixmap, &fmt))
 
203
                return FALSE;
 
204
 
 
205
        BEGIN_RING(NvContextSurfaces, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
 
206
        OUT_RING  (fmt);
 
207
        OUT_RING  ((exaGetPixmapPitch(pDstPixmap) << 16) |
 
208
                   (exaGetPixmapPitch(pSrcPixmap)));
 
209
        OUT_PIXMAPl(pSrcPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
 
210
        OUT_PIXMAPl(pDstPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
 
211
 
 
212
        return TRUE;
 
213
}
 
214
 
 
215
static void NVExaCopy(PixmapPtr pDstPixmap,
 
216
                      int       srcX,
 
217
                      int       srcY,
 
218
                      int       dstX,
 
219
                      int       dstY,
 
220
                      int       width,
 
221
                      int       height)
 
222
{
 
223
        ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
 
224
        NVPtr pNv = NVPTR(pScrn);
 
225
 
 
226
        /* We want to catch people who have this bug, to find a decent fix */
 
227
#if 0
 
228
        /* Now check whether we have the same values for srcY and dstY and
 
229
           whether the used chipset is buggy. Currently we flag all of G70
 
230
           cards as buggy, which is probably much to broad. KoalaBR 
 
231
           16 is an abritrary threshold. It should define the maximum number
 
232
           of lines between dstY and srcY  If the number of lines is below
 
233
           we guess, that the bug won't trigger...
 
234
         */
 
235
        if ( ((abs(srcY - dstY)< 16)||(abs(srcX-dstX)<16)) &&
 
236
                ((((pNv->Chipset & 0xfff0) == CHIPSET_G70) ||
 
237
                 ((pNv->Chipset & 0xfff0) == CHIPSET_G71) ||
 
238
                 ((pNv->Chipset & 0xfff0) == CHIPSET_G72) ||
 
239
                 ((pNv->Chipset & 0xfff0) == CHIPSET_G73) ||
 
240
                 ((pNv->Chipset & 0xfff0) == CHIPSET_C512))) )
 
241
        {
 
242
                int dx=abs(srcX - dstX),dy=abs(srcY - dstY);
 
243
                // Ok, let's do it manually unless someone comes up with a better idea
 
244
                // 1. If dstY and srcY are really the same, do a copy rowwise
 
245
                if (dy<dx) {
 
246
                        int i,xpos,inc;
 
247
                        NVDEBUG("ExaCopy: Lines identical:\n");
 
248
                        if (srcX>=dstX) {
 
249
                                xpos=0;
 
250
                                inc=1;
 
251
                        } else {
 
252
                                xpos=width-1;
 
253
                                inc=-1;
 
254
                        }
 
255
                        for (i = 0; i < width; i++) {
 
256
                                BEGIN_RING(NvImageBlit,
 
257
                                           NV_IMAGE_BLIT_POINT_IN, 3);
 
258
                                OUT_RING  ((srcY << 16) | (srcX+xpos));
 
259
                                OUT_RING  ((dstY << 16) | (dstX+xpos));
 
260
                                OUT_RING  ((height  << 16) | 1);
 
261
                                xpos+=inc;
 
262
                        }
 
263
                } else {
 
264
                        // 2. Otherwise we will try a line by line copy in the hope to avoid
 
265
                        //    the card's bug.
 
266
                        int i,ypos,inc;
 
267
                        NVDEBUG("ExaCopy: Lines nearly the same srcY=%d, dstY=%d:\n", srcY, dstY);
 
268
                        if (srcY>=dstY) {
 
269
                                ypos=0;
 
270
                                inc=1;
 
271
                        } else {
 
272
                                ypos=height-1;
 
273
                                inc=-1;
 
274
                        }
 
275
                        for (i = 0; i < height; i++) {
 
276
                                BEGIN_RING(NvImageBlit,
 
277
                                           NV_IMAGE_BLIT_POINT_IN, 3);
 
278
                                OUT_RING  (((srcY+ypos) << 16) | srcX);
 
279
                                OUT_RING  (((dstY+ypos) << 16) | dstX);
 
280
                                OUT_RING  ((1  << 16) | width);
 
281
                                ypos+=inc;
 
282
                        }
 
283
                } 
 
284
        } else {
 
285
                NVDEBUG("ExaCopy: Using default path\n");
 
286
                BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_POINT_IN, 3);
 
287
                OUT_RING  ((srcY << 16) | srcX);
 
288
                OUT_RING  ((dstY << 16) | dstX);
 
289
                OUT_RING  ((height  << 16) | width);
 
290
        }
 
291
#endif /* 0 */
 
292
 
 
293
        NVDEBUG("ExaCopy: Using default path\n");
 
294
        BEGIN_RING(NvImageBlit, NV01_IMAGE_BLIT_POINT_IN, 3);
 
295
        OUT_RING  ((srcY << 16) | srcX);
 
296
        OUT_RING  ((dstY << 16) | dstX);
 
297
        OUT_RING  ((height  << 16) | width);
 
298
 
 
299
        if((width * height) >= 512)
 
300
                FIRE_RING(); 
 
301
}
 
302
 
 
303
static void NVExaDoneCopy (PixmapPtr pDstPixmap) {}
 
304
 
 
305
static inline Bool NVAccelMemcpyRect(char *dst, const char *src, int height,
 
306
                       int dst_pitch, int src_pitch, int line_len)
 
307
{
 
308
        if ((src_pitch == line_len) && (src_pitch == dst_pitch)) {
 
309
                memcpy(dst, src, line_len*height);
 
310
        } else {
 
311
                while (height--) {
 
312
                        memcpy(dst, src, line_len);
 
313
                        src += src_pitch;
 
314
                        dst += dst_pitch;
 
315
                }
 
316
        }
 
317
 
 
318
        return TRUE;
 
319
}
 
320
 
 
321
static inline Bool
 
322
NVAccelDownloadM2MF(ScrnInfoPtr pScrn, char *dst, PixmapPtr pspix,
 
323
                    uint32_t src_offset, int dst_pitch, int src_pitch,
 
324
                    int line_len, int line_count)
 
325
{
 
326
        NVPtr pNv = NVPTR(pScrn);
 
327
 
 
328
        BEGIN_RING(NvMemFormat, 0x184, 2);
 
329
        OUT_PIXMAPo(pspix, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
 
330
        OUT_RELOCo(pNv->GART, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
 
331
 
 
332
        while (line_count) {
 
333
                char *src = pNv->GART->map;
 
334
                int lc, i;
 
335
 
 
336
                if (line_count * line_len <= pNv->GART->size) {
 
337
                        lc = line_count;
 
338
                } else {
 
339
                        lc = pNv->GART->size / line_len;
 
340
                        if (lc > line_count)
 
341
                                lc = line_count;
 
342
                }
 
343
 
 
344
                /* HW limitations */
 
345
                if (lc > 2047)
 
346
                        lc = 2047;
 
347
 
 
348
                if (pNv->Architecture >= NV_ARCH_50) {
 
349
                        BEGIN_RING(NvMemFormat, 0x200, 1);
 
350
                        OUT_RING  (1);
 
351
                        BEGIN_RING(NvMemFormat, 0x21c, 1);
 
352
                        OUT_RING  (1);
 
353
                        /* probably high-order bits of address */
 
354
                        BEGIN_RING(NvMemFormat, 0x238, 2);
 
355
                        OUT_PIXMAPh(pspix, src_offset, NOUVEAU_BO_GART |
 
356
                                    NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
 
357
                        OUT_RELOCh(pNv->GART, 0, NOUVEAU_BO_GART |
 
358
                                   NOUVEAU_BO_WR);
 
359
                }
 
360
 
 
361
                BEGIN_RING(NvMemFormat,
 
362
                           NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
 
363
                OUT_PIXMAPl(pspix, src_offset, NOUVEAU_BO_GART |
 
364
                            NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
 
365
                OUT_RELOCl(pNv->GART, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
 
366
                OUT_RING  (src_pitch);
 
367
                OUT_RING  (line_len);
 
368
                OUT_RING  (line_len);
 
369
                OUT_RING  (lc);
 
370
                OUT_RING  ((1<<8)|1);
 
371
                OUT_RING  (0);
 
372
 
 
373
                nouveau_notifier_reset(pNv->notify0, 0);
 
374
                BEGIN_RING(NvMemFormat, NV04_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
 
375
                OUT_RING  (0);
 
376
                BEGIN_RING(NvMemFormat, 0x100, 1);
 
377
                OUT_RING  (0);
 
378
                FIRE_RING();
 
379
                if (nouveau_notifier_wait_status(pNv->notify0, 0, 0,
 
380
                                                 2000))
 
381
                        return FALSE;
 
382
 
 
383
                if (dst_pitch == line_len) {
 
384
                        memcpy(dst, src, dst_pitch * lc);
 
385
                        dst += dst_pitch * lc;
 
386
                } else {
 
387
                        for (i = 0; i < lc; i++) {
 
388
                                memcpy(dst, src, line_len);
 
389
                                src += line_len;
 
390
                                dst += dst_pitch;
 
391
                        }
 
392
                }
 
393
 
 
394
                line_count -= lc;
 
395
                src_offset += lc * src_pitch;
 
396
        }
 
397
 
 
398
        return TRUE;
 
399
}
 
400
 
 
401
static inline void *
 
402
NVExaPixmapMap(PixmapPtr pPix)
 
403
{
 
404
        void *map;
 
405
#if NOUVEAU_EXA_PIXMAPS
 
406
        struct nouveau_pixmap *nvpix;
 
407
 
 
408
        nvpix = exaGetPixmapDriverPrivate(pPix);
 
409
        if (!nvpix || !nvpix->bo)
 
410
                return NULL;
 
411
 
 
412
        map = nvpix->bo->map;
 
413
#else
 
414
        ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
 
415
        NVPtr pNv = NVPTR(pScrn);
 
416
        map = pNv->FB->map + exaGetPixmapOffset(pPix);
 
417
#endif /* NOUVEAU_EXA_PIXMAPS */
 
418
        return map;
 
419
}
 
420
 
 
421
static Bool NVDownloadFromScreen(PixmapPtr pSrc,
 
422
                                 int x,  int y,
 
423
                                 int w,  int h,
 
424
                                 char *dst,  int dst_pitch)
 
425
{
 
426
        ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
 
427
        NVPtr pNv = NVPTR(pScrn);
 
428
        int src_pitch, cpp, offset;
 
429
        const char *src;
 
430
 
 
431
        src_pitch  = exaGetPixmapPitch(pSrc);
 
432
        cpp = pSrc->drawable.bitsPerPixel >> 3;
 
433
        offset = (y * src_pitch) + (x * cpp);
 
434
 
 
435
        if (pNv->GART) {
 
436
                if (NVAccelDownloadM2MF(pScrn, dst, pSrc, offset,
 
437
                                        dst_pitch, src_pitch, w * cpp, h))
 
438
                        return TRUE;
 
439
        }
 
440
 
 
441
        src = NVExaPixmapMap(pSrc);
 
442
        if (!src)
 
443
                return FALSE;
 
444
        src += offset;
 
445
        exaWaitSync(pSrc->drawable.pScreen);
 
446
        if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
 
447
                return TRUE;
 
448
 
 
449
        return FALSE;
 
450
}
 
451
 
 
452
static inline Bool
 
453
NVAccelUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch, 
 
454
                 PixmapPtr pDst, int x, int y, int w, int h, int cpp)
 
455
{
 
456
        NVPtr pNv = NVPTR(pScrn);
 
457
        int line_len = w * cpp;
 
458
        int iw, id, surf_fmt, ifc_fmt;
 
459
        int padbytes;
 
460
 
 
461
        if (pNv->Architecture >= NV_ARCH_50)
 
462
                return FALSE;
 
463
 
 
464
        if (h > 1024)
 
465
                return FALSE;
 
466
 
 
467
        switch (cpp) {
 
468
        case 2: ifc_fmt = 1; break;
 
469
        case 4: ifc_fmt = 4; break;
 
470
        default:
 
471
                return FALSE;
 
472
        }
 
473
 
 
474
        if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDst, &surf_fmt))
 
475
                return FALSE;
 
476
 
 
477
        BEGIN_RING(NvContextSurfaces, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
 
478
        OUT_RING  (surf_fmt);
 
479
        OUT_RING  ((exaGetPixmapPitch(pDst) << 16) | exaGetPixmapPitch(pDst));
 
480
        OUT_PIXMAPl(pDst, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
 
481
        OUT_PIXMAPl(pDst, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
 
482
 
 
483
        /* Pad out input width to cover both COLORA() and COLORB() */
 
484
        iw  = (line_len + 7) & ~7;
 
485
        padbytes = iw - line_len;
 
486
        id  = iw / 4; /* line push size */
 
487
        iw /= cpp;
 
488
 
 
489
        /* Don't support lines longer than max push size yet.. */
 
490
        if (id > 1792)
 
491
                return FALSE;
 
492
 
 
493
        BEGIN_RING(NvClipRectangle, NV01_CONTEXT_CLIP_RECTANGLE_POINT, 2);
 
494
        OUT_RING  (0x0); 
 
495
        OUT_RING  (0x7FFF7FFF);
 
496
 
 
497
        BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_OPERATION, 2);
 
498
        OUT_RING  (NV01_IMAGE_FROM_CPU_OPERATION_SRCCOPY);
 
499
        OUT_RING  (ifc_fmt);
 
500
        BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_POINT, 3);
 
501
        OUT_RING  ((y << 16) | x); /* dst point */
 
502
        OUT_RING  ((h << 16) | w); /* width/height out */
 
503
        OUT_RING  ((h << 16) | iw); /* width/height in */
 
504
 
 
505
        if (padbytes)
 
506
                h--;
 
507
        while (h--) {
 
508
                /* send a line */
 
509
                BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_COLOR(0), id);
 
510
                OUT_RINGp (src, id);
 
511
 
 
512
                src += src_pitch;
 
513
        }
 
514
        if (padbytes) {
 
515
                char padding[8];
 
516
                int aux = (padbytes + 7) >> 2;
 
517
                BEGIN_RING(NvImageFromCpu, NV01_IMAGE_FROM_CPU_COLOR(0), id);
 
518
                OUT_RINGp (src, id - aux);
 
519
                memcpy(padding, src + (id - aux) * 4, padbytes);
 
520
                OUT_RINGp (padding, aux);
 
521
        }
 
522
 
 
523
        return TRUE;
 
524
}
 
525
 
 
526
static inline Bool
 
527
NVAccelUploadM2MF(ScrnInfoPtr pScrn, PixmapPtr pdpix, uint32_t dst_offset,
 
528
                  const char *src, int dst_pitch, int src_pitch,
 
529
                  int line_len, int line_count)
 
530
{
 
531
        NVPtr pNv = NVPTR(pScrn);
 
532
 
 
533
        BEGIN_RING(NvMemFormat, 0x184, 2);
 
534
        OUT_RELOCo(pNv->GART, NOUVEAU_BO_GART | NOUVEAU_BO_RD);
 
535
        OUT_PIXMAPo(pdpix, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_WR);
 
536
 
 
537
        while (line_count) {
 
538
                char *dst = pNv->GART->map;
 
539
                int lc, i;
 
540
 
 
541
                /* Determine max amount of data we can DMA at once */
 
542
                if (line_count * line_len <= pNv->GART->size) {
 
543
                        lc = line_count;
 
544
                } else {
 
545
                        lc = pNv->GART->size / line_len;
 
546
                        if (lc > line_count)
 
547
                                lc = line_count;
 
548
                }
 
549
 
 
550
                /* HW limitations */
 
551
                if (lc > 2047)
 
552
                        lc = 2047;
 
553
 
 
554
                /* Upload to GART */
 
555
                if (src_pitch == line_len) {
 
556
                        memcpy(dst, src, src_pitch * lc);
 
557
                        src += src_pitch * lc;
 
558
                } else {
 
559
                        for (i = 0; i < lc; i++) {
 
560
                                memcpy(dst, src, line_len);
 
561
                                src += src_pitch;
 
562
                                dst += line_len;
 
563
                        }
 
564
                }
 
565
 
 
566
                if (pNv->Architecture >= NV_ARCH_50) {
 
567
                        BEGIN_RING(NvMemFormat, 0x200, 1);
 
568
                        OUT_RING  (1);
 
569
                        BEGIN_RING(NvMemFormat, 0x21c, 1);
 
570
                        OUT_RING  (1);
 
571
                        /* probably high-order bits of address */
 
572
                        BEGIN_RING(NvMemFormat, 0x238, 2);
 
573
                        OUT_RELOCh(pNv->GART, 0, NOUVEAU_BO_GART |
 
574
                                   NOUVEAU_BO_RD);
 
575
                        OUT_PIXMAPh(pdpix, 0, NOUVEAU_BO_VRAM | 
 
576
                                    NOUVEAU_BO_GART | NOUVEAU_BO_WR);
 
577
                }
 
578
 
 
579
                /* DMA to VRAM */
 
580
                BEGIN_RING(NvMemFormat,
 
581
                           NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
 
582
                OUT_RELOCl(pNv->GART, 0, NOUVEAU_BO_GART | NOUVEAU_BO_RD);
 
583
                OUT_PIXMAPl(pdpix, dst_offset, NOUVEAU_BO_VRAM |
 
584
                            NOUVEAU_BO_GART | NOUVEAU_BO_WR);
 
585
                OUT_RING  (line_len);
 
586
                OUT_RING  (dst_pitch);
 
587
                OUT_RING  (line_len);
 
588
                OUT_RING  (lc);
 
589
                OUT_RING  ((1<<8)|1);
 
590
                OUT_RING  (0);
 
591
 
 
592
                nouveau_notifier_reset(pNv->notify0, 0);
 
593
                BEGIN_RING(NvMemFormat, NV04_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
 
594
                OUT_RING  (0);
 
595
                BEGIN_RING(NvMemFormat, 0x100, 1);
 
596
                OUT_RING  (0);
 
597
                FIRE_RING();
 
598
                if (nouveau_notifier_wait_status(pNv->notify0, 0, 0, 2000))
 
599
                        return FALSE;
 
600
 
 
601
                dst_offset += lc * dst_pitch;
 
602
                line_count -= lc;
 
603
        }
 
604
 
 
605
        return TRUE;
 
606
}
 
607
 
 
608
static Bool NVUploadToScreen(PixmapPtr pDst,
 
609
                             int x, int y, int w, int h,
 
610
                             char *src, int src_pitch)
 
611
{
 
612
        ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
 
613
        NVPtr pNv = NVPTR(pScrn);
 
614
        int dst_pitch, cpp;
 
615
        char *dst;
 
616
 
 
617
        dst_pitch  = exaGetPixmapPitch(pDst);
 
618
        cpp = pDst->drawable.bitsPerPixel >> 3;
 
619
 
 
620
        /* try hostdata transfer */
 
621
        if (w * h * cpp < 16*1024) /* heuristic */
 
622
        {
 
623
                if (pNv->Architecture < NV_ARCH_50) {
 
624
                        if (NVAccelUploadIFC(pScrn, src, src_pitch, pDst,
 
625
                                             x, y, w, h, cpp)) {
 
626
                                exaMarkSync(pDst->drawable.pScreen);
 
627
                                return TRUE;
 
628
                        }
 
629
                } else {
 
630
                        if (NV50EXAUploadSIFC(pScrn, src, src_pitch, pDst,
 
631
                                              x, y, w, h, cpp)) {
 
632
                                exaMarkSync(pDst->drawable.pScreen);
 
633
                                return TRUE;
 
634
                        }
 
635
                }
 
636
        }
 
637
 
 
638
        /* try gart-based transfer */
 
639
        if (pNv->GART) {
 
640
                if (NVAccelUploadM2MF(pScrn, pDst, (y * dst_pitch) + (x * cpp),
 
641
                                      src, dst_pitch, src_pitch, w * cpp, h))
 
642
                        return TRUE;
 
643
        }
 
644
 
 
645
        /* fallback to memcpy-based transfer */
 
646
        dst = NVExaPixmapMap(pDst);
 
647
        if (!dst)
 
648
                return FALSE;
 
649
        dst += (y * dst_pitch) + (x * cpp);
 
650
        exaWaitSync(pDst->drawable.pScreen);
 
651
        if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
 
652
                return TRUE;
 
653
 
 
654
        return FALSE;
 
655
}
 
656
 
 
657
#if NOUVEAU_EXA_PIXMAPS
 
658
static Bool
 
659
NVExaPrepareAccess(PixmapPtr pPix, int index)
 
660
{
 
661
        ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
 
662
        NVPtr pNv = NVPTR(pScrn);
 
663
        struct nouveau_pixmap *nvpix;
 
664
        (void)pNv;
 
665
 
 
666
        nvpix = exaGetPixmapDriverPrivate(pPix);
 
667
        if (!nvpix || !nvpix->bo)
 
668
                return FALSE;
 
669
 
 
670
        /*XXX: ho hum.. sync if needed */
 
671
 
 
672
        if (nvpix->mapped)
 
673
                return TRUE;
 
674
 
 
675
        if (nouveau_bo_map(nvpix->bo, NOUVEAU_BO_RDWR))
 
676
                return FALSE;
 
677
        pPix->devPrivate.ptr = nvpix->bo->map;
 
678
        nvpix->mapped = TRUE;
 
679
        return TRUE;
 
680
}
 
681
 
 
682
static void
 
683
NVExaFinishAccess(PixmapPtr pPix, int index)
 
684
{
 
685
        ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
 
686
        NVPtr pNv = NVPTR(pScrn);
 
687
        struct nouveau_pixmap *nvpix;
 
688
        (void)pNv;
 
689
 
 
690
        nvpix = exaGetPixmapDriverPrivate(pPix);
 
691
        if (!nvpix || !nvpix->bo || !nvpix->mapped)
 
692
                return;
 
693
 
 
694
        nouveau_bo_unmap(nvpix->bo);
 
695
        pPix->devPrivate.ptr = NULL;
 
696
        nvpix->mapped = FALSE;
 
697
}
 
698
 
 
699
static Bool
 
700
NVExaPixmapIsOffscreen(PixmapPtr pPix)
 
701
{
 
702
        ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
 
703
        NVPtr pNv = NVPTR(pScrn);
 
704
        struct nouveau_pixmap *nvpix;
 
705
        (void)pNv;
 
706
 
 
707
        nvpix = exaGetPixmapDriverPrivate(pPix);
 
708
        if (!nvpix || !nvpix->bo)
 
709
                return FALSE;
 
710
 
 
711
        return TRUE;
 
712
}
 
713
 
 
714
static void *
 
715
NVExaCreatePixmap(ScreenPtr pScreen, int size, int align)
 
716
{
 
717
        ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
 
718
        NVPtr pNv = NVPTR(pScrn);
 
719
        struct nouveau_pixmap *nvpix;
 
720
 
 
721
        nvpix = xcalloc(1, sizeof(struct nouveau_pixmap));
 
722
        if (!nvpix)
 
723
                return NULL;
 
724
 
 
725
        if (size) {
 
726
                if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM, 0, size,
 
727
                                   &nvpix->bo)) {
 
728
                        xfree(nvpix);
 
729
                        return NULL;
 
730
                }
 
731
        }
 
732
 
 
733
        return nvpix;
 
734
}
 
735
 
 
736
static void
 
737
NVExaDestroyPixmap(ScreenPtr pScreen, void *driverPriv)
 
738
{
 
739
        ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
 
740
        NVPtr pNv = NVPTR(pScrn);
 
741
        struct nouveau_pixmap *nvpix = driverPriv;
 
742
 
 
743
        if (!driverPriv)
 
744
                return;
 
745
 
 
746
        /*XXX: only if pending relocs reference this buffer..*/
 
747
        FIRE_RING();
 
748
 
 
749
        nouveau_bo_del(&nvpix->bo);
 
750
        xfree(nvpix);
 
751
}
 
752
 
 
753
static Bool
 
754
NVExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth,
 
755
                        int bitsPerPixel, int devKind, pointer pPixData)
 
756
{
 
757
        ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
 
758
        NVPtr pNv = NVPTR(pScrn);
 
759
        struct nouveau_pixmap *nvpix;
 
760
 
 
761
        if (pPixData == pNv->FB->map) {
 
762
                nvpix = exaGetPixmapDriverPrivate(pPixmap);
 
763
                if (!nvpix)
 
764
                        return FALSE;
 
765
 
 
766
                if (nouveau_bo_ref(pNv->dev, pNv->FB->handle, &nvpix->bo))
 
767
                        return FALSE;
 
768
 
 
769
                miModifyPixmapHeader(pPixmap, width, height, depth,
 
770
                                     bitsPerPixel, devKind, NULL);
 
771
                return TRUE;
 
772
        }
 
773
 
 
774
        return FALSE;
 
775
}
 
776
#endif
 
777
 
 
778
#if !NOUVEAU_EXA_PIXMAPS
 
779
static Bool
 
780
nouveau_exa_pixmap_is_offscreen(PixmapPtr pPixmap)
 
781
{
 
782
        ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
 
783
        NVPtr pNv = NVPTR(pScrn);
 
784
        void *addr = (void *)pPixmap->devPrivate.ptr;
 
785
 
 
786
        if (addr >= pNv->FB->map && addr < (pNv->FB->map + pNv->FB->size))
 
787
                return TRUE;
 
788
 
 
789
        if (pNv->shadow[0] && (addr >= pNv->shadow[0]->map && addr < (pNv->shadow[0]->map + pNv->shadow[0]->size)))
 
790
                return TRUE;
 
791
 
 
792
        if (pNv->shadow[1] && (addr >= pNv->shadow[1]->map && addr < (pNv->shadow[1]->map + pNv->shadow[1]->size)))
 
793
                return TRUE;
 
794
 
 
795
        return FALSE;
 
796
}
 
797
#endif /* !NOUVEAU_EXA_PIXMAPS */
 
798
 
 
799
Bool
 
800
NVExaPixmapIsOnscreen(PixmapPtr pPixmap)
 
801
{
 
802
        ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
 
803
        NVPtr pNv = NVPTR(pScrn);
 
804
 
 
805
#if NOUVEAU_EXA_PIXMAPS
 
806
        struct nouveau_pixmap *nvpix;
 
807
        nvpix = exaGetPixmapDriverPrivate(pPixmap);
 
808
 
 
809
        if (nvpix && nvpix->bo == pNv->FB)
 
810
                return TRUE;
 
811
 
 
812
#else
 
813
        unsigned long offset = exaGetPixmapOffset(pPixmap);
 
814
 
 
815
        if (offset < pNv->EXADriverPtr->offScreenBase)
 
816
                return TRUE;
 
817
#endif /* NOUVEAU_EXA_PIXMAPS */
 
818
 
 
819
        return FALSE;
 
820
}
 
821
 
 
822
Bool
 
823
NVExaInit(ScreenPtr pScreen) 
 
824
{
 
825
        ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
 
826
        NVPtr pNv = NVPTR(pScrn);
 
827
 
 
828
        if(!(pNv->EXADriverPtr = (ExaDriverPtr) xnfcalloc(sizeof(ExaDriverRec), 1))) {
 
829
                pNv->NoAccel = TRUE;
 
830
                return FALSE;
 
831
        }
 
832
 
 
833
        pNv->EXADriverPtr->exa_major = EXA_VERSION_MAJOR;
 
834
        pNv->EXADriverPtr->exa_minor = EXA_VERSION_MINOR;
 
835
 
 
836
#if NOUVEAU_EXA_PIXMAPS
 
837
        if (NOUVEAU_EXA_PIXMAPS) {
 
838
                pNv->EXADriverPtr->flags = EXA_OFFSCREEN_PIXMAPS |
 
839
                                           EXA_HANDLES_PIXMAPS;
 
840
                pNv->EXADriverPtr->PrepareAccess = NVExaPrepareAccess;
 
841
                pNv->EXADriverPtr->FinishAccess = NVExaFinishAccess;
 
842
                pNv->EXADriverPtr->PixmapIsOffscreen = NVExaPixmapIsOffscreen;
 
843
                pNv->EXADriverPtr->CreatePixmap = NVExaCreatePixmap;
 
844
                pNv->EXADriverPtr->DestroyPixmap = NVExaDestroyPixmap;
 
845
                pNv->EXADriverPtr->ModifyPixmapHeader = NVExaModifyPixmapHeader;
 
846
        } else
 
847
#endif
 
848
        {
 
849
                pNv->EXADriverPtr->flags = EXA_OFFSCREEN_PIXMAPS;
 
850
                pNv->EXADriverPtr->memoryBase = pNv->FB->map;
 
851
                pNv->EXADriverPtr->offScreenBase =
 
852
                        NOUVEAU_ALIGN(pScrn->virtualX, 64) * NOUVEAU_ALIGN(pScrn->virtualY,64) * 
 
853
                        (pScrn->bitsPerPixel / 8); 
 
854
                pNv->EXADriverPtr->memorySize           = pNv->FB->size; 
 
855
#if EXA_VERSION_MINOR >= 2
 
856
                pNv->EXADriverPtr->PixmapIsOffscreen = nouveau_exa_pixmap_is_offscreen;
 
857
#endif
 
858
        }
 
859
        pNv->EXADriverPtr->pixmapOffsetAlign    = 256; 
 
860
        pNv->EXADriverPtr->pixmapPitchAlign     = 64; 
 
861
 
 
862
        if (pNv->Architecture >= NV_ARCH_50) {
 
863
                pNv->EXADriverPtr->maxX = 8192;
 
864
                pNv->EXADriverPtr->maxY = 8192;
 
865
        } else
 
866
        if (pNv->Architecture >= NV_ARCH_20) {
 
867
                pNv->EXADriverPtr->maxX = 4096;
 
868
                pNv->EXADriverPtr->maxY = 4096;
 
869
        } else {
 
870
                pNv->EXADriverPtr->maxX = 2048;
 
871
                pNv->EXADriverPtr->maxY = 2048;
 
872
        }
 
873
 
 
874
        pNv->EXADriverPtr->WaitMarker = NVExaWaitMarker;
 
875
 
 
876
        /* Install default hooks */
 
877
        pNv->EXADriverPtr->DownloadFromScreen = NVDownloadFromScreen; 
 
878
        pNv->EXADriverPtr->UploadToScreen = NVUploadToScreen; 
 
879
 
 
880
        if (pNv->Architecture < NV_ARCH_50) {
 
881
                pNv->EXADriverPtr->PrepareCopy = NVExaPrepareCopy;
 
882
                pNv->EXADriverPtr->Copy = NVExaCopy;
 
883
                pNv->EXADriverPtr->DoneCopy = NVExaDoneCopy;
 
884
 
 
885
                pNv->EXADriverPtr->PrepareSolid = NVExaPrepareSolid;
 
886
                pNv->EXADriverPtr->Solid = NVExaSolid;
 
887
                pNv->EXADriverPtr->DoneSolid = NVExaDoneSolid;
 
888
        } else {
 
889
                pNv->EXADriverPtr->PrepareCopy = NV50EXAPrepareCopy;
 
890
                pNv->EXADriverPtr->Copy = NV50EXACopy;
 
891
                pNv->EXADriverPtr->DoneCopy = NV50EXADoneCopy;
 
892
 
 
893
                pNv->EXADriverPtr->PrepareSolid = NV50EXAPrepareSolid;
 
894
                pNv->EXADriverPtr->Solid = NV50EXASolid;
 
895
                pNv->EXADriverPtr->DoneSolid = NV50EXADoneSolid;
 
896
        }
 
897
 
 
898
        switch (pNv->Architecture) {
 
899
        
 
900
        case NV_ARCH_10:
 
901
        case NV_ARCH_20:
 
902
                pNv->EXADriverPtr->CheckComposite   = NV10CheckComposite;
 
903
                pNv->EXADriverPtr->PrepareComposite = NV10PrepareComposite;
 
904
                pNv->EXADriverPtr->Composite        = NV10Composite;
 
905
                pNv->EXADriverPtr->DoneComposite    = NV10DoneComposite;
 
906
                break;
 
907
        case NV_ARCH_30:
 
908
                pNv->EXADriverPtr->CheckComposite   = NV30EXACheckComposite;
 
909
                pNv->EXADriverPtr->PrepareComposite = NV30EXAPrepareComposite;
 
910
                pNv->EXADriverPtr->Composite        = NV30EXAComposite;
 
911
                pNv->EXADriverPtr->DoneComposite    = NV30EXADoneComposite;
 
912
                break;
 
913
        case NV_ARCH_40:
 
914
                pNv->EXADriverPtr->CheckComposite   = NV40EXACheckComposite;
 
915
                pNv->EXADriverPtr->PrepareComposite = NV40EXAPrepareComposite;
 
916
                pNv->EXADriverPtr->Composite        = NV40EXAComposite;
 
917
                pNv->EXADriverPtr->DoneComposite    = NV40EXADoneComposite;
 
918
                break;
 
919
        case NV_ARCH_50:
 
920
                break;
 
921
        default:
 
922
                break;
 
923
        }
 
924
 
 
925
        if (!exaDriverInit(pScreen, pNv->EXADriverPtr))
 
926
                return FALSE;
 
927
        else
 
928
                /* EXA init catches this, but only for xserver >= 1.4 */
 
929
                if (pNv->VRAMPhysicalSize / 2 < NOUVEAU_ALIGN(pScrn->virtualX, 64) * NOUVEAU_ALIGN(pScrn->virtualY, 64) * (pScrn->bitsPerPixel >> 3)) {
 
930
                        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "The virtual screen size's resolution is too big for the video RAM framebuffer at this colour depth.\n");
 
931
                        return FALSE;
 
932
                }
 
933
 
 
934
        return TRUE;
 
935
}