/*
 * Copyright 1997-2003 by Alan Hourihane, North Wales, UK.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that the above copyright notice appear in all copies
 * and that both that copyright notice and this permission notice
 * appear in supporting documentation, and that the name of Alan
 * Hourihane not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior
 * permission.  Alan Hourihane makes no representations about the
 * suitability of this software for any purpose.  It is provided
 * "as is" without express or implied warranty.
 *
 * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS, IN NO EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
 * Authors:  Alan Hourihane, <alanh@fairlite.demon.co.uk>
 *
 * Trident Blade3D accelerated options.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "xf86.h"
#include "xf86_OSproc.h"

#include "xf86Pci.h"

#include "miline.h"

#include "trident.h"
#include "trident_regs.h"

#ifdef HAVE_XAA_H
#include "xaarop.h"
#include "xaalocal.h"

static void BladeSync(ScrnInfoPtr pScrn);
#if 0
static void BladeSetupForSolidLine(ScrnInfoPtr pScrn,
                                    int color,
                                    int rop,
                                    unsigned int planemask);
static void BladeSubsequentSolidBresenhamLine(ScrnInfoPtr pScrn,
                                                int x, int y,
                                                int dmaj, int dmin,
                                                int e, int len,
                                                int octant);
static void BladeSubsequentSolidTwoPointLine(ScrnInfoPtr pScrn,
                                                int x1, int y1,
                                                int x2, int y2,
                                                int flags);
static void BladeSetupForDashedLine(ScrnInfoPtr pScrn,
                                    int fg, int bg,
                                    int rop,
                                    unsigned int planemask,
                                    int length,
                                    unsigned char *pattern);
static void BladeSubsequentDashedTwoPointLine(ScrnInfoPtr pScrn,
                                                int x1, int y1,
                                                int x2, int y2,
                                                int flags, int phase);
#endif
static void BladeSetupForFillRectSolid(ScrnInfoPtr pScrn,
                                        int color,
                                        int rop,
                                        unsigned int planemask);
static void BladeSubsequentFillRectSolid(ScrnInfoPtr pScrn,
                                            int x, int y,
                                            int w, int h);
static void BladeSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn,
                                                int x1, int y1,
                                                int x2, int y2,
                                                int w, int h);
static void BladeSetupForScreenToScreenCopy(ScrnInfoPtr pScrn,
                                            int xdir, int ydir,
                                            int rop,
                                            unsigned int planemask,
                                            int transparency_color);
#if 0
static void BladeSetupForScreenToScreenColorExpand(ScrnInfoPtr pScrn,
                                            int fg, int bg,
                                            int rop,
                                            unsigned int planemask);
static void BladeSubsequentScreenToScreenColorExpand(ScrnInfoPtr pScrn,
                                                    int x, int y,
                                                    int w, int h,
                                                    int srcx, int srcy,
                                                    int offset);
#endif
static void BladeSetupForCPUToScreenColorExpand(ScrnInfoPtr pScrn,
                                            int fg, int bg,
                                            int rop,
                                            unsigned int planemask);
static void BladeSubsequentCPUToScreenColorExpand(ScrnInfoPtr pScrn,
                                                    int x, int y,
                                                    int w, int h,
                                                    int skipleft);
static void BladeSetClippingRectangle(ScrnInfoPtr pScrn,
                                        int x1, int y1,
                                        int x2, int y2);
static void BladeDisableClipping(ScrnInfoPtr pScrn);
static void BladeSetupForMono8x8PatternFill(ScrnInfoPtr pScrn,
                                            int patternx,
                                            int patterny,
                                            int fg, int bg,
                                            int rop,
                                            unsigned int planemask);
static void BladeSubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn,
                                                    int patternx,
                                                    int patterny,
                                                    int x, int y,
                                                    int w, int h);
#if 0
static void BladeSetupForColor8x8PatternFill(ScrnInfoPtr pScrn,
                                                int patternx,
                                                int patterny,
                                                int rop,
                                                unsigned int planemask,
                                                int trans_col);
static void BladeSubsequentColor8x8PatternFillRect(ScrnInfoPtr pScrn,
                                                    int patternx,
                                                    int patterny,
                                                    int x, int y,
                                                    int w, int h);
#endif
static void BladeSetupForImageWrite(ScrnInfoPtr pScrn,
                                    int rop,
                                    unsigned int planemask,
                                    int transparency_color,
                                    int bpp, int depth);
static void BladeSubsequentImageWriteRect(ScrnInfoPtr pScrn,
                                            int x, int y,
                                            int w, int h,
                                            int skipleft);

static void
BladeInitializeAccelerator(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    CARD32 stride;

    stride = (pScrn->displayWidth >> 3) << 20;

    BLADE_OUT(0x21C8, stride);
    BLADE_OUT(0x21CC, stride);
    BLADE_OUT(0x21D0, stride);
    BLADE_OUT(0x21D4, stride);
    switch (pScrn->depth) {
        case 8:
        stride |= (0 << 29);
        break;
        case 15:
        stride |= (5 << 29);
        break;
        case 16:
        stride |= (1 << 29);
        break;
        case 24:
        stride |= (2 << 29);
        break;
    }

    BLADE_OUT(0x21B8, 0);
    BLADE_OUT(0x21B8, stride);
    BLADE_OUT(0x21BC, stride);
    BLADE_OUT(0x21C0, stride);
    BLADE_OUT(0x21C4, stride);
#if 0
    /* It appears that the driver sometimes misdetects the RAM type, so we
     * don't force this for now */
    if (pTrident->HasSGRAM)
        BLADE_OUT(0x2168, 1 << 26); /* Enables Block Write if available (SGRAM) */
    else
        BLADE_OUT(0x2168, 0);
