via_exa_h2.c revision 90b17f1b
1/*
2 * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
4 * Copyright 2006 Thomas Hellström. All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sub license,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26/*
27 * 2D acceleration functions for the VIA/S3G UniChrome IGPs.
28 *
29 * Mostly rewritten, and modified for EXA support, by Thomas Hellström.
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include <X11/Xarch.h>
37#include "miline.h"
38
39#include "via_driver.h"
40#include "via_regs.h"
41#include "via_dmabuffer.h"
42#include "via_rop.h"
43
44/*
45 * Emit clipping borders to the command buffer and update the 2D context
46 * current command with clipping info.
47 */
48static int
49viaAccelClippingHelper_H2(VIAPtr pVia, int refY)
50{
51    ViaTwodContext *tdc = &pVia->td;
52
53    RING_VARS;
54
55    if (tdc->clipping) {
56        refY = (refY < tdc->clipY1) ? refY : tdc->clipY1;
57        tdc->cmd |= VIA_GEC_CLIP_ENABLE;
58        BEGIN_RING(4);
59        OUT_RING_H1(VIA_REG_CLIPTL,
60                    ((tdc->clipY1 - refY) << 16) | tdc->clipX1);
61        OUT_RING_H1(VIA_REG_CLIPBR,
62		    ((tdc->clipY2 - refY) << 16) | tdc->clipX2);
63    } else {
64        tdc->cmd &= ~VIA_GEC_CLIP_ENABLE;
65    }
66    return refY;
67}
68
69/*
70 * Check if we can use a planeMask and update the 2D context accordingly.
71 */
72static Bool
73viaAccelPlaneMaskHelper_H2(ViaTwodContext * tdc, CARD32 planeMask)
74{
75    CARD32 modeMask = (1 << ((1 << tdc->bytesPPShift) << 3)) - 1;
76    CARD32 curMask = 0x00000000;
77    CARD32 curByteMask;
78    int i;
79
80    if ((planeMask & modeMask) != modeMask) {
81
82        /* Masking doesn't work in 8bpp. */
83        if (modeMask == 0xFF) {
84            tdc->keyControl &= 0x0FFFFFFF;
85            return FALSE;
86        }
87
88        /* Translate the bit planemask to a byte planemask. */
89        for (i = 0; i < (1 << tdc->bytesPPShift); ++i) {
90            curByteMask = (0xFF << (i << 3));
91
92            if ((planeMask & curByteMask) == 0) {
93                curMask |= (1 << i);
94            } else if ((planeMask & curByteMask) != curByteMask) {
95                tdc->keyControl &= 0x0FFFFFFF;
96                return FALSE;
97            }
98        }
99        ErrorF("DEBUG: planeMask 0x%08x, curMask 0%02x\n",
100               (unsigned)planeMask, (unsigned)curMask);
101
102        tdc->keyControl = (tdc->keyControl & 0x0FFFFFFF) | (curMask << 28);
103    }
104
105    return TRUE;
106}
107
108/*
109 * Emit transparency state and color to the command buffer.
110 */
111static void
112viaAccelTransparentHelper_H2(VIAPtr pVia, CARD32 keyControl,
113                          CARD32 transColor, Bool usePlaneMask)
114{
115    ViaTwodContext *tdc = &pVia->td;
116
117    RING_VARS;
118
119    tdc->keyControl &= ((usePlaneMask) ? 0xF0000000 : 0x00000000);
120    tdc->keyControl |= (keyControl & 0x0FFFFFFF);
121    BEGIN_RING(4);
122    OUT_RING_H1(VIA_REG_KEYCONTROL, tdc->keyControl);
123    if (keyControl) {
124        OUT_RING_H1(VIA_REG_SRCCOLORKEY, transColor);
125    }
126}
127
128/*
129 * Mark Sync using the 2D blitter for AGP. NoOp for PCI.
130 * In the future one could even launch a NULL PCI DMA command
131 * to have an interrupt generated, provided it is possible to
132 * write to the PCI DMA engines from the AGP command stream.
133 */
134int
135viaAccelMarkSync_H2(ScreenPtr pScreen)
136{
137    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
138    VIAPtr pVia = VIAPTR(pScrn);
139
140    RING_VARS;
141
142    ++pVia->curMarker;
143
144    /* Wrap around without affecting the sign bit. */
145    pVia->curMarker &= 0x7FFFFFFF;
146
147    if (pVia->agpDMA) {
148        BEGIN_RING(16);
149        OUT_RING_H1(VIA_REG_KEYCONTROL, 0x00);
150        OUT_RING_H1(VIA_REG_GEMODE, VIA_GEM_32bpp);
151        OUT_RING_H1(VIA_REG_DSTBASE, pVia->markerOffset >> 3);
152        OUT_RING_H1(VIA_REG_PITCH, VIA_PITCH_ENABLE);
153        OUT_RING_H1(VIA_REG_DSTPOS, 0);
154        OUT_RING_H1(VIA_REG_DIMENSION, 0);
155        OUT_RING_H1(VIA_REG_FGCOLOR, pVia->curMarker);
156        OUT_RING_H1(VIA_REG_GECMD, (0xF0 << 24) | VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT);
157
158        ADVANCE_RING;
159    }
160    return pVia->curMarker;
161}
162
163/*
164 * Exa functions. It is assumed that EXA does not exceed the blitter limits.
165 */
166Bool
167viaExaPrepareSolid_H2(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg)
168{
169    ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen);
170    VIAPtr pVia = VIAPTR(pScrn);
171    ViaTwodContext *tdc = &pVia->td;
172
173    RING_VARS;
174
175    if (exaGetPixmapPitch(pPixmap) & 7)
176        return FALSE;
177
178    if (!viaAccelSetMode(pPixmap->drawable.depth, tdc))
179        return FALSE;
180
181    if (!viaAccelPlaneMaskHelper_H2(tdc, planeMask))
182        return FALSE;
183
184    viaAccelTransparentHelper_H2(pVia, 0x0, 0x0, TRUE);
185
186    tdc->cmd = VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT | VIAACCELPATTERNROP(alu);
187
188    tdc->fgColor = fg;
189
190    return TRUE;
191}
192
193void
194viaExaSolid_H2(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
195{
196    ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen);
197    CARD32 dstOffset = exaGetPixmapOffset(pPixmap);
198    CARD32 dstPitch = exaGetPixmapPitch(pPixmap);
199    int w = x2 - x1, h = y2 - y1;
200    VIAPtr pVia = VIAPTR(pScrn);
201    ViaTwodContext *tdc = &pVia->td;
202
203    RING_VARS;
204
205    BEGIN_RING(14);
206    OUT_RING_H1(VIA_REG_GEMODE, tdc->mode);
207    OUT_RING_H1(VIA_REG_DSTBASE, dstOffset >> 3);
208    OUT_RING_H1(VIA_REG_PITCH, VIA_PITCH_ENABLE | (dstPitch >> 3) << 16);
209    OUT_RING_H1(VIA_REG_DSTPOS, (y1 << 16) | (x1 & 0xFFFF));
210    OUT_RING_H1(VIA_REG_DIMENSION, ((h - 1) << 16) | (w - 1));
211    OUT_RING_H1(VIA_REG_FGCOLOR, tdc->fgColor);
212    OUT_RING_H1(VIA_REG_GECMD, tdc->cmd);
213
214    ADVANCE_RING;
215}
216
217void
218viaExaDoneSolidCopy_H2(PixmapPtr pPixmap)
219{
220}
221
222Bool
223viaExaPrepareCopy_H2(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir,
224                        int ydir, int alu, Pixel planeMask)
225{
226    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen);
227    VIAPtr pVia = VIAPTR(pScrn);
228    ViaTwodContext *tdc = &pVia->td;
229
230    RING_VARS;
231
232    if (pSrcPixmap->drawable.bitsPerPixel != pDstPixmap->drawable.bitsPerPixel)
233        return FALSE;
234
235    if ((tdc->srcPitch = exaGetPixmapPitch(pSrcPixmap)) & 3)
236        return FALSE;
237
238    if (exaGetPixmapPitch(pDstPixmap) & 7)
239        return FALSE;
240
241    tdc->srcOffset = exaGetPixmapOffset(pSrcPixmap);
242
243    tdc->cmd = VIA_GEC_BLT | VIAACCELCOPYROP(alu);
244    if (xdir < 0)
245        tdc->cmd |= VIA_GEC_DECX;
246    if (ydir < 0)
247        tdc->cmd |= VIA_GEC_DECY;
248
249    if (!viaAccelSetMode(pDstPixmap->drawable.bitsPerPixel, tdc))
250        return FALSE;
251
252    if (!viaAccelPlaneMaskHelper_H2(tdc, planeMask))
253        return FALSE;
254    viaAccelTransparentHelper_H2(pVia, 0x0, 0x0, TRUE);
255
256    return TRUE;
257}
258
259void
260viaExaCopy_H2(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY,
261                int width, int height)
262{
263    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen);
264    CARD32 dstOffset = exaGetPixmapOffset(pDstPixmap), val;
265    CARD32 dstPitch = exaGetPixmapPitch(pDstPixmap);
266    VIAPtr pVia = VIAPTR(pScrn);
267    ViaTwodContext *tdc = &pVia->td;
268
269    if (!width || !height)
270        return;
271
272    if (tdc->cmd & VIA_GEC_DECY) {
273        srcY += height - 1;
274        dstY += height - 1;
275    }
276
277    if (tdc->cmd & VIA_GEC_DECX) {
278        srcX += width - 1;
279        dstX += width - 1;
280    }
281    val = VIA_PITCH_ENABLE | (dstPitch >> 3) << 16 | (tdc->srcPitch >> 3);
282
283    RING_VARS;
284
285    BEGIN_RING(16);
286    OUT_RING_H1(VIA_REG_GEMODE, tdc->mode);
287    OUT_RING_H1(VIA_REG_SRCBASE, tdc->srcOffset >> 3);
288    OUT_RING_H1(VIA_REG_DSTBASE, dstOffset >> 3);
289    OUT_RING_H1(VIA_REG_PITCH, val);
290    OUT_RING_H1(VIA_REG_SRCPOS, (srcY << 16) | (srcX & 0xFFFF));
291    OUT_RING_H1(VIA_REG_DSTPOS, (dstY << 16) | (dstX & 0xFFFF));
292    OUT_RING_H1(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1));
293    OUT_RING_H1(VIA_REG_GECMD, tdc->cmd);
294
295    ADVANCE_RING;
296}
297
298Bool
299viaExaCheckComposite_H2(int op, PicturePtr pSrcPicture,
300                        PicturePtr pMaskPicture, PicturePtr pDstPicture)
301{
302    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPicture->pDrawable->pScreen);
303    VIAPtr pVia = VIAPTR(pScrn);
304    Via3DState *v3d = &pVia->v3d;
305
306    if (!pSrcPicture->pDrawable)
307        return FALSE;
308
309    /* Reject small composites early. They are done much faster in software. */
310    if (!pSrcPicture->repeat &&
311        pSrcPicture->pDrawable->width *
312        pSrcPicture->pDrawable->height < VIA_MIN_COMPOSITE)
313        return FALSE;
314
315    if (pMaskPicture && pMaskPicture->pDrawable &&
316        !pMaskPicture->repeat &&
317        pMaskPicture->pDrawable->width *
318        pMaskPicture->pDrawable->height < VIA_MIN_COMPOSITE)
319        return FALSE;
320
321    if (pMaskPicture && pMaskPicture->repeat &&
322        pMaskPicture->repeatType != RepeatNormal)
323        return FALSE;
324
325    if (pMaskPicture && pMaskPicture->componentAlpha) {
326#ifdef VIA_DEBUG_COMPOSITE
327        viaExaPrintCompositeInfo("Component Alpha operation", op,  pSrcPicture, pMaskPicture, pDstPicture);
328#endif
329        return FALSE;
330    }
331
332    if (!v3d->opSupported(op)) {
333#ifdef VIA_DEBUG_COMPOSITE
334        viaExaPrintCompositeInfo("Operator not supported", op, pSrcPicture, pMaskPicture, pDstPicture);
335#endif
336        return FALSE;
337    }
338
339    /*
340     * FIXME: A8 destination formats are currently not supported and do not
341     * seem supported by the hardware, although there are some leftover
342     * register settings apparent in the via_3d_reg.h file. We need to fix this
343     * (if important), by using component ARGB8888 operations with bitmask.
344     */
345
346    if (!v3d->dstSupported(pDstPicture->format)) {
347#ifdef VIA_DEBUG_COMPOSITE
348        viaExaPrintCompositeInfo(" Destination format not supported", op, pSrcPicture, pMaskPicture, pDstPicture);
349#endif
350        return FALSE;
351    }
352
353    if (v3d->texSupported(pSrcPicture->format)) {
354        if (pMaskPicture && (PICT_FORMAT_A(pMaskPicture->format) == 0 ||
355                             !v3d->texSupported(pMaskPicture->format))) {
356#ifdef VIA_DEBUG_COMPOSITE
357            viaExaPrintCompositeInfo("Mask format not supported", op, pSrcPicture, pMaskPicture, pDstPicture);
358#endif
359            return FALSE;
360        }
361        return TRUE;
362    }
363#ifdef VIA_DEBUG_COMPOSITE
364    viaExaPrintCompositeInfo("Src format not supported", op, pSrcPicture, pMaskPicture, pDstPicture);
365#endif
366    return FALSE;
367}
368
369static Bool
370viaIsAGP(VIAPtr pVia, PixmapPtr pPix, unsigned long *offset)
371{
372#ifdef HAVE_DRI
373    unsigned long offs;
374
375    if (pVia->directRenderingType && !pVia->IsPCI) {
376        offs = ((unsigned long)pPix->devPrivate.ptr
377                - (unsigned long)pVia->agpMappedAddr);
378
379        if ((offs - pVia->scratchOffset) < pVia->agpSize) {
380            *offset = offs + pVia->agpAddr;
381            return TRUE;
382        }
383    }
384#endif
385    return FALSE;
386}
387
388static Bool
389viaExaIsOffscreen(PixmapPtr pPix)
390{
391    ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen);
392    VIAPtr pVia = VIAPTR(pScrn);
393
394    return ((unsigned long)pPix->devPrivate.ptr -
395            (unsigned long) drm_bo_map(pScrn, pVia->drmmode.front_bo)) < pVia->drmmode.front_bo->size;
396}
397
398Bool
399viaExaPrepareComposite_H2(int op, PicturePtr pSrcPicture,
400                            PicturePtr pMaskPicture, PicturePtr pDstPicture,
401                            PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
402{
403    CARD32 height, width;
404    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
405    VIAPtr pVia = VIAPTR(pScrn);
406    Via3DState *v3d = &pVia->v3d;
407    int curTex = 0;
408    ViaTexBlendingModes srcMode;
409    Bool isAGP;
410    unsigned long offset;
411
412    /* Workaround: EXA crash with new libcairo2 on a VIA VX800 (#298) */
413    /* TODO Add real source only pictures */
414    if (!pSrc) {
415	    ErrorF("pSrc is NULL\n");
416	    return FALSE;
417	}
418
419    v3d->setDestination(v3d, exaGetPixmapOffset(pDst),
420                        exaGetPixmapPitch(pDst), pDstPicture->format);
421    v3d->setCompositeOperator(v3d, op);
422    v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, 0x000000FF, 0xFF);
423
424    viaOrder(pSrc->drawable.width, &width);
425    viaOrder(pSrc->drawable.height, &height);
426
427    /*
428     * For one-pixel repeat mask pictures we avoid using multitexturing by
429     * modifying the src's texture blending equation and feed the pixel
430     * value as a constant alpha for the src's texture. Multitexturing on the
431     * Unichromes seems somewhat slow, so this speeds up translucent windows.
432     */
433
434    srcMode = via_src;
435    pVia->maskP = NULL;
436    if (pMaskPicture &&
437        (pMaskPicture->pDrawable->height == 1) &&
438        (pMaskPicture->pDrawable->width == 1) &&
439        pMaskPicture->repeat && viaExpandablePixel(pMaskPicture->format)) {
440        pVia->maskP = pMask->devPrivate.ptr;
441        pVia->maskFormat = pMaskPicture->format;
442        pVia->componentAlpha = pMaskPicture->componentAlpha;
443        srcMode = ((pMaskPicture->componentAlpha)
444                   ? via_src_onepix_comp_mask : via_src_onepix_mask);
445    }
446
447    /*
448     * One-Pixel repeat src pictures go as solid color instead of textures.
449     * Speeds up window shadows.
450     */
451
452    pVia->srcP = NULL;
453    if (pSrcPicture && pSrcPicture->repeat
454        && (pSrcPicture->pDrawable->height == 1)
455        && (pSrcPicture->pDrawable->width == 1)
456        && viaExpandablePixel(pSrcPicture->format)) {
457        pVia->srcP = pSrc->devPrivate.ptr;
458        pVia->srcFormat = pSrcPicture->format;
459    }
460
461    /* Exa should be smart enough to eliminate this IN operation. */
462    if (pVia->srcP && pVia->maskP) {
463        ErrorF("Bad one-pixel IN composite operation. "
464               "EXA needs to be smarter.\n");
465        return FALSE;
466    }
467
468    if (!pVia->srcP) {
469        offset = exaGetPixmapOffset(pSrc);
470        isAGP = viaIsAGP(pVia, pSrc, &offset);
471        if (!isAGP && !viaExaIsOffscreen(pSrc))
472            return FALSE;
473        if (!v3d->setTexture(v3d, curTex, offset,
474                             exaGetPixmapPitch(pSrc), pVia->nPOT[curTex],
475                             1 << width, 1 << height, pSrcPicture->format,
476                             via_repeat, via_repeat, srcMode, isAGP)) {
477            return FALSE;
478        }
479        curTex++;
480    }
481
482    if (pMaskPicture && !pVia->maskP) {
483        offset = exaGetPixmapOffset(pMask);
484        isAGP = viaIsAGP(pVia, pMask, &offset);
485        if (!isAGP && !viaExaIsOffscreen(pMask))
486            return FALSE;
487        viaOrder(pMask->drawable.width, &width);
488        viaOrder(pMask->drawable.height, &height);
489        if (!v3d->setTexture(v3d, curTex, offset,
490                             exaGetPixmapPitch(pMask), pVia->nPOT[curTex],
491                             1 << width, 1 << height, pMaskPicture->format,
492                             via_repeat, via_repeat,
493                             ((pMaskPicture->componentAlpha)
494                              ? via_comp_mask : via_mask), isAGP)) {
495            return FALSE;
496        }
497        curTex++;
498    }
499
500    v3d->setFlags(v3d, curTex, FALSE, TRUE, TRUE);
501    v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d));
502    v3d->emitClipRect(v3d, &pVia->cb, 0, 0, pDst->drawable.width,
503                      pDst->drawable.height);
504
505    return TRUE;
506}
507
508void
509viaExaComposite_H2(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
510                    int dstX, int dstY, int width, int height)
511{
512    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
513    VIAPtr pVia = VIAPTR(pScrn);
514    Via3DState *v3d = &pVia->v3d;
515    CARD32 col;
516
517    if (pVia->maskP) {
518        viaPixelARGB8888(pVia->maskFormat, pVia->maskP, &col);
519        v3d->setTexBlendCol(v3d, 0, pVia->componentAlpha, col);
520    }
521    if (pVia->srcP) {
522        viaPixelARGB8888(pVia->srcFormat, pVia->srcP, &col);
523        v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, col & 0x00FFFFFF, col >> 24);
524        srcX = maskX;
525        srcY = maskY;
526    }
527
528    if (pVia->maskP || pVia->srcP)
529        v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d));
530
531    v3d->emitQuad(v3d, &pVia->cb, dstX, dstY, srcX, srcY, maskX, maskY,
532                  width, height);
533}
534
535void
536viaAccelTextureBlit(ScrnInfoPtr pScrn, unsigned long srcOffset,
537                    unsigned srcPitch, unsigned w, unsigned h, unsigned srcX,
538                    unsigned srcY, unsigned srcFormat, unsigned long dstOffset,
539                    unsigned dstPitch, unsigned dstX, unsigned dstY,
540                    unsigned dstFormat, int rotate)
541{
542    VIAPtr pVia = VIAPTR(pScrn);
543    CARD32 wOrder, hOrder;
544    Via3DState *v3d = &pVia->v3d;
545
546    viaOrder(w, &wOrder);
547    viaOrder(h, &hOrder);
548
549    v3d->setDestination(v3d, dstOffset, dstPitch, dstFormat);
550    v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, 0x000000FF, 0x00);
551    v3d->setFlags(v3d, 1, TRUE, TRUE, FALSE);
552    v3d->setTexture(v3d, 0, srcOffset, srcPitch, TRUE,
553                    1 << wOrder, 1 << hOrder, srcFormat,
554                    via_single, via_single, via_src, FALSE);
555    v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d));
556    v3d->emitClipRect(v3d, &pVia->cb, dstX, dstY, w, h);
557    v3d->emitQuad(v3d, &pVia->cb, dstX, dstY, srcX, srcY, 0, 0, w, h);
558}
559