#include "ffb.h"
#include "ffb_regs.h"
#include "ffb_rcache.h"
#include "ffb_fifo.h"
#include "ffb_stip.h"
#include "ffb_loops.h"
#include "pixmapstr.h"
#include "scrnintstr.h"
#define PSZ 8
#include "cfb.h"
#undef PSZ
#include "cfb32.h"
#define PAGEFILL_DISABLED(pFfb) ((pFfb)->disable_pagefill != 0)
#define FASTFILL_AP_DISABLED(pFfb) ((pFfb)->disable_fastfill_ap != 0)
void
CreatorFillBoxStipple (DrawablePtr pDrawable, int nBox, BoxPtr pBox, CreatorStipplePtr stipple)
{
FFBPtr pFfb = GET_FFB_FROM_SCREEN (pDrawable->pScreen);
WindowPtr pWin = (WindowPtr) pDrawable;
ffb_fbcPtr ffb = pFfb->regs;
unsigned int bits[32];
unsigned int newalign;
FFBLOG(("CreatorFillBoxStipple: nbox(%d)\n", nBox));
newalign = ((pDrawable->y & 31) << 16) | (pDrawable->x & 31);
if (stipple->patalign != newalign) {
int x, y, i;
x = (pDrawable->x - (stipple->patalign & 0xffff)) & 31;
y = (pDrawable->y - (stipple->patalign >> 16)) & 31;
if (x | y) {
memcpy(bits, stipple->bits, sizeof(bits));
for (i = 0; i < 32; i++)
stipple->bits[(i + y) & 31] =
(bits[i] >> x) | (bits[i] << (32 - x));
stipple->inhw = 0;
}
stipple->patalign = newalign;
}
FFBSetStipple(pFfb, ffb, stipple,
FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST|FFB_PPC_XS_WID,
FFB_PPC_APE_MASK|FFB_PPC_CS_MASK|FFB_PPC_XS_MASK);
FFB_WRITE_PMASK(pFfb, ffb, ~0);
FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_RECTANGLE);
FFB_WRITE_FBC(pFfb, ffb, FFB_FBC_WIN(pWin));
FFB_WRITE_WID(pFfb, ffb, FFB_WID_WIN(pWin));
while(nBox--) {
register int x, y, w, h;
x = pBox->x1;
y = pBox->y1;
w = (pBox->x2 - x);
h = (pBox->y2 - y);
FFBFifo(pFfb, 4);
FFB_WRITE64(&ffb->by, y, x);
FFB_WRITE64_2(&ffb->bh, h, w);
pBox++;
}
pFfb->rp_active = 1;
FFBSync(pFfb, ffb);
}
enum ffb_fillrect_method { fillrect_page,
fillrect_fast, fillrect_fast_opaque,
fillrect_normal };
#define BOX_AREA(__w, __h) ((int)(__w) * (int)(__h))
#define CreatorPageFillParms(pFfb, ffp, x, y, w, h, px, py, pw, ph, ework) \
do { int xdiff, ydiff; \
int pf_bh = ffp->pagefill_height; \
int pf_bw = ffp->pagefill_width; \
py = ((y + (pf_bh - 1)) & ~(pf_bh - 1)); \
ydiff = py - y; \
px = pFfb->Pf_AlignTab[x + (pf_bw - 1)]; \
xdiff = px - x; \
ph = ((h - ydiff) & ~(pf_bh - 1)); \
if(ph <= 0) \
ework = -1; \
else { \
pw = pFfb->Pf_AlignTab[w - xdiff]; \
if(pw <= 0) { \
ework = -1; \
} else { \
ework = (((xdiff > 0) || \
(ydiff > 0) || \
((w - pw) > 0) || \
((h - ph) > 0))) ? 1 : 0; \
} \
} \
} while(0);
static __inline__ int
CreatorComputePageFillFixups(xRectangle *fixups,
int x, int y, int w, int h,
int paligned_x, int paligned_y,
int paligned_w, int paligned_h)
{
int nfixups = 0;
if(paligned_x != x) {
fixups[nfixups].x = x;
fixups[nfixups].y = paligned_y;
fixups[nfixups].width = paligned_x - x;
fixups[nfixups].height = paligned_h;
nfixups++;
}
if(paligned_y != y) {
fixups[nfixups].x = x;
fixups[nfixups].y = y;
fixups[nfixups].width = w;
fixups[nfixups].height = paligned_y - y;
nfixups++;
}
if((x+w) != (paligned_x+paligned_w)) {
fixups[nfixups].x = (paligned_x+paligned_w);
fixups[nfixups].y = paligned_y;
fixups[nfixups].width = (x+w) - fixups[nfixups].x;
fixups[nfixups].height = paligned_h;
nfixups++;
}
if((y+h) != (paligned_y+paligned_h)) {
fixups[nfixups].x = x;
fixups[nfixups].y = (paligned_y+paligned_h);
fixups[nfixups].width = w;
fixups[nfixups].height = (y+h) - fixups[nfixups].y;
nfixups++;
}
return nfixups;
}
static void
CreatorBoxFillNormal(FFBPtr pFfb,
int nbox, BoxPtr pbox)
{
ffb_fbcPtr ffb = pFfb->regs;
FFBLOG(("BFNormal: "));
if(nbox)
FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_RECTANGLE);
while(nbox--) {
register int x, y, w, h;
x = pbox->x1;
y = pbox->y1;
w = (pbox->x2 - x);
h = (pbox->y2 - y);
pbox++;
FFBLOG(("[%08x:%08x:%08x:%08x] ", x, y, w, h));
FFBFifo(pFfb, 4);
FFB_WRITE64(&ffb->by, y, x);
FFB_WRITE64_2(&ffb->bh, h, w);
}
FFBLOG(("\n"));
}
static void
CreatorBoxFillFast(FFBPtr pFfb,
int nbox, BoxPtr pbox)
{
ffb_fbcPtr ffb = pFfb->regs;
FFBLOG(("BFFast: "));
while(nbox--) {
struct fastfill_parms *ffp = &FFB_FFPARMS(pFfb);
register int x, y, w, h;
x = pbox->x1;
y = pbox->y1;
w = (pbox->x2 - x);
h = (pbox->y2 - y);
pbox++;
if(BOX_AREA(w, h) < ffp->fastfill_small_area) {
FFBLOG(("NRM(%08x:%08x:%08x:%08x) ",
x, y, w, h));
FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_RECTANGLE);
FFBFifo(pFfb, 4);
FFB_WRITE64(&ffb->by, y, x);
FFB_WRITE64_2(&ffb->bh, h, w);
} else {
FFBLOG(("FST(%08x:%08x:%08x:%08x:[%08x:%08x]) ",
x, y, w, h,
(w + (x & (ffp->fastfill_width - 1))),
(h + (y & (ffp->fastfill_height - 1)))));
if (pFfb->ffb_res == ffb_res_high &&
((x & 7) != 0 || (w & 7) != 0)) {
FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_RECTANGLE);
if ((x & 7) != 0) {
register int nx = x;
register int nw;
nw = 8 - (nx & 7);
if (nw > w)
nw = w;
FFBFifo(pFfb, 4);
FFB_WRITE64(&ffb->by, y, nx);
FFB_WRITE64_2(&ffb->bh, h, nw);
x += nw;
w -= nw;
}
if ((w & 7) != 0) {
register int nx, nw;
nw = (w & 7);
nx = x + (w - nw);
FFBFifo(pFfb, 4);
FFB_WRITE64(&ffb->by, y, nx);
FFB_WRITE64_2(&ffb->bh, h, nw);
w -= nw;
}
if (w <= 0)
goto next_rect;
}
FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_FASTFILL);
FFBFifo(pFfb, 10);
ffb->by = FFB_FASTFILL_COLOR_BLK;
FFB_WRITE64(&ffb->dy, 0, 0);
FFB_WRITE64_2(&ffb->bh,
ffp->fastfill_height,
(ffp->fastfill_width * 4));
FFB_WRITE64_3(&ffb->dy, y, x);
ffb->bh = (h + (y & (ffp->fastfill_height - 1)));
FFB_WRITE64(&ffb->by, FFB_FASTFILL_BLOCK,
(w + (x & (ffp->fastfill_width - 1))));
}
next_rect:
;
}
FFBLOG(("\n"));
}
static void
CreatorBoxFillPage(FFBPtr pFfb,
int nbox, BoxPtr pbox)
{
ffb_fbcPtr ffb = pFfb->regs;
FFBLOG(("BFPage: "));
while(nbox--) {
struct fastfill_parms *ffp = &FFB_FFPARMS(pFfb);
register int x, y, w, h;
x = pbox->x1;
y = pbox->y1;
w = (pbox->x2 - x);
h = (pbox->y2 - y);
pbox++;
if(BOX_AREA(w, h) < ffp->fastfill_small_area) {
FFBLOG(("NRM(%08x:%08x:%08x:%08x) ",
x, y, w, h));
FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_RECTANGLE);
FFBFifo(pFfb, 4);
FFB_WRITE64(&ffb->by, y, x);
FFB_WRITE64_2(&ffb->bh, h, w);
} else {
int paligned_y, paligned_x;
int paligned_h, paligned_w = 0;
int extra_work;
if (pFfb->ffb_res == ffb_res_high &&
((x & 7) != 0 || (w & 7) != 0)) {
FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_RECTANGLE);
if ((x & 7) != 0) {
register int nx = x;
register int nw;
nw = 8 - (nx & 7);
if (nw > w)
nw = w;
FFBFifo(pFfb, 4);
FFB_WRITE64(&ffb->by, y, nx);
FFB_WRITE64_2(&ffb->bh, h, nw);
x += nw;
w -= nw;
}
if ((w & 7) != 0) {
register int nx, nw;
nw = (w & 7);
nx = x + (w - nw);
FFBFifo(pFfb, 4);
FFB_WRITE64(&ffb->by, y, nx);
FFB_WRITE64_2(&ffb->bh, h, nw);
w -= nw;
}
if (w <= 0)
goto next_rect;
}
FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_FASTFILL);
if((w < (ffp->pagefill_width<<1)) ||
(h < (ffp->pagefill_height<<1)))
goto do_fastfill;
CreatorPageFillParms(pFfb, ffp,
x, y, w, h,
paligned_x, paligned_y,
paligned_w, paligned_h, extra_work);
if(extra_work < 0 ||
BOX_AREA(paligned_w, paligned_h) < ffp->pagefill_small_area) {
do_fastfill:
FFBLOG(("FST(%08x:%08x:%08x:%08x:[%08x:%08x]) ",
x, y, w, h,
(w + (x & (ffp->fastfill_width - 1))),
(h + (y & (ffp->fastfill_height - 1)))));
FFBFifo(pFfb, 10);
ffb->by = FFB_FASTFILL_COLOR_BLK;
FFB_WRITE64(&ffb->dy, 0, 0);
FFB_WRITE64_2(&ffb->bh,
ffp->fastfill_height,
(ffp->fastfill_width * 4));
FFB_WRITE64_3(&ffb->dy, y, x);
ffb->bh = (h + (y & (ffp->fastfill_height - 1)));
FFB_WRITE64(&ffb->by, FFB_FASTFILL_BLOCK,
(w + (x & (ffp->fastfill_width - 1))));
} else {
FFBLOG(("PAG(%08x:%08x:%08x:%08x) ",
paligned_x, paligned_y, paligned_w, paligned_h));
FFBFifo(pFfb, 15);
ffb->by = FFB_FASTFILL_COLOR_BLK;
FFB_WRITE64(&ffb->dy, 0, 0);
FFB_WRITE64_2(&ffb->bh, ffp->fastfill_height, (ffp->fastfill_width * 4));
ffb->by = FFB_FASTFILL_BLOCK_X;
FFB_WRITE64(&ffb->dy, 0, 0);
FFB_WRITE64_2(&ffb->bh, ffp->pagefill_height, (ffp->pagefill_width * 4));
FFB_WRITE64_3(&ffb->dy, paligned_y, paligned_x);
ffb->bh = paligned_h;
FFB_WRITE64(&ffb->by, FFB_FASTFILL_PAGE, paligned_w);
if(extra_work) {
register int nfixups;
nfixups = CreatorComputePageFillFixups(pFfb->Pf_Fixups,
x, y, w, h,
paligned_x, paligned_y,
paligned_w, paligned_h);
FFBFifo(pFfb, 5 + (nfixups * 5));
ffb->by = FFB_FASTFILL_COLOR_BLK;
FFB_WRITE64(&ffb->dy, 0, 0);
FFB_WRITE64_2(&ffb->bh, ffp->fastfill_height, (ffp->fastfill_width * 4));
while(--nfixups >= 0) {
register int xx, yy, ww, hh;
xx = pFfb->Pf_Fixups[nfixups].x;
yy = pFfb->Pf_Fixups[nfixups].y;
FFB_WRITE64(&ffb->dy, yy, xx);
ww = (pFfb->Pf_Fixups[nfixups].width +
(xx & (ffp->fastfill_width - 1)));
hh = (pFfb->Pf_Fixups[nfixups].height +
(yy & (ffp->fastfill_height - 1)));
FFBLOG(("FIXUP(%08x:%08x:%08x:%08x) ",
xx, yy, ww, hh));
if(nfixups != 0) {
ffb->by = FFB_FASTFILL_BLOCK;
FFB_WRITE64_2(&ffb->bh, hh, ww);
} else {
ffb->bh = hh;
FFB_WRITE64(&ffb->by, FFB_FASTFILL_BLOCK, ww);
}
}
}
}
}
next_rect:
;
}
FFBLOG(("\n"));
}
void
CreatorFillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox, unsigned long pixel)
{
FFBPtr pFfb = GET_FFB_FROM_SCREEN (pDrawable->pScreen);
WindowPtr pWin = (WindowPtr) pDrawable;
FFBLOG(("CreatorFillBoxSolid: nbox(%d)\n", nBox));
FFB_ATTR_FFWIN(pFfb, pWin,
FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
pixel);
if (PAGEFILL_DISABLED(pFfb))
CreatorBoxFillNormal(pFfb, nBox, pBox);
else
CreatorBoxFillPage(pFfb, nBox, pBox);
pFfb->rp_active = 1;
FFBSync(pFfb, pFfb->regs);
}
static void
FFBSetStippleFast(FFBPtr pFfb, ffb_fbcPtr ffb,
CreatorStipplePtr stipple,
unsigned int ppc, unsigned int ppc_mask)
{
ppc |= FFB_PPC_APE_ENABLE | FFB_PPC_TBE_TRANSPARENT | FFB_PPC_XS_WID;
ppc_mask |= FFB_PPC_APE_MASK | FFB_PPC_TBE_MASK | FFB_PPC_XS_MASK;
FFB_WRITE_PPC(pFfb, ffb, ppc, ppc_mask);
FFB_WRITE_ROP(pFfb, ffb, (FFB_ROP_EDIT_BIT|stipple->alu)|(FFB_ROP_NEW<<8));
FFB_WRITE_FG(pFfb, ffb, stipple->fg);
FFBFifo(pFfb, 32);
FFB_STIPPLE_LOAD(&ffb->pattern[0], &stipple->bits[0]);
}
static void
FFBSetStippleFastIdentity(FFBPtr pFfb,
ffb_fbcPtr ffb,
CreatorStipplePtr stipple)
{
int i;
FFB_WRITE_FG(pFfb, ffb, stipple->bg);
FFBFifo(pFfb, 32);
for(i = 0; i < 32; i++)
ffb->pattern[i] = ~stipple->bits[i];
stipple->inhw = 0;
pFfb->laststipple = NULL;
}
void
CreatorPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, xRectangle *prectInit)
{
FFBPtr pFfb = GET_FFB_FROM_SCREEN (pDrawable->pScreen);
ffb_fbcPtr ffb = pFfb->regs;
xRectangle *prect;
RegionPtr prgnClip;
register BoxPtr pbox;
register BoxPtr pboxClipped;
BoxPtr pboxClippedBase;
BoxPtr pextent;
CreatorPrivGCPtr gcPriv;
int numRects;
int n;
int xorg, yorg;
if (nrectFill <= 0)
return;
gcPriv = CreatorGetGCPrivate (pGC);
FFBLOG(("CreatorPolyFillRect: nrect(%d) ALU(%x) STIP(%p) pmsk(%08x)\n",
nrectFill, pGC->alu, gcPriv->stipple, pGC->planemask));
prgnClip = cfbGetCompositeClip(pGC);
prect = prectInit;
xorg = pDrawable->x;
yorg = pDrawable->y;
if (xorg || yorg) {
prect = prectInit;
n = nrectFill;
while (n--) {
prect->x += xorg;
prect->y += yorg;
prect++;
}
}
prect = prectInit;
numRects = REGION_NUM_RECTS (prgnClip) * nrectFill;
if (numRects > 64) {
pboxClippedBase = (BoxPtr)ALLOCATE_LOCAL(numRects * sizeof(BoxRec));
if (!pboxClippedBase)
return;
} else
pboxClippedBase = pFfb->ClippedBoxBuf;
pboxClipped = pboxClippedBase;
if (REGION_NUM_RECTS(prgnClip) == 1) {
int x1, y1, x2, y2, bx2, by2;
pextent = REGION_RECTS(prgnClip);
x1 = pextent->x1;
y1 = pextent->y1;
x2 = pextent->x2;
y2 = pextent->y2;
while (nrectFill--) {
if ((pboxClipped->x1 = prect->x) < x1)
pboxClipped->x1 = x1;
if ((pboxClipped->y1 = prect->y) < y1)
pboxClipped->y1 = y1;
bx2 = (int) prect->x + (int) prect->width;
if (bx2 > x2)
bx2 = x2;
pboxClipped->x2 = bx2;
by2 = (int) prect->y + (int) prect->height;
if (by2 > y2)
by2 = y2;
pboxClipped->y2 = by2;
prect++;
if ((pboxClipped->x1 < pboxClipped->x2) &&
(pboxClipped->y1 < pboxClipped->y2))
pboxClipped++;
}
} else {
int x1, y1, x2, y2, bx2, by2;
pextent = REGION_EXTENTS(pGC->pScreen, prgnClip);
x1 = pextent->x1;
y1 = pextent->y1;
x2 = pextent->x2;
y2 = pextent->y2;
while (nrectFill--) {
BoxRec box;
if ((box.x1 = prect->x) < x1)
box.x1 = x1;
if ((box.y1 = prect->y) < y1)
box.y1 = y1;
bx2 = (int) prect->x + (int) prect->width;
if (bx2 > x2)
bx2 = x2;
box.x2 = bx2;
by2 = (int) prect->y + (int) prect->height;
if (by2 > y2)
by2 = y2;
box.y2 = by2;
prect++;
if ((box.x1 >= box.x2) || (box.y1 >= box.y2))
continue;
n = REGION_NUM_RECTS (prgnClip);
pbox = REGION_RECTS(prgnClip);
while(n--) {
pboxClipped->x1 = max(box.x1, pbox->x1);
pboxClipped->y1 = max(box.y1, pbox->y1);
pboxClipped->x2 = min(box.x2, pbox->x2);
pboxClipped->y2 = min(box.y2, pbox->y2);
pbox++;
if(pboxClipped->x1 < pboxClipped->x2 &&
pboxClipped->y1 < pboxClipped->y2)
pboxClipped++;
}
}
}
if(pboxClipped != pboxClippedBase) {
enum ffb_fillrect_method how = fillrect_page;
int num = (pboxClipped - pboxClippedBase);
int f_w = pboxClippedBase->x2 - pboxClippedBase->x1;
int f_h = pboxClippedBase->y2 - pboxClippedBase->y1;
WindowPtr pWin = (WindowPtr) pDrawable;
unsigned int fbc = FFB_FBC_WIN(pWin);
unsigned int drawop = FFB_DRAWOP_FASTFILL;
if (PAGEFILL_DISABLED(pFfb) ||
pGC->alu != GXcopy ||
BOX_AREA(f_w, f_h) < 128) {
drawop = FFB_DRAWOP_RECTANGLE;
how = fillrect_normal;
} else if (gcPriv->stipple != NULL) {
if (FASTFILL_AP_DISABLED(pFfb)) {
drawop = FFB_DRAWOP_RECTANGLE;
how = fillrect_normal;
} else {
if ((gcPriv->stipple->alu & FFB_ROP_EDIT_BIT) != 0)
how = fillrect_fast;
else
how = fillrect_fast_opaque;
}
} else {
int all_planes;
if (pGC->depth == 8)
all_planes = 0xff;
else
all_planes = 0xffffff;
if ((pGC->planemask & all_planes) != all_planes)
how = fillrect_fast;
}
if (how == fillrect_page) {
fbc &= ~(FFB_FBC_XE_MASK | FFB_FBC_RGBE_MASK);
fbc |= FFB_FBC_XE_ON | FFB_FBC_RGBE_ON;
}
if (pFfb->ffb_res == ffb_res_high)
fbc |= FFB_FBC_WB_B;
if (gcPriv->stipple == NULL) {
FFB_ATTR_RAW(pFfb,
FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST|FFB_PPC_XS_WID,
FFB_PPC_APE_MASK|FFB_PPC_CS_MASK|FFB_PPC_XS_MASK,
pGC->planemask,
((FFB_ROP_EDIT_BIT|pGC->alu)|(FFB_ROP_NEW<<8)),
drawop,
pGC->fgPixel,
fbc, FFB_WID_WIN(pWin));
} else {
if (how == fillrect_fast_opaque) {
FFBSetStippleFast(pFfb, ffb, gcPriv->stipple,
FFB_PPC_CS_CONST|FFB_PPC_XS_WID,
FFB_PPC_CS_MASK|FFB_PPC_XS_MASK);
} else {
FFBSetStipple(pFfb, ffb, gcPriv->stipple,
FFB_PPC_CS_CONST|FFB_PPC_XS_WID,
FFB_PPC_CS_MASK|FFB_PPC_XS_MASK);
}
FFB_WRITE_DRAWOP(pFfb, ffb, drawop);
FFB_WRITE_FBC(pFfb, ffb, fbc);
FFB_WRITE_WID(pFfb, ffb, FFB_WID_WIN(pWin));
}
if(how == fillrect_normal)
CreatorBoxFillNormal(pFfb, num, pboxClippedBase);
else if(how == fillrect_fast || how == fillrect_fast_opaque)
CreatorBoxFillFast(pFfb, num, pboxClippedBase);
else
CreatorBoxFillPage(pFfb, num, pboxClippedBase);
if(how == fillrect_fast_opaque) {
FFBSetStippleFastIdentity(pFfb, ffb, gcPriv->stipple);
CreatorBoxFillFast(pFfb, num, pboxClippedBase);
}
pFfb->rp_active = 1;
FFBSync(pFfb, ffb);
}
if (pboxClippedBase != pFfb->ClippedBoxBuf)
DEALLOCATE_LOCAL (pboxClippedBase);
}