#endif
    BLADE_OUT(0x216C, 0);
}
#endif

Bool BladeXaaInit(ScreenPtr pScreen) {
#ifdef HAVE_XAA_H
    XAAInfoRecPtr infoPtr;
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    if (pTrident->NoAccel)
        return FALSE;

    pTrident->AccelInfoRec = infoPtr = XAACreateInfoRec();
    if (!infoPtr) return FALSE;

    pTrident->InitializeAccelerator = BladeInitializeAccelerator;
    BladeInitializeAccelerator(pScrn);

    infoPtr->Flags = PIXMAP_CACHE |
                        LINEAR_FRAMEBUFFER |
                        OFFSCREEN_PIXMAPS;

    infoPtr->Sync = BladeSync;

    infoPtr->SetClippingRectangle = BladeSetClippingRectangle;
    infoPtr->DisableClipping = BladeDisableClipping;

#if 0
    infoPtr->SolidLineFlags = 0;
    infoPtr->SetupForSolidLine = BladeSetupForSolidLine;
    infoPtr->SubsequentSolidTwoPointLine =
                                    BladeSubsequentSolidTwoPointLine;
    infoPtr->SetupForDashedLine = BladeSetupForDashedLine;
    infoPtr->SubsequentDashedTwoPointLine =
                                    BladeSubsequentDashedTwoPointLine;
    infoPtr->DashPatternMaxLength = 16;
    infoPtr->DashedLineFlags = LINE_PATTERN_LSBFIRST_LSBJUSTIFIED |
                                LINE_PATTERN_POWER_OF_2_ONLY;
#endif

    infoPtr->SolidFillFlags = NO_PLANEMASK;
    infoPtr->SetupForSolidFill = BladeSetupForFillRectSolid;
    infoPtr->SubsequentSolidFillRect = BladeSubsequentFillRectSolid;

    infoPtr->ScreenToScreenCopyFlags = ONLY_TWO_BITBLT_DIRECTIONS |
                                        NO_PLANEMASK |
                                        NO_TRANSPARENCY;

    infoPtr->SetupForScreenToScreenCopy =
                                    BladeSetupForScreenToScreenCopy;
    infoPtr->SubsequentScreenToScreenCopy =
                                    BladeSubsequentScreenToScreenCopy;

    infoPtr->Mono8x8PatternFillFlags = NO_PLANEMASK |
                                    NO_TRANSPARENCY |
                                    BIT_ORDER_IN_BYTE_MSBFIRST |
                                    HARDWARE_PATTERN_SCREEN_ORIGIN |
                                    HARDWARE_PATTERN_PROGRAMMED_BITS;

    infoPtr->SetupForMono8x8PatternFill =
                                    BladeSetupForMono8x8PatternFill;
    infoPtr->SubsequentMono8x8PatternFillRect =
                                BladeSubsequentMono8x8PatternFillRect;

#if 0
    infoPtr->Color8x8PatternFillFlags =
                                    HARDWARE_PATTERN_SCREEN_ORIGIN |
                                    BIT_ORDER_IN_BYTE_MSBFIRST;

    infoPtr->SetupForColor8x8PatternFill =
                                TridentSetupForColor8x8PatternFill;
    infoPtr->SubsequentColor8x8PatternFillRect =
                            TridentSubsequentColor8x8PatternFillRect;

    infoPtr->ScreenToScreenColorExpandFillFlags = 0;

    infoPtr->SetupForScreenToScreenColorExpandFill =
                            BladeSetupForScreenToScreenColorExpand;
    infoPtr->SubsequentScreenToScreenColorExpandFill =
                            BladeSubsequentScreenToScreenColorExpand;
#endif

    infoPtr->CPUToScreenColorExpandFillFlags =
                                        CPU_TRANSFER_PAD_DWORD |
                                        LEFT_EDGE_CLIPPING |
                                        SYNC_AFTER_COLOR_EXPAND |
                                        NO_PLANEMASK |
                                        BIT_ORDER_IN_BYTE_MSBFIRST |
                                        SCANLINE_PAD_DWORD;
    infoPtr->ColorExpandRange = 0x10000;
    infoPtr->ColorExpandBase = pTrident->IOBase + 0x10000;
    infoPtr->SetupForCPUToScreenColorExpandFill =
                                BladeSetupForCPUToScreenColorExpand;
    infoPtr->SubsequentCPUToScreenColorExpandFill =
                                BladeSubsequentCPUToScreenColorExpand;

    infoPtr->SetupForImageWrite = BladeSetupForImageWrite;
    infoPtr->SubsequentImageWriteRect =
                                        BladeSubsequentImageWriteRect;
    infoPtr->ImageWriteFlags = NO_PLANEMASK |
                                LEFT_EDGE_CLIPPING |
                                CPU_TRANSFER_PAD_DWORD |
                                SYNC_AFTER_IMAGE_WRITE;
    infoPtr->ImageWriteBase = pTrident->IOBase + 0x10000;
    infoPtr->ImageWriteRange = 0x10000;

    return(XAAInit(pScreen, infoPtr));
#else
    return FALSE;
#endif
}

