mirror of https://github.com/tongzx/nt5src
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.
801 lines
28 KiB
801 lines
28 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: bltmm.c
|
|
*
|
|
* Contains the low-level memory-mapped blt functions. This module mirrors
|
|
* 'bltio.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-1995 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMmFillSolid
|
|
*
|
|
* Fills a list of rectangles with a solid colour.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMmFillSolid( // Type FNFILL
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // List of rectangles to be filled, in relative
|
|
// coordinates
|
|
ULONG rop4, // Mix
|
|
RBRUSH_COLOR rbc, // Drawing colour is rbc.iSolidColor
|
|
POINTL* pptlBrush) // Not used
|
|
{
|
|
BYTE* pjMmBase;
|
|
|
|
ASSERTDD((rop4 >> 8) == (rop4 & 0xff), "Illegal mix");
|
|
|
|
pjMmBase = ppdev->pjMmBase;
|
|
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
|
|
MM_PREG_COLOR_8(ppdev, pjMmBase, rbc.iSolidColor);
|
|
MM_BLT_CMD_1(ppdev, pjMmBase, XY_SRC_ADDR |
|
|
XY_DEST_ADDR);
|
|
if (rop4 == 0xf0f0)
|
|
{
|
|
// Note block write:
|
|
|
|
MM_CTRL_REG_1(ppdev, pjMmBase, PACKED_PIXEL_VIEW |
|
|
BLOCK_WRITE |
|
|
BITS_PER_PIX_8 |
|
|
ENAB_TRITON_MODE);
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_PATTERN_REGS);
|
|
}
|
|
else
|
|
{
|
|
MM_CTRL_REG_1(ppdev, pjMmBase, PACKED_PIXEL_VIEW |
|
|
BITS_PER_PIX_8 |
|
|
ENAB_TRITON_MODE);
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_ALL |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_PATTERN_REGS);
|
|
MM_ROP_A(ppdev, pjMmBase, rop4 >> 2);
|
|
}
|
|
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, prcl->bottom - prcl->top);
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, prcl->right - prcl->left);
|
|
MM_DEST_XY(ppdev, pjMmBase, prcl->left, prcl->top);
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
|
|
while (prcl++, --c)
|
|
{
|
|
MM_WAIT_BUFFER_NOT_BUSY(ppdev, pjMmBase);
|
|
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, prcl->bottom - prcl->top);
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, prcl->right - prcl->left);
|
|
MM_DEST_XY(ppdev, pjMmBase, prcl->left, prcl->top);
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMmFillPat2Color
|
|
*
|
|
* This routine uses the QVision pattern hardware to draw a patterned list of
|
|
* rectangles.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMmFillPat2Color( // Type FNFILL
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // List of rectangles to be filled, in relative
|
|
// coordinates
|
|
ULONG rop4, // Mix
|
|
RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
|
|
POINTL* pptlBrush) // Pattern alignment
|
|
{
|
|
BYTE* pjMmBase;
|
|
LONG xAlign;
|
|
LONG yAlign;
|
|
|
|
ASSERTDD(((rop4 >> 8) == (rop4 & 0xff)) || ((rop4 & 0xff00) == 0xaa00),
|
|
"Illegal mix");
|
|
|
|
pjMmBase = ppdev->pjMmBase;
|
|
xAlign = pptlBrush->x;
|
|
yAlign = pptlBrush->y;
|
|
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
|
|
MM_FG_COLOR(ppdev, pjMmBase, rbc.prb->ulForeColor);
|
|
MM_BG_COLOR(ppdev, pjMmBase, rbc.prb->ulBackColor);
|
|
MM_PREG_PATTERN(ppdev, pjMmBase, rbc.prb->aulPattern);
|
|
|
|
MM_CTRL_REG_1(ppdev, pjMmBase, EXPAND_TO_FG |
|
|
BITS_PER_PIX_8 |
|
|
ENAB_TRITON_MODE);
|
|
MM_BLT_CMD_1(ppdev, pjMmBase, XY_SRC_ADDR |
|
|
XY_DEST_ADDR);
|
|
|
|
if (rop4 == 0xf0f0)
|
|
{
|
|
// Opaque brush with PATCOPY rop:
|
|
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_PATTERN_REGS);
|
|
}
|
|
else if (((rop4 >> 8) & 0xff) == (rop4 & 0xff))
|
|
{
|
|
// Opaque brush with rop other than PATCOPY:
|
|
|
|
MM_ROP_A(ppdev, pjMmBase, rop4 >> 2);
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_ALL |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_PATTERN_REGS);
|
|
}
|
|
else if ((rop4 & 0xff) == 0xcc)
|
|
{
|
|
// Transparent brush with PATCOPY rop:
|
|
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
|
|
PIXELMASK_AND_SRC_DATA |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_PATTERN_REGS);
|
|
}
|
|
else
|
|
{
|
|
// Transparent brush with rop other than PATCOPY:
|
|
|
|
MM_ROP_A(ppdev, pjMmBase, rop4 >> 2);
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_ALL |
|
|
PIXELMASK_AND_SRC_DATA |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_PATTERN_REGS);
|
|
}
|
|
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, prcl->bottom - prcl->top);
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, prcl->right - prcl->left);
|
|
MM_DEST_XY(ppdev, pjMmBase, prcl->left, prcl->top);
|
|
MM_SRC_ALIGN(ppdev, pjMmBase, ((prcl->left - xAlign) & 7) |
|
|
((prcl->top - yAlign) << 3));
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
|
|
while (prcl++, --c)
|
|
{
|
|
MM_WAIT_BUFFER_NOT_BUSY(ppdev, pjMmBase);
|
|
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, prcl->bottom - prcl->top);
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, prcl->right - prcl->left);
|
|
MM_DEST_XY(ppdev, pjMmBase, prcl->left, prcl->top);
|
|
MM_SRC_ALIGN(ppdev, pjMmBase, ((prcl->left - xAlign) & 7) |
|
|
((prcl->top - yAlign) << 3));
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMmFillPatArbitraryRop
|
|
*
|
|
* This routine uses the QVision pattern hardware to draw a patterned list of
|
|
* rectangles.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMmFillPatArbitraryRop( // Type FNFILL
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // List of rectangles to be filled, in relative
|
|
// coordinates
|
|
ULONG rop4, // Mix
|
|
RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
|
|
POINTL* pptlBrush) // Pattern alignment
|
|
{
|
|
BYTE* pjMmBase;
|
|
LONG xAlign;
|
|
LONG yAlign;
|
|
LONG lLinearDelta;
|
|
BYTE* pjPatternStart;
|
|
LONG xLeft;
|
|
LONG yTop;
|
|
LONG yBottom;
|
|
LONG lLinearDest;
|
|
LONG cy;
|
|
LONG iPattern;
|
|
LONG cyHeightOfEachBlt;
|
|
LONG cBltsBeforeHeightChange;
|
|
LONG cBlts;
|
|
|
|
ASSERTDD((rop4 >> 8) == (rop4 & 0xff), "Illegal mix");
|
|
|
|
pjMmBase = ppdev->pjMmBase;
|
|
xAlign = pptlBrush->x;
|
|
yAlign = pptlBrush->y;
|
|
lLinearDelta = ppdev->lDelta << 3;
|
|
pjPatternStart = (BYTE*) rbc.prb->aulPattern;
|
|
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
MM_DEST_PITCH(ppdev, pjMmBase, (ppdev->lDelta << rbc.prb->cyLog2) >> 2);
|
|
MM_CTRL_REG_1(ppdev, pjMmBase, PACKED_PIXEL_VIEW |
|
|
BITS_PER_PIX_8 |
|
|
ENAB_TRITON_MODE);
|
|
MM_BLT_CMD_1(ppdev, pjMmBase, XY_SRC_ADDR |
|
|
LIN_DEST_ADDR);
|
|
|
|
if (rop4 == 0xf0f0)
|
|
{
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_PATTERN_REGS);
|
|
}
|
|
else
|
|
{
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_ALL |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_PATTERN_REGS);
|
|
MM_ROP_A(ppdev, pjMmBase, rop4 >> 2);
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
xLeft = prcl->left;
|
|
yTop = prcl->top;
|
|
lLinearDest = ((yTop + ppdev->yOffset) * lLinearDelta)
|
|
+ ((xLeft + ppdev->xOffset) << 3);
|
|
|
|
// Note that any registers we set now before the
|
|
// WAIT_FOR_IDLE must be buffered, as this loop may be
|
|
// executed multiple times when doing more than one
|
|
// rectangle:
|
|
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, prcl->right - xLeft);
|
|
MM_DEST_X(ppdev, pjMmBase, xLeft);
|
|
MM_SRC_ALIGN(ppdev, pjMmBase, xLeft - xAlign);
|
|
|
|
yBottom = prcl->bottom;
|
|
cy = yBottom - yTop;
|
|
iPattern = 8 * (yTop - yAlign);
|
|
|
|
cyHeightOfEachBlt = (cy >> rbc.prb->cyLog2) + 1;
|
|
cBlts = min(cy, rbc.prb->cy);
|
|
cBltsBeforeHeightChange = (cy & (rbc.prb->cy - 1)) + 1;
|
|
|
|
if (cBltsBeforeHeightChange != 1)
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, cyHeightOfEachBlt);
|
|
|
|
do {
|
|
// Need to wait for idle because we're about to modify the
|
|
// pattern registers, which aren't buffered:
|
|
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
|
|
MM_PREG_PATTERN(ppdev, pjMmBase, pjPatternStart + (iPattern & 63));
|
|
iPattern += 8;
|
|
|
|
MM_DEST_LIN(ppdev, pjMmBase, lLinearDest);
|
|
lLinearDest += lLinearDelta;
|
|
|
|
cBltsBeforeHeightChange--;
|
|
if (cBltsBeforeHeightChange == 0)
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, cyHeightOfEachBlt - 1);
|
|
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
|
|
} while (--cBlts != 0);
|
|
|
|
if (--c == 0)
|
|
break;
|
|
|
|
prcl++;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMmFillPat
|
|
*
|
|
* This routine uses the QVision pattern hardware to draw a patterned list of
|
|
* rectangles.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMmFillPat( // Type FNFILL
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // List of rectangles to be filled, in relative
|
|
// coordinates
|
|
ULONG rop4, // Mix
|
|
RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
|
|
POINTL* pptlBrush) // Pattern alignment
|
|
{
|
|
BYTE* pjMmBase;
|
|
LONG xAlign;
|
|
LONG yAlign;
|
|
LONG iMax;
|
|
LONG lLinearDelta;
|
|
BYTE* pjPatternStart;
|
|
LONG xLeft;
|
|
LONG yTop;
|
|
LONG yBottom;
|
|
LONG lLinearDest;
|
|
LONG cy;
|
|
LONG iPattern;
|
|
LONG cyHeightOfEachBlt;
|
|
LONG cBltsBeforeHeightChange;
|
|
LONG cBlts;
|
|
BYTE* pjSrc;
|
|
BYTE* pjDst;
|
|
LONG i;
|
|
LONG j;
|
|
ULONG* pulPattern;
|
|
BOOL bWriteMaskSet;
|
|
|
|
if (!(rbc.prb->fl & RBRUSH_2COLOR))
|
|
{
|
|
if (rop4 == 0xf0f0)
|
|
{
|
|
pjMmBase = ppdev->pjMmBase;
|
|
xAlign = ((pptlBrush->x + ppdev->xOffset) & 7);
|
|
iMax = (8 << rbc.prb->cyLog2) - 1;
|
|
|
|
// The pattern must be pre-aligned to use the QVision's
|
|
// block-write capability for patterns. We keep a cached
|
|
// aligned copy in the brush itself:
|
|
|
|
if (xAlign != rbc.prb->xBlockAlign)
|
|
{
|
|
rbc.prb->xBlockAlign = xAlign;
|
|
|
|
pjSrc = (BYTE*) rbc.prb->aulPattern;
|
|
pjDst = (BYTE*) rbc.prb->aulBlockPattern;
|
|
|
|
i = rbc.prb->cy;
|
|
do {
|
|
for (j = 0; j != 8; j++)
|
|
pjDst[(xAlign + j) & 7] = *pjSrc++;
|
|
|
|
pjDst += 8;
|
|
} while (--i != 0);
|
|
}
|
|
|
|
bWriteMaskSet = FALSE;
|
|
pjPatternStart = (BYTE*) rbc.prb->aulBlockPattern;
|
|
yAlign = pptlBrush->y;
|
|
lLinearDelta = ppdev->lDelta << 3;
|
|
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
MM_DEST_PITCH(ppdev, pjMmBase, (ppdev->lDelta << rbc.prb->cyLog2) >> 2);
|
|
MM_CTRL_REG_1(ppdev, pjMmBase, PACKED_PIXEL_VIEW |
|
|
BLOCK_WRITE |
|
|
BITS_PER_PIX_8 |
|
|
ENAB_TRITON_MODE);
|
|
MM_BLT_CMD_1(ppdev, pjMmBase, XY_SRC_ADDR |
|
|
LIN_DEST_ADDR);
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_PATTERN_REGS);
|
|
|
|
while (TRUE)
|
|
{
|
|
xLeft = prcl->left;
|
|
yTop = prcl->top;
|
|
lLinearDest = ((yTop + ppdev->yOffset) * lLinearDelta)
|
|
+ ((xLeft + ppdev->xOffset) << 3);
|
|
|
|
// Note that any registers we set now before the
|
|
// WAIT_FOR_IDLE must be buffered, as this loop may be
|
|
// executed multiple times when doing more than one
|
|
// rectangle:
|
|
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, prcl->right - xLeft);
|
|
MM_DEST_X(ppdev, pjMmBase, xLeft);
|
|
|
|
yBottom = prcl->bottom;
|
|
cy = yBottom - yTop;
|
|
iPattern = 8 * (yTop - yAlign);
|
|
|
|
cyHeightOfEachBlt = (cy >> rbc.prb->cyLog2) + 1;
|
|
cBlts = min(cy, rbc.prb->cy);
|
|
cBltsBeforeHeightChange = (cy & (rbc.prb->cy - 1)) + 1;
|
|
|
|
if (cBltsBeforeHeightChange != 1)
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, cyHeightOfEachBlt);
|
|
|
|
do {
|
|
// Need to wait for idle because we're about to modify the
|
|
// pattern registers, which aren't buffered:
|
|
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
|
|
MM_DEST_LIN(ppdev, pjMmBase, lLinearDest);
|
|
lLinearDest += lLinearDelta;
|
|
|
|
cBltsBeforeHeightChange--;
|
|
if (cBltsBeforeHeightChange == 0)
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, cyHeightOfEachBlt - 1);
|
|
|
|
pulPattern = (ULONG*) (pjPatternStart + (iPattern & iMax));
|
|
iPattern += 8;
|
|
|
|
if (*(pulPattern) == *(pulPattern + 1))
|
|
{
|
|
// The pattern on this scan is 4 pixels wide, so we can
|
|
// do it in one pass:
|
|
|
|
MM_PREG_BLOCK(ppdev, pjMmBase, (pulPattern));
|
|
if (bWriteMaskSet)
|
|
{
|
|
bWriteMaskSet = FALSE;
|
|
MM_PIXEL_WRITE_MASK(ppdev, pjMmBase, 0xff);
|
|
}
|
|
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
}
|
|
else
|
|
{
|
|
// The pattern on this scan is 8 pixels wide, so we
|
|
// have to do it in two passes, using the pixel mask
|
|
// register:
|
|
|
|
bWriteMaskSet = TRUE;
|
|
MM_PREG_BLOCK(ppdev, pjMmBase, (pulPattern));
|
|
MM_PIXEL_WRITE_MASK(ppdev, pjMmBase, 0xf0);
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
MM_PREG_BLOCK(ppdev, pjMmBase, (pulPattern + 1));
|
|
MM_PIXEL_WRITE_MASK(ppdev, pjMmBase, 0x0f);
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
}
|
|
} while (--cBlts != 0);
|
|
|
|
if (--c == 0)
|
|
break;
|
|
|
|
prcl++;
|
|
}
|
|
|
|
// Don't forget to reset the write mask when we're done:
|
|
|
|
if (bWriteMaskSet)
|
|
{
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
MM_PIXEL_WRITE_MASK(ppdev, pjMmBase, 0xff);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vMmFillPatArbitraryRop(ppdev, c, prcl, rop4, rbc, pptlBrush);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vMmFillPat2Color(ppdev, c, prcl, rop4, rbc, pptlBrush);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMmXfer1bpp
|
|
*
|
|
* This routine colours 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 vMmXfer1bpp( // Type FNXFER
|
|
PDEV* ppdev,
|
|
LONG c, // Count of rectangles, can't be zero
|
|
RECTL* prcl, // List of destination rectangles, in relative
|
|
// coordinates
|
|
ULONG rop4, // 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* pjMmBase;
|
|
LONG dxSrc;
|
|
LONG dySrc; // Add delta to destination to get source
|
|
LONG lSrcDelta;
|
|
BYTE* pjSrcScan0;
|
|
BYTE* pjDstStart;
|
|
LONG yTop;
|
|
LONG xLeft;
|
|
LONG xRight;
|
|
LONG cx;
|
|
LONG cy; // Dimensions of blt rectangle
|
|
LONG xBias;
|
|
LONG cjSrc;
|
|
LONG cdSrc;
|
|
LONG lSrcSkip;
|
|
BYTE* pjSrc;
|
|
BYTE* pjDst;
|
|
LONG i;
|
|
LONG j;
|
|
|
|
ASSERTDD((rop4 >> 8) == (rop4 & 0xff), "Illegal mix");
|
|
|
|
pjMmBase = ppdev->pjMmBase;
|
|
|
|
dxSrc = pptlSrc->x - prclDst->left;
|
|
dySrc = pptlSrc->y - prclDst->top;
|
|
|
|
lSrcDelta = psoSrc->lDelta;
|
|
pjSrcScan0 = psoSrc->pvScan0;
|
|
pjDstStart = ppdev->pjScreen;
|
|
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
MM_CTRL_REG_1(ppdev, pjMmBase, EXPAND_TO_FG |
|
|
BITS_PER_PIX_8 |
|
|
ENAB_TRITON_MODE);
|
|
MM_BLT_CMD_1(ppdev, pjMmBase, XY_SRC_ADDR |
|
|
XY_DEST_ADDR);
|
|
MM_FG_COLOR(ppdev, pjMmBase, pxlo->pulXlate[1]);
|
|
MM_BG_COLOR(ppdev, pjMmBase, pxlo->pulXlate[0]);
|
|
|
|
if (rop4 == 0xcccc)
|
|
{
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_CPU_DATA);
|
|
}
|
|
else
|
|
{
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_ALL |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_CPU_DATA);
|
|
MM_ROP_A(ppdev, pjMmBase, rop4);
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
yTop = prcl->top;
|
|
xLeft = prcl->left;
|
|
xRight = prcl->right;
|
|
|
|
cy = prcl->bottom - yTop;
|
|
cx = xRight - xLeft;
|
|
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, cx);
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, cy);
|
|
MM_DEST_XY(ppdev, pjMmBase, xLeft, yTop);
|
|
|
|
xBias = (xLeft + dxSrc) & 7;
|
|
MM_SRC_ALIGN(ppdev, pjMmBase, xBias);
|
|
xLeft -= xBias;
|
|
|
|
cjSrc = (xRight - xLeft + 7) >> 3;
|
|
cdSrc = cjSrc >> 2;
|
|
lSrcSkip = lSrcDelta - (cdSrc << 2);
|
|
|
|
pjSrc = pjSrcScan0 + (yTop + dySrc) * lSrcDelta
|
|
+ ((xLeft + dxSrc) >> 3);
|
|
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
|
|
switch(cjSrc & 3)
|
|
{
|
|
case 0:
|
|
for (i = cy; i != 0; i--)
|
|
{
|
|
MEMORY_BARRIER();
|
|
pjDst = pjDstStart;
|
|
for (j = cdSrc; j != 0; j--)
|
|
{
|
|
WRITE_REGISTER_ULONG(pjDst, *((ULONG UNALIGNED *) pjSrc));
|
|
pjDst += sizeof(ULONG);
|
|
pjSrc += sizeof(ULONG);
|
|
}
|
|
pjSrc += lSrcSkip;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
for (i = cy; i != 0; i--)
|
|
{
|
|
MEMORY_BARRIER();
|
|
pjDst = pjDstStart;
|
|
for (j = cdSrc; j != 0; j--)
|
|
{
|
|
WRITE_REGISTER_ULONG(pjDst, *((ULONG UNALIGNED *) pjSrc));
|
|
pjDst += sizeof(ULONG);
|
|
pjSrc += sizeof(ULONG);
|
|
}
|
|
WRITE_REGISTER_UCHAR(pjDst, *pjSrc);
|
|
pjSrc += lSrcSkip;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
for (i = cy; i != 0; i--)
|
|
{
|
|
MEMORY_BARRIER();
|
|
pjDst = pjDstStart;
|
|
for (j = cdSrc; j != 0; j--)
|
|
{
|
|
WRITE_REGISTER_ULONG(pjDst, *((ULONG UNALIGNED *) pjSrc));
|
|
pjDst += sizeof(ULONG);
|
|
pjSrc += sizeof(ULONG);
|
|
}
|
|
WRITE_REGISTER_USHORT(pjDst, *((USHORT UNALIGNED *) pjSrc));
|
|
pjSrc += lSrcSkip;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
for (i = cy; i != 0; i--)
|
|
{
|
|
MEMORY_BARRIER();
|
|
pjDst = pjDstStart;
|
|
for (j = cdSrc; j != 0; j--)
|
|
{
|
|
WRITE_REGISTER_ULONG(pjDst, *((ULONG UNALIGNED *) pjSrc));
|
|
pjDst += sizeof(ULONG);
|
|
pjSrc += sizeof(ULONG);
|
|
}
|
|
WRITE_REGISTER_USHORT(pjDst, *((USHORT UNALIGNED *) pjSrc));
|
|
WRITE_REGISTER_UCHAR((pjDst + 2), *(pjSrc + 2));
|
|
pjSrc += lSrcSkip;
|
|
}
|
|
break;
|
|
}
|
|
|
|
MM_WAIT_TRANSFER_DONE(ppdev, pjMmBase);
|
|
|
|
if (--c == 0)
|
|
break;
|
|
|
|
prcl++;
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMmCopyBlt
|
|
*
|
|
* Does a screen-to-screen blt of a list of rectangles.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMmCopyBlt( // Type FNCOPY
|
|
PDEV* ppdev,
|
|
LONG c, // Can't be zero
|
|
RECTL* prcl, // Array of relative coordinates destination rectangles
|
|
ULONG rop4, // Hardware mix
|
|
POINTL* pptlSrc, // Original unclipped source point
|
|
RECTL* prclDst) // Original unclipped destination rectangle
|
|
{
|
|
BYTE* pjMmBase;
|
|
LONG dxSrc;
|
|
LONG dySrc; // Add delta to destination to get source
|
|
LONG cx;
|
|
LONG cy; // Dimensions of blt rectangle
|
|
LONG xDst;
|
|
LONG yDst; // Start point of destination
|
|
|
|
ASSERTDD((rop4 >> 8) == (rop4 & 0xff), "Illegal mix");
|
|
|
|
pjMmBase = ppdev->pjMmBase;
|
|
|
|
dxSrc = pptlSrc->x - prclDst->left;
|
|
dySrc = pptlSrc->y - prclDst->top;
|
|
|
|
MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
|
|
MM_CTRL_REG_1(ppdev, pjMmBase, PACKED_PIXEL_VIEW | // !!! Need this each time?
|
|
BITS_PER_PIX_8 |
|
|
ENAB_TRITON_MODE);
|
|
MM_BLT_CMD_1(ppdev, pjMmBase, XY_SRC_ADDR |
|
|
XY_DEST_ADDR);
|
|
if (rop4 == 0xcccc)
|
|
{
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_SCRN_LATCHES);
|
|
}
|
|
else
|
|
{
|
|
MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_ALL |
|
|
PIXELMASK_ONLY |
|
|
PLANARMASK_NONE_0XFF |
|
|
SRC_IS_SCRN_LATCHES);
|
|
MM_ROP_A(ppdev, pjMmBase, rop4);
|
|
}
|
|
|
|
if ((prclDst->top < pptlSrc->y) ||
|
|
(prclDst->top == pptlSrc->y) && (prclDst->left <= pptlSrc->x))
|
|
{
|
|
// Forward blt:
|
|
|
|
cx = prcl->right - prcl->left;
|
|
cy = prcl->bottom - prcl->top;
|
|
xDst = prcl->left;
|
|
yDst = prcl->top;
|
|
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, cx);
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, cy);
|
|
MM_DEST_XY(ppdev, pjMmBase, xDst, yDst);
|
|
MM_SRC_XY(ppdev, pjMmBase, xDst + dxSrc, yDst + dySrc);
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
|
|
while (prcl++, --c)
|
|
{
|
|
cx = prcl->right - prcl->left;
|
|
cy = prcl->bottom - prcl->top;
|
|
xDst = prcl->left;
|
|
yDst = prcl->top;
|
|
|
|
MM_WAIT_BUFFER_NOT_BUSY(ppdev, pjMmBase);
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, cx);
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, cy);
|
|
MM_DEST_XY(ppdev, pjMmBase, xDst, yDst);
|
|
MM_SRC_XY(ppdev, pjMmBase, xDst + dxSrc, yDst + dySrc);
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Backward blt:
|
|
|
|
cx = prcl->right - prcl->left;
|
|
cy = prcl->bottom - prcl->top;
|
|
xDst = prcl->left + cx - 1;
|
|
yDst = prcl->top + cy - 1;
|
|
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, cx);
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, cy);
|
|
MM_DEST_XY(ppdev, pjMmBase, xDst, yDst);
|
|
MM_SRC_XY(ppdev, pjMmBase, xDst + dxSrc, yDst + dySrc);
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT | BACKWARD);
|
|
|
|
while (prcl++, --c)
|
|
{
|
|
cx = prcl->right - prcl->left;
|
|
cy = prcl->bottom - prcl->top;
|
|
xDst = prcl->left + cx - 1;
|
|
yDst = prcl->top + cy - 1;
|
|
|
|
MM_WAIT_BUFFER_NOT_BUSY(ppdev, pjMmBase);
|
|
MM_BITMAP_WIDTH(ppdev, pjMmBase, cx);
|
|
MM_BITMAP_HEIGHT(ppdev, pjMmBase, cy);
|
|
MM_DEST_XY(ppdev, pjMmBase, xDst, yDst);
|
|
MM_SRC_XY(ppdev, pjMmBase, xDst + dxSrc, yDst + dySrc);
|
|
MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT | BACKWARD);
|
|
}
|
|
}
|
|
}
|