150806d53Smrg/*
250806d53Smrg * Copyright 1997-2000 by Robin Cutshaw <robin@XFree86.Org>
350806d53Smrg * Copyright 2005 Adam Jackson <ajax@nwnk.net>
450806d53Smrg *
550806d53Smrg * Permission to use, copy, modify, distribute, and sell this software and its
650806d53Smrg * documentation for any purpose is hereby granted without fee, provided that
750806d53Smrg * the above copyright notice appear in all copies and that both that
850806d53Smrg * copyright notice and this permission notice appear in supporting
950806d53Smrg * documentation, and that the names of the authors not be used in
1050806d53Smrg * advertising or publicity pertaining to distribution of the software without
1150806d53Smrg * specific, written prior permission.  The authors make no representations
1250806d53Smrg * about the suitability of this software for any purpose.  It is provided
1350806d53Smrg * "as is" without express or implied warranty.
1450806d53Smrg *
1550806d53Smrg * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1650806d53Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1750806d53Smrg * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1850806d53Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1950806d53Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2050806d53Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2150806d53Smrg * PERFORMANCE OF THIS SOFTWARE.
2250806d53Smrg */
2350806d53Smrg
2450806d53Smrg/* Solid and Copy support derived from the i128 XAA code */
2550806d53Smrg
2650806d53Smrg#ifdef HAVE_CONFIG_H
2750806d53Smrg#include "config.h"
2850806d53Smrg#endif
2950806d53Smrg
3050806d53Smrg#include "exa.h"
3150806d53Smrg#include "miline.h"
3250806d53Smrg#include "servermd.h"
3350806d53Smrg#include "picture.h"
3450806d53Smrg
3550806d53Smrg#include "xf86.h"
3650806d53Smrg#include "xf86_OSproc.h"
3750806d53Smrg#include "xf86Pci.h"
3850806d53Smrg
3950806d53Smrg#include "i128.h"
4050806d53Smrg#include "i128reg.h"
4150806d53Smrg
4250806d53Smrg#define PI128_FROM_PIXMAP(x) \
43a73423d7Smrg    I128Ptr pI128 = I128PTR(xf86ScreenToScrn(x->drawable.pScreen))
4450806d53Smrg#define PI128_FROM_SCREEN(x) \
45a73423d7Smrg    I128Ptr pI128 = I128PTR(xf86ScreenToScrn(x))
4650806d53Smrg#define PI128_FROM_PICTURE(x) \
47a73423d7Smrg    I128Ptr pI128 = I128PTR(xf86ScreenToScrn(x->pDrawable->pScreen))
4850806d53Smrg
4950806d53Smrg/* we might be able to do something smarter than this */
5050806d53Smrg#define ENG_PIPELINE_READY() \
5150806d53Smrg    while (pI128->mem.rbase_a[BUSY] & BUSY_BUSY)
5250806d53Smrg#define ENG_DONE() \
5350806d53Smrg    while (pI128->mem.rbase_a[FLOW] & (FLOW_DEB | FLOW_MCB | FLOW_PRV))
5450806d53Smrg
5550806d53Smrg#if 1
5650806d53Smrg#define I128_EXA_DEBUG(x)
5750806d53Smrg#else
5850806d53Smrg#define I128_EXA_DEBUG(x) ErrorF x
5950806d53Smrg#endif
6050806d53Smrg
6150806d53Smrg/* technically we should set the caches to bogus things during init... */
6250806d53Smrg#define CACHE_DEBUG 0
6350806d53Smrg
6450806d53Smrg#define CACHED_UPDATE(val, reg) \
6550806d53Smrg    do if (pI128->val != val) { \
66e9f7eabcSmrg        if (CACHE_DEBUG) { I128_EXA_DEBUG(("Updated cache for " #reg "\n")); } \
6750806d53Smrg        pI128->mem.rbase_a[reg] = pI128->val = val; \
6850806d53Smrg    } while (0)
6950806d53Smrg
7050806d53Smrgstatic void
7150806d53Smrgi128SetBufCtrl(I128Ptr pI128, int dest_bpp)
7250806d53Smrg{
7350806d53Smrg    unsigned int buf_ctrl;
7450806d53Smrg
7550806d53Smrg    switch (dest_bpp) {
7650806d53Smrg        case 8:  buf_ctrl = BC_PSIZ_8B;  break;
7750806d53Smrg        case 16: buf_ctrl = BC_PSIZ_16B; break;
7850806d53Smrg        case 24:
7950806d53Smrg        case 32: buf_ctrl = BC_PSIZ_32B; break;
8050806d53Smrg        default: buf_ctrl = 0;           break; /* error */
8150806d53Smrg    }
8250806d53Smrg    if (pI128->Chipset == PCI_CHIP_I128_T2R) {
8350806d53Smrg        if (pI128->MemoryType == I128_MEMORY_SGRAM)
8450806d53Smrg            buf_ctrl |= BC_MDM_PLN;
8550806d53Smrg        else
8650806d53Smrg            buf_ctrl |= BC_BLK_ENA;
8750806d53Smrg    }
8850806d53Smrg
8950806d53Smrg    CACHED_UPDATE(buf_ctrl, BUF_CTRL);
9050806d53Smrg}
9150806d53Smrg
9250806d53Smrgstatic const CARD32 i128alu[16] =
9350806d53Smrg{
9450806d53Smrg    CR_CLEAR << 8,
9550806d53Smrg    CR_AND << 8,
9650806d53Smrg    CR_AND_REV << 8,
9750806d53Smrg    CR_COPY << 8,
9850806d53Smrg    CR_AND_INV << 8,
9950806d53Smrg    CR_NOOP << 8,
10050806d53Smrg    CR_XOR << 8,
10150806d53Smrg    CR_OR << 8,
10250806d53Smrg    CR_NOR << 8,
10350806d53Smrg    CR_EQUIV << 8,
10450806d53Smrg    CR_INVERT << 8,
10550806d53Smrg    CR_OR_REV << 8,
10650806d53Smrg    CR_COPY_INV << 8,
10750806d53Smrg    CR_OR_INV << 8,
10850806d53Smrg    CR_NAND << 8,
10950806d53Smrg    CR_SET << 8
11050806d53Smrg};
11150806d53Smrg
11250806d53Smrg/*                                8bpp   16bpp  32bpp unused */
11350806d53Smrgstatic const int min_size[]   = { 0x62,  0x32,  0x1A, 0x00 };
11450806d53Smrgstatic const int max_size[]   = { 0x80,  0x40,  0x20, 0x00 };
11550806d53Smrgstatic const int split_size[] = { 0x20,  0x10,  0x08, 0x00 };
11650806d53Smrg
11750806d53Smrg/*
11850806d53Smrg * this is the workhorse for our solid and copy routines.  this works because
11950806d53Smrg * when CS_SOLID is set, the color comes from the FORE register regardless of
12050806d53Smrg * the source pixmap coords.
12150806d53Smrg */
12250806d53Smrg
12350806d53Smrgstatic void
12450806d53Smrgi128ExaBlit(PixmapPtr dst, int x1, int y1, int x2, int y2, int w, int h)
12550806d53Smrg{
12650806d53Smrg    int wh;
12750806d53Smrg    PI128_FROM_PIXMAP(dst);
12850806d53Smrg
12950806d53Smrg    I128_EXA_DEBUG(("Blit: %d %d %d %d %d %d\n", x1, y1, x2, y2, w, h));
13050806d53Smrg    ENG_PIPELINE_READY();
13150806d53Smrg
13250806d53Smrg    /*
13350806d53Smrg     * this deserves explanation.  XY3_DIR == 0 means left to right, top to
13450806d53Smrg     * bottom.  setting bit zero (DIR_LR_BT) switches to bottom to top, and
13550806d53Smrg     * setting bit one (DIR_RL_TB) switches to right to left. XXX rewrite me.
13650806d53Smrg     */
13750806d53Smrg    if (pI128->blitdir & DIR_RL_TB) { /* right-to-left */
13850806d53Smrg        x1 += w; x1--;
13950806d53Smrg        x2 += w; x2--;
14050806d53Smrg    }
14150806d53Smrg    if (pI128->blitdir & DIR_LR_BT) { /* bottom-to-top */
14250806d53Smrg        y1 += h; y1--;
14350806d53Smrg        y2 += h; y2--;
14450806d53Smrg    }
14550806d53Smrg
14650806d53Smrg    if (pI128->Chipset == PCI_CHIP_I128) {
14750806d53Smrg        int bppi;
14850806d53Smrg
14950806d53Smrg        /* The I128-1 has a nasty bitblit bug
15050806d53Smrg         * that occurs when dest is exactly 8 pages wide
15150806d53Smrg         */
15250806d53Smrg
15350806d53Smrg        bppi = (pI128->mem.rbase_a[BUF_CTRL] & BC_PSIZ_MSK) >> 24;
15450806d53Smrg
15550806d53Smrg        if ((w >= min_size[bppi]) && (w <= max_size[bppi])) {
15650806d53Smrg            bppi = split_size[bppi];
15750806d53Smrg#if 1
15850806d53Smrg            /* split method */
15950806d53Smrg
16050806d53Smrg            wh = (bppi << 16) | h;
16150806d53Smrg            CACHED_UPDATE(wh, XY2_WH);
16250806d53Smrg            pI128->mem.rbase_a[XY0_SRC] = (x1 << 16) | y1;    MB;
16350806d53Smrg            pI128->mem.rbase_a[XY1_DST] = (x2 << 16) | y2;    MB;
16450806d53Smrg
16550806d53Smrg            ENG_PIPELINE_READY();
16650806d53Smrg
16750806d53Smrg            w -= bppi;
16850806d53Smrg
16950806d53Smrg            if (pI128->blitdir & DIR_RL_TB) {
17050806d53Smrg                /* right to left blit */
17150806d53Smrg                x1 -= bppi;
17250806d53Smrg                x2 -= bppi;
17350806d53Smrg            } else {
17450806d53Smrg                /* left to right blit */
17550806d53Smrg                x1 += bppi;
17650806d53Smrg                x2 += bppi;
17750806d53Smrg            }
17850806d53Smrg#else
17950806d53Smrg            /* clip method */
18050806d53Smrg            pI128->mem.rbase_a[CLPTL] = (x2 << 16) | y2;
18150806d53Smrg            pI128->mem.rbase_a[CLPBR] = ((x2 + w) << 16) | (y2 + h);
18250806d53Smrg            w += bppi;
18350806d53Smrg#endif
18450806d53Smrg        }
18550806d53Smrg    }
18650806d53Smrg
18750806d53Smrg    /* this is overkill, but you can never have too much overkill */
18850806d53Smrg    wh = (w << 16) | h;
18950806d53Smrg    CACHED_UPDATE(wh, XY2_WH);
19050806d53Smrg
19150806d53Smrg    pI128->mem.rbase_a[XY0_SRC] = (x1 << 16) | y1;    MB;
19250806d53Smrg    pI128->mem.rbase_a[XY1_DST] = (x2 << 16) | y2;    MB;
19350806d53Smrg}
19450806d53Smrg
19550806d53Smrgstatic void
19650806d53Smrgi128WaitMarker(ScreenPtr pScreen, int Marker)
19750806d53Smrg{
19850806d53Smrg    PI128_FROM_SCREEN(pScreen);
19950806d53Smrg    ENG_DONE();
20050806d53Smrg}
20150806d53Smrg
20250806d53Smrgstatic void
20350806d53Smrgi128SetPlanemask(I128Ptr pI128, Pixel p)
20450806d53Smrg{
20550806d53Smrg    Pixel planemask;
20650806d53Smrg    I128_EXA_DEBUG(("SetPlanemask: %d\n", (int)p));
20750806d53Smrg    if (p == -1)
20850806d53Smrg        planemask = -1;
20950806d53Smrg    else switch (pI128->bitsPerPixel) {
21050806d53Smrg        case 8:
21150806d53Smrg            planemask = p * 0x01010101; break;
21250806d53Smrg        case 16:
21350806d53Smrg            planemask = p * 0x00010001; break;
21450806d53Smrg        default:
21550806d53Smrg            planemask = p; break;
21650806d53Smrg    }
21750806d53Smrg
21850806d53Smrg    CACHED_UPDATE(planemask, MASK);
21950806d53Smrg}
22050806d53Smrg
22150806d53Smrg/* this should be superfluous... */
22250806d53Smrgstatic void
22350806d53Smrgi128SetClip(I128Ptr pI128)
22450806d53Smrg{
22550806d53Smrg#if 0
22650806d53Smrg    pI128->clptl = pI128->mem.rbase_a[CLPTL] = 0x00000000;
22750806d53Smrg    pI128->clpbr = pI128->mem.rbase_a[CLPBR] = (4095 << 16) | 2047;
22850806d53Smrg#endif
22950806d53Smrg}
23050806d53Smrg
23150806d53Smrgstatic void
23250806d53Smrgi128SetBlitDirection(I128Ptr pI128, int dx, int dy)
23350806d53Smrg{
23450806d53Smrg    int blitdir;
23550806d53Smrg
23650806d53Smrg    I128_EXA_DEBUG(("SetBlitDirection: %d %d\n", dx, dy));
23750806d53Smrg
23850806d53Smrg    if (dx < 0) {
23950806d53Smrg        if (dy < 0) blitdir = DIR_RL_BT;
24050806d53Smrg        else blitdir = DIR_RL_TB;
24150806d53Smrg    } else {
24250806d53Smrg        if (dy < 0) blitdir = DIR_LR_BT;
24350806d53Smrg        else blitdir = DIR_LR_TB;
24450806d53Smrg    }
24550806d53Smrg
24650806d53Smrg    CACHED_UPDATE(blitdir, XY3_DIR);
24750806d53Smrg}
24850806d53Smrg
24950806d53Smrgstatic void
25050806d53Smrgi128SetRop(I128Ptr pI128, int alu, int solid)
25150806d53Smrg{
25250806d53Smrg    int cmd;
25350806d53Smrg
25450806d53Smrg    I128_EXA_DEBUG(("SetRop: %d %d\n", alu, solid));
25550806d53Smrg
25650806d53Smrg    cmd = i128alu[alu] | CO_BITBLT | (solid ? (CS_SOLID << 16) : 0);
25750806d53Smrg
25850806d53Smrg    CACHED_UPDATE(cmd, CMD);
25950806d53Smrg}
26050806d53Smrg
26150806d53Smrgstatic void
26250806d53Smrgi128SetSourcePixmap(I128Ptr pI128, PixmapPtr src)
26350806d53Smrg{
26450806d53Smrg    unsigned int sorg = exaGetPixmapOffset(src);
26550806d53Smrg    unsigned int sptch = exaGetPixmapPitch(src);
26650806d53Smrg
26750806d53Smrg    I128_EXA_DEBUG(("SetSourcePixmap: %x, %d\n", sorg, sptch));
26850806d53Smrg
26950806d53Smrg    CACHED_UPDATE(sorg, DE_SORG);
27050806d53Smrg    CACHED_UPDATE(sptch, DE_SPTCH);
27150806d53Smrg}
27250806d53Smrg
27350806d53Smrgstatic void
27450806d53Smrgi128SetDestPixmap(I128Ptr pI128, PixmapPtr dst)
27550806d53Smrg{
27650806d53Smrg    unsigned int dorg = exaGetPixmapOffset(dst);
27750806d53Smrg    unsigned int dptch = exaGetPixmapPitch(dst);
27850806d53Smrg
27950806d53Smrg    I128_EXA_DEBUG(("SetDestPixmap: %x, %d\n", dorg, dptch));
28050806d53Smrg
28150806d53Smrg    CACHED_UPDATE(dorg, DE_DORG);
28250806d53Smrg    CACHED_UPDATE(dptch, DE_DPTCH);
28350806d53Smrg}
28450806d53Smrg
28550806d53Smrgstatic void
28650806d53Smrgi128SetTexture(I128Ptr pI128, PixmapPtr tex)
28750806d53Smrg{
28850806d53Smrg    unsigned int torg = exaGetPixmapOffset(tex);
28950806d53Smrg    unsigned int tptch = exaGetPixmapPitch(tex);
29050806d53Smrg
29150806d53Smrg    I128_EXA_DEBUG(("SetTexture: %x, %d\n", torg, tptch));
29250806d53Smrg
29350806d53Smrg    CACHED_UPDATE(torg, LOD0_ORG);
29450806d53Smrg    CACHED_UPDATE(tptch, DE_TPTCH);
29550806d53Smrg}
29650806d53Smrg
29750806d53Smrgstatic const int func_tab[13][2] = {
29850806d53Smrg        /* source function,         destination function */
29950806d53Smrg        { ABLEND_SRC_ZERO,          ABLEND_DST_ZERO        }, /* clear */
30050806d53Smrg        { ABLEND_SRC_ONE,           ABLEND_DST_ZERO        }, /* src */
30150806d53Smrg        { ABLEND_SRC_ZERO,          ABLEND_DST_ONE         }, /* dst */
30250806d53Smrg        { ABLEND_SRC_ONE,           ABLEND_DST_OMSRC_ALPHA }, /* over */
30350806d53Smrg        { ABLEND_SRC_OMDST_ALPHA,   ABLEND_DST_ONE         }, /* overreverse */
30450806d53Smrg        { ABLEND_SRC_DST_ALPHA,     ABLEND_DST_ZERO        }, /* in */
30550806d53Smrg        { ABLEND_SRC_ZERO,          ABLEND_DST_SRC_ALPHA   }, /* inreverse */
30650806d53Smrg        { ABLEND_SRC_OMDST_ALPHA,   ABLEND_DST_ZERO        }, /* out */
30750806d53Smrg        { ABLEND_SRC_ZERO,          ABLEND_DST_OMSRC_ALPHA }, /* outreverse */
30850806d53Smrg        { ABLEND_SRC_DST_ALPHA,     ABLEND_DST_OMSRC_ALPHA }, /* atop */
30950806d53Smrg        { ABLEND_SRC_OMDST_ALPHA,   ABLEND_DST_SRC_ALPHA   }, /* atopreverse */
31050806d53Smrg        { ABLEND_SRC_OMDST_ALPHA,   ABLEND_DST_OMSRC_ALPHA }, /* xor */
31150806d53Smrg        { ABLEND_SRC_ONE,           ABLEND_DST_ONE         }  /* add */
31250806d53Smrg};
31350806d53Smrg
31450806d53Smrgstatic void
31550806d53Smrgi128SetAlphaForOp(I128Ptr pI128, int op, int enable)
31650806d53Smrg{
31750806d53Smrg    int acntrl = 0;
31850806d53Smrg
31950806d53Smrg    if (enable) {
32050806d53Smrg        acntrl |= ACTL_BE;  /* blend enable */
32150806d53Smrg        acntrl |= func_tab[op][0];  /* source factor */
32250806d53Smrg        acntrl |= func_tab[op][1];  /* dest_factor */
32350806d53Smrg        acntrl |= 0; /* ACTL_AMD; / * modulate alpha */
32450806d53Smrg    } else {
32550806d53Smrg        acntrl = 0;
32650806d53Smrg    }
32750806d53Smrg
32850806d53Smrg    I128_EXA_DEBUG(("SetAlphaForOp: %d, %d\n", op, enable));
32950806d53Smrg
33050806d53Smrg    CACHED_UPDATE(acntrl, ACNTRL);
33150806d53Smrg}
33250806d53Smrg
33350806d53Smrg/* we don't need a finalizer, yet */
33450806d53Smrgstatic void
33550806d53Smrgi128Done(PixmapPtr p) {
33650806d53Smrg    I128_EXA_DEBUG(("Done\n\n"));
33750806d53Smrg    return;
33850806d53Smrg}
33950806d53Smrg
34050806d53Smrg/* Solid */
34150806d53Smrg
34250806d53Smrgstatic Bool
34350806d53Smrgi128PrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg)
34450806d53Smrg{
34550806d53Smrg    PI128_FROM_PIXMAP(pPixmap);
34650806d53Smrg
34750806d53Smrg    ENG_PIPELINE_READY();
34850806d53Smrg
34950806d53Smrg    i128SetPlanemask(pI128, planemask);
35050806d53Smrg
35150806d53Smrg    if (alu != GXclear && alu != GXset)
35250806d53Smrg        pI128->mem.rbase_a[FORE] = fg;
35350806d53Smrg
35450806d53Smrg    i128SetClip(pI128);
35550806d53Smrg    i128SetBlitDirection(pI128, 1, 1); /* probably unnecessary/ignored */
35650806d53Smrg
35750806d53Smrg    i128SetAlphaForOp(pI128, 0, 0);
35850806d53Smrg    i128SetRop(pI128, alu, 1);
35950806d53Smrg
36050806d53Smrg    /* no need to set the source, the chip ignores it */
36150806d53Smrg    i128SetDestPixmap(pI128, pPixmap);
36250806d53Smrg
36350806d53Smrg    return TRUE;
36450806d53Smrg}
36550806d53Smrg
36650806d53Smrgstatic void
36750806d53Smrgi128Solid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
36850806d53Smrg{
36950806d53Smrg    i128ExaBlit(pPixmap, 0, 0, x1, y1, x2 - x1, y2 - y1);
37050806d53Smrg}
37150806d53Smrg
37250806d53Smrg/* Copy */
37350806d53Smrg
37450806d53Smrgstatic Bool
37550806d53Smrgi128PrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int dx, int dy,
37650806d53Smrg                int alu, Pixel planemask)
37750806d53Smrg{
37850806d53Smrg    PI128_FROM_PIXMAP(pSrcPixmap);
37950806d53Smrg
38050806d53Smrg    ENG_PIPELINE_READY();
38150806d53Smrg
38250806d53Smrg    i128SetPlanemask(pI128, planemask);
38350806d53Smrg    i128SetClip(pI128);
38450806d53Smrg    i128SetBlitDirection(pI128, dx, dy);
38550806d53Smrg
38650806d53Smrg    i128SetAlphaForOp(pI128, 0, 0);
38750806d53Smrg    i128SetRop(pI128, alu, 0);
38850806d53Smrg
38950806d53Smrg    i128SetSourcePixmap(pI128, pSrcPixmap);
39050806d53Smrg    i128SetDestPixmap(pI128, pDstPixmap);
39150806d53Smrg
39250806d53Smrg    return TRUE;
39350806d53Smrg}
39450806d53Smrg
39550806d53Smrgstatic void
39650806d53Smrgi128Copy(PixmapPtr pDstPixmap, int x1, int y1, int x2, int y2, int w, int h)
39750806d53Smrg{
39850806d53Smrg    i128ExaBlit(pDstPixmap, x1, y1, x2, y2, w, h);
39950806d53Smrg}
40050806d53Smrg
40150806d53Smrg/* Composite */
40250806d53Smrg
40350806d53Smrgstatic const struct source_format source_formats[] = {
40450806d53Smrg    /* 32bpp */
40550806d53Smrg    { PICT_a8r8g8b8,    0x14,   0,  0 },
40650806d53Smrg    { PICT_x8r8g8b8,    0x14,   0,  1 },
40750806d53Smrg#if 0
40850806d53Smrg    { PICT_a8b8g8r8,    0x14,   0,  0 },
40950806d53Smrg    { PICT_x8b8g8r8,    0x14,   0,  1 },
41050806d53Smrg    /* no direct 24bpp formats */
41150806d53Smrg    /* 16bpp */
41250806d53Smrg    { PICT_r5g6b5,      0x12,   0,  0 },
41350806d53Smrg    { PICT_b5g6r5,      0x12,   0,  0 },
41450806d53Smrg    { PICT_a1r5g5b5,    0x11,   0,  0 },
41550806d53Smrg    { PICT_x1r5g5b5,    0x11,   0,  1 },
41650806d53Smrg    { PICT_a1b5g5r5,    0x11,   0,  0 },
41750806d53Smrg    { PICT_x1b5g5r5,    0x11,   0,  1 },
41850806d53Smrg    { PICT_a4r4g4b4,    0x10,   0,  0 },
41950806d53Smrg    { PICT_x4r4g4b4,    0x10,   0,  1 },
42050806d53Smrg    { PICT_a4b4g4r4,    0x10,   0,  0 },
42150806d53Smrg    { PICT_x4b4g4r4,    0x10,   0,  1 },
42250806d53Smrg    /* 8bpp */
42350806d53Smrg    { PICT_a8,          0x21,   0,  0 },
42450806d53Smrg    { PICT_r3g3b2,      0x0D,   0,  0 },
42550806d53Smrg    { PICT_b2g3r3,      0x0D,   0,  0 },
42650806d53Smrg    { PICT_a2r2g2b2,    0x30,   0,  0 },
42750806d53Smrg    { PICT_a2b2g2r2,    0x30,   0,  0 },
42850806d53Smrg    /* 4bpp */
42950806d53Smrg    { PICT_a4,          0x20,   0,  0 },
43050806d53Smrg#endif
43150806d53Smrg    /* terminator */
43250806d53Smrg    { 0,                0,      0,  0 }
43350806d53Smrg};
43450806d53Smrg
43550806d53Smrgstatic struct source_format *
43650806d53Smrgi128MapSourceFormat(int fmt)
43750806d53Smrg{
43850806d53Smrg    struct source_format *f;
43950806d53Smrg    for (f = (struct source_format *)source_formats; f->render_format; f++)
44050806d53Smrg        if (f->render_format == fmt)
44150806d53Smrg            return f;
44250806d53Smrg    return NULL;
44350806d53Smrg}
44450806d53Smrg
44550806d53Smrgstruct dest_format {
44650806d53Smrg    int render_format;
44750806d53Smrg    int i128_format;
44850806d53Smrg};
44950806d53Smrg
450e9f7eabcSmrg#if 0
45150806d53Smrgstatic const struct dest_format dest_formats[] = {
45250806d53Smrg    { 0, 0 }
45350806d53Smrg};
45450806d53Smrg
45550806d53Smrgstatic struct dest_format *
45650806d53Smrgi128MapDestFormat(int fmt)
45750806d53Smrg{
45850806d53Smrg    return NULL;
45950806d53Smrg}
4607965d9acSmrg#endif
46150806d53Smrg
46250806d53Smrg/* Composite is probably t2r and t2r4 only */
46350806d53Smrgstatic Bool
46450806d53Smrgi128CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
46550806d53Smrg                   PicturePtr pDstPicture)
46650806d53Smrg{
46750806d53Smrg    PI128_FROM_PICTURE(pDstPicture);
46850806d53Smrg
46950806d53Smrg    if (op >= PictOpSaturate) return FALSE;
47050806d53Smrg
47150806d53Smrg    /*
47250806d53Smrg     * no direct alpha mask support.  we only have one TMU, so while we
47350806d53Smrg     * can emulate it, we should emulate it in the generic EXA layer.
47450806d53Smrg     */
47550806d53Smrg    if (pMaskPicture) return FALSE;
47650806d53Smrg
47750806d53Smrg    /* when transforms added, be sure to check for linear/nearest */
478af1a9c97Smrg    if (pSrcPicture->transform && pSrcPicture->filter != PictFilterNearest)
479af1a9c97Smrg        return FALSE;
48050806d53Smrg
48150806d53Smrg    /* no support for external alpha */
48250806d53Smrg    if (pSrcPicture->alphaMap || pDstPicture->alphaMap) return FALSE;
48350806d53Smrg
484af1a9c97Smrg    /* driver currently doesn't support repeating */
485af1a9c97Smrg    if (pSrcPicture->repeat) return FALSE;
486af1a9c97Smrg
48750806d53Smrg    pI128->source = i128MapSourceFormat(pSrcPicture->format);
48850806d53Smrg    if (!pI128->source)
48950806d53Smrg        return FALSE;
49050806d53Smrg#if 0
49150806d53Smrg    if (!i128MapDestFormat(pDstPicture->format)) return FALSE;
49250806d53Smrg#endif
49350806d53Smrg
49450806d53Smrg    return TRUE;
49550806d53Smrg}
49650806d53Smrg
49750806d53Smrgstatic Bool
49850806d53Smrgi128PrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
49950806d53Smrg                     PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask,
50050806d53Smrg                     PixmapPtr pDst)
50150806d53Smrg{
50250806d53Smrg    unsigned int cmd;
50350806d53Smrg    unsigned int tex_ctl = 0;
50450806d53Smrg    unsigned int threedctl = 0;
50550806d53Smrg    PI128_FROM_PIXMAP(pDst);
50650806d53Smrg
50750806d53Smrg    /* 2D setup */
50850806d53Smrg    i128SetBufCtrl(pI128, pDst->drawable.bitsPerPixel);
50950806d53Smrg    i128SetPlanemask(pI128, -1);
51050806d53Smrg    i128SetSourcePixmap(pI128, pSrc);
51150806d53Smrg    i128SetDestPixmap(pI128, pDst);
51250806d53Smrg
51350806d53Smrg    /* TEX_INV command here? */
51450806d53Smrg
51550806d53Smrg    cmd = CO_TRIAN3D;
51650806d53Smrg    CACHED_UPDATE(cmd, CMD);
51750806d53Smrg
51850806d53Smrg    /* 3D setup */
51950806d53Smrg    i128SetTexture(pI128, pSrc);
52050806d53Smrg
52150806d53Smrg    i128SetAlphaForOp(pI128, op, 1);
52250806d53Smrg
52350806d53Smrg    /* it looks pointless to cache these, but we'll need it for DRI */
52450806d53Smrg
52550806d53Smrg    tex_ctl |= TEX_TM;  /* enable texture mapping */
52650806d53Smrg    tex_ctl |= TEX_NMG | TEX_NMN;   /* nearest interpolation */
52750806d53Smrg    tex_ctl |= 0; /* TEX_RM;  / * modulate RGB */
52850806d53Smrg    CACHED_UPDATE(tex_ctl, TEX_CTL);
52950806d53Smrg
53050806d53Smrg    threedctl |= 0; /* COMP_TRUE << TCTL_ZOP_SHIFT;   / * always pass Z check */
53150806d53Smrg    threedctl |= TCTL_ABS;  /* enable alpha blend */
53250806d53Smrg    threedctl |= TCTL_TBS;  /* enable texture blend */
53350806d53Smrg    threedctl |= TCTL_RT;   /* draw textured rectangle */
53450806d53Smrg    CACHED_UPDATE(threedctl, THREEDCTL);
53550806d53Smrg
53650806d53Smrg    return TRUE;
53750806d53Smrg}
53850806d53Smrg
53950806d53Smrgstatic void
54050806d53Smrgi128Composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
54150806d53Smrg              int dstX, int dstY, int width, int height)
54250806d53Smrg{
54350806d53Smrg    PI128_FROM_PIXMAP(pDst);
54450806d53Smrg
54550806d53Smrg    /*
54650806d53Smrg     * vertex setup.  vertex layout must be:
54750806d53Smrg     * V0    V1
54850806d53Smrg     * V2   (V3 is implicit)
54950806d53Smrg     */
55050806d53Smrg
55150806d53Smrg    pI128->mem.rbase_af[V0_X] = 0.0;
55250806d53Smrg    pI128->mem.rbase_af[V0_Y] = 0.0;
55350806d53Smrg    pI128->mem.rbase_af[V0_W] = 1.0;
55450806d53Smrg    pI128->mem.rbase_af[V0_U] = 0.0;
55550806d53Smrg    pI128->mem.rbase_af[V0_V] = 0.0;
55650806d53Smrg    pI128->mem.rbase_af[V1_X] = 300.0;
55750806d53Smrg    pI128->mem.rbase_af[V1_Y] = 0.0;
55850806d53Smrg    pI128->mem.rbase_af[V1_W] = 1.0;
55950806d53Smrg    pI128->mem.rbase_af[V1_U] = 1.0;
56050806d53Smrg    pI128->mem.rbase_af[V1_V] = 0.0;
56150806d53Smrg    pI128->mem.rbase_af[V2_X] = 0.0;
56250806d53Smrg    pI128->mem.rbase_af[V2_Y] = 300.0;
56350806d53Smrg    pI128->mem.rbase_af[V2_W] = 1.0;
56450806d53Smrg    pI128->mem.rbase_af[V2_U] = 0.0;
56550806d53Smrg    pI128->mem.rbase_af[V2_V] = 1.0;
56650806d53Smrg
56750806d53Smrg    /* and fire */
56850806d53Smrg    pI128->mem.rbase_a[TRIGGER3D] = 1; MB;
56950806d53Smrg
57050806d53Smrg#if 0
57150806d53Smrg    static int i = 0;
57250806d53Smrg    /* test for raster */
57350806d53Smrg    if (!(i = (i + 1) % 32)) {
57450806d53Smrg        ErrorF("Composite test: %d %d %d %d %d %d\n", srcX, srcY, dstX, dstY,
57550806d53Smrg                width, height);
57650806d53Smrg    }
57750806d53Smrg    i128SetRop(pI128, GXxor, 0);
57850806d53Smrg    i128ExaBlit(pDst, srcX, srcY, dstX, dstY, width, height);
57950806d53Smrg#endif
58050806d53Smrg}
58150806d53Smrg
58250806d53Smrg#if 0
58350806d53Smrg/*
58450806d53Smrg * upload and download will require a DRM.  AGP DMA only works on T2R4, and
58550806d53Smrg * then only for upload.  we could probably use memory windows on other chips,
58650806d53Smrg * but those have goofy alignment restrictions and need to be disabled when
58750806d53Smrg * not in use.
58850806d53Smrg */
58950806d53Smrgstatic Bool
59050806d53Smrgi128DownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst,
59150806d53Smrg                       int dst_pitch)
59250806d53Smrg{
59350806d53Smrg}
59450806d53Smrg
59550806d53Smrgstatic Bool
59650806d53Smrgi128UploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
59750806d53Smrg                   int src_pitch)
59850806d53Smrg{
59950806d53Smrg}
60050806d53Smrg#endif
60150806d53Smrg
60250806d53SmrgBool
60350806d53SmrgI128ExaInit(ScreenPtr pScreen)
60450806d53Smrg{
60550806d53Smrg    ExaDriverPtr pExa;
606a73423d7Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
60750806d53Smrg    I128Ptr pI128 = I128PTR(pScrn);
60850806d53Smrg
60950806d53Smrg    if (!(pExa = exaDriverAlloc())) {
61050806d53Smrg        pI128->NoAccel = TRUE;
61150806d53Smrg        return FALSE;
61250806d53Smrg    }
61350806d53Smrg    pI128->ExaDriver = pExa;
61450806d53Smrg
61550806d53Smrg    pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_OFFSCREEN_ALIGN_POT;
61650806d53Smrg    pExa->memoryBase = pI128->MemoryPtr;
61750806d53Smrg    pExa->memorySize = pI128->MemorySize * 1024;
61850806d53Smrg    pExa->offScreenBase = (pScrn->virtualX * pScrn->virtualY) *
61950806d53Smrg                               (pScrn->bitsPerPixel / 8) + 4096;
62050806d53Smrg    /* these two are probably right */
62150806d53Smrg    pExa->pixmapOffsetAlign = 16;
62250806d53Smrg    pExa->pixmapPitchAlign = 16;
62350806d53Smrg    /* these two are guesses */
62450806d53Smrg    pExa->maxX = 2048;
62550806d53Smrg    pExa->maxY = 2048;
62650806d53Smrg
62750806d53Smrg    pExa->WaitMarker = i128WaitMarker;
62850806d53Smrg
62950806d53Smrg    pExa->PrepareSolid = i128PrepareSolid;
63050806d53Smrg    pExa->Solid = i128Solid;
63150806d53Smrg    pExa->DoneSolid = i128Done;
63250806d53Smrg
63350806d53Smrg    pExa->PrepareCopy = i128PrepareCopy;
63450806d53Smrg    pExa->Copy = i128Copy;
63550806d53Smrg    pExa->DoneCopy = i128Done;
63650806d53Smrg
63750806d53Smrg    if (0 && (pI128->Chipset == PCI_CHIP_I128_T2R ||
63850806d53Smrg        pI128->Chipset == PCI_CHIP_I128_T2R4))
63950806d53Smrg    {
64050806d53Smrg#if 0
64150806d53Smrg        pExa->DownloadFromScreen = i128DownloadFromScreen;
64250806d53Smrg        pExa->UploadToScreen = i128UploadToScreen;
64350806d53Smrg#endif
64450806d53Smrg        pExa->CheckComposite = i128CheckComposite;
64550806d53Smrg        pExa->PrepareComposite = i128PrepareComposite;
64650806d53Smrg        pExa->Composite = i128Composite;
64750806d53Smrg        pExa->DoneComposite = i128Done;
64850806d53Smrg    }
64950806d53Smrg
65050806d53Smrg    /*
65150806d53Smrg     * XXX much of this is duplicated from the XAA code, but I expect the XAA
65250806d53Smrg     * support to disappear eventually.
65350806d53Smrg     */
65450806d53Smrg    pI128->buf_ctrl = 0; /* force write */
65550806d53Smrg    i128SetBufCtrl(pI128, pI128->bitsPerPixel);
65650806d53Smrg
65750806d53Smrg    /* all of this needs to be properly documented */
65850806d53Smrg    {
65950806d53Smrg        pI128->mem.rbase_a[DE_PGE] = 0x00;
66050806d53Smrg        pI128->mem.rbase_a[DE_SORG] = pI128->displayOffset;
66150806d53Smrg        pI128->mem.rbase_a[DE_DORG] = pI128->displayOffset;
66250806d53Smrg        pI128->mem.rbase_a[DE_MSRC] = 0x00;
66350806d53Smrg        pI128->mem.rbase_a[DE_WKEY] = 0x00;
66450806d53Smrg        pI128->mem.rbase_a[DE_SPTCH] = pI128->mem.rbase_g[DB_PTCH];
66550806d53Smrg        pI128->mem.rbase_a[DE_DPTCH] = pI128->mem.rbase_g[DB_PTCH];
66650806d53Smrg        if (pI128->Chipset == PCI_CHIP_I128_T2R4)
66750806d53Smrg            pI128->mem.rbase_a[DE_ZPTCH] = pI128->mem.rbase_g[DB_PTCH];
66850806d53Smrg        pI128->mem.rbase_a[RMSK] = 0x00000000;
66950806d53Smrg        pI128->mem.rbase_a[XY4_ZM] = ZOOM_NONE;
67050806d53Smrg        pI128->mem.rbase_a[LPAT] = 0xffffffff;  /* for lines */
67150806d53Smrg        pI128->mem.rbase_a[PCTRL] = 0x00000000; /* for lines */
67250806d53Smrg        pI128->mem.rbase_a[CLPTL] = 0x00000000;
67350806d53Smrg        pI128->mem.rbase_a[CLPBR] = (4095 << 16) | 2047 ;
67450806d53Smrg        pI128->mem.rbase_a[ACNTRL] = 0x00000000;
67550806d53Smrg        pI128->mem.rbase_a[INTM] = 0x03;
67650806d53Smrg    }
67750806d53Smrg
67850806d53Smrg    /* need this as a float * for vertex setup */
67950806d53Smrg    pI128->mem.rbase_af = (float *)pI128->mem.rbase_a;
68050806d53Smrg
68150806d53Smrg    if (pI128->Debug) {
68250806d53Smrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I128ExaInit done\n");
68350806d53Smrg        I128DumpActiveRegisters(pScrn);
68450806d53Smrg    }
68550806d53Smrg
68650806d53Smrg    return(exaDriverInit(pScreen, pExa));
68750806d53Smrg}
688