#ifdef HAVE_XAA_H
static void
BladeSync(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    int busy;
    int cnt = 10000000;

    if (pTrident->Clipping) BladeDisableClipping(pScrn);
    BLADE_OUT(0x216C, 0);

    BLADEBUSY(busy);
    while (busy != 0) {
        if (--cnt < 0) {
            ErrorF("GE timeout\n");
            BLADE_OUT(0x2124, 1 << 7);
            BLADE_OUT(0x2124, 0);
            break;
        }

        BLADEBUSY(busy);
    }
}

static void
BladeSetupForScreenToScreenCopy(ScrnInfoPtr pScrn,
                                int xdir, int ydir,
                                int rop,
                                unsigned int planemask,
                                int transparency_color)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    pTrident->BltScanDirection = 0;
    if ((xdir < 0) || (ydir < 0))
        pTrident->BltScanDirection |= (1 << 1);

#if 0
    if (transparency_color != -1) {
        BLADE_OUT(0x2168, transparency_color & 0xffffff);
        pTrident->BltScanDirection |= (1 << 6);
    }

    REPLICATE(planemask);
    if (planemask != (unsigned int)-1) {
        BLADE_OUT(0x2184, ~planemask);
        pTrident->BltScanDirection |= (1 << 5);
    }

#endif
    BLADE_OUT(0x2148, XAAGetCopyROP(rop));
}

