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