|
|
/******************************************************************************\
* * $Workfile: bltmm.c $ * * Contains the low-level MM 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 * Copyright (c) 1996 Cirrus Logic, Inc. * * $Log: S:/projects/drivers/ntsrc/display/bltmm.c_v $ * * Rev 1.4 Jan 14 1997 15:16:14 unknown * take out GR33 clearing after 80 blt. * * Rev 1.2 Nov 07 1996 16:47:52 unknown * * * Rev 1.1 Oct 10 1996 15:36:14 unknown * * * Rev 1.4 12 Aug 1996 16:58:56 frido * Removed unaccessed local variables. * Renamed vMmPatternBlt into vMmFillPat36. * * Rev 1.3 08 Aug 1996 16:55:10 frido * Added new vMmCopyBlt36 routine. * * Rev 1.2 08 Aug 1996 12:59:28 frido * bank#1 - Removed banking code since MMIO is always linear. * * Rev 1.1 31 Jul 1996 15:43:14 frido * Added new pattern blit. * * jl01 10-08-96 Do Transparent BLT w/o Solid Fill. Refer to PDRs#5511/6817. * chu01 01-09-97 Make sure to reset GR33. * \******************************************************************************/
#include "precomp.h"
/**************************************************************************
* VOID vMmFastPatRealize * * Realizes a pattern into offscreen memory. * **************************************************************************/
VOID vMmFastPatRealize( PDEV* ppdev, RBRUSH* prb) // Points to brush realization structure
{ BRUSHENTRY* pbe; LONG iBrushCache; BYTE* pjPattern; LONG cjPattern; BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; LONG lDeltaPat; LONG lDeltaSrc; LONG xCnt; LONG yCnt; ULONG ulDst;
DISPDBG((10,"vFastPatRealize called"));
pbe = prb->pbe;
if ((pbe == NULL) || (pbe->prbVerify != prb)) { // We have to allocate a new offscreen 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; }
//
// Download brush into cache
//
pjPattern = (PBYTE) &prb->aulPattern[0]; // Copy from brush buffer
cjPattern = PELS_TO_BYTES(TOTAL_BRUSH_SIZE);
lDeltaPat = PELS_TO_BYTES(8); xCnt = PELS_TO_BYTES(8); yCnt = 8;
if (ppdev->cBitsPerPixel == 24) { lDeltaSrc = 32; // same as PELS_TO_BYTES(8) for 32bpp
} else { lDeltaSrc = lDeltaPat; // PELS_TO_BYTES(8)
}
ulDst = (pbe->y * ppdev->lDelta) + PELS_TO_BYTES(pbe->x);
#if BANKING //bank#1
ppdev->pfnBankMap(ppdev, ppdev->lXferBank); #endif
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_DST_Y_OFFSET(ppdev, pjBase, (lDeltaSrc * 2)); CP_MM_XCNT(ppdev, pjBase, (xCnt - 1)); CP_MM_YCNT(ppdev, pjBase, (yCnt - 1)); #if 1 // D5480
CP_MM_BLT_MODE_PACKED(ppdev, pjBase, CL_PACKED_SRC_COPY | SRC_CPU_DATA); #else
CP_MM_BLT_MODE(ppdev, pjBase, SRC_CPU_DATA); CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0); CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY); #endif // D5480
CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDst);
CP_MM_START_BLT(ppdev, pjBase);
vImageTransfer(ppdev, pjPattern, lDeltaPat, xCnt, yCnt);
//
// Duplicate brush horizontally
//
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_XCNT(ppdev, pjBase, (xCnt - 1)); CP_MM_YCNT(ppdev, pjBase, (yCnt - 1)); CP_MM_BLT_MODE(ppdev, pjBase, 0); CP_MM_SRC_Y_OFFSET(ppdev, pjBase, (lDeltaSrc * 2)); CP_MM_SRC_ADDR(ppdev, pjBase, ulDst); CP_MM_DST_ADDR_ABS(ppdev, pjBase, (ulDst + lDeltaPat));
CP_MM_START_BLT(ppdev, pjBase);
//
// Duplicate brush vertically
//
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_SRC_Y_OFFSET(ppdev, pjBase, (lDeltaSrc * 2)); CP_MM_DST_Y_OFFSET(ppdev, pjBase, (lDeltaSrc * 2)); CP_MM_BLT_MODE(ppdev, pjBase, 0); CP_MM_XCNT(ppdev, pjBase, ((lDeltaSrc * 2) - 1)); CP_MM_YCNT(ppdev, pjBase, (yCnt - 1)); CP_MM_SRC_ADDR(ppdev, pjBase, ulDst);
if (ppdev->cBitsPerPixel == 24) { CP_MM_DST_ADDR_ABS(ppdev, pjBase, (ulDst + 512)); // 128 * 4
} else { CP_MM_DST_ADDR_ABS(ppdev, pjBase, (ulDst + PELS_TO_BYTES(128))); }
CP_MM_START_BLT(ppdev, pjBase);
#if 0
{ ////////////////////////////////////////////////////////////////
// DEBUG TILED PATTERNS
//
// The following code helps to debug patterns if you break the
// realization code. It copies the 2x2 tiled copy of the brush
// to the visible screen.
//
POINTL ptl; RECTL rcl;
ptl.x = pbe->x; ptl.y = pbe->y;
rcl.left = 10; rcl.right = 10 + 16; rcl.top = ppdev->cyScreen - 10 - 16; rcl.bottom = ppdev->cyScreen - 10;
{ LONG lDelta = ppdev->lDelta; BYTE jHwRop; BYTE jMode;
//
// Make sure we can write to the video registers.
//
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY); CP_MM_SRC_Y_OFFSET(ppdev, pjBase, PELS_TO_BYTES(16)); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
{ //
// Top to Bottom - Left to Right
//
jMode |= DIR_TBLR; CP_MM_BLT_MODE(ppdev, pjBase, ppdev->jModeColor);
{
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_XCNT(ppdev, pjBase, (PELS_TO_BYTES(rcl.right - rcl.left) - 1)); CP_MM_YCNT(ppdev, pjBase, (rcl.bottom - rcl.top - 1));
CP_MM_SRC_ADDR(ppdev, pjBase, (0 + ((ptl.y) * lDelta) + PELS_TO_BYTES(ptl.x))); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ((rcl.top * lDelta) + PELS_TO_BYTES(rcl.left))); CP_MM_START_BLT(ppdev, pjBase); } } } } #endif
}
/**************************************************************************
* VOID vMmFillPat * * This routine uses the pattern hardware to draw a patterned list of * rectangles. * **************************************************************************/
VOID vMmFillPat( PDEV* ppdev, LONG c, // Can't be zero
RECTL* prcl, // Array of relative coordinate destination rects
ROP4 rop4, // Obvious?
RBRUSH_COLOR rbc, // Drawing color is rbc.iSolidColor
POINTL* pptlBrush) //
{ BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; ULONG ulAlignedPatternOffset = ppdev->ulAlignedPatternOffset; ULONG ulPatternAddrBase; BYTE jHwRop; BYTE jMode; 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
DISPDBG((10,"vFillPat called"));
ASSERTDD(c > 0, "Can't handle zero rectangles"); ASSERTDD(ppdev->cBpp < 4, "vFillPat only works at 8bpp, 16bpp, and 24bpp");
if ((rbc.prb->pbe == NULL) || (rbc.prb->pbe->prbVerify != rbc.prb)) { vMmFastPatRealize(ppdev, rbc.prb); DISPDBG((5, " -- Brush cache miss, put it at (%d,%d)", rbc.prb->pbe->x, rbc.prb->pbe->y)); } else { DISPDBG((5, " -- Brush cache hit on brush at (%d,%d)", rbc.prb->pbe->x, rbc.prb->pbe->y)); }
pbe = rbc.prb->pbe;
//
// Fill the list of rectangles
//
ulPatternAddrBase = pbe->xy; jHwRop = gajHwMixFromRop2[(rop4 >> 2) & 0xf]; jMode = ppdev->jModeColor | ENABLE_8x8_PATTERN_COPY;
do { ULONG offset = 0; ULONG XOffset, YOffset;
YOffset = ((prcl->top - pptlBrush->y) & 7) << 4; XOffset = (prcl->left - pptlBrush->x) & 7;
// align the pattern to a new location
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); #if 1 // D5480
CP_MM_BLT_MODE_PACKED(ppdev, pjBase, CL_PACKED_SRC_COPY); #else
CP_MM_BLT_MODE(ppdev, pjBase, 0); CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY); #endif // D5480
if (ppdev->cBitsPerPixel == 24) { offset = (YOffset * 4) + (XOffset * 3);
CP_MM_SRC_Y_OFFSET(ppdev, pjBase, 64); CP_MM_DST_Y_OFFSET(ppdev, pjBase, 32); } else { offset = PELS_TO_BYTES(YOffset + XOffset);
CP_MM_SRC_Y_OFFSET(ppdev, pjBase, PELS_TO_BYTES(16)); CP_MM_DST_Y_OFFSET(ppdev, pjBase, PELS_TO_BYTES(8)); }
CP_MM_SRC_ADDR(ppdev, pjBase, (ulPatternAddrBase + offset)); CP_MM_XCNT(ppdev, pjBase, (PELS_TO_BYTES(8) - 1)); CP_MM_YCNT(ppdev, pjBase, (8 - 1)); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulAlignedPatternOffset); CP_MM_START_BLT(ppdev, pjBase);
// fill using aligned pattern
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_BLT_MODE(ppdev, pjBase, jMode); CP_MM_ROP(ppdev, pjBase, jHwRop); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_SRC_ADDR(ppdev, pjBase, ulAlignedPatternOffset); CP_MM_XCNT(ppdev, pjBase, (PELS_TO_BYTES(prcl->right - prcl->left) - 1)); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top - 1)); CP_MM_DST_ADDR(ppdev, pjBase, ((prcl->top * lDelta) + PELS_TO_BYTES(prcl->left))); CP_MM_START_BLT(ppdev, pjBase);
prcl++;
} while (--c != 0); }
/**************************************************************************
* VOID vMmFillSolid * * Does a solid fill to a list of rectangles. * **************************************************************************/
VOID vMmFillSolid( PDEV* ppdev, LONG c, // Can't be zero
RECTL* prcl, // Array of relative coordinate destination rects
ROP4 rop4, // Obvious?
RBRUSH_COLOR rbc, // Drawing color is rbc.iSolidColor
POINTL* pptlBrush) // Not used
{ BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; LONG cBpp = ppdev->cBpp; ULONG ulSolidColor; BYTE jHwRop;
DISPDBG((10,"vFillSolid called"));
ASSERTDD(c > 0, "Can't handle zero rectangles");
ulSolidColor = rbc.iSolidColor;
if (cBpp == 1) { ulSolidColor |= ulSolidColor << 8; ulSolidColor |= ulSolidColor << 16; } else if (cBpp == 2) { ulSolidColor |= ulSolidColor << 16; }
jHwRop = gajHwMixFromRop2[(rop4 >> 2) & 0xf];
//
// Make sure we can write to the video registers.
//
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_ROP(ppdev, pjBase, jHwRop); CP_MM_SRC_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_BLT_MODE(ppdev, pjBase, ENABLE_COLOR_EXPAND | ENABLE_8x8_PATTERN_COPY | ppdev->jModeColor); CP_MM_FG_COLOR(ppdev, pjBase, ulSolidColor);
if (ppdev->flCaps & CAPS_AUTOSTART) { CP_MM_BLT_EXT_MODE(ppdev, pjBase, ENABLE_SOLID_FILL); }
//
// Fill the list of rectangles
//
while (TRUE) { CP_MM_XCNT(ppdev, pjBase, (PELS_TO_BYTES(prcl->right - prcl->left) - 1)); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top - 1)); CP_MM_DST_ADDR(ppdev, pjBase, ((prcl->top * lDelta) + PELS_TO_BYTES(prcl->left))); CP_MM_START_BLT(ppdev, pjBase);
if (--c == 0) return;
prcl++; CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); } }
/**************************************************************************
* VOID vMmCopyBlt * * Does a screen-to-screen blt of a list of rectangles. * **************************************************************************/
VOID vMmCopyBlt( PDEV* ppdev, LONG c, // Can't be zero
RECTL* prcl, // Array of relative coordinates destination rectangles
ROP4 rop4, // Obvious?
POINTL* pptlSrc, // Original unclipped source point
RECTL* prclDst) // Original unclipped destination rectangle
{ LONG dx; LONG dy; // Add delta to destination to get source
LONG xyOffset = ppdev->xyOffset; BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; BYTE jHwRop;
DISPDBG((10,"vCopyBlt called"));
ASSERTDD(c > 0, "Can't handle zero rectangles");
//
// The src-dst delta will be the same for all rectangles
//
dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top;
//
// Make sure we can write to the video registers.
//
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
jHwRop = gajHwMixFromRop2[rop4 & 0xf]; CP_MM_ROP(ppdev, pjBase, jHwRop);
CP_MM_SRC_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
//
// 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) || (prclDst->top < pptlSrc->y) || ((prclDst->top == pptlSrc->y) && (prclDst->left <= pptlSrc->x)) ) { //
// Top to Bottom - Left to Right
//
DISPDBG((12,"Top to Bottom - Left to Right"));
CP_MM_BLT_MODE(ppdev, pjBase, DIR_TBLR);
while (TRUE) { CP_MM_XCNT(ppdev, pjBase, (PELS_TO_BYTES(prcl->right - prcl->left) - 1)); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top - 1));
CP_MM_SRC_ADDR(ppdev, pjBase, (xyOffset + ((prcl->top + dy) * lDelta) + PELS_TO_BYTES(prcl->left + dx))); CP_MM_DST_ADDR(ppdev, pjBase, ((prcl->top * lDelta) + PELS_TO_BYTES(prcl->left))); CP_MM_START_BLT(ppdev, pjBase);
if (--c == 0) return;
prcl++; CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); } } else { //
// Bottom to Top - Right to Left
//
DISPDBG((12,"Bottom to Top - Right to Left"));
CP_MM_BLT_MODE(ppdev, pjBase, DIR_BTRL);
while (TRUE) { CP_MM_XCNT(ppdev, pjBase, (PELS_TO_BYTES(prcl->right - prcl->left) - 1)); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top - 1));
CP_MM_SRC_ADDR(ppdev, pjBase, (xyOffset + ((prcl->bottom - 1 + dy) * lDelta) + PELS_TO_BYTES(prcl->right + dx) - 1)); CP_MM_DST_ADDR(ppdev, pjBase, (((prcl->bottom - 1) * lDelta) + PELS_TO_BYTES(prcl->right) - 1)); CP_MM_START_BLT(ppdev, pjBase);
if (--c == 0) return;
prcl++; CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); } } }
/******************************Public*Routine******************************\
* VOID vMmXfer1bpp * * Low-level routine used to transfer monochrome data to the screen using * DWORD writes to the blt engine. * * This can handle opaque or transparent expansions. It does opaque * expansions by drawing the opaque rectangle first and then transparently * expands the foreground bits. * \**************************************************************************/
VOID vMmXfer1bpp( PDEV* ppdev, LONG c, // Count of rectangles, can't be zero
RECTL* prcl, // List of destination rectangles, in relative
// coordinates
ROP4 rop4, // Actually had better be a rop3
SURFOBJ* psoSrc, // Source surface
POINTL* pptlSrc, // Original unclipped source point
RECTL* prclDst, // Original unclipped destination rectangle
XLATEOBJ* pxlo) // Translate that provides color-expansion information
{ ULONG* pulXfer; ULONG* pul; LONG ix; LONG iy; LONG cxWidthInBytes; BYTE* pjBits; POINTL ptlDst; POINTL ptlSrc; SIZEL sizlDst; LONG cxLeftMask; LONG cxRightMask; ULONG ulDstAddr; INT nDwords; ULONG ulLeftMask; ULONG ulRightMask; LONG dx; LONG dy;
BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; LONG lDeltaSrc = psoSrc->lDelta; LONG cBpp = ppdev->cBpp; ULONG ulFgColor = pxlo->pulXlate[1]; ULONG ulBgColor = pxlo->pulXlate[0];
// Since the hardware clipping on some of the Cirrus chips is broken, we
// do the clipping by rounding out the edges to dword boundaries and then
// doing the blt transparently. In the event that we want the expansion
// to be opaque, we do the opaquing blt in advance. One side effect of
// this is that the destination bits are no longer valid for processing
// the rop. This could probably be optimized by doing the edges seperately
// and then doing the middle section in one pass. However, this is
// complicated by a 5434 bug that breaks blts less than 10 pixels wide.
ASSERTDD(c > 0, "Can't handle zero rectangles"); ASSERTDD(((rop4 & 0xff00) == 0xcc00), "Expected foreground rop of 0xcc");
//
// The src-dst delta will be the same for all rectangles
//
dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top;
if (cBpp == 1) { ulFgColor = (ulFgColor << 8) | (ulFgColor & 0xff); ulBgColor = (ulBgColor << 8) | (ulBgColor & 0xff); ulFgColor = (ulFgColor << 16) | (ulFgColor & 0xffff); ulBgColor = (ulBgColor << 16) | (ulBgColor & 0xffff); } else if (cBpp == 2) { ulFgColor = (ulFgColor << 16) | (ulFgColor & 0xffff); ulBgColor = (ulBgColor << 16) | (ulBgColor & 0xffff); }
pulXfer = ppdev->pulXfer; #if BANKING //bank#1
ppdev->pfnBankMap(ppdev, ppdev->lXferBank); #endif
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
if (rop4 != 0xCCAA) { LONG lCnt = c; RECTL* prclTmp = prcl; BYTE jHwBgRop = gajHwMixFromRop2[rop4 & 0xf];
CP_MM_ROP(ppdev, pjBase, jHwBgRop); CP_MM_FG_COLOR(ppdev, pjBase, ulBgColor); CP_MM_SRC_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset); CP_MM_BLT_MODE(ppdev, pjBase, ppdev->jModeColor | ENABLE_COLOR_EXPAND | ENABLE_8x8_PATTERN_COPY);
do { // calculate the size of the blt
ptlDst.x = prclTmp->left; ptlDst.y = prclTmp->top; sizlDst.cx = prclTmp->right - ptlDst.x; sizlDst.cy = prclTmp->bottom - ptlDst.y;
//
// Fill the background rectangle with the background color
//
// Set the dest addresses
ulDstAddr = (ptlDst.y * lDelta) + PELS_TO_BYTES(ptlDst.x);
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_XCNT(ppdev, pjBase, PELS_TO_BYTES(sizlDst.cx) - 1); CP_MM_YCNT(ppdev, pjBase, sizlDst.cy - 1); CP_MM_DST_ADDR(ppdev, pjBase, ulDstAddr);
// Start the blt operation
CP_MM_START_BLT(ppdev, pjBase); prclTmp++; } while (--lCnt != 0);
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); }
CP_MM_FG_COLOR(ppdev, pjBase, ulFgColor); CP_MM_BG_COLOR(ppdev, pjBase, ~ulFgColor); CP_IO_XPAR_COLOR(ppdev, pjBase, ~ulFgColor); CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY); CP_MM_BLT_MODE(ppdev, pjBase, ppdev->jModeColor | ENABLE_COLOR_EXPAND | ENABLE_TRANSPARENCY_COMPARE | SRC_CPU_DATA); CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0); // jl01
do { // calculate the size of the blt
ptlDst.x = prcl->left; ptlDst.y = prcl->top; sizlDst.cx = prcl->right - ptlDst.x; sizlDst.cy = prcl->bottom - ptlDst.y;
// calculate the number of dwords per scan line
ptlSrc.x = prcl->left + dx; ptlSrc.y = prcl->top + dy;
// Floor the source.
// Extend the width by the amount required to floor to a dword boundary.
// Set the size of the left mask.
// Floor the dest, so it aligns with the floored source.
if ((cxLeftMask = (ptlSrc.x & 31))) { sizlDst.cx += cxLeftMask; ptlSrc.x &= ~31; ptlDst.x -= cxLeftMask; }
ulLeftMask = gaulLeftClipMask[cxLeftMask];
// Ceil the cx to a dword boundary.
if (cxRightMask = (sizlDst.cx & 31)) { cxRightMask = 32 - cxRightMask; sizlDst.cx = (sizlDst.cx + 31) & ~31; }
ulRightMask = gaulRightClipMask[cxRightMask];
if (sizlDst.cx == 32) { ulLeftMask &= ulRightMask; ulRightMask = 0; }
// Note: At this point sizlDst.cx is the width of the blt in pixels,
// floored to a dword boundary, and ceiled to a dword boundary.
// Calculate the width in Bytes
cxWidthInBytes = sizlDst.cx >> 3;
// Calculate the number of Dwords and any remaining bytes
nDwords = cxWidthInBytes >> 2;
ASSERTDD(((cxWidthInBytes & 0x03) == 0), "cxWidthInBytes is not a DWORD multiple");
// Calculate the address of the source bitmap
// This is to a byte boundary.
pjBits = (PBYTE) psoSrc->pvScan0; pjBits += ptlSrc.y * lDeltaSrc; pjBits += ptlSrc.x >> 3;
ASSERTDD((((ULONG_PTR)pjBits & 0x03) == 0), "pjBits not DWORD aligned like it should be");
//
// Blt the 1 bpp bitmap
//
ulDstAddr = (ptlDst.y * lDelta) + PELS_TO_BYTES(ptlDst.x);
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
//
// Tell the hardware that we want to write (sizlDst.cx) X amd (sizlDst.cy) Y bytes
//
CP_MM_XCNT(ppdev, pjBase, PELS_TO_BYTES(sizlDst.cx) - 1); CP_MM_YCNT(ppdev, pjBase, sizlDst.cy - 1);
//
// The 542x chips require a write to the Src Address Register when
// doing a host transfer with color expansion. The value is
// irrelevant, but the write is crucial. This is documented in
// the manual, not the errata. Go figure.
//
CP_MM_SRC_ADDR(ppdev, pjBase, 0); CP_MM_DST_ADDR(ppdev, pjBase, ulDstAddr);
CP_MM_START_BLT(ppdev, pjBase);
//
// Transfer the host bitmap.
//
if (ulRightMask) { //
// Blt is > 1 DWORD wide (nDwords > 1)
//
for (iy = 0; iy < sizlDst.cy; iy++) { pul = (ULONG*) pjBits;
//*pulXfer++ = *(((ULONG*)pul)++) & ulLeftMask;
WRITE_REGISTER_ULONG(pulXfer, (*((ULONG*)pul) & ulLeftMask)); pul++;
for (ix = 0; ix < (nDwords-2); ix++) { //*pulXfer++ = *(((ULONG*)pul)++);
WRITE_REGISTER_ULONG(pulXfer, (*((ULONG*)pul))); pul++; } //*pulXfer++ = *(((ULONG*)pul)++) & ulRightMask;
WRITE_REGISTER_ULONG(pulXfer, (*((ULONG*)pul) & ulRightMask)); pul++;
pjBits += lDeltaSrc; //pulXfer = ppdev->pulXfer;
CP_MEMORY_BARRIER(); // Flush memory cache when we reset the address
} } else { //
// Blt is 1 DWORD wide (nDwords == 1)
//
for (iy = 0; iy < sizlDst.cy; iy++) { //*pulXfer = *((ULONG*)pjBits) & ulLeftMask;
WRITE_REGISTER_ULONG(pulXfer, (*((ULONG*)pjBits) & ulLeftMask)); pjBits += lDeltaSrc; CP_MEMORY_BARRIER(); // Flush memory cache
} }
prcl++; } while (--c != 0); }
/******************************Public*Routine******************************\
* VOID vMmXfer4bpp * * 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 vMmXfer4bpp( 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
{ ULONG ulDstAddr; 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 cdwThis; BYTE* pjBuf; BYTE ajBuf[XLATE_BUFFER_SIZE];
ULONG* pulXfer = ppdev->pulXfer; BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta;
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");
DISPDBG((5, "vXfer4bpp: entry"));
dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top; // Add to destination to get source
lSrcDelta = psoSrc->lDelta; pjSrcScan0 = psoSrc->pvScan0;
#if BANKING //bank#1
ppdev->pfnBankMap(ppdev, ppdev->lXferBank); #endif
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
#if 1 // D5480
CP_MM_BLT_MODE_PACKED(ppdev, pjBase, gajHwPackedMixFromRop2[rop4 & 0xf] | SRC_CPU_DATA); #else
CP_MM_ROP(ppdev, pjBase, gajHwMixFromRop2[rop4 & 0xf]); CP_MM_BLT_MODE(ppdev, pjBase, SRC_CPU_DATA); #endif
while(TRUE) { ulDstAddr = (prcl->top * lDelta) + PELS_TO_BYTES(prcl->left); cx = prcl->right - prcl->left; cy = prcl->bottom - prcl->top;
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_XCNT(ppdev, pjBase, PELS_TO_BYTES(cx) - 1); CP_MM_YCNT(ppdev, pjBase, cy - 1); CP_MM_DST_ADDR(ppdev, pjBase, ulDstAddr);
pulXlate = pxlo->pulXlate; xSrc = prcl->left + dx; pjScan = pjSrcScan0 + (prcl->top + dy) * lSrcDelta + (xSrc >> 1);
CP_MM_START_BLT(ppdev, pjBase);
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:
cdwThis = (cxThis + 3) >> 2; pjBuf = ajBuf;
TRANSFER_DWORD_ALIGNED(ppdev, pulXfer, pjBuf, cdwThis);
} 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);
if (--c == 0) return;
prcl++; } }
/******************************Public*Routine******************************\
* VOID vMmXferNative * * Transfers a bitmap that is the same color depth as the display to * the screen via the data transfer register, with no translation. * \**************************************************************************/
VOID vMmXferNative( 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
{ ULONG ulDstAddr; LONG dx; LONG dy; LONG cx; LONG cy; LONG lSrcDelta; BYTE* pjSrcScan0; BYTE* pjSrc; LONG cjSrc;
ULONG* pulXfer = ppdev->pulXfer; BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta;
ASSERTDD((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL), "Can handle trivial xlate only"); ASSERTDD(psoSrc->iBitmapFormat == ppdev->iBitmapFormat, "Source must be same color 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;
#if BANKING //bank#1
ppdev->pfnBankMap(ppdev, ppdev->lXferBank); #endif
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); #if 1 // D5480
CP_MM_BLT_MODE_PACKED(ppdev, pjBase, gajHwPackedMixFromRop2[rop4 & 0xf] | SRC_CPU_DATA); #else
CP_MM_ROP(ppdev, pjBase, gajHwMixFromRop2[rop4 & 0xf]); CP_MM_BLT_MODE(ppdev, pjBase, SRC_CPU_DATA); #endif
while(TRUE) { ulDstAddr = (prcl->top * lDelta) + PELS_TO_BYTES(prcl->left); cx = prcl->right - prcl->left; cy = prcl->bottom - prcl->top;
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_XCNT(ppdev, pjBase, PELS_TO_BYTES(cx) - 1); CP_MM_YCNT(ppdev, pjBase, cy - 1); CP_MM_DST_ADDR(ppdev, pjBase, ulDstAddr);
cjSrc = PELS_TO_BYTES(cx); pjSrc = pjSrcScan0 + (prcl->top + dy) * lSrcDelta + (PELS_TO_BYTES(prcl->left + dx));
CP_MM_START_BLT(ppdev, pjBase); vImageTransfer(ppdev, pjSrc, lSrcDelta, cjSrc, cy);
if (--c == 0) return;
prcl++; } }
////////////////////////////////////////////////////////////////////////////////
// //
// N E W B L T R O U T I N E S F O R B R U S H C A C H E //
// //
////////////////////////////////////////////////////////////////////////////////
VOID vMmFillSolid36( PDEV* ppdev, LONG c, RECTL* prcl, ROP4 rop4, RBRUSH_COLOR rbc, POINTL* pptlBrush) { BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; BYTE jHwRop = gajHwMixFromRop2[(rop4 >> 2) & 0x0F]; BYTE jMode = ppdev->jModeColor | ENABLE_8x8_PATTERN_COPY | ENABLE_COLOR_EXPAND;
while (c-- > 0) { ULONG ulDstOffset; SIZEL sizlDst;
// Calculate the destination address and size.
ulDstOffset = (prcl->top * lDelta) + PELS_TO_BYTES(prcl->left); sizlDst.cx = PELS_TO_BYTES(prcl->right - prcl->left) - 1; sizlDst.cy = (prcl->bottom - prcl->top) - 1;
// Wait for the bitblt engine.
WAIT_BUSY_BLT(ppdev, pjBase);
// Setup the bitblt registers.
CP_MM_FG_COLOR(ppdev, pjBase, rbc.iSolidColor); CP_MM_XCNT(ppdev, pjBase, sizlDst.cx); CP_MM_YCNT(ppdev, pjBase, sizlDst.cy); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_DST_WRITE_MASK(ppdev, pjBase, 0); // Disable clipping.
CP_MM_BLT_MODE(ppdev, pjBase, jMode); CP_MM_ROP(ppdev, pjBase, jHwRop); CP_MM_BLT_EXT_MODE(ppdev, pjBase, ENABLE_SOLID_FILL); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset);
// Next rectangle.
prcl++; } }
VOID vMmFillPat36( PDEV* ppdev, LONG c, RECTL* prcl, ROP4 rop4, RBRUSH_COLOR rbc, POINTL* pptlBrush) { BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; BYTE jHwRop = gajHwMixFromRop2[(rop4 >> 2) & 0x0F];
CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0) ; // chu01
// Dithered brush...
if (rbc.prb->fl == RBRUSH_DITHER) { DITHERCACHE* pdc;
pdc = (DITHERCACHE*) ((ULONG_PTR)ppdev + rbc.prb->ulSlot); if (pdc->ulColor != rbc.prb->ulUniq) { // Cache entry is invalid, realize the brush again.
bCacheDither(ppdev, rbc.prb); }
while (c-- > 0) { ULONG ulDstOffset, ulSrcOffset; SIZEL sizlDst; LONG xOffset, yOffset; LONG x;
// Calculate the brush rotation.
xOffset = (prcl->left - pptlBrush->x) & 7; yOffset = (prcl->top - pptlBrush->y) & 7; ulSrcOffset = rbc.prb->ulBrush | yOffset;
// Calculate the destination and size.
x = prcl->left - xOffset; ulDstOffset = (prcl->top * lDelta) + x; sizlDst.cx = (prcl->right - x) - 1; sizlDst.cy = (prcl->bottom - prcl->top) - 1;
// Wait for the bitblt engine.
WAIT_BUSY_BLT(ppdev, pjBase);
// Setup the bitblt registers.
CP_MM_XCNT(ppdev, pjBase, sizlDst.cx); CP_MM_YCNT(ppdev, pjBase, sizlDst.cy); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_SRC_ADDR(ppdev, pjBase, ulSrcOffset); CP_MM_DST_WRITE_MASK(ppdev, pjBase, xOffset); CP_MM_BLT_MODE(ppdev, pjBase, ENABLE_8x8_PATTERN_COPY); CP_MM_ROP(ppdev, pjBase, jHwRop); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset);
// Next rectangle.
prcl++; } }
// Monochrome brush...
else if (rbc.prb->fl == RBRUSH_MONOCHROME) { MONOCACHE* pmc; BYTE jMode; ULONG ulBgColor, ulFgColor;
pmc = (MONOCACHE*) ((ULONG_PTR)ppdev + rbc.prb->ulSlot); if (pmc->ulUniq != rbc.prb->ulUniq) { // Cache entry is invalid, realize the brush again.
bCacheMonochrome(ppdev, rbc.prb); }
// Setup the common parameters.
jMode = ppdev->jModeColor | ENABLE_8x8_PATTERN_COPY | ENABLE_COLOR_EXPAND; ulBgColor = rbc.prb->ulBackColor; ulFgColor = rbc.prb->ulForeColor;
// Monochrome brushes in 24-bpp are already cached expanded.
if (ppdev->cBpp == 3) { jMode = ppdev->jModeColor | ENABLE_8x8_PATTERN_COPY; }
// Walk through all rectangles.
while (c-- > 0) { ULONG ulDstOffset, ulSrcOffset; SIZEL sizlDst; LONG xOffset, yOffset; LONG x;
// Calculate the brush rotation.
xOffset = (prcl->left - pptlBrush->x) & 7; yOffset = (prcl->top - pptlBrush->y) & 7; ulSrcOffset = rbc.prb->ulBrush | yOffset;
// Calculate the destination and size.
x = prcl->left - xOffset; ulDstOffset = (prcl->top * lDelta) + PELS_TO_BYTES(x); sizlDst.cx = PELS_TO_BYTES(prcl->right - x) - 1; sizlDst.cy = (prcl->bottom - prcl->top) - 1; if (ppdev->cBpp == 3) { xOffset *= 3; }
// Wait for the bitblt engine.
WAIT_BUSY_BLT(ppdev, pjBase);
// Setup the bitblt registers.
CP_MM_BG_COLOR(ppdev, pjBase, ulBgColor); CP_MM_FG_COLOR(ppdev, pjBase, ulFgColor); CP_MM_XCNT(ppdev, pjBase, sizlDst.cx); CP_MM_YCNT(ppdev, pjBase, sizlDst.cy); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_SRC_ADDR(ppdev, pjBase, ulSrcOffset); CP_MM_DST_WRITE_MASK(ppdev, pjBase, xOffset); CP_MM_BLT_MODE(ppdev, pjBase, jMode); CP_MM_ROP(ppdev, pjBase, jHwRop); CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset);
// Next rectangle.
prcl++; } }
// Patterned brush...
else if (ppdev->flStatus & STAT_PATTERN_CACHE) { PATTERNCACHE* ppc;
BYTE jMode = ppdev->jModeColor | ENABLE_8x8_PATTERN_COPY;
ppc = (PATTERNCACHE*) ((ULONG_PTR)ppdev + rbc.prb->ulSlot); if (ppc->prbUniq != rbc.prb) { // Cache entry is invalid, realize the brush again.
bCachePattern(ppdev, rbc.prb); }
while (c-- > 0) { ULONG ulDstOffset, ulSrcOffset; SIZEL sizlDst; LONG xOffset, yOffset; LONG x;
// Calculate the brush rotation.
xOffset = (prcl->left - pptlBrush->x) & 7; yOffset = (prcl->top - pptlBrush->y) & 7; ulSrcOffset = rbc.prb->ulBrush | yOffset;
// Calculate the destination and size.
x = prcl->left - xOffset; ulDstOffset = (prcl->top * lDelta) + PELS_TO_BYTES(x); sizlDst.cx = PELS_TO_BYTES(prcl->right - x) - 1; sizlDst.cy = (prcl->bottom - prcl->top) - 1; if (ppdev->cBpp == 3) { xOffset *= 3; }
// Wait for the bitblt engine.
WAIT_BUSY_BLT(ppdev, pjBase);
// Setup the bitblt registers.
CP_MM_XCNT(ppdev, pjBase, sizlDst.cx); CP_MM_YCNT(ppdev, pjBase, sizlDst.cy); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_SRC_ADDR(ppdev, pjBase, ulSrcOffset); CP_MM_DST_WRITE_MASK(ppdev, pjBase, xOffset); CP_MM_BLT_MODE(ppdev, pjBase, jMode); CP_MM_ROP(ppdev, pjBase, jHwRop); CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset);
// Next rectangle.
prcl++; } }
// Old-style brush cache.
else { vMmFillPat(ppdev, c, prcl, rop4, rbc, pptlBrush); } }
VOID vMmCopyBlt36( PDEV* ppdev, LONG c, RECTL* prcl, ROP4 rop4, POINTL* pptlSrc, RECTL* prclDst) { LONG xy; LONG cx, cy; ULONG ulSrc, ulDst;
BYTE jHwRop = gajHwMixFromRop2[rop4 & 0x0F]; LONG xyOffset = ppdev->xyOffset; BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta;
DISPDBG((10, "vMmCopyBlt36 called"));
// The src-dst delta will be the same for all rectangles.
xy = ((pptlSrc->y - prclDst->top) * lDelta) + PELS_TO_BYTES(pptlSrc->x - prclDst->left);
// Determine the direction of the blit.
if ((xy >= 0) || !OVERLAP(prclDst, pptlSrc)) { DISPDBG((12, "Top to Bottom - Left to Right"));
while (c-- > 0) { // Calculate the blit size and offsets.
cx = PELS_TO_BYTES(prcl->right - prcl->left) - 1; cy = (prcl->bottom - prcl->top) - 1; ulDst = xyOffset + (prcl->top * lDelta) + PELS_TO_BYTES(prcl->left); ulSrc = ulDst + xy;
// Wait for the bitblt engine.
WAIT_BUSY_BLT(ppdev, pjBase);
// Perform the move.
CP_MM_XCNT(ppdev, pjBase, cx); CP_MM_YCNT(ppdev, pjBase, cy); CP_MM_SRC_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_SRC_ADDR(ppdev, pjBase, ulSrc); CP_MM_BLT_MODE(ppdev, pjBase, DIR_TBLR); CP_MM_ROP(ppdev, pjBase, jHwRop); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDst);
// Next rectangle.
prcl++; } }
else { DISPDBG((12, "Bottom to Top - Right to Left"));
while (c-- > 0) { // Calculate the blit size and offsets.
cx = PELS_TO_BYTES(prcl->right - prcl->left) - 1; cy = (prcl->bottom - prcl->top) - 1; ulDst = xyOffset + ((prcl->bottom - 1) * lDelta) + (PELS_TO_BYTES(prcl->right) - 1); ulSrc = ulDst + xy;
// Wait for the bitblt engine.
WAIT_BUSY_BLT(ppdev, pjBase);
// Perform the move.
CP_MM_XCNT(ppdev, pjBase, cx); CP_MM_YCNT(ppdev, pjBase, cy); CP_MM_SRC_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_SRC_ADDR(ppdev, pjBase, ulSrc); CP_MM_BLT_MODE(ppdev, pjBase, DIR_BTRL); CP_MM_ROP(ppdev, pjBase, jHwRop); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDst);
// Next rectangle.
prcl++; } } }
#if 1 // D5480
VOID vMmFillSolid80( PDEV* ppdev, LONG c, RECTL* prcl, ROP4 rop4, RBRUSH_COLOR rbc, POINTL* pptlBrush) { ULONG_PTR* ulCLStart; ULONG ulWidthHeight; ULONG xCLOffset; ULONG ulDstOffset = 0; BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; DWORD jHwRop = gajHwPackedMixFromRop2[(rop4 >> 2) & 0x0F]; DWORD jExtMode = ENABLE_SOLID_FILL_PACKED | ENABLE_XY_POSITION_PACKED | ppdev->jModeColor | ENABLE_8x8_PATTERN_COPY | ENABLE_COLOR_EXPAND;
//
// Make sure we can write to the video registers.
//
// We need to change to wait for buffer ready
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
// Setup the bitblt registers.
CP_MM_FG_COLOR(ppdev, pjBase, rbc.iSolidColor); // Do we really need to set it every time?
CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
// Do we need to clear Source XY?
CP_MM_SRC_XY_PACKED(ppdev, pjBase, 0); CP_MM_DST_WRITE_MASK(ppdev, pjBase, 0); // Disable clipping.
// Setup first set registers
xCLOffset = prcl->left; CP_MM_DST_Y(ppdev, pjBase, prcl->top); CP_MM_XCNT(ppdev, pjBase, (prcl->right - prcl->left) - 1); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top) - 1);
if (--c) { // There are more than one rectangle
prcl++; jExtMode |= ENABLE_COMMAND_LIST_PACKED; ulCLStart = ppdev->pCommandList; ulDstOffset |= ((ULONG)((ULONG_PTR)ulCLStart - (ULONG_PTR)ppdev->pjScreen) << 14); CP_MM_CL_SWITCH(ppdev); while (TRUE) { // Command List
// Calculate the destination address and size.
ulWidthHeight = PACKXY_FAST((prcl->right - prcl->left) - 1, (prcl->bottom - prcl->top) - 1); ulWidthHeight |= COMMAND_NOSRC_NOTHING; // XY
*(ulCLStart + 1) = PACKXY_FAST(prcl->left, prcl->top); // Source Start address
*(ulCLStart + 2) = 0;
if (c == 1) { ulWidthHeight |= COMMAND_LAST_PACKET; *ulCLStart = ulWidthHeight; // Last Command
break; } *ulCLStart = ulWidthHeight; // Next rectangle.
prcl++; c--; ulCLStart += 4; } } CP_MM_BLT_MODE_PACKED(ppdev, pjBase, jExtMode | jHwRop ); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset); CP_MM_DST_X(ppdev, pjBase, xCLOffset); }
VOID vMmFillPat80( PDEV* ppdev, LONG c, RECTL* prcl, ROP4 rop4, RBRUSH_COLOR rbc, POINTL* pptlBrush) { ULONG xOffset, yOffset; ULONG ulSrcOffset; ULONG_PTR* ulCLStart; ULONG ulWidthHeight; ULONG xCLOffset; ULONG ulDstOffset = 0; BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; DWORD jHwRop = gajHwPackedMixFromRop2[(rop4 >> 2) & 0x0F]; DWORD jExtMode = ENABLE_XY_POSITION_PACKED | ENABLE_8x8_PATTERN_COPY;
// Dithered brush...
if (rbc.prb->fl == RBRUSH_DITHER) { DITHERCACHE* pdc;
pdc = (DITHERCACHE*) ((ULONG_PTR)ppdev + rbc.prb->ulSlot); if (pdc->ulColor != rbc.prb->ulUniq) { // Cache entry is invalid, realize the brush again.
bCacheDither(ppdev, rbc.prb); }
// Calculate the brush rotation.
xOffset = (prcl->left - pptlBrush->x) & 7; yOffset = (prcl->top - pptlBrush->y) & 7; ulSrcOffset = rbc.prb->ulBrush | yOffset | (xOffset << 24);
// Calculate the destination and size.
xCLOffset = prcl->left - xOffset;
//
// Make sure we can write to the video registers.
//
// We need to change to wait for buffer ready
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
// Do we really need to set it every time?
CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
// Do we need to clear Source XY?
CP_MM_SRC_XY_PACKED(ppdev, pjBase, 0); // Setup first set registers
CP_MM_SRC_ADDR(ppdev, pjBase, ulSrcOffset); CP_MM_DST_Y(ppdev, pjBase, prcl->top); CP_MM_XCNT(ppdev, pjBase, (prcl->right - xCLOffset) - 1); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top) - 1);
if (--c) { // There are more than one rectangle
prcl++; jExtMode |= ENABLE_COMMAND_LIST_PACKED; ulCLStart = ppdev->pCommandList; ulDstOffset |= ((ULONG)((ULONG_PTR)ulCLStart - (ULONG_PTR)ppdev->pjScreen) << 14); CP_MM_CL_SWITCH(ppdev); while (TRUE) { // Command List
// Calculate the brush rotation.
xOffset = (prcl->left - pptlBrush->x) & 7; yOffset = (prcl->top - pptlBrush->y) & 7;
// Calculate the destination address and size.
ulWidthHeight = PACKXY_FAST((prcl->right - prcl->left + xOffset ) - 1, (prcl->bottom - prcl->top) - 1); ulWidthHeight |= COMMAND_FOURTH_NOTHING; // XY
*(ulCLStart + 1) = PACKXY_FAST(prcl->left - xOffset, prcl->top); // Source Start address
*(ulCLStart + 2) = rbc.prb->ulBrush | yOffset | (xOffset << 24);
if (c == 1) { ulWidthHeight |= COMMAND_LAST_PACKET; *ulCLStart = ulWidthHeight; // Last Command
break; } *ulCLStart = ulWidthHeight; // Next rectangle.
prcl++; c--; ulCLStart += 4; } } CP_MM_BLT_MODE_PACKED(ppdev, pjBase, jExtMode | jHwRop ); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset); CP_MM_DST_X(ppdev, pjBase, xCLOffset); }
// Monochrome brush...
else if (rbc.prb->fl == RBRUSH_MONOCHROME) { MONOCACHE* pmc; BYTE jMode; ULONG ulBgColor, ulFgColor;
pmc = (MONOCACHE*) ((ULONG_PTR) ppdev + rbc.prb->ulSlot); if (pmc->ulUniq != rbc.prb->ulUniq) { // Cache entry is invalid, realize the brush again.
bCacheMonochrome(ppdev, rbc.prb); }
ulBgColor = rbc.prb->ulBackColor; ulFgColor = rbc.prb->ulForeColor; // Calculate the brush rotation.
xOffset = (prcl->left - pptlBrush->x) & 7; yOffset = (prcl->top - pptlBrush->y) & 7; // Monochrome brushes in 24-bpp are already cached expanded.
if (ppdev->cBpp == 3) { jExtMode |= ppdev->jModeColor; ulSrcOffset = rbc.prb->ulBrush | yOffset | ((xOffset * 3) << 24); } else { jExtMode |= (ppdev->jModeColor | ENABLE_COLOR_EXPAND); ulSrcOffset = rbc.prb->ulBrush | yOffset | (xOffset << 24); }
// Calculate the destination and size.
xCLOffset = prcl->left - xOffset; //
// Make sure we can write to the video registers.
//
// We need to change to wait for buffer ready
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
// Do we really need to set it every time?
CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
// Do we need to clear Source XY?
CP_MM_SRC_XY_PACKED(ppdev, pjBase, 0); // Setup first set registers
CP_MM_SRC_ADDR(ppdev, pjBase, ulSrcOffset); CP_MM_DST_Y(ppdev, pjBase, prcl->top); CP_MM_XCNT(ppdev, pjBase, (prcl->right - xCLOffset) - 1); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top) - 1); CP_MM_BG_COLOR(ppdev, pjBase, ulBgColor); CP_MM_FG_COLOR(ppdev, pjBase, ulFgColor);
if (--c) { // There are more than one rectangle
prcl++; jExtMode |= ENABLE_COMMAND_LIST_PACKED; ulCLStart = ppdev->pCommandList; ulDstOffset |= (ULONG)(((ULONG_PTR)ulCLStart - (ULONG_PTR)ppdev->pjScreen)<<14); CP_MM_CL_SWITCH(ppdev); while (TRUE) { // Command List
// Calculate the brush rotation.
xOffset = (prcl->left - pptlBrush->x) & 7; yOffset = (prcl->top - pptlBrush->y) & 7;
// Calculate the destination address and size.
ulWidthHeight = PACKXY_FAST((prcl->right - prcl->left + xOffset ) - 1, (prcl->bottom - prcl->top) - 1); ulWidthHeight |= COMMAND_FOURTH_NOTHING; // XY
*(ulCLStart + 1) = PACKXY_FAST(prcl->left - xOffset, prcl->top); // Source Start address
if(ppdev->cBpp == 3) *(ulCLStart + 2) = rbc.prb->ulBrush | yOffset | ((xOffset * 3) << 24); else *(ulCLStart + 2) = rbc.prb->ulBrush | yOffset | (xOffset << 24);
if (c == 1) { ulWidthHeight |= COMMAND_LAST_PACKET; *ulCLStart = ulWidthHeight; // Last Command
break; } *ulCLStart = ulWidthHeight; // Next rectangle.
prcl++; c--; ulCLStart += 4; } } CP_MM_BLT_MODE_PACKED(ppdev, pjBase, jExtMode | jHwRop ); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset); CP_MM_DST_X(ppdev, pjBase, xCLOffset); }
// Patterned brush...
else if (ppdev->flStatus & STAT_PATTERN_CACHE) { PATTERNCACHE* ppc;
ppc = (PATTERNCACHE*) ((ULONG_PTR) ppdev + rbc.prb->ulSlot); if (ppc->prbUniq != rbc.prb) { // Cache entry is invalid, realize the brush again.
bCachePattern(ppdev, rbc.prb); }
// Calculate the brush rotation.
xOffset = (prcl->left - pptlBrush->x) & 7; yOffset = (prcl->top - pptlBrush->y) & 7; // Monochrome brushes in 24-bpp are already cached expanded.
jExtMode |= ppdev->jModeColor; if (ppdev->cBpp == 3) { ulSrcOffset = rbc.prb->ulBrush | yOffset | ((xOffset * 3) << 24); } else { ulSrcOffset = rbc.prb->ulBrush | yOffset | (xOffset << 24); }
// Calculate the destination and size.
xCLOffset = prcl->left - xOffset; //
// Make sure we can write to the video registers.
//
// We need to change to wait for buffer ready
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
// Do we really need to set it every time?
CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
// Do we need to clear Source XY?
CP_MM_SRC_XY_PACKED(ppdev, pjBase, 0); // Setup first set registers
CP_MM_SRC_ADDR(ppdev, pjBase, ulSrcOffset); CP_MM_DST_Y(ppdev, pjBase, prcl->top); CP_MM_XCNT(ppdev, pjBase, (prcl->right - xCLOffset) - 1); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top) - 1);
if (--c) { // There are more than one rectangle
prcl++; jExtMode |= ENABLE_COMMAND_LIST_PACKED; ulCLStart = ppdev->pCommandList; ulDstOffset |= (ULONG)(((ULONG_PTR)ulCLStart-(ULONG_PTR)ppdev->pjScreen)<<14); CP_MM_CL_SWITCH(ppdev); while (TRUE) { // Command List
// Calculate the brush rotation.
xOffset = (prcl->left - pptlBrush->x) & 7; yOffset = (prcl->top - pptlBrush->y) & 7;
// Calculate the destination address and size.
ulWidthHeight = PACKXY_FAST((prcl->right - prcl->left + xOffset ) - 1, (prcl->bottom - prcl->top) - 1); ulWidthHeight |= COMMAND_FOURTH_NOTHING; // XY
*(ulCLStart + 1) = PACKXY_FAST(prcl->left - xOffset, prcl->top); // Source Start address
if(ppdev->cBpp == 3) *(ulCLStart + 2) = rbc.prb->ulBrush | yOffset | ((xOffset * 3) << 24); else *(ulCLStart + 2) = rbc.prb->ulBrush | yOffset | (xOffset << 24);
if (c == 1) { ulWidthHeight |= COMMAND_LAST_PACKET; *ulCLStart = ulWidthHeight; // Last Command
break; } *ulCLStart = ulWidthHeight; // Next rectangle.
prcl++; c--; ulCLStart += 4; } } CP_MM_BLT_MODE_PACKED(ppdev, pjBase, jExtMode | jHwRop ); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset); CP_MM_DST_X(ppdev, pjBase, xCLOffset); }
// Old-style brush cache.
else { vMmFillPat(ppdev, c, prcl, rop4, rbc, pptlBrush); } }
VOID vMmCopyBlt80( PDEV* ppdev, LONG c, // Can't be zero
RECTL* prcl, // Array of relative coordinates destination rectangles
ROP4 rop4, // Obvious?
POINTL* pptlSrc, // Original unclipped source point
RECTL* prclDst) // Original unclipped destination rectangle
{ LONG dx; LONG dy; // Add delta to destination to get source
ULONG jHwRop; ULONG_PTR* ulCLStart; ULONG ulWidthHeight; ULONG xCLOffset; ULONG ulDstOffset = 0; LONG xyOffset = ppdev->xyOffset; BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; DWORD jExtMode = ENABLE_XY_POSITION_PACKED | ppdev->jModeColor;
DISPDBG((10,"vCopyBlt called"));
ASSERTDD(c > 0, "Can't handle zero rectangles");
//
// The src-dst delta will be the same for all rectangles
//
dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top;
//
// Make sure we can write to the video registers.
//
// We need to change to wait for buffer ready
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
jHwRop = gajHwPackedMixFromRop2[rop4 & 0xf];
CP_MM_SRC_Y_OFFSET(ppdev, pjBase, lDelta); // Do we really need to set it every time?
CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
//
// 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) || (prclDst->top < pptlSrc->y) || ((prclDst->top == pptlSrc->y) && (prclDst->left <= pptlSrc->x)) ) { //
// Top to Bottom - Left to Right
//
DISPDBG((12,"Top to Bottom - Left to Right"));
// Setup first set registers
xCLOffset = prcl->left; CP_MM_DST_Y(ppdev, pjBase, prcl->top); CP_MM_XCNT(ppdev, pjBase, (prcl->right - prcl->left) - 1); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top) - 1); CP_MM_SRC_ADDR(ppdev, pjBase, (xyOffset + ((prcl->top + dy) * lDelta) + PELS_TO_BYTES(prcl->left + dx))); CP_MM_SRC_XY_PACKED(ppdev, pjBase, 0);
if (--c) { // There are more than one rectangle
prcl++; jExtMode |= ENABLE_COMMAND_LIST_PACKED; ulCLStart = ppdev->pCommandList; ulDstOffset |= (ULONG)(((ULONG_PTR)ulCLStart - (ULONG_PTR)ppdev->pjScreen)<<14); CP_MM_CL_SWITCH(ppdev); while (TRUE) { // Command List
// Calculate the destination address and size.
ulWidthHeight = PACKXY_FAST((prcl->right - prcl->left) - 1, (prcl->bottom - prcl->top) - 1); ulWidthHeight |= COMMAND_FOURTH_NOTHING; // XY
*(ulCLStart + 1) = PACKXY_FAST(prcl->left, prcl->top); // Source Start address
*(ulCLStart + 2) = xyOffset + (prcl->top + dy) * lDelta + PELS_TO_BYTES(prcl->left + dx); if (c == 1) { ulWidthHeight |= COMMAND_LAST_PACKET; *ulCLStart = ulWidthHeight; // Last Command
break; } *ulCLStart = ulWidthHeight; // Next rectangle.
prcl++; c--; ulCLStart += 4; } } CP_MM_BLT_MODE_PACKED(ppdev, pjBase, jExtMode | jHwRop); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset); CP_MM_DST_X(ppdev, pjBase, xCLOffset); } else { //
// Bottom to Top - Right to Left
//
DISPDBG((12,"Bottom to Top - Right to Left"));
// Setup first set registers
xCLOffset = prcl->right - 1; CP_MM_DST_Y(ppdev, pjBase, prcl->bottom - 1); CP_MM_XCNT(ppdev, pjBase, (prcl->right - prcl->left) - 1); CP_MM_YCNT(ppdev, pjBase, (prcl->bottom - prcl->top) - 1); CP_MM_SRC_ADDR(ppdev, pjBase, (xyOffset + ((prcl->bottom - 1 + dy) * lDelta) + PELS_TO_BYTES(prcl->right + dx - 1))); CP_MM_SRC_XY_PACKED(ppdev, pjBase, 0);
if (--c) { // There are more than one rectangle
prcl++; jExtMode |= ENABLE_COMMAND_LIST_PACKED; ulCLStart = ppdev->pCommandList; ulDstOffset |=(ULONG)(((ULONG_PTR)ulCLStart - (ULONG_PTR)ppdev->pjScreen) << 14); CP_MM_CL_SWITCH(ppdev); while (TRUE) { // Command List
// Calculate the destination address and size.
ulWidthHeight = PACKXY_FAST((prcl->right - prcl->left) - 1, (prcl->bottom - prcl->top) - 1); ulWidthHeight |= COMMAND_FOURTH_NOTHING; // XY
*(ulCLStart + 1) = PACKXY_FAST(prcl->right - 1, prcl->bottom - 1); // Source Start address
*(ulCLStart + 2) = xyOffset + (prcl->bottom - 1 + dy) * lDelta + PELS_TO_BYTES(prcl->right + dx - 1); if (c == 1) { ulWidthHeight |= COMMAND_LAST_PACKET; *ulCLStart = ulWidthHeight; // Last Command
break; } *ulCLStart = ulWidthHeight; // Next rectangle.
prcl++; c--; ulCLStart += 4; } } CP_MM_BLT_MODE_PACKED(ppdev, pjBase, jExtMode | jHwRop | DIR_BTRL); CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset); CP_MM_DST_X(ppdev, pjBase, xCLOffset); } }
/******************************Public*Routine******************************\
* VOID vMmXfer1bpp80 * * Low-level routine used to transfer monochrome data to the screen using * DWORD writes to the blt engine. * * This can handle opaque or transparent expansions. It does opaque * expansions by drawing the opaque rectangle first and then transparently * expands the foreground bits. * \**************************************************************************/
VOID vMmXfer1bpp80( PDEV* ppdev, LONG c, // Count of rectangles, can't be zero
RECTL* prcl, // List of destination rectangles, in relative
// coordinates
ROP4 rop4, // Actually had better be a rop3
SURFOBJ* psoSrc, // Source surface
POINTL* pptlSrc, // Original unclipped source point
RECTL* prclDst, // Original unclipped destination rectangle
XLATEOBJ* pxlo) // Translate that provides color-expansion information
{ ULONG* pulXfer; ULONG* pul; LONG ix; LONG iy; LONG cxWidthInBytes; BYTE* pjBits; POINTL ptlDst; POINTL ptlSrc; SIZEL sizlDst; LONG cxLeftMask; LONG cxRightMask; ULONG ulDstAddr; INT nDwords; ULONG ulLeftMask; ULONG ulRightMask; LONG dx; LONG dy;
BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; LONG lDeltaSrc = psoSrc->lDelta; LONG cBpp = ppdev->cBpp; ULONG ulFgColor = pxlo->pulXlate[1]; ULONG ulBgColor = pxlo->pulXlate[0];
// Since the hardware clipping on some of the Cirrus chips is broken, we
// do the clipping by rounding out the edges to dword boundaries and then
// doing the blt transparently. In the event that we want the expansion
// to be opaque, we do the opaquing blt in advance. One side effect of
// this is that the destination bits are no longer valid for processing
// the rop. This could probably be optimized by doing the edges seperately
// and then doing the middle section in one pass. However, this is
// complicated by a 5434 bug that breaks blts less than 10 pixels wide.
ASSERTDD(c > 0, "Can't handle zero rectangles"); ASSERTDD(((rop4 & 0xff00) == 0xcc00), "Expected foreground rop of 0xcc");
//
// The src-dst delta will be the same for all rectangles
//
dx = pptlSrc->x - prclDst->left; dy = pptlSrc->y - prclDst->top;
#if 0
if (cBpp == 1) { ulFgColor = (ulFgColor << 8) | (ulFgColor & 0xff); ulBgColor = (ulBgColor << 8) | (ulBgColor & 0xff); ulFgColor = (ulFgColor << 16) | (ulFgColor & 0xffff); ulBgColor = (ulBgColor << 16) | (ulBgColor & 0xffff); } else if (cBpp == 2) { ulFgColor = (ulFgColor << 16) | (ulFgColor & 0xffff); ulBgColor = (ulBgColor << 16) | (ulBgColor & 0xffff); } #endif
pulXfer = ppdev->pulXfer;
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_SRC_XY_PACKED(ppdev, pjBase, 0);
if (rop4 != 0xCCAA) { LONG lCnt = c; RECTL* prclTmp = prcl; DWORD jHwBgRop = gajHwPackedMixFromRop2[rop4 & 0xf];
CP_MM_FG_COLOR(ppdev, pjBase, ulBgColor); CP_MM_BLT_MODE_PACKED(ppdev, pjBase, ENABLE_XY_POSITION_PACKED | ENABLE_SOLID_FILL_PACKED | jHwBgRop | ppdev->jModeColor | ENABLE_COLOR_EXPAND | ENABLE_8x8_PATTERN_COPY);
CP_MM_DST_ADDR(ppdev, pjBase, 0); do { // calculate the size of the blt
ptlDst.x = prclTmp->left; ptlDst.y = prclTmp->top;
//
// Fill the background rectangle with the background color
//
// Set the dest addresses
ulDstAddr = (ptlDst.y * lDelta) + PELS_TO_BYTES(ptlDst.x);
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_XCNT(ppdev, pjBase, prclTmp->right - ptlDst.x - 1); CP_MM_YCNT(ppdev, pjBase, prclTmp->bottom - ptlDst.y - 1); CP_MM_DST_Y(ppdev, pjBase, ptlDst.y); CP_MM_DST_X(ppdev, pjBase, ptlDst.x); prclTmp++; } while (--lCnt != 0);
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); }
CP_MM_FG_COLOR(ppdev, pjBase, ulFgColor); CP_MM_BG_COLOR(ppdev, pjBase, ~ulFgColor); // CP_IO_XPAR_COLOR(ppdev, pjBase, ~ulFgColor);
CP_MM_BLT_MODE_PACKED(ppdev, pjBase, ENABLE_XY_POSITION_PACKED | ENABLE_CLIP_RECT_PACKED | CL_PACKED_SRC_COPY | ppdev->jModeColor | ENABLE_COLOR_EXPAND | ENABLE_TRANSPARENCY_COMPARE | SRC_CPU_DATA | SOURCE_GRANULARITY_PACKED);
CP_MM_DST_ADDR(ppdev, pjBase, 0); do { // calculate the size of the blt
ptlDst.x = prcl->left; ptlDst.y = prcl->top; sizlDst.cx = prcl->right - ptlDst.x; sizlDst.cy = prcl->bottom - ptlDst.y;
// calculate the number of dwords per scan line
ptlSrc.x = prcl->left + dx; ptlSrc.y = prcl->top + dy;
// Floor the source.
// Extend the width by the amount required to floor to a dword boundary.
// Set the size of the left mask.
// Floor the dest, so it aligns with the floored source.
if ((cxLeftMask = (ptlSrc.x & 31))) { sizlDst.cx += cxLeftMask; ptlSrc.x &= ~31; ptlDst.x -= cxLeftMask; }
// Calculate the width in Bytes
cxWidthInBytes = (sizlDst.cx + 7) >> 3;
// Calculate the address of the source bitmap
// This is to a byte boundary.
pjBits = (PBYTE) psoSrc->pvScan0; pjBits += ptlSrc.y * lDeltaSrc; pjBits += ptlSrc.x >> 3;
ASSERTDD((((ULONG_PTR)pjBits & 0x03) == 0), "pjBits not DWORD aligned like it should be");
//
// Blt the 1 bpp bitmap
//
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); // set clipping register
CP_MM_CLIP_ULXY(ppdev, pjBase, prcl->left, prcl->top); CP_MM_CLIP_LRXY(ppdev, pjBase, prcl->right - 1, prcl->bottom - 1);
CP_MM_DST_Y(ppdev, pjBase, ptlDst.y); CP_MM_XCNT(ppdev, pjBase, sizlDst.cx - 1); CP_MM_YCNT(ppdev, pjBase, sizlDst.cy - 1); CP_MM_DST_X(ppdev, pjBase, ptlDst.x);
//
// Transfer the host bitmap.
//
vImageTransfer(ppdev, pjBits, lDeltaSrc, cxWidthInBytes, sizlDst.cy); prcl++; } while (--c != 0); }
/******************************Public*Routine******************************\
* VOID vMmXferNative80 * * Transfers a bitmap that is the same color depth as the display to * the screen via the data transfer register, with no translation. * \**************************************************************************/
VOID vMmXferNative80( 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;
BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; DWORD jHwRop = gajHwPackedMixFromRop2[rop4 & 0x0F]; DWORD jExtMode= ENABLE_XY_POSITION_PACKED | SRC_CPU_DATA | ppdev->jModeColor;
ASSERTDD((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL), "Can handle trivial xlate only"); ASSERTDD(psoSrc->iBitmapFormat == ppdev->iBitmapFormat, "Source must be same color 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;
//
// Make sure we can write to the video registers.
//
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_BLT_MODE_PACKED(ppdev, pjBase, jHwRop | jExtMode); CP_MM_SRC_XY_PACKED(ppdev, pjBase, 0);
while(TRUE) { cx = prcl->right - prcl->left; cy = prcl->bottom - prcl->top;
cjSrc = PELS_TO_BYTES(cx); pjSrc = pjSrcScan0 + (prcl->top + dy) * lSrcDelta + (PELS_TO_BYTES(prcl->left + dx));
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_XCNT(ppdev, pjBase, cx - 1); CP_MM_YCNT(ppdev, pjBase, cy - 1);
CP_MM_DST_Y(ppdev, pjBase, prcl->top); CP_MM_DST_ADDR(ppdev, pjBase, 0); CP_MM_DST_X(ppdev, pjBase, prcl->left); vImageTransfer(ppdev, pjSrc, lSrcDelta, cjSrc, cy);
if (--c == 0) break;
prcl++; } }
#endif // endif D5480
|