static void
BladeSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn,
                                    int x1, int y1,
                                    int x2, int y2,
                                    int w, int h)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    int clip = 0;

    if (pTrident->Clipping) clip = 1;

    BLADE_OUT(0x2144, 0xE0000000 |
                        (1 << 19) | (1 << 4) | (1 << 2) |
                        pTrident->BltScanDirection | clip);

    if (pTrident->BltScanDirection) {
        BLADE_OUT(0x2100, ((y1 + h - 1) << 16) | (x1 + w - 1));
        BLADE_OUT(0x2104, (y1 << 16) | x1);
        BLADE_OUT(0x2108, ((y2 + h - 1) << 16) | (x2 + w - 1));
        BLADE_OUT(0x210C, ((y2 & 0xfff) << 16) | (x2 & 0xfff));
    } else {
        BLADE_OUT(0x2100, (y1 << 16) | x1);
        BLADE_OUT(0x2104, ((y1 + h - 1) << 16) | (x1 + w - 1));
        BLADE_OUT(0x2108, (y2 << 16) | x2);
        BLADE_OUT(0x210C, (((y2 + h - 1) & 0xfff) << 16) |
                            ((x2 + w - 1) & 0xfff));
    }
}

static void
BladeSetClippingRectangle(ScrnInfoPtr pScrn,
                            int x1, int y1,
                            int x2, int y2)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    BLADE_OUT(0x2154, ((y1 & 0x0fff) << 16) | (x1 & 0x0fff));
    BLADE_OUT(0x2158, ((y2 & 0x0fff) << 16) | (x2 & 0x0fff));
    pTrident->Clipping = TRUE;
}

static void
BladeDisableClipping(ScrnInfoPtr pScrn)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    pTrident->Clipping = FALSE;
}

#if 0
static void
BladeSetupForSolidLine(ScrnInfoPtr pScrn,
                        int color,
                        int rop,
                        unsigned int planemask)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    REPLICATE(color);
    BLADE_OUT(0x2160, color);
    BLADE_OUT(0x2148, XAAGetCopyROP(rop));
    pTrident->BltScanDirection = 0;
    REPLICATE(planemask);
    if (planemask != -1) {
        BLADE_OUT(0x2184, ~planemask);
        pTrident->BltScanDirection |= (1 << 5);
    }
}

static void
BladeSubsequentSolidBresenhamLine(ScrnInfoPtr pScrn,
                                    int x, int y,
                                    int dmaj, int dmin,
                                    int e, int len,
                                    int octant)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    int tmp;
    int D = 0, E = 0, ymajor = 0;

    BLADE_OUT(0x2144, 0x20000000 |
                        (3 << 19) | (1 << 4) | (2 << 2) |
                        (pTrident->Clipping ? 1 : 0));

    if (!(octant & YMAJOR)) {
        if ((!(octant & XDECREASING)) && (!(octant & YDECREASING))) {
            E = 1; D = 0;
        }

        if ((!(octant & XDECREASING)) && ( (octant & YDECREASING))) {
            E = 1; D = 1;
        }

        if (( (octant & XDECREASING)) && (!(octant & YDECREASING))) {
            E = 1; D = 2;
        }

        if (( (octant & XDECREASING)) && ( (octant & YDECREASING))) {
            E = 1; D = 3;
        }

        ymajor = 0;
    } else {
        if ((!(octant & XDECREASING)) && (!(octant & YDECREASING))) {
            E = 0; D = 0;
        }

        if ((!(octant & XDECREASING)) && ( (octant & YDECREASING))) {
            E = 0; D = 2;
        }

        if (( (octant & XDECREASING)) && (!(octant & YDECREASING))) {
            E = 0; D = 1;
        }

        if (( (octant & XDECREASING)) && ( (octant & YDECREASING))) {
            E = 0; D = 3;
        }

        ymajor = 1 << 21;
    }

    if (E) {
        tmp = x; x = y; y = tmp;
    }

    BLADE_OUT(0x2130, 0x00000001);
    if (D & 0x02) {
        BLADE_OUT(0x213C, 0x10000000 |
                            (1 << 25) | (1 << 19) | (1 << 17) |
                            ymajor | ((x + len - 1) << 4));
    } else {
        BLADE_OUT(0x213C, 0x10000000 |
                            (1 << 25) | (1 << 19) | (1 << 17) |
                            ymajor | ((y + len - 1) << 4));
    }

    BLADE_OUT(0x2140, (E << 30) |
                        ((y & 0xfff) << 20) | ((x & 0xfff) << 4));
    BLADE_OUT(0x2144, (D << 30) |
                        (((dmaj - dmin) & 0xfff) << 16) |
                        (-dmin & 0xfff));
    BLADE_OUT(0x2148, ((-(dmin + e) & 0xfff) << 16));
}

