via_exa.c revision 963d66ac
190b17f1bSmrg/*
290b17f1bSmrg * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
390b17f1bSmrg * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
490b17f1bSmrg * Copyright 2006 Thomas Hellström. All Rights Reserved.
590b17f1bSmrg *
690b17f1bSmrg * Permission is hereby granted, free of charge, to any person obtaining a
790b17f1bSmrg * copy of this software and associated documentation files (the "Software"),
890b17f1bSmrg * to deal in the Software without restriction, including without limitation
990b17f1bSmrg * the rights to use, copy, modify, merge, publish, distribute, sub license,
1090b17f1bSmrg * and/or sell copies of the Software, and to permit persons to whom the
1190b17f1bSmrg * Software is furnished to do so, subject to the following conditions:
1290b17f1bSmrg *
1390b17f1bSmrg * The above copyright notice and this permission notice (including the
1490b17f1bSmrg * next paragraph) shall be included in all copies or substantial portions
1590b17f1bSmrg * of the Software.
1690b17f1bSmrg *
1790b17f1bSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1890b17f1bSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1990b17f1bSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2090b17f1bSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2190b17f1bSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2290b17f1bSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2390b17f1bSmrg * DEALINGS IN THE SOFTWARE.
2490b17f1bSmrg */
2590b17f1bSmrg
2690b17f1bSmrg/*
2790b17f1bSmrg * 2D acceleration functions for the VIA/S3G UniChrome IGPs.
2890b17f1bSmrg *
2990b17f1bSmrg * Mostly rewritten, and modified for EXA support, by Thomas Hellström.
3090b17f1bSmrg */
3190b17f1bSmrg
3290b17f1bSmrg#ifdef HAVE_CONFIG_H
3390b17f1bSmrg#include "config.h"
3490b17f1bSmrg#endif
3590b17f1bSmrg
3690b17f1bSmrg#include <X11/Xarch.h>
3790b17f1bSmrg#include "miline.h"
3890b17f1bSmrg
3990b17f1bSmrg#include <GL/gl.h>
4090b17f1bSmrg#include <sys/mman.h>
4190b17f1bSmrg
4290b17f1bSmrg#include "via_driver.h"
4390b17f1bSmrg#include "via_regs.h"
4490b17f1bSmrg#include "via_dmabuffer.h"
4590b17f1bSmrg#include "via_rop.h"
4690b17f1bSmrg
4790b17f1bSmrg/*
4890b17f1bSmrg * Use PCI MMIO to flush the command buffer when AGP DMA is not available.
4990b17f1bSmrg */
5090b17f1bSmrgstatic void
5190b17f1bSmrgviaDumpDMA(ViaCommandBuffer *cb)
5290b17f1bSmrg{
5390b17f1bSmrg    register CARD32 *bp = cb->buf;
5490b17f1bSmrg    CARD32 *endp = bp + cb->pos;
5590b17f1bSmrg
5690b17f1bSmrg    while (bp != endp) {
5790b17f1bSmrg        if (((bp - cb->buf) & 3) == 0) {
5890b17f1bSmrg            ErrorF("\n %04lx: ", (unsigned long)(bp - cb->buf));
5990b17f1bSmrg        }
6090b17f1bSmrg        ErrorF("0x%08x ", (unsigned)*bp++);
6190b17f1bSmrg    }
6290b17f1bSmrg    ErrorF("\n");
6390b17f1bSmrg}
6490b17f1bSmrg
6590b17f1bSmrgvoid
6690b17f1bSmrgviaFlushPCI(ViaCommandBuffer *cb)
6790b17f1bSmrg{
6890b17f1bSmrg    register CARD32 *bp = cb->buf;
6990b17f1bSmrg    CARD32 transSetting;
7090b17f1bSmrg    CARD32 *endp = bp + cb->pos;
7190b17f1bSmrg    unsigned loop = 0;
7290b17f1bSmrg    register CARD32 offset = 0;
7390b17f1bSmrg    register CARD32 value;
7490b17f1bSmrg    VIAPtr pVia = VIAPTR(cb->pScrn);
7590b17f1bSmrg
7690b17f1bSmrg    while (bp < endp) {
7790b17f1bSmrg        if (*bp == HALCYON_HEADER2) {
7890b17f1bSmrg            if (++bp == endp)
7990b17f1bSmrg                return;
8090b17f1bSmrg            VIASETREG(VIA_REG_TRANSET, transSetting = *bp++);
8190b17f1bSmrg            while (bp < endp) {
8290b17f1bSmrg                if ((transSetting != HC_ParaType_CmdVdata)
8390b17f1bSmrg                    && ((*bp == HALCYON_HEADER2)
8490b17f1bSmrg                        || (*bp & HALCYON_HEADER1MASK) == HALCYON_HEADER1))
8590b17f1bSmrg                    break;
8690b17f1bSmrg                VIASETREG(VIA_REG_TRANSPACE, *bp++);
8790b17f1bSmrg            }
8890b17f1bSmrg        } else if ((*bp & HALCYON_HEADER1MASK) == HALCYON_HEADER1) {
8990b17f1bSmrg
9090b17f1bSmrg            while (bp < endp) {
9190b17f1bSmrg                if (*bp == HALCYON_HEADER2)
9290b17f1bSmrg                    break;
9390b17f1bSmrg                if (offset == 0) {
9490b17f1bSmrg                    /*
9590b17f1bSmrg                     * Not doing this wait will probably stall the processor
9690b17f1bSmrg                     * for an unacceptable amount of time in VIASETREG while
9790b17f1bSmrg                     * other high priority interrupts may be pending.
9890b17f1bSmrg                     */
9990b17f1bSmrg                    switch (pVia->Chipset) {
10090b17f1bSmrg                    case VIA_VX800:
10190b17f1bSmrg                    case VIA_VX855:
10290b17f1bSmrg                    case VIA_VX900:
10390b17f1bSmrg                        while ((VIAGETREG(VIA_REG_STATUS) &
10490b17f1bSmrg                                (VIA_CMD_RGTR_BUSY_H5 | VIA_2D_ENG_BUSY_H5)) &&
10590b17f1bSmrg                                (loop++ < MAXLOOP)) ;
10690b17f1bSmrg                        break;
10790b17f1bSmrg
10890b17f1bSmrg                    case VIA_P4M890:
109963d66acSmrg                    case VIA_K8M890:
11090b17f1bSmrg                    case VIA_P4M900:
11190b17f1bSmrg                        while ((VIAGETREG(VIA_REG_STATUS) &
11290b17f1bSmrg                                (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY)) &&
11390b17f1bSmrg                                (loop++ < MAXLOOP)) ;
11490b17f1bSmrg                        break;
11590b17f1bSmrg
11690b17f1bSmrg                    default:
11790b17f1bSmrg                        while (!(VIAGETREG(VIA_REG_STATUS) & VIA_VR_QUEUE_EMPTY) &&
11890b17f1bSmrg                                (loop++ < MAXLOOP)) ;
11990b17f1bSmrg                        while ((VIAGETREG(VIA_REG_STATUS) &
12090b17f1bSmrg                                (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY)) &&
12190b17f1bSmrg                                (loop++ < MAXLOOP)) ;
12290b17f1bSmrg                    }
12390b17f1bSmrg                }
12490b17f1bSmrg                offset = (*bp++ & 0x0FFFFFFF) << 2;
12590b17f1bSmrg                value = *bp++;
12690b17f1bSmrg                VIASETREG(offset, value);
12790b17f1bSmrg            }
12890b17f1bSmrg        } else {
12990b17f1bSmrg            ErrorF("Command stream parser error.\n");
13090b17f1bSmrg        }
13190b17f1bSmrg    }
13290b17f1bSmrg    cb->pos = 0;
13390b17f1bSmrg    cb->mode = 0;
13490b17f1bSmrg    cb->has3dState = FALSE;
13590b17f1bSmrg}
13690b17f1bSmrg
13790b17f1bSmrg#ifdef HAVE_DRI
13890b17f1bSmrg/*
13990b17f1bSmrg * Flush the command buffer using DRM. If in PCI mode, we can bypass DRM,
14090b17f1bSmrg * but not for command buffers that contain 3D engine state, since then
14190b17f1bSmrg * the DRM command verifier will lose track of the 3D engine state.
14290b17f1bSmrg */
14390b17f1bSmrgstatic void
14490b17f1bSmrgviaFlushDRIEnabled(ViaCommandBuffer *cb)
14590b17f1bSmrg{
14690b17f1bSmrg    ScrnInfoPtr pScrn = cb->pScrn;
14790b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
14890b17f1bSmrg    char *tmp = (char *)cb->buf;
14990b17f1bSmrg    int tmpSize;
15090b17f1bSmrg    drm_via_cmdbuffer_t b;
15190b17f1bSmrg
15290b17f1bSmrg    /* Align end of command buffer for AGP DMA. */
15390b17f1bSmrg    OUT_RING_H1(0x2f8, 0x67676767);
15490b17f1bSmrg    if (pVia->agpDMA && cb->mode == 2 && cb->rindex != HC_ParaType_CmdVdata
15590b17f1bSmrg        && (cb->pos & 1)) {
15690b17f1bSmrg        OUT_RING(HC_DUMMY);
15790b17f1bSmrg    }
15890b17f1bSmrg
15990b17f1bSmrg    tmpSize = cb->pos * sizeof(CARD32);
16090b17f1bSmrg    if (pVia->agpDMA || (pVia->directRenderingType && cb->has3dState)) {
16190b17f1bSmrg        cb->mode = 0;
16290b17f1bSmrg        cb->has3dState = FALSE;
16390b17f1bSmrg        while (tmpSize > 0) {
16490b17f1bSmrg            b.size = (tmpSize > VIA_DMASIZE) ? VIA_DMASIZE : tmpSize;
16590b17f1bSmrg            tmpSize -= b.size;
16690b17f1bSmrg            b.buf = tmp;
16790b17f1bSmrg            tmp += b.size;
16890b17f1bSmrg            if (drmCommandWrite(pVia->drmmode.fd, ((pVia->agpDMA)
16990b17f1bSmrg                                              ? DRM_VIA_CMDBUFFER :
17090b17f1bSmrg                                              DRM_VIA_PCICMD), &b, sizeof(b))) {
17190b17f1bSmrg                ErrorF("DRM command buffer submission failed.\n");
17290b17f1bSmrg                viaDumpDMA(cb);
17390b17f1bSmrg                return;
17490b17f1bSmrg            }
17590b17f1bSmrg        }
17690b17f1bSmrg        cb->pos = 0;
17790b17f1bSmrg    } else {
17890b17f1bSmrg        viaFlushPCI(cb);
17990b17f1bSmrg    }
18090b17f1bSmrg}
18190b17f1bSmrg#endif
18290b17f1bSmrg
18390b17f1bSmrg/*
18490b17f1bSmrg * Initialize a command buffer. Some fields are currently not used since they
18590b17f1bSmrg * are intended for Unichrome Pro group A video commands.
18690b17f1bSmrg */
18790b17f1bSmrgstatic int
18890b17f1bSmrgviaSetupCBuffer(ScrnInfoPtr pScrn, ViaCommandBuffer *cb, unsigned size)
18990b17f1bSmrg{
19090b17f1bSmrg#ifdef HAVE_DRI
19190b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
19290b17f1bSmrg#endif
19390b17f1bSmrg
19490b17f1bSmrg    cb->pScrn = pScrn;
19590b17f1bSmrg    cb->bufSize = ((size == 0) ? VIA_DMASIZE : size) >> 2;
19690b17f1bSmrg    cb->buf = (CARD32 *) calloc(cb->bufSize, sizeof(CARD32));
19790b17f1bSmrg    if (!cb->buf)
19890b17f1bSmrg        return BadAlloc;
19990b17f1bSmrg    cb->waitFlags = 0;
20090b17f1bSmrg    cb->pos = 0;
20190b17f1bSmrg    cb->mode = 0;
20290b17f1bSmrg    cb->header_start = 0;
20390b17f1bSmrg    cb->rindex = 0;
20490b17f1bSmrg    cb->has3dState = FALSE;
20590b17f1bSmrg    cb->flushFunc = viaFlushPCI;
20690b17f1bSmrg#ifdef HAVE_DRI
20790b17f1bSmrg    if (pVia->directRenderingType == DRI_1) {
20890b17f1bSmrg        cb->flushFunc = viaFlushDRIEnabled;
20990b17f1bSmrg    }
21090b17f1bSmrg#endif
21190b17f1bSmrg    return Success;
21290b17f1bSmrg}
21390b17f1bSmrg
21490b17f1bSmrg/*
21590b17f1bSmrg * Free resources associated with a command buffer.
21690b17f1bSmrg */
21790b17f1bSmrgstatic void
21890b17f1bSmrgviaTearDownCBuffer(ViaCommandBuffer *cb)
21990b17f1bSmrg{
220963d66acSmrg    if (cb && cb->buf) {
22190b17f1bSmrg        free(cb->buf);
222963d66acSmrg        cb->buf = NULL;
223963d66acSmrg    }
22490b17f1bSmrg}
22590b17f1bSmrg
22690b17f1bSmrg/*
22790b17f1bSmrg * Update our 2D state (TwoDContext) with a new mode.
22890b17f1bSmrg */
22990b17f1bSmrgBool
23090b17f1bSmrgviaAccelSetMode(int bpp, ViaTwodContext * tdc)
23190b17f1bSmrg{
23290b17f1bSmrg    switch (bpp) {
23390b17f1bSmrg    case 16:
23490b17f1bSmrg        tdc->mode = VIA_GEM_16bpp;
23590b17f1bSmrg        tdc->bytesPPShift = 1;
23690b17f1bSmrg        return TRUE;
23790b17f1bSmrg    case 32:
23890b17f1bSmrg        tdc->mode = VIA_GEM_32bpp;
23990b17f1bSmrg        tdc->bytesPPShift = 2;
24090b17f1bSmrg        return TRUE;
24190b17f1bSmrg    case 8:
24290b17f1bSmrg        tdc->mode = VIA_GEM_8bpp;
24390b17f1bSmrg        tdc->bytesPPShift = 0;
24490b17f1bSmrg        return TRUE;
24590b17f1bSmrg    default:
24690b17f1bSmrg        tdc->bytesPPShift = 0;
24790b17f1bSmrg        return FALSE;
24890b17f1bSmrg    }
24990b17f1bSmrg}
25090b17f1bSmrg
25190b17f1bSmrg/*
25290b17f1bSmrg * Switch 2D state clipping on.
25390b17f1bSmrg */
25490b17f1bSmrgvoid
25590b17f1bSmrgviaSetClippingRectangle(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2)
25690b17f1bSmrg{
25790b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
25890b17f1bSmrg    ViaTwodContext *tdc = &pVia->td;
25990b17f1bSmrg
26090b17f1bSmrg    tdc->clipping = TRUE;
26190b17f1bSmrg    tdc->clipX1 = (x1 & 0xFFFF);
26290b17f1bSmrg    tdc->clipY1 = y1;
26390b17f1bSmrg    tdc->clipX2 = (x2 & 0xFFFF);
26490b17f1bSmrg    tdc->clipY2 = y2;
26590b17f1bSmrg}
26690b17f1bSmrg
26790b17f1bSmrg/*
26890b17f1bSmrg * Check if we need to force upload of the whole 3D state (when other
26990b17f1bSmrg * clients or subsystems have touched the 3D engine). Also tell DRI
27090b17f1bSmrg * clients and subsystems that we have touched the 3D engine.
27190b17f1bSmrg */
27290b17f1bSmrgBool
27390b17f1bSmrgviaCheckUpload(ScrnInfoPtr pScrn, Via3DState * v3d)
27490b17f1bSmrg{
27590b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
27690b17f1bSmrg    Bool forceUpload;
27790b17f1bSmrg
27890b17f1bSmrg    forceUpload = (pVia->lastToUpload != v3d);
27990b17f1bSmrg    pVia->lastToUpload = v3d;
28090b17f1bSmrg
28190b17f1bSmrg#ifdef HAVE_DRI
28290b17f1bSmrg    if (pVia->directRenderingType == DRI_1) {
28390b17f1bSmrg        volatile drm_via_sarea_t *saPriv = (drm_via_sarea_t *)
28490b17f1bSmrg                DRIGetSAREAPrivate(pScrn->pScreen);
28590b17f1bSmrg        int myContext = DRIGetContext(pScrn->pScreen);
28690b17f1bSmrg
28790b17f1bSmrg        forceUpload = forceUpload || (saPriv->ctxOwner != myContext);
28890b17f1bSmrg        saPriv->ctxOwner = myContext;
28990b17f1bSmrg    }
29090b17f1bSmrg#endif
29190b17f1bSmrg    return forceUpload;
29290b17f1bSmrg}
29390b17f1bSmrg
29490b17f1bSmrgBool
29590b17f1bSmrgviaOrder(CARD32 val, CARD32 * shift)
29690b17f1bSmrg{
29790b17f1bSmrg    *shift = 0;
29890b17f1bSmrg
29990b17f1bSmrg    while (val > (1 << *shift))
30090b17f1bSmrg        (*shift)++;
30190b17f1bSmrg    return (val == (1 << *shift));
30290b17f1bSmrg}
30390b17f1bSmrg
30490b17f1bSmrg/*
30590b17f1bSmrg * Helper for bitdepth expansion.
30690b17f1bSmrg */
30790b17f1bSmrgCARD32
30890b17f1bSmrgviaBitExpandHelper(CARD32 pixel, CARD32 bits)
30990b17f1bSmrg{
31090b17f1bSmrg    CARD32 component, mask, tmp;
31190b17f1bSmrg
31290b17f1bSmrg    component = pixel & ((1 << bits) - 1);
31390b17f1bSmrg    mask = (1 << (8 - bits)) - 1;
31490b17f1bSmrg    tmp = component << (8 - bits);
31590b17f1bSmrg    return ((component & 1) ? (tmp | mask) : tmp);
31690b17f1bSmrg}
31790b17f1bSmrg
31890b17f1bSmrg/*
31990b17f1bSmrg * Extract the components from a pixel of the given format to an argb8888 pixel. * This is used to extract data from one-pixel repeat pixmaps.
32090b17f1bSmrg * Assumes little endian.
32190b17f1bSmrg */
32290b17f1bSmrgvoid
32390b17f1bSmrgviaPixelARGB8888(unsigned format, void *pixelP, CARD32 * argb8888)
32490b17f1bSmrg{
32590b17f1bSmrg    CARD32 bits, shift, pixel, bpp;
32690b17f1bSmrg
32790b17f1bSmrg    bpp = PICT_FORMAT_BPP(format);
32890b17f1bSmrg
32990b17f1bSmrg    if (bpp <= 8) {
33090b17f1bSmrg        pixel = *((CARD8 *) pixelP);
33190b17f1bSmrg    } else if (bpp <= 16) {
33290b17f1bSmrg        pixel = *((CARD16 *) pixelP);
33390b17f1bSmrg    } else {
33490b17f1bSmrg        pixel = *((CARD32 *) pixelP);
33590b17f1bSmrg    }
33690b17f1bSmrg
33790b17f1bSmrg    switch (PICT_FORMAT_TYPE(format)) {
33890b17f1bSmrg        case PICT_TYPE_A:
33990b17f1bSmrg            bits = PICT_FORMAT_A(format);
34090b17f1bSmrg            *argb8888 = viaBitExpandHelper(pixel, bits) << 24;
34190b17f1bSmrg            return;
34290b17f1bSmrg        case PICT_TYPE_ARGB:
34390b17f1bSmrg            shift = 0;
34490b17f1bSmrg            bits = PICT_FORMAT_B(format);
34590b17f1bSmrg            *argb8888 = viaBitExpandHelper(pixel, bits);
34690b17f1bSmrg            shift += bits;
34790b17f1bSmrg            bits = PICT_FORMAT_G(format);
34890b17f1bSmrg            *argb8888 |= viaBitExpandHelper(pixel >> shift, bits) << 8;
34990b17f1bSmrg            shift += bits;
35090b17f1bSmrg            bits = PICT_FORMAT_R(format);
35190b17f1bSmrg            *argb8888 |= viaBitExpandHelper(pixel >> shift, bits) << 16;
35290b17f1bSmrg            shift += bits;
35390b17f1bSmrg            bits = PICT_FORMAT_A(format);
35490b17f1bSmrg            *argb8888 |= ((bits) ? viaBitExpandHelper(pixel >> shift,
35590b17f1bSmrg                                                      bits) : 0xFF) << 24;
35690b17f1bSmrg            return;
35790b17f1bSmrg        case PICT_TYPE_ABGR:
35890b17f1bSmrg            shift = 0;
35990b17f1bSmrg            bits = PICT_FORMAT_B(format);
36090b17f1bSmrg            *argb8888 = viaBitExpandHelper(pixel, bits) << 16;
36190b17f1bSmrg            shift += bits;
36290b17f1bSmrg            bits = PICT_FORMAT_G(format);
36390b17f1bSmrg            *argb8888 |= viaBitExpandHelper(pixel >> shift, bits) << 8;
36490b17f1bSmrg            shift += bits;
36590b17f1bSmrg            bits = PICT_FORMAT_R(format);
36690b17f1bSmrg            *argb8888 |= viaBitExpandHelper(pixel >> shift, bits);
36790b17f1bSmrg            shift += bits;
36890b17f1bSmrg            bits = PICT_FORMAT_A(format);
36990b17f1bSmrg            *argb8888 |= ((bits) ? viaBitExpandHelper(pixel >> shift,
37090b17f1bSmrg                                                      bits) : 0xFF) << 24;
37190b17f1bSmrg            return;
37290b17f1bSmrg        default:
37390b17f1bSmrg            break;
37490b17f1bSmrg    }
37590b17f1bSmrg    return;
37690b17f1bSmrg}
37790b17f1bSmrg
37890b17f1bSmrgBool
37990b17f1bSmrgviaExpandablePixel(int format)
38090b17f1bSmrg{
38190b17f1bSmrg    int formatType = PICT_FORMAT_TYPE(format);
38290b17f1bSmrg
38390b17f1bSmrg    return (formatType == PICT_TYPE_A ||
38490b17f1bSmrg            formatType == PICT_TYPE_ABGR || formatType == PICT_TYPE_ARGB);
38590b17f1bSmrg}
38690b17f1bSmrg
38790b17f1bSmrg#ifdef VIA_DEBUG_COMPOSITE
38890b17f1bSmrgvoid
38990b17f1bSmrgviaExaCompositePictDesc(PicturePtr pict, char *string, int n)
39090b17f1bSmrg{
39190b17f1bSmrg    char format[20];
39290b17f1bSmrg    char size[20];
39390b17f1bSmrg
39490b17f1bSmrg    if (!pict) {
39590b17f1bSmrg        snprintf(string, n, "None");
39690b17f1bSmrg        return;
39790b17f1bSmrg    }
39890b17f1bSmrg
39990b17f1bSmrg    switch (pict->format) {
40090b17f1bSmrg        case PICT_x8r8g8b8:
40190b17f1bSmrg            snprintf(format, 20, "RGB8888");
40290b17f1bSmrg            break;
40390b17f1bSmrg        case PICT_a8r8g8b8:
40490b17f1bSmrg            snprintf(format, 20, "ARGB8888");
40590b17f1bSmrg            break;
40690b17f1bSmrg        case PICT_r5g6b5:
40790b17f1bSmrg            snprintf(format, 20, "RGB565  ");
40890b17f1bSmrg            break;
40990b17f1bSmrg        case PICT_x1r5g5b5:
41090b17f1bSmrg            snprintf(format, 20, "RGB555  ");
41190b17f1bSmrg            break;
41290b17f1bSmrg        case PICT_a8:
41390b17f1bSmrg            snprintf(format, 20, "A8      ");
41490b17f1bSmrg            break;
41590b17f1bSmrg        case PICT_a1:
41690b17f1bSmrg            snprintf(format, 20, "A1      ");
41790b17f1bSmrg            break;
41890b17f1bSmrg        default:
41990b17f1bSmrg            snprintf(format, 20, "0x%x", (int)pict->format);
42090b17f1bSmrg            break;
42190b17f1bSmrg    }
42290b17f1bSmrg
42390b17f1bSmrg    if (pict->pDrawable) {
42490b17f1bSmrg       snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
42590b17f1bSmrg                pict->pDrawable->height, pict->repeat ? " R" : "");
42690b17f1bSmrg
42790b17f1bSmrg       snprintf(string, n, "0x%lx: fmt %s (%s)", (long)pict->pDrawable, format,
42890b17f1bSmrg                size);
42990b17f1bSmrg    }
43090b17f1bSmrg}
43190b17f1bSmrg
43290b17f1bSmrgvoid
43390b17f1bSmrgviaExaPrintCompositeInfo(char *info, CARD8 op, PicturePtr pSrc, PicturePtr pMask,
43490b17f1bSmrg                        PicturePtr pDst)
43590b17f1bSmrg{
43690b17f1bSmrg    char sop[20];
43790b17f1bSmrg    char srcdesc[40], maskdesc[40], dstdesc[40];
43890b17f1bSmrg
43990b17f1bSmrg    switch (op) {
44090b17f1bSmrg	case PictOpClear:
44190b17f1bSmrg		sprintf(sop, "PictOpClear ");
44290b17f1bSmrg		break;
44390b17f1bSmrg	case PictOpSrc:
44490b17f1bSmrg		sprintf(sop, "PictOpSrc ");
44590b17f1bSmrg		break;
44690b17f1bSmrg	case PictOpDst:
44790b17f1bSmrg		sprintf(sop, "PictOpDst ");
44890b17f1bSmrg		break;
44990b17f1bSmrg	case PictOpOver:
45090b17f1bSmrg		sprintf(sop, "PictOpOver ");
45190b17f1bSmrg		break;
45290b17f1bSmrg	case PictOpOutReverse:
45390b17f1bSmrg		sprintf(sop, "PictOpOutReverse ");
45490b17f1bSmrg		break;
45590b17f1bSmrg	case PictOpAdd:
45690b17f1bSmrg		sprintf(sop, "PictOpAdd ");
45790b17f1bSmrg		break;
45890b17f1bSmrg	default:
45990b17f1bSmrg		sprintf(sop, "PictOp%d ", op);
46090b17f1bSmrg    }
46190b17f1bSmrg
46290b17f1bSmrg    viaExaCompositePictDesc(pSrc, srcdesc, 40);
46390b17f1bSmrg    viaExaCompositePictDesc(pMask, maskdesc, 40);
46490b17f1bSmrg    viaExaCompositePictDesc(pDst, dstdesc, 40);
46590b17f1bSmrg
46690b17f1bSmrg    ErrorF("Composite fallback: %s, \n"
46790b17f1bSmrg           "                    op %s, \n"
46890b17f1bSmrg           "                    src  %s, \n"
46990b17f1bSmrg           "                    mask %s, \n"
47090b17f1bSmrg           "                    dst  %s, \n", info, sop, srcdesc, maskdesc, dstdesc);
47190b17f1bSmrg}
47290b17f1bSmrg#endif /* VIA_DEBUG_COMPOSITE */
47390b17f1bSmrg
47490b17f1bSmrg/*
47590b17f1bSmrg * Wait for acceleration engines idle. An expensive way to sync.
47690b17f1bSmrg */
47790b17f1bSmrgvoid
47890b17f1bSmrgviaAccelSync(ScrnInfoPtr pScrn)
47990b17f1bSmrg{
48090b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
48190b17f1bSmrg    int loop = 0;
48290b17f1bSmrg
48390b17f1bSmrg    mem_barrier();
48490b17f1bSmrg
48590b17f1bSmrg    switch (pVia->Chipset) {
48690b17f1bSmrg        case VIA_VX800:
48790b17f1bSmrg        case VIA_VX855:
48890b17f1bSmrg        case VIA_VX900:
48990b17f1bSmrg            while ((VIAGETREG(VIA_REG_STATUS) &
49090b17f1bSmrg                    (VIA_CMD_RGTR_BUSY_H5 | VIA_2D_ENG_BUSY_H5 | VIA_3D_ENG_BUSY_H5))
49190b17f1bSmrg                   && (loop++ < MAXLOOP)) ;
49290b17f1bSmrg            break;
49390b17f1bSmrg        case VIA_P4M890:
49490b17f1bSmrg        case VIA_K8M890:
49590b17f1bSmrg        case VIA_P4M900:
49690b17f1bSmrg            while ((VIAGETREG(VIA_REG_STATUS) &
49790b17f1bSmrg                    (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))
49890b17f1bSmrg                   && (loop++ < MAXLOOP)) ;
49990b17f1bSmrg            break;
50090b17f1bSmrg        default:
50190b17f1bSmrg            while (!(VIAGETREG(VIA_REG_STATUS) & VIA_VR_QUEUE_EMPTY)
50290b17f1bSmrg                   && (loop++ < MAXLOOP)) ;
50390b17f1bSmrg
50490b17f1bSmrg            while ((VIAGETREG(VIA_REG_STATUS) &
50590b17f1bSmrg                    (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))
50690b17f1bSmrg                   && (loop++ < MAXLOOP)) ;
50790b17f1bSmrg            break;
50890b17f1bSmrg    }
50990b17f1bSmrg}
51090b17f1bSmrg
51190b17f1bSmrg/*
51290b17f1bSmrg * Wait for the value to get blitted, or in the PCI case for engine idle.
51390b17f1bSmrg */
51490b17f1bSmrgstatic void
51590b17f1bSmrgviaAccelWaitMarker(ScreenPtr pScreen, int marker)
51690b17f1bSmrg{
51790b17f1bSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
51890b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
51990b17f1bSmrg    CARD32 uMarker = marker;
52090b17f1bSmrg
52190b17f1bSmrg    if (pVia->agpDMA) {
52290b17f1bSmrg        while ((pVia->lastMarkerRead - uMarker) > (1 << 24))
52390b17f1bSmrg            pVia->lastMarkerRead = *(CARD32 *) pVia->markerBuf;
52490b17f1bSmrg    } else {
52590b17f1bSmrg        viaAccelSync(pScrn);
52690b17f1bSmrg    }
52790b17f1bSmrg}
52890b17f1bSmrg
52990b17f1bSmrg#ifdef HAVE_DRI
53090b17f1bSmrgstatic int
53190b17f1bSmrgviaAccelDMADownload(ScrnInfoPtr pScrn, unsigned long fbOffset,
53290b17f1bSmrg                    unsigned srcPitch, unsigned char *dst,
53390b17f1bSmrg                    unsigned dstPitch, unsigned w, unsigned h)
53490b17f1bSmrg{
53590b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
53690b17f1bSmrg    drm_via_dmablit_t blit[2], *curBlit;
53790b17f1bSmrg    unsigned char *sysAligned = NULL;
53890b17f1bSmrg    Bool doSync[2], useBounceBuffer;
53990b17f1bSmrg    unsigned pitch, numLines[2];
54090b17f1bSmrg    int curBuf, err, i, ret, blitHeight;
54190b17f1bSmrg
54290b17f1bSmrg    ret = 0;
54390b17f1bSmrg
54490b17f1bSmrg    useBounceBuffer = (((unsigned long)dst & 15) || (dstPitch & 15));
54590b17f1bSmrg    doSync[0] = FALSE;
54690b17f1bSmrg    doSync[1] = FALSE;
54790b17f1bSmrg    curBuf = 1;
54890b17f1bSmrg    blitHeight = h;
54990b17f1bSmrg    pitch = dstPitch;
55090b17f1bSmrg    if (useBounceBuffer) {
55190b17f1bSmrg        pitch = ALIGN_TO(dstPitch, 16);
55290b17f1bSmrg        blitHeight = VIA_DMA_DL_SIZE / pitch;
55390b17f1bSmrg    }
55490b17f1bSmrg
55590b17f1bSmrg    while (doSync[0] || doSync[1] || h != 0) {
55690b17f1bSmrg        curBuf = 1 - curBuf;
55790b17f1bSmrg        curBlit = &blit[curBuf];
55890b17f1bSmrg        if (doSync[curBuf]) {
55990b17f1bSmrg
56090b17f1bSmrg            do {
56190b17f1bSmrg                err = drmCommandWrite(pVia->drmmode.fd, DRM_VIA_BLIT_SYNC,
56290b17f1bSmrg                                      &curBlit->sync, sizeof(curBlit->sync));
56390b17f1bSmrg            } while (err == -EAGAIN);
56490b17f1bSmrg
56590b17f1bSmrg            if (err)
56690b17f1bSmrg                return err;
56790b17f1bSmrg
56890b17f1bSmrg            doSync[curBuf] = FALSE;
56990b17f1bSmrg            if (useBounceBuffer) {
57090b17f1bSmrg                for (i = 0; i < numLines[curBuf]; ++i) {
57190b17f1bSmrg                    memcpy(dst, curBlit->mem_addr, w);
57290b17f1bSmrg                    dst += dstPitch;
57390b17f1bSmrg                    curBlit->mem_addr += pitch;
57490b17f1bSmrg                }
57590b17f1bSmrg            }
57690b17f1bSmrg        }
57790b17f1bSmrg
57890b17f1bSmrg        if (h == 0)
57990b17f1bSmrg            continue;
58090b17f1bSmrg
58190b17f1bSmrg        curBlit->num_lines = (h > blitHeight) ? blitHeight : h;
58290b17f1bSmrg        h -= curBlit->num_lines;
58390b17f1bSmrg        numLines[curBuf] = curBlit->num_lines;
58490b17f1bSmrg
58590b17f1bSmrg        sysAligned =
58690b17f1bSmrg                (unsigned char *)pVia->dBounce + (curBuf * VIA_DMA_DL_SIZE);
58790b17f1bSmrg        sysAligned = (unsigned char *)
58890b17f1bSmrg                ALIGN_TO((unsigned long)sysAligned, 16);
58990b17f1bSmrg
59090b17f1bSmrg        curBlit->mem_addr = (useBounceBuffer) ? sysAligned : dst;
59190b17f1bSmrg        curBlit->line_length = w;
59290b17f1bSmrg        curBlit->mem_stride = pitch;
59390b17f1bSmrg        curBlit->fb_addr = fbOffset;
59490b17f1bSmrg        curBlit->fb_stride = srcPitch;
59590b17f1bSmrg        curBlit->to_fb = 0;
59690b17f1bSmrg        fbOffset += curBlit->num_lines * srcPitch;
59790b17f1bSmrg
59890b17f1bSmrg        do {
59990b17f1bSmrg            err = drmCommandWriteRead(pVia->drmmode.fd, DRM_VIA_DMA_BLIT, curBlit,
60090b17f1bSmrg                                      sizeof(*curBlit));
60190b17f1bSmrg        } while (err == -EAGAIN);
60290b17f1bSmrg
60390b17f1bSmrg        if (err) {
60490b17f1bSmrg            ret = err;
60590b17f1bSmrg            h = 0;
60690b17f1bSmrg            continue;
60790b17f1bSmrg        }
60890b17f1bSmrg
60990b17f1bSmrg        doSync[curBuf] = TRUE;
61090b17f1bSmrg    }
61190b17f1bSmrg
61290b17f1bSmrg    return ret;
61390b17f1bSmrg}
61490b17f1bSmrg
61590b17f1bSmrg/*
61690b17f1bSmrg * Use PCI DMA if we can. If the system alignments don't match, we're using
61790b17f1bSmrg * an aligned bounce buffer for pipelined PCI DMA and memcpy.
61890b17f1bSmrg * Throughput for large transfers is around 65 MB/s.
61990b17f1bSmrg */
62090b17f1bSmrgstatic Bool
62190b17f1bSmrgviaExaDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
62290b17f1bSmrg                         char *dst, int dst_pitch)
62390b17f1bSmrg{
62490b17f1bSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pSrc->drawable.pScreen);
62590b17f1bSmrg    unsigned wBytes = (pSrc->drawable.bitsPerPixel * w + 7) >> 3;
62690b17f1bSmrg    unsigned srcPitch = exaGetPixmapPitch(pSrc), srcOffset;
62790b17f1bSmrg    char *bounceAligned = NULL;
62890b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
62990b17f1bSmrg    unsigned totSize;
63090b17f1bSmrg
63190b17f1bSmrg    if (!w || !h)
63290b17f1bSmrg        return TRUE;
63390b17f1bSmrg
63490b17f1bSmrg    srcOffset = x * pSrc->drawable.bitsPerPixel;
63590b17f1bSmrg    if (srcOffset & 3)
63690b17f1bSmrg        return FALSE;
63790b17f1bSmrg    srcOffset = exaGetPixmapOffset(pSrc) + y * srcPitch + (srcOffset >> 3);
63890b17f1bSmrg
63990b17f1bSmrg    totSize = wBytes * h;
64090b17f1bSmrg
64190b17f1bSmrg    exaWaitSync(pScrn->pScreen);
64290b17f1bSmrg    if (totSize < VIA_MIN_DOWNLOAD) {
64390b17f1bSmrg        bounceAligned = (char *) drm_bo_map(pScrn, pVia->drmmode.front_bo) + srcOffset;
64490b17f1bSmrg
64590b17f1bSmrg        while (h--) {
64690b17f1bSmrg            memcpy(dst, bounceAligned, wBytes);
64790b17f1bSmrg            dst += dst_pitch;
64890b17f1bSmrg            bounceAligned += srcPitch;
64990b17f1bSmrg        }
65090b17f1bSmrg        return TRUE;
65190b17f1bSmrg    }
65290b17f1bSmrg
65390b17f1bSmrg    if (!pVia->directRenderingType)
65490b17f1bSmrg        return FALSE;
65590b17f1bSmrg
65690b17f1bSmrg    if ((srcPitch & 3) || (srcOffset & 3)) {
65790b17f1bSmrg        ErrorF("VIA EXA download src_pitch misaligned\n");
65890b17f1bSmrg        return FALSE;
65990b17f1bSmrg    }
66090b17f1bSmrg
66190b17f1bSmrg    if (viaAccelDMADownload(pScrn, srcOffset, srcPitch, (unsigned char *)dst,
66290b17f1bSmrg                            dst_pitch, wBytes, h))
66390b17f1bSmrg        return FALSE;
66490b17f1bSmrg
66590b17f1bSmrg    return TRUE;
66690b17f1bSmrg}
66790b17f1bSmrg
66890b17f1bSmrg/*
66990b17f1bSmrg * Upload to framebuffer memory using memcpy to AGP pipelined with a
67090b17f1bSmrg * 3D engine texture operation from AGP to framebuffer. The AGP buffers (2)
67190b17f1bSmrg * should be kept rather small for optimal pipelining.
67290b17f1bSmrg */
67390b17f1bSmrgstatic Bool
67490b17f1bSmrgviaExaTexUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
67590b17f1bSmrg                        int src_pitch)
67690b17f1bSmrg{
67790b17f1bSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
67890b17f1bSmrg    unsigned dstPitch = exaGetPixmapPitch(pDst), dstOffset;
67990b17f1bSmrg    unsigned wBytes = (w * pDst->drawable.bitsPerPixel + 7) >> 3;
68090b17f1bSmrg    int i, sync[2], yOffs, bufH, bufOffs, height, format;
68190b17f1bSmrg    CARD32 texWidth, texHeight, texPitch;
68290b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
68390b17f1bSmrg    Via3DState *v3d = &pVia->v3d;
68490b17f1bSmrg    char *dst, *texAddr;
68590b17f1bSmrg    Bool buf;
68690b17f1bSmrg
68790b17f1bSmrg    if (!w || !h)
68890b17f1bSmrg        return TRUE;
68990b17f1bSmrg
69090b17f1bSmrg    if (wBytes * h < VIA_MIN_TEX_UPLOAD) {
69190b17f1bSmrg        dstOffset = x * pDst->drawable.bitsPerPixel;
69290b17f1bSmrg        if (dstOffset & 3)
69390b17f1bSmrg            return FALSE;
69490b17f1bSmrg
69590b17f1bSmrg        dst = (char *) drm_bo_map(pScrn, pVia->drmmode.front_bo) +
69690b17f1bSmrg                        (exaGetPixmapOffset(pDst) + y * dstPitch +
69790b17f1bSmrg                        (dstOffset >> 3));
69890b17f1bSmrg        exaWaitSync(pScrn->pScreen);
69990b17f1bSmrg
70090b17f1bSmrg        while (h--) {
70190b17f1bSmrg            memcpy(dst, src, wBytes);
70290b17f1bSmrg            dst += dstPitch;
70390b17f1bSmrg            src += src_pitch;
70490b17f1bSmrg        }
70590b17f1bSmrg        return TRUE;
70690b17f1bSmrg    }
70790b17f1bSmrg
70890b17f1bSmrg    if (!pVia->texAGPBuffer->ptr)
70990b17f1bSmrg        return FALSE;
71090b17f1bSmrg
71190b17f1bSmrg    switch (pDst->drawable.bitsPerPixel) {
71290b17f1bSmrg        case 32:
71390b17f1bSmrg            format = PICT_a8r8g8b8;
71490b17f1bSmrg            break;
71590b17f1bSmrg        case 16:
71690b17f1bSmrg            format = PICT_r5g6b5;
71790b17f1bSmrg            break;
71890b17f1bSmrg        default:
71990b17f1bSmrg            return FALSE;
72090b17f1bSmrg    }
72190b17f1bSmrg
72290b17f1bSmrg    dstOffset = exaGetPixmapOffset(pDst);
72390b17f1bSmrg
72490b17f1bSmrg    if (pVia->nPOT[0]) {
72590b17f1bSmrg        texPitch = ALIGN_TO(wBytes, 32);
72690b17f1bSmrg        height = VIA_AGP_UPL_SIZE / texPitch;
72790b17f1bSmrg    } else {
72890b17f1bSmrg        viaOrder(wBytes, &texPitch);
72990b17f1bSmrg        if (texPitch < 3)
73090b17f1bSmrg            texPitch = 3;
73190b17f1bSmrg        height = VIA_AGP_UPL_SIZE >> texPitch;
73290b17f1bSmrg        texPitch = 1 << texPitch;
73390b17f1bSmrg    }
73490b17f1bSmrg
73590b17f1bSmrg    if (height > 1024)
73690b17f1bSmrg        height = 1024;
73790b17f1bSmrg    viaOrder(w, &texWidth);
73890b17f1bSmrg    texWidth = 1 << texWidth;
73990b17f1bSmrg
74090b17f1bSmrg    texHeight = height << 1;
74190b17f1bSmrg    bufOffs = texPitch * height;
74290b17f1bSmrg    texAddr = (char *) drm_bo_map(pScrn, pVia->texAGPBuffer);
74390b17f1bSmrg
74490b17f1bSmrg    v3d->setDestination(v3d, dstOffset, dstPitch, format);
74590b17f1bSmrg    v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, 0x000000FF, 0x00);
74690b17f1bSmrg    v3d->setFlags(v3d, 1, TRUE, TRUE, FALSE);
74790b17f1bSmrg    if (!v3d->setTexture(v3d, 0, (unsigned long) texAddr, texPitch,
74890b17f1bSmrg                         pVia->nPOT[0], texWidth, texHeight, format,
74990b17f1bSmrg                         via_single, via_single, via_src, TRUE))
75090b17f1bSmrg        return FALSE;
75190b17f1bSmrg
75290b17f1bSmrg    v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d));
75390b17f1bSmrg    v3d->emitClipRect(v3d, &pVia->cb, 0, 0, pDst->drawable.width,
75490b17f1bSmrg                      pDst->drawable.height);
75590b17f1bSmrg
75690b17f1bSmrg    buf = 1;
75790b17f1bSmrg    yOffs = 0;
75890b17f1bSmrg    sync[0] = -1;
75990b17f1bSmrg    sync[1] = -1;
76090b17f1bSmrg
76190b17f1bSmrg    while (h) {
76290b17f1bSmrg        buf = (buf) ? 0 : 1;
76390b17f1bSmrg        bufH = (h > height) ? height : h;
76490b17f1bSmrg        dst = texAddr + ((buf) ? bufOffs : 0);
76590b17f1bSmrg
76690b17f1bSmrg        if (sync[buf] >= 0)
76790b17f1bSmrg            pVia->exaDriverPtr->WaitMarker(pScrn->pScreen, sync[buf]);
76890b17f1bSmrg
76990b17f1bSmrg        for (i = 0; i < bufH; ++i) {
77090b17f1bSmrg            memcpy(dst, src, wBytes);
77190b17f1bSmrg            dst += texPitch;
77290b17f1bSmrg            src += src_pitch;
77390b17f1bSmrg        }
77490b17f1bSmrg
77590b17f1bSmrg        v3d->emitQuad(v3d, &pVia->cb, x, y + yOffs, 0, (buf) ? height : 0, 0,
77690b17f1bSmrg                      0, w, bufH);
77790b17f1bSmrg
77890b17f1bSmrg        sync[buf] = pVia->exaDriverPtr->MarkSync(pScrn->pScreen);
77990b17f1bSmrg
78090b17f1bSmrg        h -= bufH;
78190b17f1bSmrg        yOffs += bufH;
78290b17f1bSmrg    }
78390b17f1bSmrg
78490b17f1bSmrg    if (sync[buf] >= 0)
78590b17f1bSmrg        pVia->exaDriverPtr->WaitMarker(pScrn->pScreen, sync[buf]);
78690b17f1bSmrg
78790b17f1bSmrg    return TRUE;
78890b17f1bSmrg}
78990b17f1bSmrg
79090b17f1bSmrg#endif /* HAVE_DRI */
79190b17f1bSmrg
79290b17f1bSmrg#define EXAOPT_MIGRATION_HEURISTIC  0
79390b17f1bSmrg
79490b17f1bSmrgBool
79590b17f1bSmrgviaInitExa(ScreenPtr pScreen)
79690b17f1bSmrg{
79790b17f1bSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
79890b17f1bSmrg    ExaDriverPtr pExa = exaDriverAlloc();
79990b17f1bSmrg    Bool nPOTSupported = TRUE;
80090b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
80190b17f1bSmrg
80290b17f1bSmrg    /*
80390b17f1bSmrg     * nPOT textures. DRM versions below 2.11.0 don't allow them.
80490b17f1bSmrg     * Also some CLE266 hardware may not allow nPOT textures for
80590b17f1bSmrg     * texture engine 1. We need to figure that out.
80690b17f1bSmrg     */
80790b17f1bSmrg#ifdef HAVE_DRI
80890b17f1bSmrg    nPOTSupported = ((!pVia->directRenderingType) ||
80990b17f1bSmrg                     (pVia->drmVerMajor > 2) ||
81090b17f1bSmrg                     ((pVia->drmVerMajor == 2) && (pVia->drmVerMinor >= 11)));
81190b17f1bSmrg#endif
81290b17f1bSmrg    pVia->nPOT[0] = nPOTSupported;
81390b17f1bSmrg    pVia->nPOT[1] = nPOTSupported;
81490b17f1bSmrg
81590b17f1bSmrg    if (Success != viaSetupCBuffer(pScrn, &pVia->cb, 0)) {
81690b17f1bSmrg        pVia->NoAccel = TRUE;
81790b17f1bSmrg        return FALSE;
81890b17f1bSmrg    }
81990b17f1bSmrg
82090b17f1bSmrg    if (!pExa)
82190b17f1bSmrg        return FALSE;
82290b17f1bSmrg
82390b17f1bSmrg    memset(pExa, 0, sizeof(*pExa));
82490b17f1bSmrg
82590b17f1bSmrg    pExa->exa_major = EXA_VERSION_MAJOR;
82690b17f1bSmrg    pExa->exa_minor = EXA_VERSION_MINOR;
82790b17f1bSmrg    pExa->memoryBase = pVia->FBBase;
82890b17f1bSmrg    pExa->memorySize = pVia->FBFreeEnd;
82990b17f1bSmrg    pExa->offScreenBase = pScrn->virtualY * pVia->Bpl;
83090b17f1bSmrg    pExa->pixmapOffsetAlign = 32;
83190b17f1bSmrg    pExa->pixmapPitchAlign = 16;
83290b17f1bSmrg    pExa->flags = EXA_OFFSCREEN_PIXMAPS |
83390b17f1bSmrg            (pVia->nPOT[1] ? 0 : EXA_OFFSCREEN_ALIGN_POT);
83490b17f1bSmrg
83590b17f1bSmrg
83690b17f1bSmrg    /*  HW Limitation are described here:
83790b17f1bSmrg     *
83890b17f1bSmrg     *  1. H2/H5/H6 2D source and destination:
83990b17f1bSmrg     *     Pitch: (1 << 14) - 1 = 16383
84090b17f1bSmrg     *     Dimension: (1 << 12) = 4096
84190b17f1bSmrg     *     X, Y position: (1 << 12) - 1 = 4095.
84290b17f1bSmrg     *
84390b17f1bSmrg     *  2. H2 3D engine Render target:
84490b17f1bSmrg     *     Pitch: (1 << 14) - 1 = 16383
84590b17f1bSmrg     *     Clip Rectangle: 0 - 2047
84690b17f1bSmrg     *
84790b17f1bSmrg     *  3. H5/H6 3D engine Render target:
84890b17f1bSmrg     *     Pitch: ((1 << 10) - 1)*32 = 32736
84990b17f1bSmrg     *     Clip Rectangle: Color Window, 12bits. As Spec saied: 0 - 2048
85090b17f1bSmrg     *                     Scissor is the same as color window.
85190b17f1bSmrg     */
85290b17f1bSmrg    pExa->maxX = 2047;
85390b17f1bSmrg    pExa->maxY = 2047;
85490b17f1bSmrg    pExa->WaitMarker = viaAccelWaitMarker;
85590b17f1bSmrg
85690b17f1bSmrg    switch (pVia->Chipset) {
85790b17f1bSmrg    case VIA_VX800:
85890b17f1bSmrg    case VIA_VX855:
85990b17f1bSmrg    case VIA_VX900:
86090b17f1bSmrg        pExa->MarkSync = viaAccelMarkSync_H6;
86190b17f1bSmrg        pExa->PrepareSolid = viaExaPrepareSolid_H6;
86290b17f1bSmrg        pExa->Solid = viaExaSolid_H6;
86390b17f1bSmrg        pExa->DoneSolid = viaExaDoneSolidCopy_H6;
86490b17f1bSmrg        pExa->PrepareCopy = viaExaPrepareCopy_H6;
86590b17f1bSmrg        pExa->Copy = viaExaCopy_H6;
86690b17f1bSmrg        pExa->DoneCopy = viaExaDoneSolidCopy_H6;
86790b17f1bSmrg        break;
86890b17f1bSmrg    default:
86990b17f1bSmrg        pExa->MarkSync = viaAccelMarkSync_H2;
87090b17f1bSmrg        pExa->PrepareSolid = viaExaPrepareSolid_H2;
87190b17f1bSmrg        pExa->Solid = viaExaSolid_H2;
87290b17f1bSmrg        pExa->DoneSolid = viaExaDoneSolidCopy_H2;
87390b17f1bSmrg        pExa->PrepareCopy = viaExaPrepareCopy_H2;
87490b17f1bSmrg        pExa->Copy = viaExaCopy_H2;
87590b17f1bSmrg        pExa->DoneCopy = viaExaDoneSolidCopy_H2;
87690b17f1bSmrg        break;
87790b17f1bSmrg    }
87890b17f1bSmrg
87990b17f1bSmrg#ifdef HAVE_DRI
88090b17f1bSmrg    if (pVia->directRenderingType == DRI_1) {
88190b17f1bSmrg#ifdef linux
88290b17f1bSmrg        pExa->DownloadFromScreen = viaExaDownloadFromScreen;
88390b17f1bSmrg#endif /* linux */
88490b17f1bSmrg        switch (pVia->Chipset) {
88590b17f1bSmrg        case VIA_K8M800:
88690b17f1bSmrg        case VIA_KM400:
88790b17f1bSmrg            pExa->UploadToScreen = NULL; //viaExaTexUploadToScreen;
88890b17f1bSmrg            break;
88990b17f1bSmrg        default:
89090b17f1bSmrg            pExa->UploadToScreen = NULL; //viaExaUploadToScreen;
89190b17f1bSmrg            break;
89290b17f1bSmrg        }
89390b17f1bSmrg    }
89490b17f1bSmrg#endif /* HAVE_DRI */
89590b17f1bSmrg
89690b17f1bSmrg    if (!pVia->noComposite) {
89790b17f1bSmrg        switch (pVia->Chipset) {
89890b17f1bSmrg        case VIA_VX800:
89990b17f1bSmrg        case VIA_VX855:
90090b17f1bSmrg        case VIA_VX900:
90190b17f1bSmrg            pExa->CheckComposite = viaExaCheckComposite_H6;
90290b17f1bSmrg            pExa->PrepareComposite = viaExaPrepareComposite_H6;
90390b17f1bSmrg            pExa->Composite = viaExaComposite_H6;
90490b17f1bSmrg            pExa->DoneComposite = viaExaDoneSolidCopy_H6;
90590b17f1bSmrg            break;
90690b17f1bSmrg        default:
90790b17f1bSmrg            pExa->CheckComposite = viaExaCheckComposite_H2;
90890b17f1bSmrg            pExa->PrepareComposite = viaExaPrepareComposite_H2;
90990b17f1bSmrg            pExa->Composite = viaExaComposite_H2;
91090b17f1bSmrg            pExa->DoneComposite = viaExaDoneSolidCopy_H2;
91190b17f1bSmrg            break;
91290b17f1bSmrg        }
91390b17f1bSmrg    } else {
91490b17f1bSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
91590b17f1bSmrg                   "[EXA] Disabling EXA accelerated composite.\n");
91690b17f1bSmrg    }
91790b17f1bSmrg
91890b17f1bSmrg    if (!exaDriverInit(pScreen, pExa)) {
91990b17f1bSmrg        free(pExa);
92090b17f1bSmrg        return FALSE;
92190b17f1bSmrg    }
92290b17f1bSmrg
92390b17f1bSmrg    pVia->exaDriverPtr = pExa;
92490b17f1bSmrg    viaInit3DState(&pVia->v3d);
92590b17f1bSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
92690b17f1bSmrg                "[EXA] Enabled EXA acceleration.\n");
92790b17f1bSmrg    return TRUE;
92890b17f1bSmrg}
92990b17f1bSmrg
93090b17f1bSmrg/*
93190b17f1bSmrg * Allocate a command buffer and  buffers for accelerated upload, download,
93290b17f1bSmrg * and EXA scratch area. The scratch area resides primarily in AGP memory,
93390b17f1bSmrg * but reverts to FB if AGP is not available.
93490b17f1bSmrg */
93590b17f1bSmrgvoid
93690b17f1bSmrgviaFinishInitAccel(ScreenPtr pScreen)
93790b17f1bSmrg{
93890b17f1bSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
93990b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
94090b17f1bSmrg    int size;
94190b17f1bSmrg
94290b17f1bSmrg#ifdef HAVE_DRI
94390b17f1bSmrg    if (pVia->directRenderingType && pVia->useEXA) {
94490b17f1bSmrg
94590b17f1bSmrg        pVia->dBounce = calloc(VIA_DMA_DL_SIZE * 2, 1);
94690b17f1bSmrg
94790b17f1bSmrg        if (!pVia->IsPCI) {
94890b17f1bSmrg
94990b17f1bSmrg            /* Allocate upload and scratch space. */
95090b17f1bSmrg            if (pVia->exaDriverPtr->UploadToScreen == viaExaTexUploadToScreen) {
95190b17f1bSmrg                size = VIA_AGP_UPL_SIZE * 2;
95290b17f1bSmrg
95390b17f1bSmrg                pVia->texAGPBuffer = drm_bo_alloc(pScrn, size, 32, TTM_PL_FLAG_TT);
95490b17f1bSmrg                if (pVia->texAGPBuffer) {
95590b17f1bSmrg                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
95690b17f1bSmrg                               "Allocated %u kiB of AGP memory for "
95790b17f1bSmrg                               "system-to-framebuffer transfer.\n",
95890b17f1bSmrg                               size / 1024);
95990b17f1bSmrg                    pVia->texAGPBuffer->offset = (pVia->texAGPBuffer->offset + 31) & ~31;
96090b17f1bSmrg                }
96190b17f1bSmrg            }
96290b17f1bSmrg
96390b17f1bSmrg            size = pVia->exaScratchSize * 1024;
96490b17f1bSmrg            pVia->scratchBuffer = drm_bo_alloc(pScrn, size, 32, TTM_PL_FLAG_TT);
96590b17f1bSmrg            if (pVia->scratchBuffer) {
96690b17f1bSmrg                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
96790b17f1bSmrg                           "Allocated %u kiB of AGP memory for "
96890b17f1bSmrg                           "EXA scratch area.\n", size / 1024);
96990b17f1bSmrg                pVia->scratchOffset =
97090b17f1bSmrg                        (pVia->scratchBuffer->offset + 31) & ~31;
97190b17f1bSmrg                pVia->scratchAddr = drm_bo_map(pScrn, pVia->scratchBuffer);
97290b17f1bSmrg            }
97390b17f1bSmrg        }
97490b17f1bSmrg    }
97590b17f1bSmrg#endif /* HAVE_DRI */
97690b17f1bSmrg    if (!pVia->scratchAddr && pVia->useEXA) {
97790b17f1bSmrg        size = pVia->exaScratchSize * 1024 + 32;
97890b17f1bSmrg        pVia->scratchBuffer = drm_bo_alloc(pScrn, size, 32, TTM_PL_FLAG_SYSTEM);
97990b17f1bSmrg
98090b17f1bSmrg        if (pVia->scratchBuffer) {
98190b17f1bSmrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
98290b17f1bSmrg                       "Allocated %u kiB of framebuffer memory for "
98390b17f1bSmrg                       "EXA scratch area.\n", pVia->exaScratchSize);
98490b17f1bSmrg            pVia->scratchOffset = pVia->scratchBuffer->offset;
98590b17f1bSmrg            pVia->scratchAddr = drm_bo_map(pScrn, pVia->scratchBuffer);
98690b17f1bSmrg        }
98790b17f1bSmrg    }
98890b17f1bSmrg    memset(pVia->markerBuf, 0, pVia->exa_sync_bo->size);
98990b17f1bSmrg}
99090b17f1bSmrg
99190b17f1bSmrg/*
99290b17f1bSmrg * Free the used acceleration resources.
99390b17f1bSmrg */
99490b17f1bSmrgvoid
99590b17f1bSmrgviaExitAccel(ScreenPtr pScreen)
99690b17f1bSmrg{
99790b17f1bSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
99890b17f1bSmrg    VIAPtr pVia = VIAPTR(pScrn);
99990b17f1bSmrg
100090b17f1bSmrg    viaAccelSync(pScrn);
100190b17f1bSmrg    viaTearDownCBuffer(&pVia->cb);
100290b17f1bSmrg
100390b17f1bSmrg    if (pVia->useEXA) {
100490b17f1bSmrg#ifdef HAVE_DRI
100590b17f1bSmrg        if (pVia->directRenderingType == DRI_1) {
100690b17f1bSmrg            if (pVia->texAGPBuffer) {
100790b17f1bSmrg                drm_bo_free(pScrn, pVia->texAGPBuffer);
100890b17f1bSmrg                pVia->texAGPBuffer = NULL;
100990b17f1bSmrg            }
101090b17f1bSmrg
101190b17f1bSmrg            if (pVia->scratchBuffer) {
101290b17f1bSmrg                drm_bo_free(pScrn, pVia->scratchBuffer);
101390b17f1bSmrg                pVia->scratchBuffer = NULL;
101490b17f1bSmrg            }
101590b17f1bSmrg        }
101690b17f1bSmrg        if (pVia->dBounce)
101790b17f1bSmrg            free(pVia->dBounce);
101890b17f1bSmrg#endif /* HAVE_DRI */
101990b17f1bSmrg        if (pVia->scratchBuffer) {
102090b17f1bSmrg            drm_bo_free(pScrn, pVia->scratchBuffer);
102190b17f1bSmrg            pVia->scratchBuffer = NULL;
102290b17f1bSmrg        }
102390b17f1bSmrg        if (pVia->vq_bo) {
102490b17f1bSmrg            drm_bo_unmap(pScrn, pVia->vq_bo);
102590b17f1bSmrg            drm_bo_free(pScrn, pVia->vq_bo);
102690b17f1bSmrg        }
102790b17f1bSmrg        if (pVia->exa_sync_bo) {
102890b17f1bSmrg            drm_bo_unmap(pScrn, pVia->exa_sync_bo);
102990b17f1bSmrg            drm_bo_free(pScrn, pVia->exa_sync_bo);
103090b17f1bSmrg        }
103190b17f1bSmrg        if (pVia->exaDriverPtr) {
103290b17f1bSmrg            exaDriverFini(pScreen);
103390b17f1bSmrg        }
103490b17f1bSmrg        free(pVia->exaDriverPtr);
103590b17f1bSmrg        pVia->exaDriverPtr = NULL;
103690b17f1bSmrg        return;
103790b17f1bSmrg    }
103890b17f1bSmrg}
1039