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_H6(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_M1,
60                    ((tdc->clipY1 - refY) << 16) | tdc->clipX1);
61        OUT_RING_H1(VIA_REG_CLIPBR_M1,
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_H6(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_H6(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_M1, tdc->keyControl);
123    if (keyControl) {
124        OUT_RING_H1(VIA_REG_SRCCOLORKEY_M1, 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_H6(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
150        OUT_RING_H1(VIA_REG_KEYCONTROL_M1, 0x00);
151        OUT_RING_H1(VIA_REG_GEMODE_M1, VIA_GEM_32bpp);
152        OUT_RING_H1(VIA_REG_DSTBASE_M1, pVia->curMarker >> 3);
153        OUT_RING_H1(VIA_REG_PITCH_M1, 0);
154        OUT_RING_H1(VIA_REG_DSTPOS_M1, 0);
155        OUT_RING_H1(VIA_REG_DIMENSION_M1, 0);
156        OUT_RING_H1(VIA_REG_MONOPATFGC_M1, pVia->curMarker);
157        OUT_RING_H1(VIA_REG_GECMD_M1, (0xF0 << 24) | VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT);
158
159        ADVANCE_RING;
160    }
161    return pVia->curMarker;
162}
163
164/*
165 * Exa functions. It is assumed that EXA does not exceed the blitter limits.
166 */
167Bool
168viaExaPrepareSolid_H6(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg)
169{
170    ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen);
171    VIAPtr pVia = VIAPTR(pScrn);
172    ViaTwodContext *tdc = &pVia->td;
173
174    if (exaGetPixmapPitch(pPixmap) & 7)
175        return FALSE;
176
177    if (!viaAccelSetMode(pPixmap->drawable.depth, tdc))
178        return FALSE;
179
180    if (!viaAccelPlaneMaskHelper_H6(tdc, planeMask))
181        return FALSE;
182
183    viaAccelTransparentHelper_H6(pVia, 0x0, 0x0, TRUE);
184
185    tdc->cmd = VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT | VIAACCELPATTERNROP(alu);
186
187    tdc->fgColor = fg;
188
189    return TRUE;
190}
191
192void
193viaExaSolid_H6(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
194{
195    ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen);
196    CARD32 dstOffset = exaGetPixmapOffset(pPixmap);
197    CARD32 dstPitch = exaGetPixmapPitch(pPixmap);
198    int w = x2 - x1, h = y2 - y1;
199    VIAPtr pVia = VIAPTR(pScrn);
200    ViaTwodContext *tdc = &pVia->td;
201
202    RING_VARS;
203
204    BEGIN_RING(14);
205    OUT_RING_H1(VIA_REG_GEMODE_M1, tdc->mode);
206    OUT_RING_H1(VIA_REG_DSTBASE_M1, dstOffset >> 3);
207    OUT_RING_H1(VIA_REG_PITCH_M1, (dstPitch >> 3) << 16);
208    OUT_RING_H1(VIA_REG_DSTPOS_M1, (y1 << 16) | (x1 & 0xFFFF));
209    OUT_RING_H1(VIA_REG_DIMENSION_M1, ((h - 1) << 16) | (w - 1));
210    OUT_RING_H1(VIA_REG_MONOPATFGC_M1, tdc->fgColor);
211    OUT_RING_H1(VIA_REG_GECMD_M1, tdc->cmd);
212
213    ADVANCE_RING;
214}
215
216void
217viaExaDoneSolidCopy_H6(PixmapPtr pPixmap)
218{
219}
220
221Bool
222viaExaPrepareCopy_H6(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir,
223                        int ydir, int alu, Pixel planeMask)
224{
225    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen);
226    VIAPtr pVia = VIAPTR(pScrn);
227    ViaTwodContext *tdc = &pVia->td;
228
229    if (pSrcPixmap->drawable.bitsPerPixel != pDstPixmap->drawable.bitsPerPixel)
230        return FALSE;
231
232    if ((tdc->srcPitch = exaGetPixmapPitch(pSrcPixmap)) & 3)
233        return FALSE;
234
235    if (exaGetPixmapPitch(pDstPixmap) & 7)
236        return FALSE;
237
238    tdc->srcOffset = exaGetPixmapOffset(pSrcPixmap);
239
240    tdc->cmd = VIA_GEC_BLT | VIAACCELCOPYROP(alu);
241    if (xdir < 0)
242        tdc->cmd |= VIA_GEC_DECX;
243    if (ydir < 0)
244        tdc->cmd |= VIA_GEC_DECY;
245
246    if (!viaAccelSetMode(pDstPixmap->drawable.bitsPerPixel, tdc))
247        return FALSE;
248
249    if (!viaAccelPlaneMaskHelper_H6(tdc, planeMask))
250        return FALSE;
251    viaAccelTransparentHelper_H6(pVia, 0x0, 0x0, TRUE);
252
253    return TRUE;
254}
255
256void
257viaExaCopy_H6(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY,
258                int width, int height)
259{
260    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen);
261    CARD32 dstOffset = exaGetPixmapOffset(pDstPixmap), val;
262    CARD32 dstPitch = exaGetPixmapPitch(pDstPixmap);
263    VIAPtr pVia = VIAPTR(pScrn);
264    ViaTwodContext *tdc = &pVia->td;
265
266    if (!width || !height)
267        return;
268
269    RING_VARS;
270
271    if (tdc->cmd & VIA_GEC_DECY) {
272        srcY += height - 1;
273        dstY += height - 1;
274    }
275
276    if (tdc->cmd & VIA_GEC_DECX) {
277        srcX += width - 1;
278        dstX += width - 1;
279    }
280    val = (dstPitch >> 3) << 16 | (tdc->srcPitch >> 3);
281
282    BEGIN_RING(16);
283    OUT_RING_H1(VIA_REG_GEMODE_M1, tdc->mode);
284    OUT_RING_H1(VIA_REG_SRCBASE_M1, tdc->srcOffset >> 3);
285    OUT_RING_H1(VIA_REG_DSTBASE_M1, dstOffset >> 3);
286    OUT_RING_H1(VIA_REG_PITCH_M1, val);
287
288    OUT_RING_H1(VIA_REG_SRCPOS_M1, (srcY << 16) | (srcX & 0xFFFF));
289    OUT_RING_H1(VIA_REG_DSTPOS_M1, (dstY << 16) | (dstX & 0xFFFF));
290    OUT_RING_H1(VIA_REG_DIMENSION_M1, ((height - 1) << 16) | (width - 1));
291    OUT_RING_H1(VIA_REG_GECMD_M1, tdc->cmd);
292
293    ADVANCE_RING;
294}
295
296Bool
297viaExaCheckComposite_H6(int op, PicturePtr pSrcPicture,
298                        PicturePtr pMaskPicture, PicturePtr pDstPicture)
299{
300    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPicture->pDrawable->pScreen);
301    VIAPtr pVia = VIAPTR(pScrn);
302    Via3DState *v3d = &pVia->v3d;
303
304    if (!pSrcPicture->pDrawable) {
305        return FALSE;
306    }
307    /* Reject small composites early. They are done much faster in software. */
308    if (!pSrcPicture->repeat &&
309        pSrcPicture->pDrawable->width *
310        pSrcPicture->pDrawable->height < VIA_MIN_COMPOSITE) {
311
312#ifdef VIA_DEBUG_COMPOSITE
313        viaExaPrintCompositeInfo("Source picture too small", op,  pSrcPicture, pMaskPicture, pDstPicture);
314#endif
315        return FALSE;
316    }
317
318    if (pMaskPicture && pMaskPicture->pDrawable &&
319        !pMaskPicture->repeat &&
320        pMaskPicture->pDrawable->width *
321        pMaskPicture->pDrawable->height < VIA_MIN_COMPOSITE) {
322#ifdef VIA_DEBUG_COMPOSITE
323        viaExaPrintCompositeInfo("Mask picture too small", op,  pSrcPicture, pMaskPicture, pDstPicture);
324#endif
325        return FALSE;
326    }
327
328    if (pMaskPicture && pMaskPicture->repeat && pMaskPicture->repeatType != RepeatNormal) {
329#ifdef VIA_DEBUG_COMPOSITE
330        viaExaPrintCompositeInfo("Repeat is different than normal", op,  pSrcPicture, pMaskPicture, pDstPicture);
331#endif
332        return FALSE;
333    }
334    if (pMaskPicture && pMaskPicture->componentAlpha) {
335#ifdef VIA_DEBUG_COMPOSITE
336        viaExaPrintCompositeInfo("Component Alpha operation", op,  pSrcPicture, pMaskPicture, pDstPicture);
337#endif
338        return FALSE;
339    }
340
341    if (!v3d->opSupported(op)) {
342#ifdef VIA_DEBUG_COMPOSITE
343        viaExaPrintCompositeInfo("Operator not supported", op, pSrcPicture, pMaskPicture, pDstPicture);
344#endif
345        return FALSE;
346    }
347
348    /*
349     * FIXME: A8 destination formats are currently not supported and do not
350     * seem supported by the hardware, although there are some leftover
351     * register settings apparent in the via_3d_reg.h file. We need to fix this
352     * (if important), by using component ARGB8888 operations with bitmask.
353     */
354
355    if (!v3d->dstSupported(pDstPicture->format)) {
356#ifdef VIA_DEBUG_COMPOSITE
357        viaExaPrintCompositeInfo("Destination format not supported", op, pSrcPicture, pMaskPicture, pDstPicture);
358#endif
359        return FALSE;
360    }
361
362    if (v3d->texSupported(pSrcPicture->format)) {
363        if (pMaskPicture && (PICT_FORMAT_A(pMaskPicture->format) == 0 ||
364                             !v3d->texSupported(pMaskPicture->format))) {
365#ifdef VIA_DEBUG_COMPOSITE
366            viaExaPrintCompositeInfo("Mask format not supported", op, pSrcPicture, pMaskPicture, pDstPicture);
367#endif
368            return FALSE;
369        }
370        return TRUE;
371    }
372#ifdef VIA_DEBUG_COMPOSITE
373    viaExaPrintCompositeInfo("Src format not supported",op, pSrcPicture, pMaskPicture, pDstPicture);
374#endif
375    return FALSE;
376}
377
378static Bool
379viaIsAGP(VIAPtr pVia, PixmapPtr pPix, unsigned long *offset)
380{
381#ifdef HAVE_DRI
382    unsigned long offs;
383
384    if (pVia->directRenderingType && !pVia->IsPCI) {
385        offs = ((unsigned long)pPix->devPrivate.ptr
386                - (unsigned long)pVia->agpMappedAddr);
387
388        if ((offs - pVia->scratchOffset) < pVia->agpSize) {
389            *offset = offs + pVia->agpAddr;
390            return TRUE;
391        }
392    }
393#endif
394    return FALSE;
395}
396
397static Bool
398viaExaIsOffscreen(PixmapPtr pPix)
399{
400    ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen);
401    VIAPtr pVia = VIAPTR(pScrn);
402
403    return ((unsigned long)pPix->devPrivate.ptr -
404            (unsigned long) drm_bo_map(pScrn, pVia->drmmode.front_bo)) < pVia->drmmode.front_bo->size;
405}
406
407Bool
408viaExaPrepareComposite_H6(int op, PicturePtr pSrcPicture,
409                            PicturePtr pMaskPicture, PicturePtr pDstPicture,
410                            PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
411{
412    CARD32 height, width;
413    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
414    VIAPtr pVia = VIAPTR(pScrn);
415    Via3DState *v3d = &pVia->v3d;
416    int curTex = 0;
417    ViaTexBlendingModes srcMode;
418    Bool isAGP;
419    unsigned long offset;
420
421    /* Workaround: EXA crash with new libcairo2 on a VIA VX800 (#298) */
422    /* TODO Add real source only pictures */
423    if (!pSrc) {
424	    ErrorF("pSrc is NULL\n");
425	    return FALSE;
426	}
427
428    v3d->setDestination(v3d, exaGetPixmapOffset(pDst),
429                        exaGetPixmapPitch(pDst), pDstPicture->format);
430    v3d->setCompositeOperator(v3d, op);
431    v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, 0x000000FF, 0xFF);
432
433    viaOrder(pSrc->drawable.width, &width);
434    viaOrder(pSrc->drawable.height, &height);
435
436    /*
437     * For one-pixel repeat mask pictures we avoid using multitexturing by
438     * modifying the src's texture blending equation and feed the pixel
439     * value as a constant alpha for the src's texture. Multitexturing on the
440     * Unichromes seems somewhat slow, so this speeds up translucent windows.
441     */
442
443    srcMode = via_src;
444    pVia->maskP = NULL;
445    if (pMaskPicture &&
446        (pMaskPicture->pDrawable->height == 1) &&
447        (pMaskPicture->pDrawable->width == 1) &&
448        pMaskPicture->repeat && viaExpandablePixel(pMaskPicture->format)) {
449        pVia->maskP = pMask->devPrivate.ptr;
450        pVia->maskFormat = pMaskPicture->format;
451        pVia->componentAlpha = pMaskPicture->componentAlpha;
452        srcMode = ((pMaskPicture->componentAlpha)
453                   ? via_src_onepix_comp_mask : via_src_onepix_mask);
454    }
455
456    /*
457     * One-Pixel repeat src pictures go as solid color instead of textures.
458     * Speeds up window shadows.
459     */
460
461    pVia->srcP = NULL;
462    if (pSrcPicture && pSrcPicture->repeat
463        && (pSrcPicture->pDrawable->height == 1)
464        && (pSrcPicture->pDrawable->width == 1)
465        && viaExpandablePixel(pSrcPicture->format)) {
466        pVia->srcP = pSrc->devPrivate.ptr;
467        pVia->srcFormat = pSrcPicture->format;
468    }
469
470    /* Exa should be smart enough to eliminate this IN operation. */
471    if (pVia->srcP && pVia->maskP) {
472        ErrorF("Bad one-pixel IN composite operation. "
473               "EXA needs to be smarter.\n");
474        return FALSE;
475    }
476
477    if (!pVia->srcP) {
478        offset = exaGetPixmapOffset(pSrc);
479        isAGP = viaIsAGP(pVia, pSrc, &offset);
480        if (!isAGP && !viaExaIsOffscreen(pSrc))
481            return FALSE;
482        if (!v3d->setTexture(v3d, curTex, offset,
483                             exaGetPixmapPitch(pSrc), pVia->nPOT[curTex],
484                             1 << width, 1 << height, pSrcPicture->format,
485                             via_repeat, via_repeat, srcMode, isAGP)) {
486            return FALSE;
487        }
488        curTex++;
489    }
490
491    if (pMaskPicture && !pVia->maskP) {
492        offset = exaGetPixmapOffset(pMask);
493        isAGP = viaIsAGP(pVia, pMask, &offset);
494        if (!isAGP && !viaExaIsOffscreen(pMask))
495            return FALSE;
496        viaOrder(pMask->drawable.width, &width);
497        viaOrder(pMask->drawable.height, &height);
498        if (!v3d->setTexture(v3d, curTex, offset,
499                             exaGetPixmapPitch(pMask), pVia->nPOT[curTex],
500                             1 << width, 1 << height, pMaskPicture->format,
501                             via_repeat, via_repeat,
502                             ((pMaskPicture->componentAlpha)
503                              ? via_comp_mask : via_mask), isAGP)) {
504            return FALSE;
505        }
506        curTex++;
507    }
508
509    v3d->setFlags(v3d, curTex, FALSE, TRUE, TRUE);
510    v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d));
511    v3d->emitClipRect(v3d, &pVia->cb, 0, 0, pDst->drawable.width,
512                      pDst->drawable.height);
513
514    return TRUE;
515}
516
517void
518viaExaComposite_H6(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
519                    int dstX, int dstY, int width, int height)
520{
521    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
522    VIAPtr pVia = VIAPTR(pScrn);
523    Via3DState *v3d = &pVia->v3d;
524    CARD32 col;
525
526    if (pVia->maskP) {
527        viaPixelARGB8888(pVia->maskFormat, pVia->maskP, &col);
528        v3d->setTexBlendCol(v3d, 0, pVia->componentAlpha, col);
529    }
530    if (pVia->srcP) {
531        viaPixelARGB8888(pVia->srcFormat, pVia->srcP, &col);
532        v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, col & 0x00FFFFFF, col >> 24);
533        srcX = maskX;
534        srcY = maskY;
535    }
536
537    if (pVia->maskP || pVia->srcP)
538        v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d));
539
540    v3d->emitQuad(v3d, &pVia->cb, dstX, dstY, srcX, srcY, maskX, maskY,
541                  width, height);
542}
543