static void
BladeSubsequentSolidTwoPointLine(ScrnInfoPtr pScrn,
                                    int x1, int y1,
                                    int x2, int y2,
                                    int flags)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

#if 0
    if (flags & OMIT_LAST)
        BladeSetClippingRectangle(pScrn, x1, y1, x2 - 1, y2 - 1);
#endif

    BLADE_OUT(0x2144, 0x20000000 |
                        pTrident->BltScanDirection |
                        (1 << 19) | (1 << 4) | (2 << 2));
    BLADE_OUT(0x2130, 0x3);
    BLADE_OUT(0x2108, (y1 << 16) | x1);
    BLADE_OUT(0x210C, ((y2 & 0xfff) << 16) | (x2 & 0xfff));

#if 0
    if (flags & OMIT_LAST)
    BladeDisableClipping(pScrn);
#endif
}

static void
BladeSetupForDashedLine(ScrnInfoPtr pScrn,
                        int fg, int bg,
                        int rop,
                        unsigned int planemask,
                        int length,
                        unsigned char *pattern)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    pTrident->LinePattern = *((CARD16 *)pattern) & ((1 << length) - 1);
    switch (length) {
        case 2:
        pTrident->LinePattern = pTrident->LinePattern |
                                (pTrident->LinePattern << 2);
        case 4:
        pTrident->LinePattern = pTrident->LinePattern |
                                (pTrident->LinePattern << 4);
        case 8:
        pTrident->LinePattern = pTrident->LinePattern |
                                (pTrident->LinePattern << 8);
    }

    REPLICATE(fg);
    REPLICATE(bg);
    BLADE_OUT(0x2160, fg);
    BLADE_OUT(0x2164, bg);
    BLADE_OUT(0x2148, XAAGetCopyROP(rop));
    pTrident->BltScanDirection = 0;
    REPLICATE(planemask);
    if (planemask != -1) {
        BLADE_OUT(0x2184, ~planemask);
        pTrident->BltScanDirection |= (1 << 5);
    }
}

static void
BladeSubsequentDashedTwoPointLine(ScrnInfoPtr pScrn,
                                    int x1, int y1,
                                    int x2, int y2,
                                    int flags, int phase)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    if (flags & OMIT_LAST)
        BladeSetClippingRectangle(pScrn, x1, y1, x2 - 1, y2 - 1);

    BLADE_OUT(0x216C, (pTrident->LinePattern >> phase) |
                        (pTrident->LinePattern << (16 - phase)));
    BLADE_OUT(0x2144, 0x20000000 |
                        pTrident->BltScanDirection |
                        (1 << 27) | (1 << 19) | (1 << 4) | (2 << 2));
    BLADE_OUT(0x2108, (y1 << 16) | x1);
    BLADE_OUT(0x210C, ((y2 & 0xfff) << 16) | (x2 & 0xfff));

    if (flags & OMIT_LAST)
        BladeDisableClipping(pScrn);
}
#endif

static void
BladeSetupForFillRectSolid(ScrnInfoPtr pScrn,
                            int color,
                            int rop,
                            unsigned int planemask)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    REPLICATE(color);
    BLADE_OUT(0x2160, color);
    BLADE_OUT(0x2148, XAAGetCopyROP(rop));
    pTrident->BltScanDirection = 0;
#if 0
    REPLICATE(planemask);
    if (planemask != -1) {
        BLADE_OUT(0x2184, ~planemask);
        pTrident->BltScanDirection |= (1 << 5);
    }
#endif
}

