1091 lines
35 KiB
C
1091 lines
35 KiB
C
/******************************Module*Header*******************************\
|
||
* Module Name: blt.c
|
||
*
|
||
* Contains the low-level in/out blt functions.
|
||
*
|
||
* Hopefully, if you're basing your display driver on this code, to
|
||
* support all of DrvBitBlt and DrvCopyBits, you'll only have to implement
|
||
* the following routines. You shouldn't have to modify much in
|
||
* 'bitblt.c'. I've tried to make these routines as few, modular, simple,
|
||
* and efficient as I could, while still accelerating as many calls as
|
||
* possible that would be cost-effective in terms of performance wins
|
||
* versus size and effort.
|
||
*
|
||
* Note: In the following, 'relative' coordinates refers to coordinates
|
||
* that haven't yet had the offscreen bitmap (DFB) offset applied.
|
||
* 'Absolute' coordinates have had the offset applied. For example,
|
||
* we may be told to blt to (1, 1) of the bitmap, but the bitmap may
|
||
* be sitting in offscreen memory starting at coordinate (0, 768) --
|
||
* (1, 1) would be the 'relative' start coordinate, and (1, 769)
|
||
* would be the 'absolute' start coordinate'.
|
||
*
|
||
* Copyright (c) 1992-1995 Microsoft Corporation
|
||
*
|
||
\**************************************************************************/
|
||
|
||
#include "precomp.h"
|
||
|
||
/******************************Public*Table********************************\
|
||
* BYTE gaulP9000OpaqueFromRop2[]
|
||
*
|
||
* Convert an opaque Rop2 to a P9000 minterm.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
#define P9000_P ((P9000_S & P9000_F) | (~P9000_S & P9000_B))
|
||
#define P9000_DSo (P9000_S | P9000_D)
|
||
#define P9000_DSna (~P9000_S & P9000_D)
|
||
|
||
ULONG gaulP9000OpaqueFromRop2[] = {
|
||
(0 ) & 0xFFFF, // 0 -- 0
|
||
(~(P9000_P | P9000_D)) & 0xFFFF, // 1 -- DPon
|
||
(~P9000_P & P9000_D ) & 0xFFFF, // 2 -- DPna
|
||
(~P9000_P ) & 0xFFFF, // 3 -- Pn
|
||
(~P9000_D & P9000_P ) & 0xFFFF, // 4 -- PDna
|
||
(~P9000_D ) & 0xFFFF, // 5 -- Dn
|
||
(P9000_D ^ P9000_P ) & 0xFFFF, // 6 -- DPx
|
||
(~(P9000_P & P9000_D)) & 0xFFFF, // 7 -- DPan
|
||
(P9000_P & P9000_D ) & 0xFFFF, // 8 -- DPa
|
||
(~(P9000_P ^ P9000_D)) & 0xFFFF, // 9 -- DPxn
|
||
(P9000_D ) & 0xFFFF, // 10 -- D
|
||
(~P9000_P | P9000_D ) & 0xFFFF, // 11 -- DPno
|
||
(P9000_P ) & 0xFFFF, // 12 -- P
|
||
(~P9000_D | P9000_P ) & 0xFFFF, // 13 -- PDno
|
||
(P9000_P | P9000_D ) & 0xFFFF, // 14 -- DPo
|
||
(~0 ) & 0xFFFF, // 15 -- 1
|
||
};
|
||
|
||
/******************************Public*Table********************************\
|
||
* BYTE gaulP9000TransparentFromRop2[]
|
||
*
|
||
* Convert a transparent Rop2 to a P9000 minterm.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
ULONG gaulP9000TransparentFromRop2[] = {
|
||
(((0 ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 0 -- 0
|
||
(((~(P9000_P | P9000_D)) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 1 -- DPon
|
||
(((~P9000_P & P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 2 -- DPna
|
||
(((~P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 3 -- Pn
|
||
(((~P9000_D & P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 4 -- PDna
|
||
(((~P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 5 -- Dn
|
||
(((P9000_D ^ P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 6 -- DPx
|
||
(((~(P9000_P & P9000_D)) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 7 -- DPan
|
||
(((P9000_P & P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 8 -- DPa
|
||
(((~(P9000_P ^ P9000_D)) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 9 -- DPxn
|
||
(((P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 10 -- D
|
||
(((~P9000_P | P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 11 -- DPno
|
||
(((P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 12 -- P
|
||
(((~P9000_D | P9000_P ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 13 -- PDno
|
||
(((P9000_P | P9000_D ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 14 -- DPo
|
||
(((~0 ) & P9000_DSo) | P9000_DSna) & 0xFFFF, // 15 -- 1
|
||
};
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vFillSolid
|
||
*
|
||
* Fills a list of rectangles with a solid colour.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vFillSolid( // Type FNFILL
|
||
PDEV* ppdev,
|
||
LONG c, // Can't be zero
|
||
RECTL* prcl, // List of rectangles to be filled, in relative
|
||
// coordinates
|
||
ULONG ulHwMix, // Hardware mix mode
|
||
RBRUSH_COLOR rbc, // Drawing colour is rbc.iSolidColor
|
||
POINTL* pptlBrush) // Not used
|
||
{
|
||
BYTE* pjBase;
|
||
|
||
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
||
|
||
pjBase = ppdev->pjBase;
|
||
|
||
CP_METARECT(ppdev, pjBase, prcl->left, prcl->top);
|
||
CP_METARECT(ppdev, pjBase, prcl->right, prcl->bottom);
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
if (P9000(ppdev))
|
||
{
|
||
CP_BACKGROUND(ppdev, pjBase, rbc.iSolidColor);
|
||
CP_RASTER(ppdev, pjBase, ulHwMix);
|
||
}
|
||
else
|
||
{
|
||
CP_COLOR0(ppdev, pjBase, rbc.iSolidColor);
|
||
CP_RASTER(ppdev, pjBase, ulHwMix & 0xff);
|
||
}
|
||
|
||
CP_START_QUAD(ppdev, pjBase);
|
||
|
||
while (prcl++, --c)
|
||
{
|
||
CP_METARECT(ppdev, pjBase, prcl->left, prcl->top);
|
||
CP_METARECT(ppdev, pjBase, prcl->right, prcl->bottom);
|
||
CP_START_QUAD_WAIT(ppdev, pjBase);
|
||
}
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vSlowPatRealize
|
||
*
|
||
* This routine transfers an 8x8 pattern to off-screen display memory, and
|
||
* duplicates it to make a 64x64 cached realization which is then used by
|
||
* vFillPatSlow as the basic building block for doing 'slow' pattern output
|
||
* via repeated screen-to-screen blts.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vSlowPatRealize(
|
||
PDEV* ppdev,
|
||
RBRUSH* prb) // Points to brush realization structure
|
||
{
|
||
BYTE* pjBase;
|
||
LONG cjPel;
|
||
BRUSHENTRY* pbe;
|
||
LONG iBrushCache;
|
||
LONG x;
|
||
LONG y;
|
||
ULONG* pulSrc;
|
||
LONG i;
|
||
|
||
ASSERTDD(!(prb->fl & (RBRUSH_2COLOR | RBRUSH_4COLOR)),
|
||
"Shouldn't realize hardware brushes");
|
||
|
||
pbe = prb->apbe[IBOARD(ppdev)];
|
||
if ((pbe == NULL) || (pbe->prbVerify != prb))
|
||
{
|
||
// We have to allocate a new off-screen cache brush entry for
|
||
// the brush:
|
||
|
||
iBrushCache = ppdev->iBrushCache;
|
||
pbe = &ppdev->abe[iBrushCache];
|
||
|
||
iBrushCache++;
|
||
if (iBrushCache >= ppdev->cBrushCache)
|
||
iBrushCache = 0;
|
||
|
||
ppdev->iBrushCache = iBrushCache;
|
||
|
||
// Update our links:
|
||
|
||
pbe->prbVerify = prb;
|
||
prb->apbe[IBOARD(ppdev)] = pbe;
|
||
}
|
||
|
||
pjBase = ppdev->pjBase;
|
||
cjPel = ppdev->cjPel;
|
||
|
||
// Load some pointer variables onto the stack, so that we don't have
|
||
// to keep dereferencing their pointers:
|
||
|
||
x = pbe->x;
|
||
y = pbe->y;
|
||
|
||
CP_ABS_XY0(ppdev, pjBase, x * cjPel, y);
|
||
CP_ABS_XY1(ppdev, pjBase, x * cjPel, y);
|
||
CP_ABS_XY2(ppdev, pjBase, (x + 8) * cjPel, y);
|
||
CP_ABS_Y3(ppdev, pjBase, 1);
|
||
|
||
pulSrc = (ULONG*) &prb->aulPattern[0];
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_RASTER(ppdev, pjBase, P9000(ppdev) ? P9000_S : P9100_S);
|
||
|
||
for (i = 4 * cjPel; i != 0; i--)
|
||
{
|
||
CP_PIXEL8(ppdev, pjBase, *(pulSrc));
|
||
CP_PIXEL8(ppdev, pjBase, *(pulSrc + 1));
|
||
CP_PIXEL8(ppdev, pjBase, *(pulSrc + 2));
|
||
CP_PIXEL8(ppdev, pjBase, *(pulSrc + 3));
|
||
pulSrc += 4;
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ
|
||
// <20>0<EFBFBD>1<EFBFBD>2<EFBFBD>3 <20>4 <20> We now have an 8x8 colour-expanded copy of
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ the pattern sitting in off-screen memory,
|
||
// <20>5 <20> represented here by square '0'.
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ
|
||
// <20>6 <20> We're now going to expand the pattern to
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ 72x72 by repeatedly copying larger rectangles
|
||
// <20>7 <20> in the indicated order.
|
||
// <20> <20>
|
||
// <20> <20>
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ
|
||
// <20>8 <20>
|
||
// <20> <20>
|
||
// <20> <20>
|
||
// <20> <20>
|
||
// <20> <20>
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
|
||
// Copy '1':
|
||
|
||
CP_ABS_XY1(ppdev, pjBase, x + 7, y + 7);
|
||
CP_ABS_XY3(ppdev, pjBase, x + 15, y + 7);
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_START_BLT(ppdev, pjBase);
|
||
|
||
// Copy '2':
|
||
|
||
CP_ABS_X2(ppdev, pjBase, x + 16);
|
||
CP_ABS_X3(ppdev, pjBase, x + 23);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
|
||
// Copy '3':
|
||
|
||
CP_ABS_X1(ppdev, pjBase, x + 15);
|
||
CP_ABS_X2(ppdev, pjBase, x + 24);
|
||
CP_ABS_X3(ppdev, pjBase, x + 39);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
|
||
// Copy '4':
|
||
|
||
CP_ABS_X1(ppdev, pjBase, x + 31);
|
||
CP_ABS_X2(ppdev, pjBase, x + 40);
|
||
CP_ABS_X3(ppdev, pjBase, x + 71);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
|
||
// Copy '5':
|
||
|
||
CP_ABS_XY1(ppdev, pjBase, x + 71, y + 7);
|
||
CP_ABS_XY2(ppdev, pjBase, x, y + 8);
|
||
CP_ABS_XY3(ppdev, pjBase, x + 71, y + 15);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
|
||
// Copy '6':
|
||
|
||
CP_ABS_Y2(ppdev, pjBase, y + 16);
|
||
CP_ABS_Y3(ppdev, pjBase, y + 23);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
|
||
// Copy '7':
|
||
|
||
CP_ABS_Y1(ppdev, pjBase, y + 15);
|
||
CP_ABS_Y2(ppdev, pjBase, y + 24);
|
||
CP_ABS_Y3(ppdev, pjBase, y + 39);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
|
||
// Copy '8':
|
||
|
||
CP_ABS_Y1(ppdev, pjBase, y + 31);
|
||
CP_ABS_Y2(ppdev, pjBase, y + 40);
|
||
CP_ABS_Y3(ppdev, pjBase, y + 71);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vFillSlowPat
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vFillSlowPat( // Type FNFILL
|
||
PDEV* ppdev,
|
||
LONG c, // Can't be zero
|
||
RECTL* prcl, // List of rectangles to be filled, in relative
|
||
// coordinates
|
||
ULONG ulHwMix, // Hardware mix mode
|
||
RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
|
||
POINTL* pptlBrush) // Pattern alignment
|
||
{
|
||
BYTE* pjBase;
|
||
BOOL bExponential;
|
||
ULONG ulRaster;
|
||
LONG xBrush;
|
||
LONG yBrush;
|
||
LONG xSrc;
|
||
LONG ySrc;
|
||
LONG x;
|
||
LONG y;
|
||
LONG xFrom;
|
||
LONG yFrom;
|
||
LONG cxToGo;
|
||
LONG cyToGo;
|
||
LONG cxThis;
|
||
LONG cyThis;
|
||
LONG xOrg;
|
||
LONG yOrg;
|
||
LONG cyOriginal;
|
||
LONG yOriginal;
|
||
LONG xOriginal;
|
||
BRUSHENTRY* pbe; // Pointer to brush entry data, which is used
|
||
// for keeping track of the location and status
|
||
// of the pattern bits cached in off-screen
|
||
// memory
|
||
|
||
if (rbc.prb->apbe[IBOARD(ppdev)]->prbVerify != rbc.prb)
|
||
{
|
||
vSlowPatRealize(ppdev, rbc.prb);
|
||
}
|
||
|
||
pjBase = ppdev->pjBase;
|
||
|
||
// We special case PATCOPY mixes because we can implement
|
||
// an exponential fill: every blt will double the size of
|
||
// the current rectangle by using the portion of the pattern
|
||
// that has already been done for this rectangle as the source.
|
||
//
|
||
// Note that there's no point in also checking for BLACK
|
||
// or WHITE because those will be taken care of by the
|
||
// solid fill routines, and I can't be bothered to check for
|
||
// NOTCOPYPEN:
|
||
|
||
bExponential = (ulHwMix == 0xf0f0);
|
||
|
||
// Convert the rop from a Rop3 between P and D to the corresponding
|
||
// Rop3 between S and D:
|
||
|
||
ulRaster = (ulHwMix & 0x3C) >> 2;
|
||
ulRaster |= (ulRaster << 4);
|
||
|
||
if (P9000(ppdev))
|
||
{
|
||
// Make the Rop3 into a true P9000 minterm:
|
||
|
||
ulRaster |= (ulRaster << 8);
|
||
}
|
||
|
||
// Note that since we do our brush alignment calculations in
|
||
// relative coordinates, we should keep the brush origin in
|
||
// relative coordinates as well:
|
||
|
||
xOrg = pptlBrush->x;
|
||
yOrg = pptlBrush->y;
|
||
|
||
pbe = rbc.prb->apbe[IBOARD(ppdev)];
|
||
xBrush = pbe->x;
|
||
yBrush = pbe->y;
|
||
|
||
do {
|
||
x = prcl->left;
|
||
y = prcl->top;
|
||
|
||
xSrc = xBrush + ((x - xOrg) & 7);
|
||
ySrc = yBrush + ((y - yOrg) & 7);
|
||
|
||
cxToGo = prcl->right - x;
|
||
cyToGo = prcl->bottom - y;
|
||
|
||
if ((cxToGo <= SLOW_BRUSH_DIMENSION) &&
|
||
(cyToGo <= SLOW_BRUSH_DIMENSION))
|
||
{
|
||
CP_ABS_XY0(ppdev, pjBase, xSrc, ySrc);
|
||
CP_ABS_XY1(ppdev, pjBase, xSrc + cxToGo - 1, ySrc + cyToGo - 1);
|
||
CP_XY2(ppdev, pjBase, x, y);
|
||
CP_XY3(ppdev, pjBase, x + cxToGo - 1, y + cyToGo - 1);
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_RASTER(ppdev, pjBase, ulRaster);
|
||
CP_START_BLT(ppdev, pjBase);
|
||
}
|
||
|
||
else if (bExponential)
|
||
{
|
||
cyThis = SLOW_BRUSH_DIMENSION;
|
||
cyToGo -= cyThis;
|
||
if (cyToGo < 0)
|
||
cyThis += cyToGo;
|
||
|
||
cxThis = SLOW_BRUSH_DIMENSION;
|
||
cxToGo -= cxThis;
|
||
if (cxToGo < 0)
|
||
cxThis += cxToGo;
|
||
|
||
CP_ABS_XY0(ppdev, pjBase, xSrc, ySrc);
|
||
CP_ABS_XY1(ppdev, pjBase, xSrc + cxThis - 1, ySrc + cyThis - 1);
|
||
CP_XY2(ppdev, pjBase, x, y);
|
||
CP_XY3(ppdev, pjBase, x + cxThis - 1, y + cyThis - 1);
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_RASTER(ppdev, pjBase, ulRaster);
|
||
CP_START_BLT(ppdev, pjBase);
|
||
|
||
CP_XY0(ppdev, pjBase, x, y);
|
||
|
||
xOriginal = x;
|
||
|
||
x += cxThis;
|
||
y += cyThis;
|
||
|
||
while (cxToGo > 0)
|
||
{
|
||
// First, expand out to the right, doubling our size
|
||
// each time:
|
||
|
||
xFrom = x;
|
||
cxToGo -= cxThis;
|
||
if (cxToGo < 0)
|
||
{
|
||
cxThis += cxToGo;
|
||
xFrom += cxToGo;
|
||
}
|
||
|
||
CP_XY1(ppdev, pjBase, xFrom - 1, y - 1);
|
||
CP_X2(ppdev, pjBase, x);
|
||
CP_X3(ppdev, pjBase, x + cxThis - 1);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
|
||
x += cxThis;
|
||
cxThis *= 2;
|
||
}
|
||
|
||
while (cyToGo > 0)
|
||
{
|
||
// Now do the same thing vertically:
|
||
|
||
yFrom = y;
|
||
cyToGo -= cyThis;
|
||
if (cyToGo < 0)
|
||
{
|
||
cyThis += cyToGo;
|
||
yFrom += cyToGo;
|
||
}
|
||
|
||
CP_XY1(ppdev, pjBase, x - 1, yFrom - 1);
|
||
CP_XY2(ppdev, pjBase, xOriginal, y);
|
||
CP_Y3(ppdev, pjBase, y + cyThis - 1);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
|
||
y += cyThis;
|
||
cyThis *= 2;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// We handle arbitrary mixes simply by repeatedly tiling
|
||
// our cached pattern over the entire rectangle:
|
||
|
||
CP_ABS_XY0(ppdev, pjBase, xSrc, ySrc);
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_RASTER(ppdev, pjBase, ulRaster);
|
||
|
||
cyOriginal = cyToGo; // Have to remember for later...
|
||
yOriginal = y;
|
||
|
||
do {
|
||
cxThis = SLOW_BRUSH_DIMENSION;
|
||
cxToGo -= cxThis;
|
||
if (cxToGo < 0)
|
||
cxThis += cxToGo;
|
||
|
||
cyToGo = cyOriginal; // Have to reset for each new column
|
||
y = yOriginal;
|
||
|
||
do {
|
||
cyThis = SLOW_BRUSH_DIMENSION;
|
||
cyToGo -= cyThis;
|
||
if (cyToGo < 0)
|
||
cyThis += cyToGo;
|
||
|
||
CP_ABS_XY1(ppdev, pjBase, xSrc + cxThis - 1,
|
||
ySrc + cyThis - 1);
|
||
CP_XY2(ppdev, pjBase, x, y);
|
||
CP_XY3(ppdev, pjBase, x + cxThis - 1,
|
||
y + cyThis - 1);
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
|
||
y += cyThis;
|
||
|
||
} while (cyToGo > 0);
|
||
|
||
x += cxThis; // Get ready for next column
|
||
|
||
} while (cxToGo > 0);
|
||
}
|
||
prcl++;
|
||
} while (--c != 0);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vFillPat
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vFillPat( // Type FNFILL
|
||
PDEV* ppdev,
|
||
LONG c, // Can't be zero
|
||
RECTL* prcl, // List of rectangles to be filled, in relative
|
||
// coordinates
|
||
ULONG ulHwMix, // Hardware mix mode
|
||
RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
|
||
POINTL* pptlBrush) // Pattern alignment
|
||
{
|
||
BYTE* pjBase;
|
||
LONG i;
|
||
ULONG* pulPattern;
|
||
ULONG ulPattern;
|
||
|
||
ASSERTDD(((ulHwMix >> 8) == (ulHwMix & 0xff)) ||
|
||
((ulHwMix & 0xff00) == 0xaa00),
|
||
"This routine handles only opaque or transparent mixes");
|
||
|
||
if (rbc.prb->fl & (RBRUSH_2COLOR | RBRUSH_4COLOR))
|
||
{
|
||
// Hardware pattern
|
||
|
||
pjBase = ppdev->pjBase;
|
||
|
||
CP_METARECT(ppdev, pjBase, prcl->left, prcl->top);
|
||
CP_METARECT(ppdev, pjBase, prcl->right, prcl->bottom);
|
||
CP_WAIT(ppdev, pjBase);
|
||
|
||
if (P9000(ppdev))
|
||
{
|
||
CP_PATTERN_ORGX(ppdev, pjBase, ppdev->xOffset + pptlBrush->x);
|
||
CP_PATTERN_ORGY(ppdev, pjBase, ppdev->yOffset + pptlBrush->y);
|
||
CP_BACKGROUND(ppdev, pjBase, rbc.prb->ulColor[0]);
|
||
CP_FOREGROUND(ppdev, pjBase, rbc.prb->ulColor[1]);
|
||
pulPattern = &rbc.prb->aulPattern[0];
|
||
for (i = 0; i < 4; i++)
|
||
{
|
||
ulPattern = *pulPattern++;
|
||
CP_PATTERN(ppdev, pjBase, i, ulPattern);
|
||
CP_PATTERN(ppdev, pjBase, i + 4, ulPattern);
|
||
}
|
||
|
||
if (((ulHwMix >> 8) & 0xff) == (ulHwMix & 0xff))
|
||
{
|
||
ulHwMix = gaulP9000OpaqueFromRop2[(ulHwMix & 0x3C) >> 2];
|
||
CP_RASTER(ppdev, pjBase, ulHwMix | P9000_ENABLE_PATTERN);
|
||
}
|
||
else
|
||
{
|
||
ulHwMix = gaulP9000TransparentFromRop2[(ulHwMix & 0x3C) >> 2];
|
||
CP_RASTER(ppdev, pjBase, ulHwMix | P9000_ENABLE_PATTERN);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
CP_PATTERN_ORGX(ppdev, pjBase, -(ppdev->xOffset + pptlBrush->x));
|
||
CP_PATTERN_ORGY(ppdev, pjBase, -(ppdev->yOffset + pptlBrush->y));
|
||
CP_COLOR0_FAST(ppdev, pjBase, rbc.prb->ulColor[0]);
|
||
CP_COLOR1_FAST(ppdev, pjBase, rbc.prb->ulColor[1]);
|
||
CP_PATTERN(ppdev, pjBase, 0, rbc.prb->aulPattern[0]);
|
||
CP_PATTERN(ppdev, pjBase, 1, rbc.prb->aulPattern[1]);
|
||
CP_PATTERN(ppdev, pjBase, 2, rbc.prb->aulPattern[2]);
|
||
CP_PATTERN(ppdev, pjBase, 3, rbc.prb->aulPattern[3]);
|
||
if (rbc.prb->fl & RBRUSH_2COLOR)
|
||
{
|
||
if (((ulHwMix >> 8) & 0xff) == (ulHwMix & 0xff))
|
||
{
|
||
CP_RASTER(ppdev, pjBase, (ulHwMix & 0xff)
|
||
| P9100_ENABLE_PATTERN);
|
||
}
|
||
else
|
||
{
|
||
CP_RASTER(ppdev, pjBase, (ulHwMix & 0xff)
|
||
| P9100_ENABLE_PATTERN | P9100_TRANSPARENT_PATTERN);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
CP_COLOR2_FAST(ppdev, pjBase, rbc.prb->ulColor[2]);
|
||
CP_COLOR3_FAST(ppdev, pjBase, rbc.prb->ulColor[3]);
|
||
CP_RASTER(ppdev, pjBase, (ulHwMix & 0xff)
|
||
| P9100_ENABLE_PATTERN | P9100_FOUR_COLOR_PATTERN);
|
||
}
|
||
}
|
||
|
||
CP_START_QUAD(ppdev, pjBase);
|
||
|
||
while (prcl++, --c)
|
||
{
|
||
CP_METARECT(ppdev, pjBase, prcl->left, prcl->top);
|
||
CP_METARECT(ppdev, pjBase, prcl->right, prcl->bottom);
|
||
CP_START_QUAD_WAIT(ppdev, pjBase);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
vFillSlowPat(ppdev, c, prcl, ulHwMix, rbc, pptlBrush);
|
||
}
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vXfer1bpp
|
||
*
|
||
* This routine colour expands a monochrome bitmap.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vXfer1bpp( // Type FNXFER
|
||
PDEV* ppdev,
|
||
LONG c, // Count of rectangles, can't be zero
|
||
RECTL* prcl, // List of destination rectangles, in relative
|
||
// coordinates
|
||
ULONG ulHwMix, // Foreground and background hardware mix
|
||
SURFOBJ* psoSrc, // Source surface
|
||
POINTL* pptlSrc, // Original unclipped source point
|
||
RECTL* prclDst, // Original unclipped destination rectangle
|
||
XLATEOBJ* pxlo) // Translate that provides colour-expansion information
|
||
{
|
||
BYTE* pjBase;
|
||
LONG dx;
|
||
LONG dy;
|
||
LONG lSrcDelta;
|
||
BYTE* pjSrcScan0;
|
||
ULONG* pulXlate;
|
||
LONG xLeft;
|
||
LONG xRight;
|
||
LONG yTop;
|
||
LONG cyScan;
|
||
LONG xBias;
|
||
LONG culScan;
|
||
LONG lSrcSkip;
|
||
ULONG* pulSrc;
|
||
LONG cRem;
|
||
LONG i;
|
||
|
||
ASSERTDD(((ulHwMix >> 8) & 0xff) == (ulHwMix & 0xff),
|
||
"Expected only an opaquing rop");
|
||
|
||
pjBase = ppdev->pjBase;
|
||
|
||
dx = pptlSrc->x - prclDst->left;
|
||
dy = pptlSrc->y - prclDst->top;
|
||
|
||
lSrcDelta = psoSrc->lDelta;
|
||
pjSrcScan0 = psoSrc->pvScan0;
|
||
|
||
do {
|
||
xLeft = prcl->left;
|
||
xRight = prcl->right;
|
||
yTop = prcl->top;
|
||
|
||
xBias = (xLeft + dx) & 31;
|
||
xLeft -= xBias;
|
||
|
||
CP_XY1(ppdev, pjBase, xLeft, yTop);
|
||
CP_X0(ppdev, pjBase, xLeft);
|
||
CP_X2(ppdev, pjBase, xRight);
|
||
CP_ABS_Y3(ppdev, pjBase, 1);
|
||
|
||
culScan = ((xRight - xLeft) >> 5);
|
||
cRem = ((xRight - xLeft) & 31) - 1;
|
||
if (cRem < 0)
|
||
{
|
||
culScan--;
|
||
cRem = 31;
|
||
}
|
||
|
||
pulSrc = (ULONG*) (pjSrcScan0 + (yTop + dy) * lSrcDelta
|
||
+ ((xLeft + dx) >> 3));
|
||
lSrcSkip = lSrcDelta - (culScan << 2);
|
||
cyScan = (prcl->bottom - yTop);
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_WLEFT(ppdev, pjBase, prcl->left);
|
||
|
||
// The following three accelerator states are invariant to this
|
||
// loop, but we set them each time anyway because we expect
|
||
// usually to have only to do one iteration of this loop, and this
|
||
// state must to be set after doing a CP_WAIT, which we want to
|
||
// delay until we get as much processing done as possible, for
|
||
// maximum overlap.
|
||
|
||
pulXlate = pxlo->pulXlate;
|
||
if (P9000(ppdev))
|
||
{
|
||
CP_BACKGROUND(ppdev, pjBase, pulXlate[0]);
|
||
CP_FOREGROUND(ppdev, pjBase, pulXlate[1]);
|
||
CP_RASTER(ppdev, pjBase, gaulP9000OpaqueFromRop2[ulHwMix & 0xf]);
|
||
}
|
||
else
|
||
{
|
||
CP_COLOR0(ppdev, pjBase, pulXlate[0]);
|
||
CP_COLOR1(ppdev, pjBase, pulXlate[1]);
|
||
CP_RASTER(ppdev, pjBase, ulHwMix & 0xff);
|
||
}
|
||
|
||
CP_START_PIXEL1(ppdev, pjBase);
|
||
|
||
do {
|
||
for (i = culScan; i != 0; i--)
|
||
{
|
||
CP_PIXEL1(ppdev, pjBase, *pulSrc);
|
||
pulSrc++;
|
||
}
|
||
CP_PIXEL1_REM(ppdev, pjBase, cRem, *pulSrc);
|
||
|
||
pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip);
|
||
|
||
} while (--cyScan != 0);
|
||
|
||
CP_END_PIXEL1(ppdev, pjBase);
|
||
|
||
} while (prcl++, --c);
|
||
|
||
// Don't forget to reset the clip register:
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_ABS_WMIN(ppdev, pjBase, 0, 0);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vXfer4bpp
|
||
*
|
||
* Does a 4bpp transfer from a bitmap to the screen.
|
||
*
|
||
* NOTE: The screen must be 8bpp for this function to be called!
|
||
*
|
||
* The reason we implement this is that a lot of resources are kept as 4bpp,
|
||
* and used to initialize DFBs, some of which we of course keep off-screen.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vXfer4bpp( // Type FNXFER
|
||
PDEV* ppdev,
|
||
LONG c, // Count of rectangles, can't be zero
|
||
RECTL* prcl, // List of destination rectangles, in relative
|
||
// coordinates
|
||
ULONG ulHwMix, // Hardware mix
|
||
SURFOBJ* psoSrc, // Source surface
|
||
POINTL* pptlSrc, // Original unclipped source point
|
||
RECTL* prclDst, // Original unclipped destination rectangle
|
||
XLATEOBJ* pxlo) // Translate that provides colour-expansion information
|
||
{
|
||
BYTE* pjBase;
|
||
LONG dx;
|
||
LONG dy;
|
||
LONG lSrcDelta;
|
||
BYTE* pjSrcScan0;
|
||
ULONG* pulXlate;
|
||
LONG xLeft;
|
||
LONG xRight;
|
||
LONG yTop;
|
||
LONG cyScan;
|
||
LONG xBias;
|
||
LONG cwSrc;
|
||
LONG lSrcSkip;
|
||
LONG cw;
|
||
BYTE* pjSrc;
|
||
BYTE jSrc;
|
||
ULONG ul;
|
||
|
||
ASSERTDD(ppdev->cjPel == 1, "This function assumes 8bpp");
|
||
|
||
pjBase = ppdev->pjBase;
|
||
|
||
dx = pptlSrc->x - prclDst->left;
|
||
dy = pptlSrc->y - prclDst->top;
|
||
|
||
lSrcDelta = psoSrc->lDelta;
|
||
pjSrcScan0 = psoSrc->pvScan0;
|
||
pulXlate = pxlo->pulXlate;
|
||
|
||
do {
|
||
xLeft = prcl->left;
|
||
xRight = prcl->right;
|
||
yTop = prcl->top;
|
||
|
||
// We compute 'xBias' in order to word-align the source pointer.
|
||
// This way, since we're processing a word of the source at a
|
||
// time, we're guaranteed not to read even a byte past the end of
|
||
// the bitmap.
|
||
|
||
xBias = ((xLeft + dx) & 3);
|
||
xLeft -= xBias;
|
||
|
||
CP_XY1(ppdev, pjBase, xLeft, yTop);
|
||
CP_X0(ppdev, pjBase, xLeft);
|
||
CP_X2(ppdev, pjBase, xRight);
|
||
CP_ABS_Y3(ppdev, pjBase, 1);
|
||
|
||
// Every word in the source is one dword in the destination:
|
||
|
||
cwSrc = ((xRight - xLeft) + 3) >> 2;
|
||
lSrcSkip = lSrcDelta - (cwSrc << 1);
|
||
pjSrc = pjSrcScan0 + (yTop + dy) * lSrcDelta + ((xLeft + dx) >> 1);
|
||
cyScan = prcl->bottom - yTop;
|
||
|
||
ASSERTDD(((ULONG_PTR) pjSrc & 1) == 0, "Source should be word aligned");
|
||
|
||
// Yes, we're setting the raster every time in the loop. But we
|
||
// have to wait for not-busy before setting the raster, and the
|
||
// chances are that we'll only have one rectangle to blt, so
|
||
// we do this here:
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_WLEFT(ppdev, pjBase, prcl->left);
|
||
CP_RASTER(ppdev, pjBase, P9000(ppdev) ? ulHwMix : (ulHwMix & 0xff));
|
||
|
||
CP_START_PIXEL8(ppdev, pjBase);
|
||
|
||
do {
|
||
cw = cwSrc;
|
||
|
||
do {
|
||
jSrc = *(pjSrc + 1);
|
||
|
||
ul = pulXlate[jSrc & 0xf];
|
||
ul <<= 8;
|
||
ul |= pulXlate[jSrc >> 4];
|
||
|
||
jSrc = *(pjSrc);
|
||
|
||
ul <<= 8;
|
||
ul |= pulXlate[jSrc & 0xf];
|
||
ul <<= 8;
|
||
ul |= pulXlate[jSrc >> 4];
|
||
|
||
CP_PIXEL8(ppdev, pjBase, ul);
|
||
pjSrc += 2;
|
||
|
||
} while (--cw != 0);
|
||
|
||
pjSrc += lSrcSkip;
|
||
|
||
} while (--cyScan != 0);
|
||
|
||
CP_END_PIXEL8(ppdev, pjBase);
|
||
|
||
} while (prcl++, --c);
|
||
|
||
// Don't forget to reset the clip register:
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_ABS_WMIN(ppdev, pjBase, 0, 0);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vXferNative
|
||
*
|
||
* Transfers a bitmap that is the same colour depth as the display to
|
||
* the screen via the data transfer register, with no translation.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vXferNative( // Type FNXFER
|
||
PDEV* ppdev,
|
||
LONG c, // Count of rectangles, can't be zero
|
||
RECTL* prcl, // Array of relative coordinates destination rectangles
|
||
ULONG ulHwMix, // Hardware mix
|
||
SURFOBJ* psoSrc, // Source surface
|
||
POINTL* pptlSrc, // Original unclipped source point
|
||
RECTL* prclDst, // Original unclipped destination rectangle
|
||
XLATEOBJ* pxlo) // Not used
|
||
{
|
||
BYTE* pjBase;
|
||
LONG cjPel;
|
||
LONG xOffset;
|
||
LONG yOffset;
|
||
LONG dx;
|
||
LONG dy;
|
||
LONG lSrcDelta;
|
||
BYTE* pjSrcScan0;
|
||
LONG xLeft;
|
||
LONG xRight;
|
||
LONG yTop;
|
||
LONG cyScan;
|
||
LONG xBias;
|
||
LONG culScan;
|
||
LONG lSrcSkip;
|
||
LONG cu;
|
||
ULONG* pulSrc;
|
||
|
||
pjBase = ppdev->pjBase;
|
||
cjPel = ppdev->cjPel;
|
||
|
||
xOffset = ppdev->xOffset;
|
||
yOffset = ppdev->yOffset;
|
||
|
||
dx = pptlSrc->x - prclDst->left;
|
||
dy = pptlSrc->y - prclDst->top;
|
||
|
||
lSrcDelta = psoSrc->lDelta;
|
||
pjSrcScan0 = psoSrc->pvScan0;
|
||
|
||
do {
|
||
xLeft = prcl->left;
|
||
xRight = prcl->right;
|
||
yTop = prcl->top;
|
||
|
||
// We compute 'xBias' in order to dword-align the source pointer.
|
||
// This way, we don't have to do unaligned reads of the source,
|
||
// and we're guaranteed not to read even a byte past the end of
|
||
// the bitmap.
|
||
//
|
||
// Note that this bias works at 24bpp, too:
|
||
|
||
xBias = ((xLeft + dx) & 3);
|
||
xLeft -= xBias;
|
||
|
||
CP_ABS_XY1(ppdev, pjBase, (xLeft + xOffset) * cjPel, yTop + yOffset);
|
||
CP_ABS_X0(ppdev, pjBase, (xLeft + xOffset) * cjPel);
|
||
CP_ABS_X2(ppdev, pjBase, (xRight + xOffset) * cjPel);
|
||
CP_ABS_Y3(ppdev, pjBase, 1);
|
||
|
||
culScan = ((xRight - xLeft) * cjPel + 3) >> 2;
|
||
lSrcSkip = lSrcDelta - (culScan << 2);
|
||
pulSrc = (ULONG*) (pjSrcScan0 + (yTop + dy) * lSrcDelta
|
||
+ (xLeft + dx) * cjPel);
|
||
cyScan = prcl->bottom - yTop;
|
||
|
||
ASSERTDD(((ULONG_PTR)pulSrc & 3) == 0, "Source should be dword aligned");
|
||
|
||
// Yes, we're setting the raster every time in the loop. But we
|
||
// have to wait for not-busy before setting the raster, and the
|
||
// chances are that we'll only have one rectangle to blt, so
|
||
// we do this here:
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_ABS_WLEFT(ppdev, pjBase, prcl->left + xOffset);
|
||
|
||
CP_RASTER(ppdev, pjBase, P9000(ppdev) ? ulHwMix : (ulHwMix & 0xff));
|
||
CP_START_PIXEL8(ppdev, pjBase);
|
||
|
||
do {
|
||
cu = culScan;
|
||
|
||
do {
|
||
CP_PIXEL8(ppdev, pjBase, *pulSrc);
|
||
pulSrc++;
|
||
} while (--cu != 0);
|
||
|
||
pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip);
|
||
|
||
} while (--cyScan != 0);
|
||
|
||
CP_END_PIXEL8(ppdev, pjBase);
|
||
|
||
} while (prcl++, --c);
|
||
|
||
// Don't forget to reset the clip register:
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_ABS_WMIN(ppdev, pjBase, 0, 0);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vCopyBlt
|
||
*
|
||
* Does a screen-to-screen blt of a list of rectangles.
|
||
*
|
||
* Note: We may call this function with weird ROPs to do colour-expansion
|
||
* from off-screen monochrome bitmaps.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vCopyBlt( // Type FNCOPY
|
||
PDEV* ppdev,
|
||
LONG c, // Can't be zero
|
||
RECTL* prcl, // Array of relative coordinates destination rectangles
|
||
ULONG ulHwMix, // Hardware mix
|
||
POINTL* pptlSrc, // Original unclipped source point
|
||
RECTL* prclDst) // Original unclipped destination rectangle
|
||
{
|
||
BYTE* pjBase;
|
||
LONG cjPel;
|
||
LONG xOffset;
|
||
LONG yOffset;
|
||
LONG dx;
|
||
LONG dy;
|
||
LONG xSrc;
|
||
LONG ySrc;
|
||
|
||
pjBase = ppdev->pjBase;
|
||
cjPel = ppdev->cjPel;
|
||
|
||
// Our DFB xOffset has to be scaled by the pixel size too:
|
||
|
||
xOffset = ppdev->xOffset;
|
||
yOffset = ppdev->yOffset;
|
||
|
||
dx = pptlSrc->x - prclDst->left;
|
||
dy = pptlSrc->y - prclDst->top;
|
||
|
||
xSrc = prcl->left + dx;
|
||
ySrc = prcl->top + dy;
|
||
|
||
CP_ABS_XY0(ppdev, pjBase, (xOffset + xSrc) * cjPel,
|
||
(yOffset + ySrc));
|
||
CP_ABS_XY1(ppdev, pjBase, (xOffset + xSrc + prcl->right - prcl->left) * cjPel - 1,
|
||
(yOffset + ySrc + prcl->bottom - prcl->top - 1));
|
||
CP_ABS_XY2(ppdev, pjBase, (xOffset + prcl->left) * cjPel,
|
||
(yOffset + prcl->top));
|
||
CP_ABS_XY3(ppdev, pjBase, (xOffset + prcl->right) * cjPel - 1,
|
||
(yOffset + prcl->bottom - 1));
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_RASTER(ppdev, pjBase, P9000(ppdev) ? ulHwMix : (ulHwMix & 0xff));
|
||
CP_START_BLT(ppdev, pjBase);
|
||
|
||
while (prcl++, --c)
|
||
{
|
||
xSrc = prcl->left + dx;
|
||
ySrc = prcl->top + dy;
|
||
|
||
CP_ABS_XY0(ppdev, pjBase, (xOffset + xSrc) * cjPel,
|
||
(yOffset + ySrc));
|
||
CP_ABS_XY1(ppdev, pjBase, (xOffset + xSrc + prcl->right - prcl->left) * cjPel - 1,
|
||
(yOffset + ySrc + prcl->bottom - prcl->top - 1));
|
||
CP_ABS_XY2(ppdev, pjBase, (xOffset + prcl->left) * cjPel,
|
||
(yOffset + prcl->top));
|
||
CP_ABS_XY3(ppdev, pjBase, (xOffset + prcl->right) * cjPel - 1,
|
||
(yOffset + prcl->bottom - 1));
|
||
CP_START_BLT_WAIT(ppdev, pjBase);
|
||
}
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vFillSolidP9000HighColor
|
||
*
|
||
* Fills a list of rectangles with a solid colour when running at 16bpp
|
||
* on the P9000, using the pattern hardware.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vFillSolidP9000HighColor( // Type FNFILL
|
||
PDEV* ppdev,
|
||
LONG c, // Can't be zero
|
||
RECTL* prcl, // List of rectangles to be filled, in relative
|
||
// coordinates
|
||
ULONG ulHwMix, // Hardware mix mode
|
||
RBRUSH_COLOR rbc, // Drawing colour is rbc.iSolidColor
|
||
POINTL* pptlBrush) // Not used
|
||
{
|
||
BYTE* pjBase;
|
||
LONG xOffset;
|
||
LONG yOffset;
|
||
|
||
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
||
ASSERTDD(P9000(ppdev), "Shouldn't need to be called on the P9100");
|
||
ASSERTDD(ppdev->iBitmapFormat == BMF_16BPP, "Only handle 16bpp for now");
|
||
|
||
pjBase = ppdev->pjBase;
|
||
|
||
// Our DFB xOffset has to be scaled by the pixel size too:
|
||
|
||
xOffset = 2 * ppdev->xOffset;
|
||
yOffset = ppdev->yOffset;
|
||
|
||
CP_ABS_METARECT(ppdev, pjBase, xOffset + 2 * prcl->left,
|
||
yOffset + prcl->top);
|
||
CP_ABS_METARECT(ppdev, pjBase, xOffset + 2 * prcl->right,
|
||
yOffset + prcl->bottom);
|
||
|
||
// We've already downloaded and set the pattern origin in
|
||
// vAssertModeBrushCache:
|
||
|
||
CP_WAIT(ppdev, pjBase);
|
||
CP_RASTER(ppdev, pjBase, P9000_ENABLE_PATTERN |
|
||
gaulP9000OpaqueFromRop2[(ulHwMix & 0x3C) >> 2]);
|
||
|
||
CP_FOREGROUND(ppdev, pjBase, rbc.iSolidColor);
|
||
CP_BACKGROUND(ppdev, pjBase, rbc.iSolidColor >> 8);
|
||
CP_START_QUAD(ppdev, pjBase);
|
||
|
||
while (prcl++, --c)
|
||
{
|
||
CP_ABS_METARECT(ppdev, pjBase, xOffset + 2 * prcl->left,
|
||
yOffset + prcl->top);
|
||
CP_ABS_METARECT(ppdev, pjBase, xOffset + 2 * prcl->right,
|
||
yOffset + prcl->bottom);
|
||
CP_START_QUAD_WAIT(ppdev, pjBase);
|
||
}
|
||
}
|