Edit

IABSD.fr/xenocara/driver/xf86-video-openchrome/src/via_exa.c

Branch :

  • Show log

    Commit

  • Author : fcambus
    Date : 2021-11-23 17:50:30
    Hash : 604ad564
    Message : Update openchrome to 0.6.409. OK and with help from matthieu@

  • driver/xf86-video-openchrome/src/via_exa.c
  • /*
     * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
     * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
     * Copyright 2006 Thomas Hellström. All Rights Reserved.
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sub license,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice (including the
     * next paragraph) shall be included in all copies or substantial portions
     * of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     * DEALINGS IN THE SOFTWARE.
     */
    
    /*
     * 2D acceleration functions for the VIA/S3G UniChrome IGPs.
     *
     * Mostly rewritten, and modified for EXA support, by Thomas Hellström.
     */
    
    #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif
    
    #include <X11/Xarch.h>
    #include "miline.h"
    
    #include <GL/gl.h>
    #include <sys/mman.h>
    
    #include "via_driver.h"
    #include "via_regs.h"
    #include "via_dmabuffer.h"
    
    static void
    viaFlushPCI(ViaCommandBuffer *cb)
    {
        register CARD32 *bp = cb->buf;
        CARD32 transSetting;
        CARD32 *endp = bp + cb->pos;
        unsigned loop = 0;
        register CARD32 offset = 0;
        register CARD32 value;
        VIAPtr pVia = VIAPTR(cb->pScrn);
    
        while (bp < endp) {
            if (*bp == HALCYON_HEADER2) {
                if (++bp == endp)
                    return;
                VIASETREG(VIA_REG_TRANSET, transSetting = *bp++);
                while (bp < endp) {
                    if ((transSetting != HC_ParaType_CmdVdata)
                        && ((*bp == HALCYON_HEADER2)
                            || (*bp & HALCYON_HEADER1MASK) == HALCYON_HEADER1))
                        break;
                    VIASETREG(VIA_REG_TRANSPACE, *bp++);
                }
            } else if ((*bp & HALCYON_HEADER1MASK) == HALCYON_HEADER1) {
    
                while (bp < endp) {
                    if (*bp == HALCYON_HEADER2)
                        break;
                    if (offset == 0) {
                        /*
                         * Not doing this wait will probably stall the processor
                         * for an unacceptable amount of time in VIASETREG while
                         * other high priority interrupts may be pending.
                         */
                        switch (pVia->Chipset) {
                        case VIA_VX800:
                        case VIA_VX855:
                        case VIA_VX900:
                            while ((VIAGETREG(VIA_REG_STATUS) &
                                    (VIA_CMD_RGTR_BUSY_H5 | VIA_2D_ENG_BUSY_H5)) &&
                                    (loop++ < MAXLOOP)) ;
                            break;
    
                        case VIA_P4M890:
                        case VIA_K8M890:
                        case VIA_P4M900:
                            while ((VIAGETREG(VIA_REG_STATUS) &
                                    (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY)) &&
                                    (loop++ < MAXLOOP)) ;
                            break;
    
                        default:
                            while (!(VIAGETREG(VIA_REG_STATUS) & VIA_VR_QUEUE_EMPTY) &&
                                    (loop++ < MAXLOOP)) ;
                            while ((VIAGETREG(VIA_REG_STATUS) &
                                    (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY)) &&
                                    (loop++ < MAXLOOP)) ;
                        }
                    }
                    offset = (*bp++ & 0x0FFFFFFF) << 2;
                    value = *bp++;
                    VIASETREG(offset, value);
                }
            } else {
                ErrorF("Command stream parser error.\n");
            }
        }
        cb->pos = 0;
        cb->mode = 0;
        cb->has3dState = FALSE;
    }
    
    #ifdef OPENCHROMEDRI
    /*
     * Use PCI MMIO to flush the command buffer when AGP DMA is not available.
     */
    static void
    viaDumpDMA(ViaCommandBuffer *cb)
    {
        register CARD32 *bp = cb->buf;
        CARD32 *endp = bp + cb->pos;
    
        while (bp != endp) {
            if (((bp - cb->buf) & 3) == 0) {
                ErrorF("\n %04lx: ", (unsigned long)(bp - cb->buf));
            }
            ErrorF("0x%08x ", (unsigned)*bp++);
        }
        ErrorF("\n");
    }
    
    /*
     * Flush the command buffer using DRM. If in PCI mode, we can bypass DRM,
     * but not for command buffers that contain 3D engine state, since then
     * the DRM command verifier will lose track of the 3D engine state.
     */
    static void
    viaFlushDRIEnabled(ViaCommandBuffer *cb)
    {
        ScrnInfoPtr pScrn = cb->pScrn;
        VIAPtr pVia = VIAPTR(pScrn);
        char *tmp = (char *)cb->buf;
        int tmpSize;
        drm_via_cmdbuffer_t b;
    
        /* Align end of command buffer for AGP DMA. */
        OUT_RING_H1(0x2f8, 0x67676767);
        if (pVia->agpDMA && cb->mode == 2 && cb->rindex != HC_ParaType_CmdVdata
            && (cb->pos & 1)) {
            OUT_RING(HC_DUMMY);
        }
    
        tmpSize = cb->pos * sizeof(CARD32);
        if (pVia->agpDMA || (pVia->directRenderingType && cb->has3dState)) {
            cb->mode = 0;
            cb->has3dState = FALSE;
            while (tmpSize > 0) {
                b.size = (tmpSize > VIA_DMASIZE) ? VIA_DMASIZE : tmpSize;
                tmpSize -= b.size;
                b.buf = tmp;
                tmp += b.size;
                if (drmCommandWrite(pVia->drmmode.fd, ((pVia->agpDMA)
                                                  ? DRM_VIA_CMDBUFFER :
                                                  DRM_VIA_PCICMD), &b, sizeof(b))) {
                    ErrorF("DRM command buffer submission failed.\n");
                    viaDumpDMA(cb);
                    return;
                }
            }
            cb->pos = 0;
        } else {
            viaFlushPCI(cb);
        }
    }
    #endif
    
    /*
     * Initialize a command buffer. Some fields are currently not used since they
     * are intended for Unichrome Pro group A video commands.
     */
    static int
    viaSetupCBuffer(ScrnInfoPtr pScrn, ViaCommandBuffer *cb, unsigned size)
    {
    #ifdef OPENCHROMEDRI
        VIAPtr pVia = VIAPTR(pScrn);
    #endif
    
        cb->pScrn = pScrn;
        cb->bufSize = ((size == 0) ? VIA_DMASIZE : size) >> 2;
        cb->buf = (CARD32 *) calloc(cb->bufSize, sizeof(CARD32));
        if (!cb->buf)
            return BadAlloc;
        cb->waitFlags = 0;
        cb->pos = 0;
        cb->mode = 0;
        cb->header_start = 0;
        cb->rindex = 0;
        cb->has3dState = FALSE;
        cb->flushFunc = viaFlushPCI;
    #ifdef OPENCHROMEDRI
        if (pVia->directRenderingType == DRI_1) {
            cb->flushFunc = viaFlushDRIEnabled;
        }
    #endif
        return Success;
    }
    
    /*
     * Free resources associated with a command buffer.
     */
    static void
    viaTearDownCBuffer(ViaCommandBuffer *cb)
    {
        if (cb && cb->buf) {
            free(cb->buf);
            cb->buf = NULL;
        }
    }
    
    /*
     * Update our 2D state (TwoDContext) with a new mode.
     */
    Bool
    viaAccelSetMode(int bpp, ViaTwodContext * tdc)
    {
        switch (bpp) {
        case 16:
            tdc->mode = VIA_GEM_16bpp;
            tdc->bytesPPShift = 1;
            return TRUE;
        case 32:
            tdc->mode = VIA_GEM_32bpp;
            tdc->bytesPPShift = 2;
            return TRUE;
        case 8:
            tdc->mode = VIA_GEM_8bpp;
            tdc->bytesPPShift = 0;
            return TRUE;
        default:
            tdc->bytesPPShift = 0;
            return FALSE;
        }
    }
    
    /*
     * Switch 2D state clipping on.
     */
    void
    viaSetClippingRectangle(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2)
    {
        VIAPtr pVia = VIAPTR(pScrn);
        ViaTwodContext *tdc = &pVia->td;
    
        tdc->clipping = TRUE;
        tdc->clipX1 = (x1 & 0xFFFF);
        tdc->clipY1 = y1;
        tdc->clipX2 = (x2 & 0xFFFF);
        tdc->clipY2 = y2;
    }
    
    /*
     * Check if we need to force upload of the whole 3D state (when other
     * clients or subsystems have touched the 3D engine). Also tell DRI
     * clients and subsystems that we have touched the 3D engine.
     */
    Bool
    viaCheckUpload(ScrnInfoPtr pScrn, Via3DState * v3d)
    {
        VIAPtr pVia = VIAPTR(pScrn);
        Bool forceUpload;
    
        forceUpload = (pVia->lastToUpload != v3d);
        pVia->lastToUpload = v3d;
    
    #ifdef OPENCHROMEDRI
        if (pVia->directRenderingType == DRI_1) {
            volatile drm_via_sarea_t *saPriv = (drm_via_sarea_t *)
                    DRIGetSAREAPrivate(pScrn->pScreen);
            int myContext = DRIGetContext(pScrn->pScreen);
    
            forceUpload = forceUpload || (saPriv->ctxOwner != myContext);
            saPriv->ctxOwner = myContext;
        }
    #endif
        return forceUpload;
    }
    
    Bool
    viaOrder(CARD32 val, CARD32 * shift)
    {
        *shift = 0;
    
        while (val > (1 << *shift))
            (*shift)++;
        return (val == (1 << *shift));
    }
    
    /*
     * Helper for bitdepth expansion.
     */
    CARD32
    viaBitExpandHelper(CARD32 pixel, CARD32 bits)
    {
        CARD32 component, mask, tmp;
    
        component = pixel & ((1 << bits) - 1);
        mask = (1 << (8 - bits)) - 1;
        tmp = component << (8 - bits);
        return ((component & 1) ? (tmp | mask) : tmp);
    }
    
    /*
     * 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.
     * Assumes little endian.
     */
    void
    viaPixelARGB8888(unsigned format, void *pixelP, CARD32 * argb8888)
    {
        CARD32 bits, shift, pixel, bpp;
    
        bpp = PICT_FORMAT_BPP(format);
    
        if (bpp <= 8) {
            pixel = *((CARD8 *) pixelP);
        } else if (bpp <= 16) {
            pixel = *((CARD16 *) pixelP);
        } else {
            pixel = *((CARD32 *) pixelP);
        }
    
        switch (PICT_FORMAT_TYPE(format)) {
            case PICT_TYPE_A:
                bits = PICT_FORMAT_A(format);
                *argb8888 = viaBitExpandHelper(pixel, bits) << 24;
                return;
            case PICT_TYPE_ARGB:
                shift = 0;
                bits = PICT_FORMAT_B(format);
                *argb8888 = viaBitExpandHelper(pixel, bits);
                shift += bits;
                bits = PICT_FORMAT_G(format);
                *argb8888 |= viaBitExpandHelper(pixel >> shift, bits) << 8;
                shift += bits;
                bits = PICT_FORMAT_R(format);
                *argb8888 |= viaBitExpandHelper(pixel >> shift, bits) << 16;
                shift += bits;
                bits = PICT_FORMAT_A(format);
                *argb8888 |= ((bits) ? viaBitExpandHelper(pixel >> shift,
                                                          bits) : 0xFF) << 24;
                return;
            case PICT_TYPE_ABGR:
                shift = 0;
                bits = PICT_FORMAT_B(format);
                *argb8888 = viaBitExpandHelper(pixel, bits) << 16;
                shift += bits;
                bits = PICT_FORMAT_G(format);
                *argb8888 |= viaBitExpandHelper(pixel >> shift, bits) << 8;
                shift += bits;
                bits = PICT_FORMAT_R(format);
                *argb8888 |= viaBitExpandHelper(pixel >> shift, bits);
                shift += bits;
                bits = PICT_FORMAT_A(format);
                *argb8888 |= ((bits) ? viaBitExpandHelper(pixel >> shift,
                                                          bits) : 0xFF) << 24;
                return;
            default:
                break;
        }
        return;
    }
    
    Bool
    viaExpandablePixel(int format)
    {
        int formatType = PICT_FORMAT_TYPE(format);
    
        return (formatType == PICT_TYPE_A ||
                formatType == PICT_TYPE_ABGR || formatType == PICT_TYPE_ARGB);
    }
    
    #ifdef VIA_DEBUG_COMPOSITE
    void
    viaExaCompositePictDesc(PicturePtr pict, char *string, int n)
    {
        char format[20];
        char size[20];
    
        if (!pict) {
            snprintf(string, n, "None");
            return;
        }
    
        switch (pict->format) {
            case PICT_x8r8g8b8:
                snprintf(format, 20, "RGB8888");
                break;
            case PICT_a8r8g8b8:
                snprintf(format, 20, "ARGB8888");
                break;
            case PICT_r5g6b5:
                snprintf(format, 20, "RGB565  ");
                break;
            case PICT_x1r5g5b5:
                snprintf(format, 20, "RGB555  ");
                break;
            case PICT_a8:
                snprintf(format, 20, "A8      ");
                break;
            case PICT_a1:
                snprintf(format, 20, "A1      ");
                break;
            default:
                snprintf(format, 20, "0x%x", (int)pict->format);
                break;
        }
    
        if (pict->pDrawable) {
           snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
                    pict->pDrawable->height, pict->repeat ? " R" : "");
    
           snprintf(string, n, "0x%lx: fmt %s (%s)", (long)pict->pDrawable, format,
                    size);
        }
    }
    
    void
    viaExaPrintCompositeInfo(char *info, CARD8 op, PicturePtr pSrc, PicturePtr pMask,
                            PicturePtr pDst)
    {
        char sop[20];
        char srcdesc[40], maskdesc[40], dstdesc[40];
    
        switch (op) {
    	case PictOpClear:
    		sprintf(sop, "PictOpClear ");
    		break;
    	case PictOpSrc:
    		sprintf(sop, "PictOpSrc ");
    		break;
    	case PictOpDst:
    		sprintf(sop, "PictOpDst ");
    		break;
    	case PictOpOver:
    		sprintf(sop, "PictOpOver ");
    		break;
    	case PictOpOutReverse:
    		sprintf(sop, "PictOpOutReverse ");
    		break;
    	case PictOpAdd:
    		sprintf(sop, "PictOpAdd ");
    		break;
    	default:
    		sprintf(sop, "PictOp%d ", op);
        }
    
        viaExaCompositePictDesc(pSrc, srcdesc, 40);
        viaExaCompositePictDesc(pMask, maskdesc, 40);
        viaExaCompositePictDesc(pDst, dstdesc, 40);
    
        ErrorF("Composite fallback: %s, \n"
               "                    op %s, \n"
               "                    src  %s, \n"
               "                    mask %s, \n"
               "                    dst  %s, \n", info, sop, srcdesc, maskdesc, dstdesc);
    }
    #endif /* VIA_DEBUG_COMPOSITE */
    
    /*
     * Wait for acceleration engines idle. An expensive way to sync.
     */
    void
    viaAccelSync(ScrnInfoPtr pScrn)
    {
        VIAPtr pVia = VIAPTR(pScrn);
        int loop = 0;
    
        mem_barrier();
    
        switch (pVia->Chipset) {
            case VIA_VX800:
            case VIA_VX855:
            case VIA_VX900:
                while ((VIAGETREG(VIA_REG_STATUS) &
                        (VIA_CMD_RGTR_BUSY_H5 | VIA_2D_ENG_BUSY_H5 | VIA_3D_ENG_BUSY_H5))
                       && (loop++ < MAXLOOP)) ;
                break;
            case VIA_P4M890:
            case VIA_K8M890:
            case VIA_P4M900:
                while ((VIAGETREG(VIA_REG_STATUS) &
                        (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))
                       && (loop++ < MAXLOOP)) ;
                break;
            default:
                while (!(VIAGETREG(VIA_REG_STATUS) & VIA_VR_QUEUE_EMPTY)
                       && (loop++ < MAXLOOP)) ;
    
                while ((VIAGETREG(VIA_REG_STATUS) &
                        (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))
                       && (loop++ < MAXLOOP)) ;
                break;
        }
    }
    
    /*
     * Wait for the value to get blitted, or in the PCI case for engine idle.
     */
    static void
    viaAccelWaitMarker(ScreenPtr pScreen, int marker)
    {
        ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
        VIAPtr pVia = VIAPTR(pScrn);
        CARD32 uMarker = marker;
    
        if (pVia->agpDMA) {
            while ((pVia->lastMarkerRead - uMarker) > (1 << 24))
                pVia->lastMarkerRead = *(CARD32 *) pVia->markerBuf;
        } else {
            viaAccelSync(pScrn);
        }
    }
    
    #ifdef OPENCHROMEDRI
    static int
    viaAccelDMADownload(ScrnInfoPtr pScrn, unsigned long fbOffset,
                        unsigned srcPitch, unsigned char *dst,
                        unsigned dstPitch, unsigned w, unsigned h)
    {
        VIAPtr pVia = VIAPTR(pScrn);
        drm_via_dmablit_t blit[2], *curBlit;
        unsigned char *sysAligned = NULL;
        Bool doSync[2], useBounceBuffer;
        unsigned pitch, numLines[2];
        int curBuf, err, i, ret, blitHeight;
    
        ret = 0;
    
        useBounceBuffer = (((unsigned long)dst & 15) || (dstPitch & 15));
        doSync[0] = FALSE;
        doSync[1] = FALSE;
        curBuf = 1;
        blitHeight = h;
        pitch = dstPitch;
        if (useBounceBuffer) {
            pitch = ALIGN_TO(dstPitch, 16);
            blitHeight = VIA_DMA_DL_SIZE / pitch;
        }
    
        while (doSync[0] || doSync[1] || h != 0) {
            curBuf = 1 - curBuf;
            curBlit = &blit[curBuf];
            if (doSync[curBuf]) {
    
                do {
                    err = drmCommandWrite(pVia->drmmode.fd, DRM_VIA_BLIT_SYNC,
                                          &curBlit->sync, sizeof(curBlit->sync));
                } while (err == -EAGAIN);
    
                if (err)
                    return err;
    
                doSync[curBuf] = FALSE;
                if (useBounceBuffer) {
                    for (i = 0; i < numLines[curBuf]; ++i) {
                        memcpy(dst, curBlit->mem_addr, w);
                        dst += dstPitch;
                        curBlit->mem_addr += pitch;
                    }
                }
            }
    
            if (h == 0)
                continue;
    
            curBlit->num_lines = (h > blitHeight) ? blitHeight : h;
            h -= curBlit->num_lines;
            numLines[curBuf] = curBlit->num_lines;
    
            sysAligned =
                    (unsigned char *)pVia->dBounce + (curBuf * VIA_DMA_DL_SIZE);
            sysAligned = (unsigned char *)
                    ALIGN_TO((unsigned long)sysAligned, 16);
    
            curBlit->mem_addr = (useBounceBuffer) ? sysAligned : dst;
            curBlit->line_length = w;
            curBlit->mem_stride = pitch;
            curBlit->fb_addr = fbOffset;
            curBlit->fb_stride = srcPitch;
            curBlit->to_fb = 0;
            fbOffset += curBlit->num_lines * srcPitch;
    
            do {
                err = drmCommandWriteRead(pVia->drmmode.fd, DRM_VIA_DMA_BLIT, curBlit,
                                          sizeof(*curBlit));
            } while (err == -EAGAIN);
    
            if (err) {
                ret = err;
                h = 0;
                continue;
            }
    
            doSync[curBuf] = TRUE;
        }
    
        return ret;
    }
    
    /*
     * Use PCI DMA if we can. If the system alignments don't match, we're using
     * an aligned bounce buffer for pipelined PCI DMA and memcpy.
     * Throughput for large transfers is around 65 MB/s.
     */
    static Bool
    viaExaDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
                             char *dst, int dst_pitch)
    {
        ScrnInfoPtr pScrn = xf86ScreenToScrn(pSrc->drawable.pScreen);
        unsigned wBytes = (pSrc->drawable.bitsPerPixel * w + 7) >> 3;
        unsigned srcPitch = exaGetPixmapPitch(pSrc), srcOffset;
        char *bounceAligned = NULL;
        VIAPtr pVia = VIAPTR(pScrn);
        unsigned totSize;
    
        if (!w || !h)
            return TRUE;
    
        srcOffset = x * pSrc->drawable.bitsPerPixel;
        if (srcOffset & 3)
            return FALSE;
        srcOffset = exaGetPixmapOffset(pSrc) + y * srcPitch + (srcOffset >> 3);
    
        totSize = wBytes * h;
    
        exaWaitSync(pScrn->pScreen);
        if (totSize < VIA_MIN_DOWNLOAD) {
            bounceAligned = (char *) drm_bo_map(pScrn, pVia->drmmode.front_bo) + srcOffset;
    
            while (h--) {
                memcpy(dst, bounceAligned, wBytes);
                dst += dst_pitch;
                bounceAligned += srcPitch;
            }
            return TRUE;
        }
    
        if (!pVia->directRenderingType)
            return FALSE;
    
        if ((srcPitch & 3) || (srcOffset & 3)) {
            ErrorF("VIA EXA download src_pitch misaligned\n");
            return FALSE;
        }
    
        if (viaAccelDMADownload(pScrn, srcOffset, srcPitch, (unsigned char *)dst,
                                dst_pitch, wBytes, h))
            return FALSE;
    
        return TRUE;
    }
    
    /*
     * Upload to framebuffer memory using memcpy to AGP pipelined with a
     * 3D engine texture operation from AGP to framebuffer. The AGP buffers (2)
     * should be kept rather small for optimal pipelining.
     */
    static Bool
    viaExaTexUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
                            int src_pitch)
    {
        ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
        unsigned dstPitch = exaGetPixmapPitch(pDst), dstOffset;
        unsigned wBytes = (w * pDst->drawable.bitsPerPixel + 7) >> 3;
        int i, sync[2], yOffs, bufH, bufOffs, height, format;
        CARD32 texWidth, texHeight, texPitch;
        VIAPtr pVia = VIAPTR(pScrn);
        Via3DState *v3d = &pVia->v3d;
        char *dst, *texAddr;
        Bool buf;
    
        if (!w || !h)
            return TRUE;
    
        if (wBytes * h < VIA_MIN_TEX_UPLOAD) {
            dstOffset = x * pDst->drawable.bitsPerPixel;
            if (dstOffset & 3)
                return FALSE;
    
            dst = (char *) drm_bo_map(pScrn, pVia->drmmode.front_bo) +
                            (exaGetPixmapOffset(pDst) + y * dstPitch +
                            (dstOffset >> 3));
            exaWaitSync(pScrn->pScreen);
    
            while (h--) {
                memcpy(dst, src, wBytes);
                dst += dstPitch;
                src += src_pitch;
            }
            return TRUE;
        }
    
        if (!pVia->texAGPBuffer->ptr)
            return FALSE;
    
        switch (pDst->drawable.bitsPerPixel) {
            case 32:
                format = PICT_a8r8g8b8;
                break;
            case 16:
                format = PICT_r5g6b5;
                break;
            default:
                return FALSE;
        }
    
        dstOffset = exaGetPixmapOffset(pDst);
    
        if (pVia->nPOT[0]) {
            texPitch = ALIGN_TO(wBytes, 32);
            height = VIA_AGP_UPL_SIZE / texPitch;
        } else {
            viaOrder(wBytes, &texPitch);
            if (texPitch < 3)
                texPitch = 3;
            height = VIA_AGP_UPL_SIZE >> texPitch;
            texPitch = 1 << texPitch;
        }
    
        if (height > 1024)
            height = 1024;
        viaOrder(w, &texWidth);
        texWidth = 1 << texWidth;
    
        texHeight = height << 1;
        bufOffs = texPitch * height;
        texAddr = (char *) drm_bo_map(pScrn, pVia->texAGPBuffer);
    
        v3d->setDestination(v3d, dstOffset, dstPitch, format);
        v3d->setDrawing(v3d, 0x0c, 0xFFFFFFFF, 0x000000FF, 0x00);
        v3d->setFlags(v3d, 1, TRUE, TRUE, FALSE);
        if (!v3d->setTexture(v3d, 0, (unsigned long) texAddr, texPitch,
                             pVia->nPOT[0], texWidth, texHeight, format,
                             via_single, via_single, via_src, TRUE))
            return FALSE;
    
        v3d->emitState(v3d, &pVia->cb, viaCheckUpload(pScrn, v3d));
        v3d->emitClipRect(v3d, &pVia->cb, 0, 0, pDst->drawable.width,
                          pDst->drawable.height);
    
        buf = 1;
        yOffs = 0;
        sync[0] = -1;
        sync[1] = -1;
    
        while (h) {
            buf = (buf) ? 0 : 1;
            bufH = (h > height) ? height : h;
            dst = texAddr + ((buf) ? bufOffs : 0);
    
            if (sync[buf] >= 0)
                pVia->exaDriverPtr->WaitMarker(pScrn->pScreen, sync[buf]);
    
            for (i = 0; i < bufH; ++i) {
                memcpy(dst, src, wBytes);
                dst += texPitch;
                src += src_pitch;
            }
    
            v3d->emitQuad(v3d, &pVia->cb, x, y + yOffs, 0, (buf) ? height : 0, 0,
                          0, w, bufH);
    
            sync[buf] = pVia->exaDriverPtr->MarkSync(pScrn->pScreen);
    
            h -= bufH;
            yOffs += bufH;
        }
    
        if (sync[buf] >= 0)
            pVia->exaDriverPtr->WaitMarker(pScrn->pScreen, sync[buf]);
    
        return TRUE;
    }
    
    #endif /* OPENCHROMEDRI */
    
    int
    viaEXAOffscreenAlloc(ScrnInfoPtr pScrn, struct buffer_object *obj,
                            unsigned long size, unsigned long alignment)
    {
        ExaOffscreenArea *pArea;
        int newSize = size;
        int newAlignment;
        int ret = 0;
    
        newAlignment = alignment;
        pArea = exaOffscreenAlloc(pScrn->pScreen, newSize,
                                    newAlignment, TRUE, NULL, NULL);
        if (!pArea) {
            ret = -ENOMEM;
            goto exit;
        }
    
        obj->offset = pArea->offset;
        obj->handle = (unsigned long) pArea;
        obj->domain = TTM_PL_VRAM;
        obj->size = newSize;
    
    exit:
        return ret;
    }
    
    Bool
    viaIsAGP(VIAPtr pVia, PixmapPtr pPix, unsigned long *offset)
    {
    #ifdef OPENCHROMEDRI
        unsigned long offs;
    
        if (pVia->directRenderingType && !pVia->IsPCI) {
            offs = ((unsigned long)pPix->devPrivate.ptr
                    - (unsigned long)pVia->agpMappedAddr);
    
            if ((offs - pVia->scratchOffset) < pVia->agpSize) {
                *offset = offs + pVia->agpAddr;
                return TRUE;
            }
        }
    #endif
        return FALSE;
    }
    
    Bool
    viaExaIsOffscreen(PixmapPtr pPix)
    {
        ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen);
        VIAPtr pVia = VIAPTR(pScrn);
        uint8_t* addr_size;
        uint8_t* front_bo;
        Bool ret;
    
        front_bo = drm_bo_map(pScrn, pVia->drmmode.front_bo);
        addr_size = (uint8_t*)pPix->devPrivate.ptr -
                                                (unsigned long)front_bo;
        ret = (addr_size < (uint8_t*)pVia->drmmode.front_bo->size) ?
                                                            TRUE : FALSE;
        return ret;
    }
    
    Bool
    viaInitExa(ScreenPtr pScreen)
    {
        ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
        ExaDriverPtr pExa;
        Bool nPOTSupported = TRUE;
        VIAPtr pVia = VIAPTR(pScrn);
    
        /*
         * nPOT textures. DRM versions below 2.11.0 don't allow them.
         * Also some CLE266 hardware may not allow nPOT textures for
         * texture engine 1. We need to figure that out.
         */
    #ifdef OPENCHROMEDRI
        nPOTSupported = ((!pVia->directRenderingType) ||
                         (pVia->drmVerMajor > 2) ||
                         ((pVia->drmVerMajor == 2) && (pVia->drmVerMinor >= 11)));
    #endif
        pVia->nPOT[0] = nPOTSupported;
        pVia->nPOT[1] = nPOTSupported;
    
        if (Success != viaSetupCBuffer(pScrn, &pVia->cb, 0)) {
            pVia->NoAccel = TRUE;
            return FALSE;
        }
    
        pExa = exaDriverAlloc();
        if (!pExa) {
            return FALSE;
        }
    
        pExa->exa_major = EXA_VERSION_MAJOR;
        pExa->exa_minor = EXA_VERSION_MINOR;
        pExa->memoryBase = pVia->FBBase;
        pExa->memorySize = pVia->FBFreeEnd;
        pExa->offScreenBase = pScrn->virtualY * pVia->Bpl;
        pExa->pixmapOffsetAlign = 32;
        pExa->pixmapPitchAlign = 16;
        pExa->flags = EXA_OFFSCREEN_PIXMAPS |
                (pVia->nPOT[1] ? 0 : EXA_OFFSCREEN_ALIGN_POT);
    
    
        /*  HW Limitation are described here:
         *
         *  1. H2/H5/H6 2D source and destination:
         *     Pitch: (1 << 14) - 1 = 16383
         *     Dimension: (1 << 12) = 4096
         *     X, Y position: (1 << 12) - 1 = 4095.
         *
         *  2. H2 3D engine Render target:
         *     Pitch: (1 << 14) - 1 = 16383
         *     Clip Rectangle: 0 - 2047
         *
         *  3. H5/H6 3D engine Render target:
         *     Pitch: ((1 << 10) - 1)*32 = 32736
         *     Clip Rectangle: Color Window, 12bits. As Spec saied: 0 - 2048
         *                     Scissor is the same as color window.
         */
        pExa->maxX = 2047;
        pExa->maxY = 2047;
        pExa->WaitMarker = viaAccelWaitMarker;
    
        switch (pVia->Chipset) {
        case VIA_VX800:
        case VIA_VX855:
        case VIA_VX900:
            pExa->MarkSync = viaAccelMarkSync_H6;
            pExa->PrepareSolid = viaExaPrepareSolid_H6;
            pExa->Solid = viaExaSolid_H6;
            pExa->DoneSolid = viaExaDoneSolidCopy_H6;
            pExa->PrepareCopy = viaExaPrepareCopy_H6;
            pExa->Copy = viaExaCopy_H6;
            pExa->DoneCopy = viaExaDoneSolidCopy_H6;
            break;
        default:
            pExa->MarkSync = viaAccelMarkSync_H2;
            pExa->PrepareSolid = viaExaPrepareSolid_H2;
            pExa->Solid = viaExaSolid_H2;
            pExa->DoneSolid = viaExaDoneSolidCopy_H2;
            pExa->PrepareCopy = viaExaPrepareCopy_H2;
            pExa->Copy = viaExaCopy_H2;
            pExa->DoneCopy = viaExaDoneSolidCopy_H2;
            break;
        }
    
    #ifdef OPENCHROMEDRI
        if (pVia->directRenderingType == DRI_1) {
    #ifdef linux
            pExa->DownloadFromScreen = viaExaDownloadFromScreen;
    #endif /* linux */
            switch (pVia->Chipset) {
            case VIA_K8M800:
            case VIA_KM400:
                pExa->UploadToScreen = NULL; //viaExaTexUploadToScreen;
                break;
            default:
                pExa->UploadToScreen = NULL; //viaExaUploadToScreen;
                break;
            }
        }
    #endif /* OPENCHROMEDRI */
    
        if (!pVia->noComposite) {
            switch (pVia->Chipset) {
            case VIA_VX800:
            case VIA_VX855:
            case VIA_VX900:
                pExa->CheckComposite = viaExaCheckComposite_H6;
                pExa->PrepareComposite = viaExaPrepareComposite_H6;
                pExa->Composite = viaExaComposite_H6;
                pExa->DoneComposite = viaExaDoneSolidCopy_H6;
                break;
            default:
                pExa->CheckComposite = viaExaCheckComposite_H2;
                pExa->PrepareComposite = viaExaPrepareComposite_H2;
                pExa->Composite = viaExaComposite_H2;
                pExa->DoneComposite = viaExaDoneSolidCopy_H2;
                break;
            }
        } else {
            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
                       "[EXA] Disabling EXA accelerated composite.\n");
        }
    
        if (!exaDriverInit(pScreen, pExa)) {
            free(pExa);
            return FALSE;
        }
    
        pVia->exaDriverPtr = pExa;
        viaInit3DState(&pVia->v3d);
        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
                    "[EXA] Enabled EXA acceleration.\n");
        return TRUE;
    }
    
    /*
     * Allocate a command buffer and  buffers for accelerated upload, download,
     * and EXA scratch area. The scratch area resides primarily in AGP memory,
     * but reverts to FB if AGP is not available.
     */
    void
    viaFinishInitAccel(ScreenPtr pScreen)
    {
        ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
        VIAPtr pVia = VIAPTR(pScrn);
        int size;
    
    #ifdef OPENCHROMEDRI
        if (pVia->directRenderingType && pVia->useEXA) {
    
            pVia->dBounce = calloc(VIA_DMA_DL_SIZE * 2, 1);
    
            if (!pVia->IsPCI) {
    
                /* Allocate upload and scratch space. */
                if (pVia->exaDriverPtr->UploadToScreen == viaExaTexUploadToScreen) {
                    size = VIA_AGP_UPL_SIZE * 2;
    
                    pVia->texAGPBuffer = drm_bo_alloc(pScrn, size, 32, TTM_PL_TT);
                    if (pVia->texAGPBuffer) {
                        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
                                   "Allocated %u kiB of AGP memory for "
                                   "system-to-framebuffer transfer.\n",
                                   size / 1024);
                        pVia->texAGPBuffer->offset = (pVia->texAGPBuffer->offset + 31) & ~31;
                    }
                }
    
                size = pVia->exaScratchSize * 1024;
                pVia->scratchBuffer = drm_bo_alloc(pScrn, size, 32, TTM_PL_TT);
                if (pVia->scratchBuffer) {
                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
                               "Allocated %u kiB of AGP memory for "
                               "EXA scratch area.\n", size / 1024);
                    pVia->scratchOffset =
                            (pVia->scratchBuffer->offset + 31) & ~31;
                    pVia->scratchAddr = drm_bo_map(pScrn, pVia->scratchBuffer);
                }
            }
        }
    #endif /* OPENCHROMEDRI */
        if (!pVia->scratchAddr && pVia->useEXA) {
            size = pVia->exaScratchSize * 1024 + 32;
            pVia->scratchBuffer = drm_bo_alloc(pScrn, size, 32, TTM_PL_SYSTEM);
    
            if (pVia->scratchBuffer) {
                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
                           "Allocated %u kiB of framebuffer memory for "
                           "EXA scratch area.\n", pVia->exaScratchSize);
                pVia->scratchOffset = pVia->scratchBuffer->offset;
                pVia->scratchAddr = drm_bo_map(pScrn, pVia->scratchBuffer);
            }
        }
        memset(pVia->markerBuf, 0, pVia->exa_sync_bo->size);
    }
    
    /*
     * Free the used acceleration resources.
     */
    void
    viaExitAccel(ScreenPtr pScreen)
    {
        ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
        VIAPtr pVia = VIAPTR(pScrn);
    
        viaAccelSync(pScrn);
        viaTearDownCBuffer(&pVia->cb);
    
        if (pVia->useEXA) {
    #ifdef OPENCHROMEDRI
            if (pVia->directRenderingType == DRI_1) {
                if (pVia->texAGPBuffer) {
                    drm_bo_free(pScrn, pVia->texAGPBuffer);
                    pVia->texAGPBuffer = NULL;
                }
    
                if (pVia->scratchBuffer) {
                    drm_bo_free(pScrn, pVia->scratchBuffer);
                    pVia->scratchBuffer = NULL;
                }
            }
            if (pVia->dBounce)
                free(pVia->dBounce);
    #endif /* OPENCHROMEDRI */
            if (pVia->scratchBuffer) {
                drm_bo_free(pScrn, pVia->scratchBuffer);
                pVia->scratchBuffer = NULL;
            }
            if (pVia->vq_bo) {
                drm_bo_unmap(pScrn, pVia->vq_bo);
                drm_bo_free(pScrn, pVia->vq_bo);
            }
            if (pVia->exa_sync_bo) {
                drm_bo_unmap(pScrn, pVia->exa_sync_bo);
                drm_bo_free(pScrn, pVia->exa_sync_bo);
            }
            if (pVia->exaDriverPtr) {
                exaDriverFini(pScreen);
            }
            free(pVia->exaDriverPtr);
            pVia->exaDriverPtr = NULL;
            return;
        }
    }