static void
BladeSubsequentFillRectSolid(ScrnInfoPtr pScrn,
                                int x, int y,
                                int w, int h)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    BLADE_OUT(0x2144, 0x20000000 |
                        pTrident->BltScanDirection |
                        (1 << 19) | (1 << 4) | (2 << 2) |
                        (pTrident->Clipping ? 1 : 0));
    BLADE_OUT(0x2108, (y << 16) | x);
    BLADE_OUT(0x210C, (((y + h - 1) & 0xfff) << 16) |
                        ((x + w - 1) & 0xfff));
}

#if 0
static void
BladeSetupForScreenToScreenColorExpand(ScrnInfoPtr pScrn,
                                        int fg, int bg,
                                        int rop,
                                        unsigned int planemask)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    pTrident->ROP = rop;

    REPLICATE(bg);
    REPLICATE(fg);
    IMAGE_OUT(0x44, fg);
    IMAGE_OUT(0x48, bg);
    IMAGE_OUT(0x20, 0x90000000 | XAAGetCopyROP(rop));
    pTrident->BltScanDirection = 0;
    REPLICATE(planemask);
    if (planemask != -1) {
        BLADE_OUT(0x2184, ~planemask);
        pTrident->BltScanDirection |= (1 << 5);
    }
}

static void
BladeSubsequentScreenToScreenColorExpand(ScrnInfoPtr pScrn,
                                            int x, int y,
                                            int w, int h,
                                            int srcx, int srcy,
                                            int offset)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    IMAGE_OUT(0x00, (srcy << 16) | srcx);
    IMAGE_OUT(0x04, ((srcy + h - 1) << 16) | (srcx + w - 1));
    IMAGE_OUT(0x08, (y << 16) | x);
    IMAGE_OUT(0x0C, ((y + h - 1) << 16) | (x + w - 1));

    IMAGE_OUT(0x24, 0x80000000 |
                    (3 << 22) | (1 << 7) |
                    pTrident->BltScanDirection |
                    (pTrident->ROP == GXcopy ? 0 : (1 << 10)) |
                    (offset << 25));
}
#endif

static void
BladeSetupForCPUToScreenColorExpand(ScrnInfoPtr pScrn,
                                    int fg, int bg,
                                    int rop,
                                    unsigned int planemask)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    pTrident->BltScanDirection = 0;
    BLADE_OUT(0x2148, XAAGetCopyROP(rop));
    if (bg == -1) {
        pTrident->BltScanDirection |= (2 << 19);
        REPLICATE(fg);
        BLADE_OUT(0x2160, fg);
        BLADE_OUT(0x2164, ~fg);
    } else {
        pTrident->BltScanDirection |= (3 << 19);
        REPLICATE(fg);
        REPLICATE(bg);
        BLADE_OUT(0x2160, fg);
        BLADE_OUT(0x2164, bg);
    }

#if 0
    REPLICATE(planemask);
    if (planemask != -1) {
        BLADE_OUT(0x2184, ~planemask);
        pTrident->BltScanDirection |= (1 << 5);
    }
#endif
}

static void
BladeSubsequentCPUToScreenColorExpand(ScrnInfoPtr pScrn,
                                        int x, int y,
                                        int w, int h,
                                        int skipleft)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    if (skipleft)
        BladeSetClippingRectangle(pScrn,
                                    x + skipleft, y,
                                    (x + w - 1), (y + h - 1));
    BLADE_OUT(0x2144, 0xE0000000 |
                        pTrident->BltScanDirection |
                        (1 << 4) |
                        (skipleft ? 1 : 0));
    BLADE_OUT(0x2108, ((y & 0xfff) << 16) | (x & 0xfff));
    BLADE_OUT(0x210C, (((y + h - 1) & 0xfff) << 16) |
                        ((x + w - 1) & 0xfff));
}

