You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1603 lines
55 KiB
1603 lines
55 KiB
/******************************Module*Header*******************************\
|
|
*
|
|
* *******************
|
|
* * GDI SAMPLE CODE *
|
|
* *******************
|
|
*
|
|
* Module Name: bltio.c
|
|
*
|
|
* Contains the low-level in/out blt functions. This module mirrors
|
|
* 'bltmm.c'.
|
|
*
|
|
* 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-1998 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoImageTransferMm16
|
|
*
|
|
* Low-level routine for transferring a bitmap image via the data transfer
|
|
* register using 16 bit writes and memory-mapped I/O for the transfer,
|
|
* but I/O for the setup.
|
|
*
|
|
* NOTE: Upon entry, there must be 1 guaranteed free empty FIFO!
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoImageTransferMm16( // Type FNIMAGETRANSFER
|
|
PDEV* ppdev,
|
|
BYTE* pjSrc, // Source pointer
|
|
LONG lDelta, // Delta from start of scan to start of next
|
|
LONG cjSrc, // Number of bytes to be output on every scan
|
|
LONG cScans, // Number of scans
|
|
ULONG ulCmd) // Accelerator command - shouldn't include bus size
|
|
{
|
|
BYTE* pjMmBase;
|
|
LONG cwSrc;
|
|
|
|
ASSERTDD(cScans > 0, "Can't handle non-positive count of scans");
|
|
ASSERTDD((ulCmd & (BUS_SIZE_8 | BUS_SIZE_16 | BUS_SIZE_32)) == 0,
|
|
"Shouldn't specify bus size in command -- we handle that");
|
|
|
|
IO_GP_WAIT(ppdev);
|
|
|
|
IO_CMD(ppdev, ulCmd | BUS_SIZE_16);
|
|
|
|
CHECK_DATA_READY(ppdev);
|
|
|
|
pjMmBase = ppdev->pjMmBase;
|
|
|
|
cwSrc = (cjSrc) >> 1; // Floor
|
|
|
|
if (cjSrc & 1)
|
|
{
|
|
do {
|
|
if (cwSrc > 0)
|
|
{
|
|
MM_TRANSFER_WORD(ppdev, pjMmBase, pjSrc, cwSrc);
|
|
}
|
|
|
|
// Make sure we do only a byte read of the last odd byte
|
|
// in the scan so that we'll never read past the end of
|
|
// the bitmap:
|
|
|
|
MM_PIX_TRANS(ppdev, pjMmBase, *(pjSrc + cjSrc - 1));
|
|
pjSrc += lDelta;
|
|
|
|
} while (--cScans != 0);
|
|
}
|
|
else
|
|
{
|
|
do {
|
|
MM_TRANSFER_WORD(ppdev, pjMmBase, pjSrc, cwSrc);
|
|
pjSrc += lDelta;
|
|
|
|
} while (--cScans != 0);
|
|
}
|
|
|
|
CHECK_DATA_COMPLETE(ppdev);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoImageTransferIo16
|
|
*
|
|
* Low-level routine for transferring a bitmap image via the data transfer
|
|
* register using entirely normal I/O.
|
|
*
|
|
* NOTE: Upon entry, there must be 1 guaranteed free empty FIFO!
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoImageTransferIo16( // Type FNIMAGETRANSFER
|
|
PDEV* ppdev,
|
|
BYTE* pjSrc, // Source pointer
|
|
LONG lDelta, // Delta from start of scan to start of next
|
|
LONG cjSrc, // Number of bytes to be output on every scan
|
|
LONG cScans, // Number of scans
|
|
ULONG ulCmd) // Accelerator command - shouldn't include bus size
|
|
{
|
|
LONG cWait;
|
|
LONG cwSrc;
|
|
volatile LONG i;
|
|
|
|
ASSERTDD(cScans > 0, "Can't handle non-positive count of scans");
|
|
ASSERTDD((ulCmd & (BUS_SIZE_8 | BUS_SIZE_16 | BUS_SIZE_32)) == 0,
|
|
"Shouldn't specify bus size in command -- we handle that");
|
|
|
|
IO_GP_WAIT(ppdev);
|
|
|
|
IO_CMD(ppdev, ulCmd | BUS_SIZE_16);
|
|
|
|
CHECK_DATA_READY(ppdev);
|
|
|
|
cwSrc = (cjSrc) >> 1; // Floor
|
|
|
|
// Old S3's in fast machines will drop data on monochrome transfers
|
|
// unless we insert a busy loop. '185' was the minimum value for which
|
|
// my DEC AXP 150 with an ISA 911 S3 stopped dropping data:
|
|
|
|
cWait = 0;
|
|
if ((ulCmd & MULTIPLE_PIXELS) &&
|
|
(ppdev->flCaps & CAPS_SLOW_MONO_EXPANDS))
|
|
{
|
|
cWait = 200; // Add some time to be safe
|
|
}
|
|
|
|
if (cjSrc & 1)
|
|
{
|
|
do {
|
|
if (cwSrc > 0)
|
|
{
|
|
IO_TRANSFER_WORD(ppdev, pjSrc, cwSrc);
|
|
}
|
|
|
|
// Make sure we do only a byte read of the last odd byte
|
|
// in the scan so that we'll never read past the end of
|
|
// the bitmap:
|
|
|
|
IO_PIX_TRANS(ppdev, *(pjSrc + cjSrc - 1));
|
|
pjSrc += lDelta;
|
|
|
|
for (i = cWait; i != 0; i--)
|
|
;
|
|
} while (--cScans != 0);
|
|
}
|
|
else
|
|
{
|
|
do {
|
|
IO_TRANSFER_WORD(ppdev, pjSrc, cwSrc);
|
|
pjSrc += lDelta;
|
|
|
|
for (i = cWait; i != 0; i--)
|
|
;
|
|
} while (--cScans != 0);
|
|
}
|
|
|
|
CHECK_DATA_COMPLETE(ppdev);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoFillSolid
|
|
*
|
|
* Fills a list of rectangles with a solid colour.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoFillSolid( // Type FNFILL
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // List of rectangles to be filled, in relative
|
|
// coordinates
|
|
ULONG rop4, // rop4
|
|
RBRUSH_COLOR rbc, // Drawing colour is rbc.iSolidColor
|
|
POINTL* pptlBrush) // Not used
|
|
{
|
|
ULONG ulHwForeMix;
|
|
|
|
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
|
|
|
ulHwForeMix = gaulHwMixFromRop2[(rop4 >> 2) & 0xf];
|
|
|
|
// It's quite likely that we've just been called from GDI, so it's
|
|
// even more likely that the accelerator's graphics engine has been
|
|
// sitting around idle. Rather than doing a FIFO_WAIT(3) here and
|
|
// then a FIFO_WAIT(5) before outputing the actual rectangle,
|
|
// we can avoid an 'in' (which can be quite expensive, depending on
|
|
// the card) by doing a single FIFO_WAIT(8) right off the bat:
|
|
|
|
if (DEPTH32(ppdev))
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | ulHwForeMix);
|
|
IO_FRGD_COLOR32(ppdev, rbc.iSolidColor);
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
}
|
|
else
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 8);
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | ulHwForeMix);
|
|
IO_FRGD_COLOR(ppdev, rbc.iSolidColor);
|
|
}
|
|
|
|
while(TRUE)
|
|
{
|
|
IO_CUR_X(ppdev, prcl->left);
|
|
IO_CUR_Y(ppdev, prcl->top);
|
|
IO_MAJ_AXIS_PCNT(ppdev, prcl->right - prcl->left - 1);
|
|
IO_MIN_AXIS_PCNT(ppdev, prcl->bottom - prcl->top - 1);
|
|
|
|
IO_CMD(ppdev, RECTANGLE_FILL | DRAWING_DIR_TBLRXM |
|
|
DRAW | DIR_TYPE_XY |
|
|
LAST_PIXEL_ON | MULTIPLE_PIXELS |
|
|
WRITE);
|
|
|
|
if (--c == 0)
|
|
return;
|
|
|
|
prcl++;
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoSlowPatRealize
|
|
*
|
|
* 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
|
|
* vIoFillPatSlow as the basic building block for doing 'slow' pattern output
|
|
* via repeated screen-to-screen blts.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoSlowPatRealize(
|
|
PDEV* ppdev,
|
|
RBRUSH* prb, // Points to brush realization structure
|
|
BOOL bTransparent) // FALSE for normal patterns; TRUE for
|
|
// patterns with a mask when the background
|
|
// mix is LEAVE_ALONE.
|
|
{
|
|
BRUSHENTRY* pbe;
|
|
LONG iBrushCache;
|
|
LONG x;
|
|
LONG y;
|
|
BYTE* pjPattern;
|
|
LONG cwPattern;
|
|
|
|
pbe = prb->pbe;
|
|
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->pbe = pbe;
|
|
}
|
|
|
|
// Load some pointer variables onto the stack, so that we don't have
|
|
// to keep dereferencing their pointers:
|
|
|
|
x = pbe->x;
|
|
y = pbe->y;
|
|
|
|
prb->bTransparent = bTransparent;
|
|
|
|
// I considered doing the colour expansion for 1bpp brushes in
|
|
// software, but by letting the hardware do it, we don't have
|
|
// to do as many OUTs to transfer the pattern.
|
|
|
|
if (prb->fl & RBRUSH_2COLOR)
|
|
{
|
|
// We're going to do a colour-expansion ('across the plane')
|
|
// bitblt of the 1bpp 8x8 pattern to the screen.
|
|
|
|
if (!bTransparent)
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
|
|
IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | OVERPAINT);
|
|
IO_BKGD_MIX(ppdev, BACKGROUND_COLOR | OVERPAINT);
|
|
IO_FRGD_COLOR(ppdev, prb->ulForeColor);
|
|
IO_BKGD_COLOR(ppdev, prb->ulBackColor);
|
|
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
}
|
|
else
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
|
|
IO_FRGD_MIX(ppdev, LOGICAL_1);
|
|
IO_BKGD_MIX(ppdev, LOGICAL_0);
|
|
}
|
|
|
|
IO_PIX_CNTL(ppdev, CPU_DATA);
|
|
IO_ABS_CUR_X(ppdev, x);
|
|
IO_ABS_CUR_Y(ppdev, y);
|
|
IO_MAJ_AXIS_PCNT(ppdev, 7); // Brush is 8 wide
|
|
IO_MIN_AXIS_PCNT(ppdev, 7); // Brush is 8 high
|
|
|
|
IO_GP_WAIT(ppdev);
|
|
|
|
IO_CMD(ppdev, RECTANGLE_FILL | BUS_SIZE_16 | WAIT |
|
|
DRAWING_DIR_TBLRXM | DRAW | LAST_PIXEL_ON |
|
|
MULTIPLE_PIXELS | WRITE | BYTE_SWAP);
|
|
|
|
CHECK_DATA_READY(ppdev);
|
|
|
|
pjPattern = (BYTE*) &prb->aulPattern[0];
|
|
IO_TRANSFER_WORD_ALIGNED(ppdev, pjPattern, 8);
|
|
// Each word transferred comprises one row of the
|
|
// pattern, and there are 8 rows in the pattern
|
|
|
|
CHECK_DATA_COMPLETE(ppdev);
|
|
}
|
|
else
|
|
{
|
|
ASSERTDD(!bTransparent,
|
|
"Shouldn't have been asked for transparency with a non-1bpp brush");
|
|
|
|
IO_FIFO_WAIT(ppdev, 6);
|
|
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, SRC_CPU_DATA | OVERPAINT);
|
|
IO_ABS_CUR_X(ppdev, x);
|
|
IO_ABS_CUR_Y(ppdev, y);
|
|
IO_MAJ_AXIS_PCNT(ppdev, 7); // Brush is 8 wide
|
|
IO_MIN_AXIS_PCNT(ppdev, 7); // Brush is 8 high
|
|
|
|
IO_GP_WAIT(ppdev);
|
|
|
|
IO_CMD(ppdev, RECTANGLE_FILL | BUS_SIZE_16| WAIT |
|
|
DRAWING_DIR_TBLRXM | DRAW | LAST_PIXEL_ON |
|
|
SINGLE_PIXEL | WRITE | BYTE_SWAP);
|
|
|
|
CHECK_DATA_READY(ppdev);
|
|
|
|
pjPattern = (BYTE*) &prb->aulPattern[0];
|
|
cwPattern = CONVERT_TO_BYTES((TOTAL_BRUSH_SIZE / 2), ppdev);
|
|
IO_TRANSFER_WORD_ALIGNED(ppdev, pjPattern, cwPattern);
|
|
|
|
CHECK_DATA_COMPLETE(ppdev);
|
|
}
|
|
|
|
// ÚÄÂÄÂÄÄÄÂÄÄÄÄÄÄÄÂÄ¿
|
|
// ³0³2³3 ³4 ³1³ We now have an 8x8 colour-expanded copy of
|
|
// ÃÄÁÄÁÄÄÄÁÄÄÄÄÄÄÄÁÄ´ the pattern sitting in off-screen memory,
|
|
// ³5 ³ represented here by square '0'.
|
|
// ³ ³
|
|
// ³ ³ We're now going to expand the pattern to
|
|
// ³ ³ 72x72 by repeatedly copying larger rectangles
|
|
// ³ ³ in the indicated order, and doing a 'rolling'
|
|
// ³ ³ blt to copy vertically.
|
|
// ³ ³
|
|
// ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
|
|
|
|
// Copy '1':
|
|
|
|
IO_FIFO_WAIT(ppdev, 6);
|
|
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, SRC_DISPLAY_MEMORY | OVERPAINT);
|
|
|
|
// Note that 'cur_x', 'maj_axis_pcnt' and 'min_axis_pcnt' are already
|
|
// correct.
|
|
|
|
IO_ABS_CUR_Y(ppdev, y);
|
|
IO_ABS_DEST_X(ppdev, x + 64);
|
|
IO_ABS_DEST_Y(ppdev, y);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
|
|
// Copy '2':
|
|
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
|
|
IO_ABS_DEST_X(ppdev, x + 8);
|
|
IO_ABS_DEST_Y(ppdev, y);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
|
|
// Copy '3':
|
|
|
|
IO_ABS_DEST_X(ppdev, x + 16);
|
|
IO_ABS_DEST_Y(ppdev, y);
|
|
IO_MAJ_AXIS_PCNT(ppdev, 15);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
|
|
// Copy '4':
|
|
|
|
IO_FIFO_WAIT(ppdev, 8);
|
|
|
|
IO_ABS_DEST_X(ppdev, x + 32);
|
|
IO_ABS_DEST_Y(ppdev, y);
|
|
IO_MAJ_AXIS_PCNT(ppdev, 31);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
|
|
// Copy '5':
|
|
|
|
IO_ABS_DEST_X(ppdev, x);
|
|
IO_MAJ_AXIS_PCNT(ppdev, 71);
|
|
IO_MIN_AXIS_PCNT(ppdev, 63);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoFillPatSlow
|
|
*
|
|
* Uses the screen-to-screen blting ability of the accelerator to fill a
|
|
* list of rectangles with a specified pattern. This routine is 'slow'
|
|
* merely in the sense that it doesn't use any built-in hardware pattern
|
|
* support that may be built into the accelerator.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoFillPatSlow( // Type FNFILL
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // List of rectangles to be filled, in relative
|
|
// coordinates
|
|
ULONG rop4, // rop4
|
|
RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
|
|
POINTL* pptlBrush) // Pattern alignment
|
|
{
|
|
BOOL bTransparent;
|
|
ULONG ulHwForeMix;
|
|
BOOL bExponential;
|
|
LONG x;
|
|
LONG y;
|
|
LONG cxToGo;
|
|
LONG cyToGo;
|
|
LONG cxThis;
|
|
LONG cyThis;
|
|
LONG xOrg;
|
|
LONG yOrg;
|
|
LONG xBrush;
|
|
LONG yBrush;
|
|
LONG cyOriginal;
|
|
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
|
|
|
|
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
|
ASSERTDD(rbc.prb->pbe != NULL,
|
|
"Unexpected Null pbe in vIoFillPatSlow");
|
|
ASSERTDD(!(ppdev->flCaps & CAPS_HW_PATTERNS),
|
|
"Shouldn't use slow patterns when can do hw patterns");
|
|
|
|
bTransparent = (((rop4 >> 8) & 0xff) != (rop4 & 0xff));
|
|
|
|
if ((rbc.prb->pbe->prbVerify != rbc.prb) ||
|
|
(rbc.prb->bTransparent != bTransparent))
|
|
{
|
|
vIoSlowPatRealize(ppdev, rbc.prb, bTransparent);
|
|
}
|
|
|
|
ASSERTDD(rbc.prb->bTransparent == bTransparent,
|
|
"Not realized with correct transparency");
|
|
|
|
ulHwForeMix = gaulHwMixFromRop2[(rop4 >> 2) & 0xf];
|
|
|
|
if (!bTransparent)
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 2);
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, SRC_DISPLAY_MEMORY | ulHwForeMix);
|
|
|
|
// We special case OVERPAINT 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 LOGICAL_0
|
|
// or LOGICAL_1 because those will be taken care of by the
|
|
// solid fill routines, and I can't be bothered to check for
|
|
// NOTNEW:
|
|
|
|
bExponential = (ulHwForeMix == OVERPAINT);
|
|
}
|
|
else
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
|
|
IO_PIX_CNTL(ppdev, DISPLAY_MEMORY);
|
|
IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | ulHwForeMix);
|
|
IO_BKGD_MIX(ppdev, BACKGROUND_COLOR | LEAVE_ALONE);
|
|
IO_FRGD_COLOR(ppdev, rbc.prb->ulForeColor);
|
|
IO_RD_MASK(ppdev, 1); // Pick a plane, any plane
|
|
|
|
bExponential = FALSE;
|
|
}
|
|
|
|
// 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->pbe;
|
|
xBrush = pbe->x;
|
|
yBrush = pbe->y;
|
|
|
|
do {
|
|
x = prcl->left;
|
|
y = prcl->top;
|
|
|
|
cxToGo = prcl->right - x;
|
|
cyToGo = prcl->bottom - y;
|
|
|
|
if ((cxToGo <= SLOW_BRUSH_DIMENSION) &&
|
|
(cyToGo <= SLOW_BRUSH_DIMENSION))
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
IO_ABS_CUR_X(ppdev, ((x - xOrg) & 7) + xBrush);
|
|
IO_ABS_CUR_Y(ppdev, ((y - yOrg) & 7) + yBrush);
|
|
IO_DEST_X(ppdev, x);
|
|
IO_DEST_Y(ppdev, y);
|
|
IO_MAJ_AXIS_PCNT(ppdev, cxToGo - 1);
|
|
IO_MIN_AXIS_PCNT(ppdev, cyToGo - 1);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
}
|
|
|
|
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;
|
|
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
IO_MAJ_AXIS_PCNT(ppdev, cxThis - 1);
|
|
IO_MIN_AXIS_PCNT(ppdev, cyThis - 1);
|
|
IO_DEST_X(ppdev, x);
|
|
IO_DEST_Y(ppdev, y);
|
|
IO_ABS_CUR_X(ppdev, ((x - xOrg) & 7) + xBrush);
|
|
IO_ABS_CUR_Y(ppdev, ((y - yOrg) & 7) + yBrush);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
|
|
IO_FIFO_WAIT(ppdev, 2);
|
|
IO_CUR_X(ppdev, x);
|
|
IO_CUR_Y(ppdev, y);
|
|
|
|
x += cxThis;
|
|
|
|
while (cxToGo > 0)
|
|
{
|
|
// First, expand out to the right, doubling our size
|
|
// each time:
|
|
|
|
cxToGo -= cxThis;
|
|
if (cxToGo < 0)
|
|
cxThis += cxToGo;
|
|
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
IO_MAJ_AXIS_PCNT(ppdev, cxThis - 1);
|
|
IO_DEST_X(ppdev, x);
|
|
IO_DEST_Y(ppdev, y);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
|
|
x += cxThis;
|
|
cxThis *= 2;
|
|
}
|
|
|
|
if (cyToGo > 0)
|
|
{
|
|
// Now do a 'rolling blt' to pattern the rest vertically:
|
|
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
IO_DEST_X(ppdev, prcl->left);
|
|
IO_MAJ_AXIS_PCNT(ppdev, prcl->right - prcl->left - 1);
|
|
IO_MIN_AXIS_PCNT(ppdev, cyToGo - 1);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We handle arbitrary mixes simply by repeatedly tiling
|
|
// our cached pattern over the entire rectangle:
|
|
|
|
IO_FIFO_WAIT(ppdev, 2);
|
|
IO_ABS_CUR_X(ppdev, ((x - xOrg) & 7) + xBrush);
|
|
IO_ABS_CUR_Y(ppdev, ((y - yOrg) & 7) + yBrush);
|
|
|
|
cyOriginal = cyToGo; // Have to remember for later...
|
|
|
|
do {
|
|
cxThis = SLOW_BRUSH_DIMENSION;
|
|
cxToGo -= cxThis;
|
|
if (cxToGo < 0)
|
|
cxThis += cxToGo;
|
|
|
|
IO_FIFO_WAIT(ppdev, 3);
|
|
IO_MAJ_AXIS_PCNT(ppdev, cxThis - 1);
|
|
IO_DEST_Y(ppdev, y);
|
|
IO_DEST_X(ppdev, x);
|
|
|
|
x += cxThis; // Get ready for next column
|
|
cyToGo = cyOriginal; // Have to reset for each new column
|
|
|
|
do {
|
|
cyThis = SLOW_BRUSH_DIMENSION;
|
|
cyToGo -= cyThis;
|
|
if (cyToGo < 0)
|
|
cyThis += cyToGo;
|
|
|
|
IO_FIFO_WAIT(ppdev, 2);
|
|
IO_MIN_AXIS_PCNT(ppdev, cyThis - 1);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
MULTIPLE_PIXELS | DRAWING_DIR_TBLRXM);
|
|
|
|
} while (cyToGo > 0);
|
|
} while (cxToGo > 0);
|
|
}
|
|
prcl++;
|
|
} while (--c != 0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoFastPatRealize
|
|
*
|
|
* This routine transfers an 8x8 pattern to off-screen display memory,
|
|
* so that it can be used by the S3 pattern hardware.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoFastPatRealize( // Type FNFASTPATREALIZE
|
|
PDEV* ppdev,
|
|
RBRUSH* prb, // Points to brush realization structure
|
|
POINTL* pptlBrush, // Brush origin for aligning realization
|
|
BOOL bTransparent) // FALSE for normal patterns; TRUE for
|
|
// patterns with a mask when the background
|
|
// mix is LEAVE_ALONE.
|
|
{
|
|
BRUSHENTRY* pbe;
|
|
LONG iBrushCache;
|
|
LONG x;
|
|
LONG y;
|
|
LONG i;
|
|
LONG xShift;
|
|
LONG yShift;
|
|
BYTE* pjSrc;
|
|
BYTE* pjDst;
|
|
LONG cjLeft;
|
|
LONG cjRight;
|
|
BYTE* pjPattern;
|
|
LONG cwPattern;
|
|
|
|
ULONG aulBrush[TOTAL_BRUSH_SIZE];
|
|
// Temporary buffer for aligning brush. Declared
|
|
// as an array of ULONGs to get proper dword
|
|
// alignment. Also leaves room for brushes that
|
|
// are up to 32bpp. Note: this takes up 1/4k!
|
|
|
|
pbe = prb->pbe;
|
|
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->pbe = pbe;
|
|
}
|
|
|
|
// Load some variables onto the stack, so that we don't have to keep
|
|
// dereferencing their pointers:
|
|
|
|
x = pbe->x;
|
|
y = pbe->y;
|
|
|
|
// Because we handle only 8x8 brushes, it is easy to compute the
|
|
// number of pels by which we have to rotate the brush pattern
|
|
// right and down. Note that if we were to handle arbitrary sized
|
|
// patterns, this calculation would require a modulus operation.
|
|
//
|
|
// The brush is aligned in absolute coordinates, so we have to add
|
|
// in the surface offset:
|
|
|
|
xShift = pptlBrush->x + ppdev->xOffset;
|
|
yShift = pptlBrush->y + ppdev->yOffset;
|
|
|
|
prb->ptlBrushOrg.x = xShift; // We have to remember the alignment
|
|
prb->ptlBrushOrg.y = yShift; // that we used for caching (we check
|
|
// this when we go to see if a brush's
|
|
// cache entry is still valid)
|
|
|
|
xShift &= 7; // Rotate pattern 'xShift' pels right
|
|
yShift &= 7; // Rotate pattern 'yShift' pels down
|
|
|
|
prb->bTransparent = bTransparent;
|
|
|
|
// I considered doing the colour expansion for 1bpp brushes in
|
|
// software, but by letting the hardware do it, we don't have
|
|
// to do as many OUTs to transfer the pattern.
|
|
|
|
if (prb->fl & RBRUSH_2COLOR)
|
|
{
|
|
// We're going to do a colour-expansion ('across the plane')
|
|
// bitblt of the 1bpp 8x8 pattern to the screen. But first
|
|
// we'll align it properly by copying it to a temporary buffer
|
|
// (which we'll conveniently pack word aligned so that we can do a
|
|
// REP OUTSW...)
|
|
|
|
pjSrc = (BYTE*) &prb->aulPattern[0]; // Copy from the start of the
|
|
// brush buffer
|
|
pjDst = (BYTE*) &aulBrush[0]; // Copy to our temp buffer
|
|
pjDst += yShift * sizeof(WORD); // starting yShift rows down
|
|
i = 8 - yShift; // for 8 - yShift rows
|
|
|
|
do {
|
|
*pjDst = (*pjSrc >> xShift) | (*pjSrc << (8 - xShift));
|
|
pjDst += sizeof(WORD); // Destination is word packed
|
|
pjSrc += sizeof(WORD); // Source is word aligned too
|
|
|
|
} while (--i != 0);
|
|
|
|
pjDst -= 8 * sizeof(WORD); // Move to the beginning of the source
|
|
|
|
ASSERTDD(pjDst == (BYTE*) &aulBrush[0], "pjDst not back at start");
|
|
|
|
for (; yShift != 0; yShift--)
|
|
{
|
|
*pjDst = (*pjSrc >> xShift) | (*pjSrc << (8 - xShift));
|
|
pjDst += sizeof(WORD); // Destination is word packed
|
|
pjSrc += sizeof(WORD); // Source is word aligned too
|
|
}
|
|
|
|
if (bTransparent)
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 3);
|
|
|
|
IO_PIX_CNTL(ppdev, CPU_DATA);
|
|
IO_FRGD_MIX(ppdev, LOGICAL_1);
|
|
IO_BKGD_MIX(ppdev, LOGICAL_0);
|
|
}
|
|
else
|
|
{
|
|
if (DEPTH32(ppdev))
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
|
|
IO_PIX_CNTL(ppdev, CPU_DATA);
|
|
IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | OVERPAINT);
|
|
IO_BKGD_MIX(ppdev, BACKGROUND_COLOR | OVERPAINT);
|
|
IO_FRGD_COLOR32(ppdev, prb->ulForeColor);
|
|
IO_BKGD_COLOR32(ppdev, prb->ulBackColor);
|
|
}
|
|
else
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
|
|
IO_PIX_CNTL(ppdev, CPU_DATA);
|
|
IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | OVERPAINT);
|
|
IO_BKGD_MIX(ppdev, BACKGROUND_COLOR | OVERPAINT);
|
|
IO_FRGD_COLOR(ppdev, prb->ulForeColor);
|
|
IO_BKGD_COLOR(ppdev, prb->ulBackColor);
|
|
}
|
|
}
|
|
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
|
|
IO_ABS_CUR_X(ppdev, x);
|
|
IO_ABS_CUR_Y(ppdev, y);
|
|
IO_MAJ_AXIS_PCNT(ppdev, 7); // Brush is 8 wide
|
|
IO_MIN_AXIS_PCNT(ppdev, 7); // Brush is 8 high
|
|
|
|
IO_GP_WAIT(ppdev);
|
|
|
|
IO_CMD(ppdev, RECTANGLE_FILL | BUS_SIZE_16 | WAIT |
|
|
DRAWING_DIR_TBLRXM | DRAW | LAST_PIXEL_ON |
|
|
MULTIPLE_PIXELS | WRITE | BYTE_SWAP);
|
|
|
|
CHECK_DATA_READY(ppdev);
|
|
|
|
pjPattern = (BYTE*) &aulBrush[0];
|
|
IO_TRANSFER_WORD_ALIGNED(ppdev, pjPattern, 8);
|
|
// Each word transferred
|
|
// comprises one row of the
|
|
// pattern, and there are
|
|
// 8 rows in the pattern
|
|
|
|
CHECK_DATA_COMPLETE(ppdev);
|
|
}
|
|
else
|
|
{
|
|
ASSERTDD(!bTransparent,
|
|
"Shouldn't have been asked for transparency with a non-1bpp brush");
|
|
|
|
// We're going to do a straight ('through the plane') bitblt
|
|
// of the Xbpp 8x8 pattern to the screen. But first we'll align
|
|
// it properly by copying it to a temporary buffer:
|
|
|
|
cjLeft = CONVERT_TO_BYTES(xShift, ppdev); // Number of bytes pattern
|
|
// is shifted to the right
|
|
cjRight = CONVERT_TO_BYTES(8, ppdev) - cjLeft; // Number of bytes pattern
|
|
// is shifted to the left
|
|
|
|
pjSrc = (BYTE*) &prb->aulPattern[0]; // Copy from brush buffer
|
|
pjDst = (BYTE*) &aulBrush[0]; // Copy to our temp buffer
|
|
pjDst += yShift * CONVERT_TO_BYTES(8, ppdev); // starting yShift rows
|
|
i = 8 - yShift; // down for 8 - yShift rows
|
|
|
|
do {
|
|
RtlCopyMemory(pjDst + cjLeft, pjSrc, cjRight);
|
|
RtlCopyMemory(pjDst, pjSrc + cjRight, cjLeft);
|
|
|
|
pjDst += cjLeft + cjRight;
|
|
pjSrc += cjLeft + cjRight;
|
|
|
|
} while (--i != 0);
|
|
|
|
pjDst = (BYTE*) &aulBrush[0]; // Move to the beginning of destination
|
|
|
|
for (; yShift != 0; yShift--)
|
|
{
|
|
RtlCopyMemory(pjDst + cjLeft, pjSrc, cjRight);
|
|
RtlCopyMemory(pjDst, pjSrc + cjRight, cjLeft);
|
|
|
|
pjDst += cjLeft + cjRight;
|
|
pjSrc += cjLeft + cjRight;
|
|
|
|
}
|
|
|
|
IO_FIFO_WAIT(ppdev, 6);
|
|
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, SRC_CPU_DATA | OVERPAINT);
|
|
|
|
IO_ABS_CUR_X(ppdev, x);
|
|
IO_ABS_CUR_Y(ppdev, y);
|
|
IO_MAJ_AXIS_PCNT(ppdev, 7); // Brush is 8 wide
|
|
IO_MIN_AXIS_PCNT(ppdev, 7); // Brush is 8 high
|
|
|
|
IO_GP_WAIT(ppdev);
|
|
|
|
IO_CMD(ppdev, RECTANGLE_FILL | BUS_SIZE_16| WAIT |
|
|
DRAWING_DIR_TBLRXM | DRAW | LAST_PIXEL_ON |
|
|
SINGLE_PIXEL | WRITE | BYTE_SWAP);
|
|
|
|
CHECK_DATA_READY(ppdev);
|
|
|
|
pjPattern = (BYTE*) &aulBrush[0];
|
|
cwPattern = CONVERT_TO_BYTES((TOTAL_BRUSH_SIZE / 2), ppdev);
|
|
IO_TRANSFER_WORD_ALIGNED(ppdev, pjPattern, cwPattern);
|
|
|
|
CHECK_DATA_COMPLETE(ppdev);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoFillPatFast
|
|
*
|
|
* This routine uses the S3 pattern hardware to draw a patterned list of
|
|
* rectangles.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoFillPatFast( // Type FNFILL
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // List of rectangles to be filled, in relative
|
|
// coordinates
|
|
ULONG rop4, // rop4
|
|
RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
|
|
POINTL* pptlBrush) // Pattern alignment
|
|
{
|
|
BOOL bTransparent;
|
|
ULONG ulHwForeMix;
|
|
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
|
|
|
|
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
|
ASSERTDD(ppdev->flCaps & CAPS_HW_PATTERNS,
|
|
"Shouldn't use fast patterns when can't do hw patterns");
|
|
|
|
bTransparent = (((rop4 >> 8) & 0xff) != (rop4 & 0xff));
|
|
|
|
// The S3's pattern hardware requires that we keep an aligned copy
|
|
// of the brush in off-screen memory. We have to update this
|
|
// realization if any of the following are true:
|
|
//
|
|
// 1) The brush alignment has changed;
|
|
// 2) The off-screen location we thought we had reserved for our
|
|
// realization got overwritten by a different pattern;
|
|
// 3) We had realized the pattern to do transparent hatches, but
|
|
// we're now being asked to do an opaque pattern, or vice
|
|
// versa (since we use different realizations for transparent
|
|
// vs. opaque patterns).
|
|
//
|
|
// To handle the initial realization of a pattern, we're a little
|
|
// tricky in order to save an 'if' in the following expression. In
|
|
// DrvRealizeBrush, we set 'prb->ptlBrushOrg.x' to be 0x80000000 (a
|
|
// very negative number), which is guaranteed not to equal 'pptlBrush->x
|
|
// + ppdev->xOffset'. So our check for brush alignment will also
|
|
// handle the initialization case (note that this check must occur
|
|
// *before* dereferencing 'prb->pbe' because that pointer will be
|
|
// NULL for a new pattern).
|
|
|
|
if ((rbc.prb->ptlBrushOrg.x != pptlBrush->x + ppdev->xOffset) ||
|
|
(rbc.prb->ptlBrushOrg.y != pptlBrush->y + ppdev->yOffset) ||
|
|
(rbc.prb->pbe->prbVerify != rbc.prb) ||
|
|
(rbc.prb->bTransparent != bTransparent))
|
|
{
|
|
vIoFastPatRealize(ppdev, rbc.prb, pptlBrush, bTransparent);
|
|
}
|
|
else if (ppdev->flCaps & CAPS_RE_REALIZE_PATTERN)
|
|
{
|
|
// The initial revs of the Vision chips have a bug where, if
|
|
// we have not just drawn the pattern to off-screen memory,
|
|
// we have to draw some sort of 1x8 rectangle before using
|
|
// the pattern hardware (note that a LEAVE_ALONE rop will not
|
|
// work).
|
|
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, SRC_DISPLAY_MEMORY | OVERPAINT);
|
|
IO_ABS_CUR_X(ppdev, ppdev->ptlReRealize.x);
|
|
IO_ABS_CUR_Y(ppdev, ppdev->ptlReRealize.y);
|
|
IO_MAJ_AXIS_PCNT(ppdev, 0);
|
|
IO_MIN_AXIS_PCNT(ppdev, 7);
|
|
IO_CMD(ppdev, RECTANGLE_FILL | DRAWING_DIR_TBLRXM |
|
|
DRAW | DIR_TYPE_XY |
|
|
LAST_PIXEL_ON | MULTIPLE_PIXELS |
|
|
WRITE);
|
|
}
|
|
|
|
ASSERTDD(rbc.prb->bTransparent == bTransparent,
|
|
"Not realized with correct transparency");
|
|
|
|
pbe = rbc.prb->pbe;
|
|
|
|
ulHwForeMix = gaulHwMixFromRop2[(rop4 >> 2) & 0xf];
|
|
|
|
if (!bTransparent)
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
|
|
IO_ABS_CUR_X(ppdev, pbe->x);
|
|
IO_ABS_CUR_Y(ppdev, pbe->y);
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, SRC_DISPLAY_MEMORY | ulHwForeMix);
|
|
}
|
|
else
|
|
{
|
|
if (DEPTH32(ppdev))
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
IO_FRGD_COLOR32(ppdev, rbc.prb->ulForeColor);
|
|
IO_RD_MASK32(ppdev, 1); // Pick a plane, any plane
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
}
|
|
else
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
IO_FRGD_COLOR(ppdev, rbc.prb->ulForeColor);
|
|
IO_RD_MASK(ppdev, 1); // Pick a plane, any plane
|
|
}
|
|
|
|
IO_ABS_CUR_X(ppdev, pbe->x);
|
|
IO_ABS_CUR_Y(ppdev, pbe->y);
|
|
IO_PIX_CNTL(ppdev, DISPLAY_MEMORY);
|
|
IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | ulHwForeMix);
|
|
IO_BKGD_MIX(ppdev, BACKGROUND_COLOR | LEAVE_ALONE);
|
|
}
|
|
|
|
do {
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
|
|
IO_DEST_X(ppdev, prcl->left);
|
|
IO_DEST_Y(ppdev, prcl->top);
|
|
IO_MAJ_AXIS_PCNT(ppdev, prcl->right - prcl->left - 1);
|
|
IO_MIN_AXIS_PCNT(ppdev, prcl->bottom - prcl->top - 1);
|
|
IO_CMD(ppdev, PATTERN_FILL | BYTE_SWAP | DRAWING_DIR_TBLRXM |
|
|
DRAW | WRITE);
|
|
|
|
prcl++;
|
|
} while (--c != 0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoXfer1bpp
|
|
*
|
|
* This routine colour expands a monochrome bitmap, possibly with different
|
|
* Rop2's for the foreground and background. It will be called in the
|
|
* following cases:
|
|
*
|
|
* 1) To colour-expand the monochrome text buffer for the vFastText routine.
|
|
* 2) To blt a 1bpp source with a simple Rop2 between the source and
|
|
* destination.
|
|
* 3) To blt a true Rop3 when the source is a 1bpp bitmap that expands to
|
|
* white and black, and the pattern is a solid colour.
|
|
* 4) To handle a true Rop4 that works out to be Rop2's between the pattern
|
|
* and destination.
|
|
*
|
|
* Needless to say, making this routine fast can leverage a lot of
|
|
* performance.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoXfer1bpp( // Type FNXFER
|
|
PDEV* ppdev,
|
|
LONG c, // Count of rectangles, can't be zero
|
|
RECTL* prcl, // List of destination rectangles, in relative
|
|
// coordinates
|
|
ROP4 rop4, // rop4
|
|
SURFOBJ* psoSrc, // Source surface
|
|
POINTL* pptlSrc, // Original unclipped source point
|
|
RECTL* prclDst, // Original unclipped destination rectangle
|
|
XLATEOBJ* pxlo) // Translate that provides colour-expansion information
|
|
{
|
|
ULONG ulHwForeMix;
|
|
ULONG ulHwBackMix;
|
|
LONG dxSrc;
|
|
LONG dySrc;
|
|
LONG cx;
|
|
LONG cy;
|
|
LONG lSrcDelta;
|
|
BYTE* pjSrcScan0;
|
|
BYTE* pjSrc;
|
|
LONG cjSrc;
|
|
LONG xLeft;
|
|
LONG yTop;
|
|
LONG xBias;
|
|
|
|
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
|
ASSERTDD(pptlSrc != NULL && psoSrc != NULL, "Can't have NULL sources");
|
|
ASSERTDD(((((rop4 & 0xff00) >> 8) == (rop4 & 0xff)) || (rop4 == 0xaacc)),
|
|
"Expect weird rops only when opaquing");
|
|
|
|
// Note that only our text routine calls us with a '0xaacc' rop:
|
|
|
|
ulHwForeMix = gaulHwMixFromRop2[rop4 & 0xf];
|
|
ulHwBackMix = (rop4 != 0xaacc) ? ulHwForeMix : LEAVE_ALONE;
|
|
|
|
if (DEPTH32(ppdev))
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
|
|
IO_PIX_CNTL(ppdev, CPU_DATA);
|
|
IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | ulHwForeMix);
|
|
IO_BKGD_MIX(ppdev, BACKGROUND_COLOR | ulHwBackMix);
|
|
IO_FRGD_COLOR32(ppdev, pxlo->pulXlate[1]);
|
|
IO_BKGD_COLOR32(ppdev, pxlo->pulXlate[0]);
|
|
}
|
|
else
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
|
|
IO_PIX_CNTL(ppdev, CPU_DATA);
|
|
IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | ulHwForeMix);
|
|
IO_BKGD_MIX(ppdev, BACKGROUND_COLOR | ulHwBackMix);
|
|
IO_FRGD_COLOR(ppdev, pxlo->pulXlate[1]);
|
|
IO_BKGD_COLOR(ppdev, pxlo->pulXlate[0]);
|
|
}
|
|
|
|
dxSrc = pptlSrc->x - prclDst->left;
|
|
dySrc = pptlSrc->y - prclDst->top; // Add to destination to get source
|
|
|
|
lSrcDelta = psoSrc->lDelta;
|
|
pjSrcScan0 = psoSrc->pvScan0;
|
|
|
|
do {
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
|
|
// We'll byte align to the source, but do word transfers
|
|
// (implying that we may be doing unaligned reads from the
|
|
// source). We do this because it may reduce the total
|
|
// number of word outs/writes that we'll have to do to the
|
|
// display:
|
|
|
|
yTop = prcl->top;
|
|
xLeft = prcl->left;
|
|
|
|
xBias = (xLeft + dxSrc) & 7; // This is the byte-align bias
|
|
if (xBias != 0)
|
|
{
|
|
// We could either align in software or use the hardware to do
|
|
// it. We'll use the hardware; the cost we pay is the time spent
|
|
// setting and resetting one scissors register:
|
|
|
|
IO_SCISSORS_L(ppdev, xLeft);
|
|
xLeft -= xBias;
|
|
}
|
|
|
|
cx = prcl->right - xLeft;
|
|
cy = prcl->bottom - yTop;
|
|
|
|
IO_CUR_X(ppdev, xLeft);
|
|
IO_CUR_Y(ppdev, yTop);
|
|
IO_MAJ_AXIS_PCNT(ppdev, cx - 1);
|
|
IO_MIN_AXIS_PCNT(ppdev, cy - 1);
|
|
|
|
cjSrc = (cx + 7) / 8; // # bytes to transfer
|
|
pjSrc = pjSrcScan0 + (yTop + dySrc) * lSrcDelta
|
|
+ (xLeft + dxSrc) / 8;
|
|
// Start is byte aligned (note
|
|
// that we don't have to add
|
|
// xBias)
|
|
|
|
ppdev->pfnImageTransfer(ppdev, pjSrc, lSrcDelta, cjSrc, cy,
|
|
(RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
|
|
DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
|
|
WRITE | BYTE_SWAP));
|
|
|
|
if (xBias != 0)
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 1);
|
|
IO_ABS_SCISSORS_L(ppdev, 0); // Reset the clipping if we used it
|
|
}
|
|
|
|
prcl++;
|
|
} while (--c != 0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoXfer4bpp
|
|
*
|
|
* 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.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
// XLATE_BUFFER_SIZE defines the size of the stack-based buffer we use
|
|
// for doing the translate. Note that in general stack buffers should
|
|
// be kept as small as possible. The OS guarantees us only 8k for stack
|
|
// from GDI down to the display driver in low memory situations; if we
|
|
// ask for more, we'll access violate. Note also that at any time the
|
|
// stack buffer cannot be larger than a page (4k) -- otherwise we may
|
|
// miss touching the 'guard page' and access violate then too.
|
|
|
|
#define XLATE_BUFFER_SIZE 256
|
|
|
|
VOID vIoXfer4bpp( // Type FNXFER
|
|
PDEV* ppdev,
|
|
LONG c, // Count of rectangles, can't be zero
|
|
RECTL* prcl, // List of destination rectangles, in relative
|
|
// coordinates
|
|
ULONG rop4, // rop4
|
|
SURFOBJ* psoSrc, // Source surface
|
|
POINTL* pptlSrc, // Original unclipped source point
|
|
RECTL* prclDst, // Original unclipped destination rectangle
|
|
XLATEOBJ* pxlo) // Translate that provides colour-expansion information
|
|
{
|
|
LONG dx;
|
|
LONG dy;
|
|
LONG cx;
|
|
LONG cy;
|
|
LONG lSrcDelta;
|
|
BYTE* pjSrcScan0;
|
|
BYTE* pjScan;
|
|
BYTE* pjSrc;
|
|
BYTE* pjDst;
|
|
LONG cxThis;
|
|
LONG cxToGo;
|
|
LONG xSrc;
|
|
LONG iLoop;
|
|
BYTE jSrc;
|
|
ULONG* pulXlate;
|
|
LONG cwThis;
|
|
BYTE* pjBuf;
|
|
BYTE ajBuf[XLATE_BUFFER_SIZE];
|
|
|
|
ASSERTDD(ppdev->iBitmapFormat == BMF_8BPP, "Screen must be 8bpp");
|
|
ASSERTDD(psoSrc->iBitmapFormat == BMF_4BPP, "Source must be 4bpp");
|
|
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
|
ASSERTDD(((rop4 & 0xff00) >> 8) == (rop4 & 0xff),
|
|
"Expect only a rop2");
|
|
|
|
dx = pptlSrc->x - prclDst->left;
|
|
dy = pptlSrc->y - prclDst->top; // Add to destination to get source
|
|
|
|
lSrcDelta = psoSrc->lDelta;
|
|
pjSrcScan0 = psoSrc->pvScan0;
|
|
|
|
IO_FIFO_WAIT(ppdev, 6);
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, SRC_CPU_DATA | gaulHwMixFromRop2[rop4 & 0xf]);
|
|
|
|
while(TRUE)
|
|
{
|
|
cx = prcl->right - prcl->left;
|
|
cy = prcl->bottom - prcl->top;
|
|
|
|
IO_CUR_X(ppdev, prcl->left);
|
|
IO_CUR_Y(ppdev, prcl->top);
|
|
IO_MAJ_AXIS_PCNT(ppdev, cx - 1);
|
|
IO_MIN_AXIS_PCNT(ppdev, cy - 1);
|
|
|
|
pulXlate = pxlo->pulXlate;
|
|
xSrc = prcl->left + dx;
|
|
pjScan = pjSrcScan0 + (prcl->top + dy) * lSrcDelta + (xSrc >> 1);
|
|
|
|
IO_GP_WAIT(ppdev);
|
|
IO_CMD(ppdev, RECTANGLE_FILL | BUS_SIZE_16| WAIT |
|
|
DRAWING_DIR_TBLRXM | DRAW | LAST_PIXEL_ON |
|
|
SINGLE_PIXEL | WRITE | BYTE_SWAP);
|
|
CHECK_DATA_READY(ppdev);
|
|
|
|
do {
|
|
pjSrc = pjScan;
|
|
cxToGo = cx; // # of pels per scan in 4bpp source
|
|
do {
|
|
cxThis = XLATE_BUFFER_SIZE;
|
|
// We can handle XLATE_BUFFER_SIZE number
|
|
// of pels in this xlate batch
|
|
cxToGo -= cxThis; // cxThis will be the actual number of
|
|
// pels we'll do in this xlate batch
|
|
if (cxToGo < 0)
|
|
cxThis += cxToGo;
|
|
|
|
pjDst = ajBuf; // Points to our temporary batch buffer
|
|
|
|
// We handle alignment ourselves because it's easy to
|
|
// do, rather than pay the cost of setting/resetting
|
|
// the scissors register:
|
|
|
|
if (xSrc & 1)
|
|
{
|
|
// When unaligned, we have to be careful not to read
|
|
// past the end of the 4bpp bitmap (that could
|
|
// potentially cause us to access violate):
|
|
|
|
iLoop = cxThis >> 1; // Each loop handles 2 pels;
|
|
// we'll handle odd pel
|
|
// separately
|
|
jSrc = *pjSrc;
|
|
while (iLoop-- != 0)
|
|
{
|
|
*pjDst++ = (BYTE) pulXlate[jSrc & 0xf];
|
|
jSrc = *(++pjSrc);
|
|
*pjDst++ = (BYTE) pulXlate[jSrc >> 4];
|
|
}
|
|
|
|
if (cxThis & 1)
|
|
*pjDst = (BYTE) pulXlate[jSrc & 0xf];
|
|
}
|
|
else
|
|
{
|
|
iLoop = (cxThis + 1) >> 1; // Each loop handles 2 pels
|
|
do {
|
|
jSrc = *pjSrc++;
|
|
|
|
*pjDst++ = (BYTE) pulXlate[jSrc >> 4];
|
|
*pjDst++ = (BYTE) pulXlate[jSrc & 0xf];
|
|
|
|
} while (--iLoop != 0);
|
|
}
|
|
|
|
// The number of bytes we'll transfer is equal to the number
|
|
// of pels we've processed in the batch. Since we're
|
|
// transferring words, we have to round up to get the word
|
|
// count:
|
|
|
|
cwThis = (cxThis + 1) >> 1;
|
|
pjBuf = ajBuf;
|
|
IO_TRANSFER_WORD_ALIGNED(ppdev, pjBuf, cwThis);
|
|
|
|
} while (cxToGo > 0);
|
|
|
|
pjScan += lSrcDelta; // Advance to next source scan. Note
|
|
// that we could have computed the
|
|
// value to advance 'pjSrc' directly,
|
|
// but this method is less
|
|
// error-prone.
|
|
|
|
} while (--cy != 0);
|
|
|
|
CHECK_DATA_COMPLETE(ppdev);
|
|
|
|
if (--c == 0)
|
|
return;
|
|
|
|
prcl++;
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoXferNative
|
|
*
|
|
* Transfers a bitmap that is the same colour depth as the display to
|
|
* the screen via the data transfer register, with no translation.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoXferNative( // Type FNXFER
|
|
PDEV* ppdev,
|
|
LONG c, // Count of rectangles, can't be zero
|
|
RECTL* prcl, // Array of relative coordinates destination rectangles
|
|
ULONG rop4, // rop4
|
|
SURFOBJ* psoSrc, // Source surface
|
|
POINTL* pptlSrc, // Original unclipped source point
|
|
RECTL* prclDst, // Original unclipped destination rectangle
|
|
XLATEOBJ* pxlo) // Not used
|
|
{
|
|
LONG dx;
|
|
LONG dy;
|
|
LONG cx;
|
|
LONG cy;
|
|
LONG lSrcDelta;
|
|
BYTE* pjSrcScan0;
|
|
BYTE* pjSrc;
|
|
LONG cjSrc;
|
|
|
|
ASSERTDD((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL),
|
|
"Can handle trivial xlate only");
|
|
ASSERTDD(psoSrc->iBitmapFormat == ppdev->iBitmapFormat,
|
|
"Source must be same colour depth as screen");
|
|
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
|
ASSERTDD(((rop4 & 0xff00) >> 8) == (rop4 & 0xff),
|
|
"Expect only a rop2");
|
|
|
|
dx = pptlSrc->x - prclDst->left;
|
|
dy = pptlSrc->y - prclDst->top; // Add to destination to get source
|
|
|
|
lSrcDelta = psoSrc->lDelta;
|
|
pjSrcScan0 = psoSrc->pvScan0;
|
|
|
|
IO_FIFO_WAIT(ppdev, 6);
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
IO_FRGD_MIX(ppdev, SRC_CPU_DATA | gaulHwMixFromRop2[rop4 & 0xf]);
|
|
|
|
while(TRUE)
|
|
{
|
|
IO_CUR_X(ppdev, prcl->left);
|
|
IO_CUR_Y(ppdev, prcl->top);
|
|
|
|
cx = prcl->right - prcl->left;
|
|
IO_MAJ_AXIS_PCNT(ppdev, cx - 1);
|
|
|
|
cy = prcl->bottom - prcl->top;
|
|
IO_MIN_AXIS_PCNT(ppdev, cy - 1);
|
|
|
|
cjSrc = CONVERT_TO_BYTES(cx, ppdev);
|
|
pjSrc = pjSrcScan0 + (prcl->top + dy) * lSrcDelta
|
|
+ CONVERT_TO_BYTES((prcl->left + dx), ppdev);
|
|
|
|
ppdev->pfnImageTransfer(ppdev, pjSrc, lSrcDelta, cjSrc, cy,
|
|
(RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
|
|
DRAW | LAST_PIXEL_ON | SINGLE_PIXEL |
|
|
WRITE | BYTE_SWAP));
|
|
|
|
if (--c == 0)
|
|
return;
|
|
|
|
prcl++;
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoCopyBlt
|
|
*
|
|
* Does a screen-to-screen blt of a list of rectangles.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoCopyBlt( // Type FNCOPY
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // Array of relative coordinates destination rectangles
|
|
ULONG rop4, // rop4
|
|
POINTL* pptlSrc, // Original unclipped source point
|
|
RECTL* prclDst) // Original unclipped destination rectangle
|
|
{
|
|
LONG dx;
|
|
LONG dy; // Add delta to destination to get source
|
|
LONG cx;
|
|
LONG cy; // Size of current rectangle - 1
|
|
|
|
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
|
ASSERTDD(((rop4 & 0xff00) >> 8) == (rop4 & 0xff),
|
|
"Expect only a rop2");
|
|
|
|
IO_FIFO_WAIT(ppdev, 2);
|
|
IO_FRGD_MIX(ppdev, SRC_DISPLAY_MEMORY | gaulHwMixFromRop2[rop4 & 0xf]);
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
|
|
dx = pptlSrc->x - prclDst->left;
|
|
dy = pptlSrc->y - prclDst->top;
|
|
|
|
// The accelerator may not be as fast at doing right-to-left copies, so
|
|
// only do them when the rectangles truly overlap:
|
|
|
|
if (!OVERLAP(prclDst, pptlSrc))
|
|
goto Top_Down_Left_To_Right;
|
|
|
|
if (prclDst->top <= pptlSrc->y)
|
|
{
|
|
if (prclDst->left <= pptlSrc->x)
|
|
{
|
|
|
|
Top_Down_Left_To_Right:
|
|
|
|
do {
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
|
|
cx = prcl->right - prcl->left - 1;
|
|
IO_MAJ_AXIS_PCNT(ppdev, cx);
|
|
IO_DEST_X(ppdev, prcl->left);
|
|
IO_CUR_X(ppdev, prcl->left + dx);
|
|
|
|
cy = prcl->bottom - prcl->top - 1;
|
|
IO_MIN_AXIS_PCNT(ppdev, cy);
|
|
IO_DEST_Y(ppdev, prcl->top);
|
|
IO_CUR_Y(ppdev, prcl->top + dy);
|
|
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
DRAWING_DIR_TBLRXM);
|
|
prcl++;
|
|
|
|
} while (--c != 0);
|
|
}
|
|
else
|
|
{
|
|
do {
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
|
|
cx = prcl->right - prcl->left - 1;
|
|
IO_MAJ_AXIS_PCNT(ppdev, cx);
|
|
IO_DEST_X(ppdev, prcl->left + cx);
|
|
IO_CUR_X(ppdev, prcl->left + cx + dx);
|
|
|
|
cy = prcl->bottom - prcl->top - 1;
|
|
IO_MIN_AXIS_PCNT(ppdev, cy);
|
|
IO_DEST_Y(ppdev, prcl->top);
|
|
IO_CUR_Y(ppdev, prcl->top + dy);
|
|
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
DRAWING_DIR_TBRLXM);
|
|
prcl++;
|
|
|
|
} while (--c != 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (prclDst->left <= pptlSrc->x)
|
|
{
|
|
do {
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
|
|
cx = prcl->right - prcl->left - 1;
|
|
IO_MAJ_AXIS_PCNT(ppdev, cx);
|
|
IO_DEST_X(ppdev, prcl->left);
|
|
IO_CUR_X(ppdev, prcl->left + dx);
|
|
|
|
cy = prcl->bottom - prcl->top - 1;
|
|
IO_MIN_AXIS_PCNT(ppdev, cy);
|
|
IO_DEST_Y(ppdev, prcl->top + cy);
|
|
IO_CUR_Y(ppdev, prcl->top + cy + dy);
|
|
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
DRAWING_DIR_BTLRXM);
|
|
prcl++;
|
|
|
|
} while (--c != 0);
|
|
}
|
|
else
|
|
{
|
|
do {
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
|
|
cx = prcl->right - prcl->left - 1;
|
|
IO_MAJ_AXIS_PCNT(ppdev, cx);
|
|
IO_DEST_X(ppdev, prcl->left + cx);
|
|
IO_CUR_X(ppdev, prcl->left + cx + dx);
|
|
|
|
cy = prcl->bottom - prcl->top - 1;
|
|
IO_MIN_AXIS_PCNT(ppdev, cy);
|
|
IO_DEST_Y(ppdev, prcl->top + cy);
|
|
IO_CUR_Y(ppdev, prcl->top + cy + dy);
|
|
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY | WRITE |
|
|
DRAWING_DIR_BTRLXM);
|
|
prcl++;
|
|
|
|
} while (--c != 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vIoCopyTransparent
|
|
*
|
|
* Does a screen-to-screen blt of a list of rectangles using a source
|
|
* colorkey for transparency.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vIoCopyTransparent( // Type FNCOPYTRANSPARENT
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // Array of relative coordinates destination rectangles
|
|
POINTL* pptlSrc, // Original unclipped source point
|
|
RECTL* prclDst, // Original unclipped destination rectangle
|
|
ULONG iColor)
|
|
{
|
|
LONG dx;
|
|
LONG dy; // Add delta to destination to get source
|
|
|
|
ASSERTDD(c > 0, "Can't handle zero rectangles");
|
|
|
|
dx = pptlSrc->x - prclDst->left;
|
|
dy = pptlSrc->y - prclDst->top;
|
|
|
|
if (DEPTH32(ppdev))
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 5);
|
|
IO_COLOR_CMP32(ppdev, iColor);
|
|
}
|
|
else
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 4);
|
|
IO_COLOR_CMP(ppdev, iColor);
|
|
}
|
|
|
|
IO_MULTIFUNC_CNTL(ppdev, ppdev->ulMiscState
|
|
| MULT_MISC_COLOR_COMPARE);
|
|
IO_FRGD_MIX(ppdev, SRC_DISPLAY_MEMORY | OVERPAINT);
|
|
IO_PIX_CNTL(ppdev, ALL_ONES);
|
|
|
|
while (TRUE)
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 7);
|
|
IO_CUR_X(ppdev, prcl->left + dx);
|
|
IO_CUR_Y(ppdev, prcl->top + dy);
|
|
IO_DEST_X(ppdev, prcl->left);
|
|
IO_DEST_Y(ppdev, prcl->top);
|
|
IO_MAJ_AXIS_PCNT(ppdev, prcl->right - prcl->left - 1);
|
|
IO_MIN_AXIS_PCNT(ppdev, prcl->bottom - prcl->top - 1);
|
|
IO_CMD(ppdev, BITBLT | DRAW | DIR_TYPE_XY |
|
|
WRITE | DRAWING_DIR_TBLRXM);
|
|
|
|
if (--c == 0)
|
|
{
|
|
IO_FIFO_WAIT(ppdev, 1);
|
|
IO_MULTIFUNC_CNTL(ppdev, ppdev->ulMiscState);
|
|
return;
|
|
}
|
|
|
|
prcl++;
|
|
}
|
|
}
|