static void
BladeSetupForMono8x8PatternFill(ScrnInfoPtr pScrn,
                                int patternx, int patterny,
                                int fg, int bg,
                                int rop,
                                unsigned int planemask)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    BladeSync(pScrn);
    BLADE_OUT(0x2148, XAAGetPatternROP(rop));

    if (bg == -1) {
        REPLICATE(fg);
        BLADE_OUT(0x216C, 0x80000000 | (1 << 30));
        BLADE_OUT(0x216C, 0x80000000 | (1 << 28) | (1 << 30));
        BLADE_OUT(0x2170, patternx);
        BLADE_OUT(0x2170, patterny);
        BLADE_OUT(0x2174, fg);
#if 0
        BLADE_OUT(0x2178, ~fg);
#endif
    } else {
        REPLICATE(fg);
        REPLICATE(bg);
        BLADE_OUT(0x216C, 0x80000000);
        BLADE_OUT(0x216C, 0x80000000 | (1 << 28));
        BLADE_OUT(0x2170, patternx);
        BLADE_OUT(0x2170, patterny);
        BLADE_OUT(0x2174, fg);
        BLADE_OUT(0x2178, bg);
    }

    pTrident->BltScanDirection = 0;
#if 0
    REPLICATE(planemask);
    if (planemask != -1) {
        BLADE_OUT(0x2184, ~planemask);
        pTrident->BltScanDirection |= (1 << 5);
    }
#endif
}

static void
BladeSubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn,
                                        int patternx, int patterny,
                                        int x, int y,
                                        int w, int h)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    int clip = 0;

    if (pTrident->Clipping) clip = 1;
    BLADE_OUT(0x2144, 0x20000000 |
                        pTrident->BltScanDirection |
                        (7 << 12) | (1 << 4) |
                        (1 << 19) | (2 << 2) | clip);
    BLADE_OUT(0x2108, (y << 16) | x);
    BLADE_OUT(0x210C, (((y + h - 1) & 0xfff) << 16) |
                        ((x + w - 1) & 0xfff));
}

#if 0
static void
BladeSetupForColor8x8PatternFill(ScrnInfoPtr pScrn,
                                    int patternx, int patterny,
                                    int rop,
                                    unsigned int planemask,
                                    int transparency_color)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    TGUI_PATLOC(((patterny *
                        pScrn->displayWidth *
                        (pScrn->bitsPerPixel / 8)) +
                    (patternx *
                        (pScrn->bitsPerPixel / 8))) >> 6);
    pTrident->BltScanDirection = 0;
    if (transparency_color != -1) {
        BLADE_OUT(0x2168, transparency_color & 0xffffff);
        pTrident->BltScanDirection |= (1 << 6);
    }
    TGUI_FMIX(XAAGetPatternROP(rop));
    REPLICATE(planemask);
    if (planemask != -1) {
        BLADE_OUT(0x2184, ~planemask);
        pTrident->BltScanDirection |= (1 << 5);
    }
}

static void
BladeSubsequentColor8x8PatternFillRect(ScrnInfoPtr pScrn,
                                        int patternx, int patterny,
                                        int x, int y,
                                        int w, int h)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    TGUI_DEST_XY(x, y);
    TGUI_DIM_XY(w, h);
    TGUI_COMMAND(GE_BLT);
    CHECKCLIPPING;
}
#endif

static void
BladeSetupForImageWrite(ScrnInfoPtr pScrn,
                        int rop,
                        unsigned int planemask,
                        int transparency_color,
                        int bpp, int depth)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    BLADE_OUT(0x2148, XAAGetCopyROP(rop));
    pTrident->BltScanDirection = 0;
#if 0
    REPLICATE(planemask);
    if (planemask != -1) {
        BLADE_OUT(0x2184, ~planemask);
        pTrident->BltScanDirection |= (1 << 5);
    }
#endif
}

static void
BladeSubsequentImageWriteRect(ScrnInfoPtr pScrn,
                                int x, int y,
                                int w, int h,
                                int skipleft)
{
    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);

    if (skipleft)
        BladeSetClippingRectangle(pScrn,
                                    x + skipleft, y,
                                    (x + w - 1), (y + h - 1));
    BLADE_OUT(0x2144, 0xE0000000 |
                        (1 << 19) | (1 << 4) |
                        pTrident->BltScanDirection |
                        (skipleft ? 1 : 0));
    BLADE_OUT(0x2108, (y << 16) | (x & 0xfff));
    BLADE_OUT(0x210C, (((y + h - 1) & 0xfff) << 16) |
                        ((x + w - 1) & 0xfff));
}
#endif