📄 swblt.cpp
字号:
/*
Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
*/
#include "precomp.h"
unsigned long ProcessROP3(
unsigned long dstValue,
unsigned long srcValue,
unsigned long brushValue,
unsigned char rop3,
unsigned char dstBitsPerPixel);
class PixelIterator
{
public:
// Fixed upon creation:
unsigned char *RowPtr;
int RowIncrement;
unsigned long CacheStateNewDWord;
unsigned long CacheStateNewRow;
unsigned long CacheStateIncrement;
unsigned long CacheStateIncrementDirty;
int Is24Bit;
unsigned long Mask;
int BytesPerAccess;
int Bpp;
unsigned char MaskShiftXor;
// IteratorState
unsigned char *Ptr;
unsigned long Cache;
unsigned long Value;
unsigned long CacheState;
void InitPixelIterator(
GPESurf *pSurf,
int xPositive,
int yPositive,
RECTL *prcl,
int xSkip,
int ySkip );
};
class BrushPixelIterator : public PixelIterator
{
public:
int PixelsRemaining; // Pixels still available this row of brush incl cache
int PixelsPerRow; // Width of source surface
int RowInitialPixelsRemaining; // PixelsRemaining at start of each Dst row
int RowsRemaining; // Rows (incl this) left in pattern
int Rows; // Total rows in pattern
unsigned char *FirstRowPtr; // Pointer to first DWord to use in top/bottom row
unsigned char *LeftRowPtr; // Ptr to *left* of pattern of current row
// (RowPtr is *start* of next row)
void InitBrushPixelIterator(
GPESurf *pSurf,
int xPositive,
int yPositive,
RECTL *prcl );
};
void BrushPixelIterator::InitBrushPixelIterator(
GPESurf *pSurf,
int xPositive,
int yPositive,
RECTL *prcl)
{
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("BrushPixelIterator::InitBrushPixelIterator\r\n")));
InitPixelIterator( pSurf, xPositive, yPositive, prcl, 0, 0 );
PixelsPerRow = pSurf->Width();
Rows = pSurf->Height();
RowInitialPixelsRemaining = xPositive?PixelsPerRow-prcl->left:prcl->right;
RowsRemaining = yPositive?Rows-prcl->top:prcl->bottom;
FirstRowPtr = RowPtr - RowIncrement * ( Rows - RowsRemaining );
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("PixelsPerRow=%d, Rows=%d, RowInitPixRem=%d, RowsRem=%d, FirstRowPtr=%08x\r\n"),
PixelsPerRow, Rows, RowInitialPixelsRemaining, RowsRemaining, FirstRowPtr ));
}
void PixelIterator::InitPixelIterator(
GPESurf *pSurf,
int xPositive,
int yPositive,
RECTL *prcl,
int xSkip,
int ySkip )
{
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("PixelIterator::PixelIterator, prcl= l:%d,t:%d - r:%d,b:%d Bpp=%d\r\n"),
prcl->left, prcl->top, prcl->right, prcl->bottom, EGPEFormatToBpp[pSurf->Format()]
));
// Set pointer to start of first row to use
RowPtr = (unsigned char *)(pSurf->Buffer());
if( yPositive )
{
RowIncrement = pSurf->Stride();
RowPtr += pSurf->Stride() * (prcl->top + ySkip );
}
else
{
RowIncrement = -pSurf->Stride();
RowPtr += pSurf->Stride() * (prcl->bottom-1-ySkip);
}
int StartX;
Bpp = EGPEFormatToBpp[pSurf->Format()];
MaskShiftXor = (Bpp<8)?(8-Bpp):0;
CacheStateNewDWord = (32/Bpp)<<8; // Initally 32/Bpp pixels in dword, 0 offset
if( xPositive )
{
StartX = prcl->left + xSkip;
CacheStateIncrement = ((Bpp<<8) - 1)<<8;
}
else
{
StartX = prcl->right-1-xSkip;
CacheStateIncrement = (((-Bpp)<<8) - 1)<<8;
CacheStateNewDWord |= (32 - Bpp)<<16; // Initial offset points to last pixel in dword
}
CacheStateIncrementDirty = CacheStateIncrement+1;
if( Is24Bit = ( pSurf->Format() == gpe24Bpp ) ) // deliberate assignment
{
RowPtr += 3 * StartX;
BytesPerAccess = 3;
}
else
{
int StartBit = Bpp * StartX;
RowPtr += (StartBit&~31) >> 3;
// Since the first pixel on row in prcl may not be on dword alignment:
CacheStateNewRow = CacheStateNewDWord;
while( (( CacheStateNewRow >> 16 ) ^ StartBit ) & 31 )
CacheStateNewRow += CacheStateIncrement;
BytesPerAccess = 4;
}
if( !xPositive )
BytesPerAccess = -BytesPerAccess;
Mask = ( 2 << (Bpp - 1) ) - 1;
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("BytesPerAccess=%d,CacheStateNewRow=%06x,CacheStateIncrement=%06x\r\n"),
BytesPerAccess, CacheStateNewRow, CacheStateIncrement ));
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("Mask=%08x, CacheStateNewDWord=%08x, StartX=0x%04x(%d)\r\n"),
Mask, CacheStateNewDWord, StartX, StartX ));
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("Buffer=0x%08x\r\n"),
(pSurf->Buffer()) ));
}
#undef SWAP
#define SWAP(a,b,type) { type tmp=a; a=b; b=tmp; }
SCODE GPE::EmulatedBlt( GPEBltParms *pParms )
{
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("New Blt. rop4=%04X\r\n"), pParms->rop4));
unsigned char rop3 = (unsigned char)pParms->rop4;
unsigned char maskedROP3 = (unsigned char)( pParms->rop4 >> 8 );
unsigned char unmaskedROP3 = rop3;
int complexBlt = 0;
int quickWrite = 0;
int width = pParms->prclDst->right - pParms->prclDst->left;
int height = pParms->prclDst->bottom - pParms->prclDst->top;
int x;
RECTL rclBrush;
int dstMatters = ((( pParms->rop4 >> 1 ) ^ pParms->rop4 ) & 0x5555 ) != 0;
int dstXPositive = pParms->xPositive; // These differ from pParms->?Positive if flipping is being performed
int dstYPositive = pParms->yPositive;
RECTL *prclDst = pParms->prclDst;
RECTL tmpRclDst;
int xShrinkStretch = 0;
int xShrink=0;
int xStretch=0;
int yShrinkStretch = 0;
int yShrink=0;
int yStretch=0;
int srcWidth;
int srcHeight;
int rowXAccum, xAccum, xDMajor, xDMinor; // only valid if xShrinkStretch
int yAccum, yDMajor, yDMinor; // only valid if yShrinkStretch
int originalMaskRowInc, originalSrcRowInc; // Used if yShrinkStretch
unsigned char *prevMaskPtr, *prevSrcPtr;
unsigned long prevMaskCache, prevSrcCache;
unsigned long prevMaskCacheState, prevSrcCacheState;
unsigned long originalSrc;
int dstXStartSkip = 0; // Number of dst pixels to not write (left if dstXPositive else right)
int dstYStartSkip = 0; // Number of rows to ignore (top if dstYPositive)
int srcXStartSkip = 0;
int srcYStartSkip = 0;
if( pParms->pDst->InVideoMemory() ||
( pParms->pSrc && pParms->pSrc->InVideoMemory() ) ||
( pParms->pMask && pParms->pMask->InVideoMemory() ) )
{
// If we have a pending blt and now attempt a software operation using
// video memory, the pipeline must be flushed.
WaitForNotBusy();
}
// DebugBreak();
// Handle improperly ordered prclDst resulting from stretch Blt
// Note that only prclDst is ever improperly ordered
if( width < 0 || height < 0 )
{
tmpRclDst = *prclDst;
prclDst = &tmpRclDst;
if( width < 0 )
{
SWAP( tmpRclDst.left, tmpRclDst.right, LONG )
width = -width;
dstXPositive = !dstXPositive;
}
if( height < 0 )
{
SWAP( tmpRclDst.top, tmpRclDst.bottom, LONG )
height = -height;
dstYPositive = !dstYPositive;
}
}
// prclDst is now properly ordered
if( pParms->bltFlags & BLT_STRETCH ) // Check for stretching or shrinking vertically &/or horizontally
{
srcWidth = pParms->prclSrc->right - pParms->prclSrc->left;
srcHeight = pParms->prclSrc->bottom - pParms->prclSrc->top;
if( width > srcWidth )
{
xStretch = 1;
xDMajor = width;
xDMinor = srcWidth;
}
if( width < srcWidth )
{
xShrink = 1;
xDMajor = srcWidth;
xDMinor = width;
}
if( xStretch || xShrink)
{
xShrinkStretch = 1;
// Convert to Bresenham parameters
xDMinor *= 2;
xDMajor = xDMinor - 2 * xDMajor;
rowXAccum = xShrink?(2*width - srcWidth):(3*srcWidth - 2*width);
// loaded into xAccum at start of each row
}
if( height > srcHeight )
{
yStretch = 1;
yDMajor = height;
yDMinor = srcHeight;
}
if( height < srcHeight )
{
yShrink = 1;
yDMajor = srcHeight;
yDMinor = height;
}
if( yStretch || yShrink)
{
yShrinkStretch = 1;
// Convert to Bresenham parameters
yDMinor *= 2;
yDMajor = yDMinor - 2 * yDMajor;
yAccum = yShrink?(2*height - srcHeight):(3*srcHeight - 2*height);
}
if( pParms->prclClip ) // ONLY happens if stretch blting
{
RECTL rclClipped = *prclDst;
if( rclClipped.left < pParms->prclClip->left )
rclClipped.left = pParms->prclClip->left;
if( rclClipped.top < pParms->prclClip->top )
rclClipped.top = pParms->prclClip->top;
if( rclClipped.bottom > pParms->prclClip->bottom )
rclClipped.bottom = pParms->prclClip->bottom;
if( rclClipped.right > pParms->prclClip->right )
rclClipped.right = pParms->prclClip->right;
if( rclClipped.right <= rclClipped.left || rclClipped.bottom <= rclClipped.top )
return S_OK; // the clipping left nothing to do
dstXStartSkip = dstXPositive?(rclClipped.left-prclDst->left):(prclDst->right-rclClipped.right);
dstYStartSkip = dstYPositive?(rclClipped.top-prclDst->top):(prclDst->bottom-rclClipped.bottom);
width = rclClipped.right - rclClipped.left; // Calculate fully clipped destination width
height = rclClipped.bottom - rclClipped.top; // Fully clipped height
}
if( xShrink )
{
while( rowXAccum < 0 )
{
rowXAccum += xDMinor;
srcXStartSkip++;
}
rowXAccum += xDMajor;
}
int skipCount;
for( skipCount = dstXStartSkip; skipCount; skipCount-- )
{
if( xShrink )
{
while( rowXAccum < 0 )
{
rowXAccum += xDMinor;
srcXStartSkip++;
}
srcXStartSkip++; // <--- this is the srcSkip inherent with a dstSkip
rowXAccum += xDMajor;
}
else if( xStretch )
{
if( rowXAccum < 0 )
rowXAccum += xDMinor;
else
{
rowXAccum += xDMajor;
srcXStartSkip++;
}
}
else
srcXStartSkip++;
}
if( yShrink )
{
yAccum += dstYStartSkip * yDMajor;
srcYStartSkip += dstYStartSkip; // <--- this is the srcSkip inherent with a dstSkip
}
else if( yStretch )
{
for( skipCount = dstYStartSkip; skipCount; skipCount-- )
{
if( yAccum < 0 )
yAccum += yDMinor;
else
{
yAccum += yDMajor;
srcYStartSkip++;
}
}
}
else
srcYStartSkip += dstYStartSkip;
}
int transparentBlt = pParms->bltFlags & BLT_TRANSPARENT;
unsigned long transparentColor = pParms->solidColor;
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("pSrc=0x%08x, pDst=0x%08x, pBrush=%08x, pMask=%08x\r\n"),
pParms->pSrc, pParms->pDst, pParms->pBrush, pParms->pMask ));
if( pParms->pBrush )
{
// Calculate an rclBrush so that the correct starting pixel is chosen for the brush iterator
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("Pattern depth: %d Bpp\r\n"), EGPEFormatToBpp[pParms->pBrush->Format()] ) );
int topIndent = (pParms->pptlBrush)?pParms->pBrush->Height()-pParms->pptlBrush->y:0;
int leftIndent = (pParms->pptlBrush)?pParms->pBrush->Width()-pParms->pptlBrush->x:0;
rclBrush.left = ( leftIndent + prclDst->left ) % pParms->pBrush->Width();
rclBrush.right = ( rclBrush.left + pParms->pBrush->Width() - 1 ) % pParms->pBrush->Width();
rclBrush.top = ( topIndent + prclDst->top ) % pParms->pBrush->Height();
rclBrush.bottom = ( rclBrush.top + pParms->pBrush->Height() - 1 ) % pParms->pBrush->Height();
}
PixelIterator src, dst, mask;
BrushPixelIterator brush;
src.Ptr = src.RowPtr = mask.Ptr = mask.RowPtr = brush.Ptr = brush.RowPtr = (unsigned char *)0;
if( pParms->pSrc )
{
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("pSrc depth: %d Bpp\r\n"), EGPEFormatToBpp[pParms->pSrc->Format()] ) );
src.InitPixelIterator( pParms->pSrc, pParms->xPositive, pParms->yPositive, pParms->prclSrc,
srcXStartSkip, srcYStartSkip );
}
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("pDst depth: %d Bpp\r\n"), EGPEFormatToBpp[pParms->pDst->Format()] ) );
if( pParms->pBrush )
{
DEBUGMSG(GPE_ZONE_BLT_LO,(TEXT("pBrush depth: %d Bpp\r\n"), EGPEFormatToBpp[pParms->pBrush->Format()] ) );
brush.InitBrushPixelIterator( pParms->pBrush, pParms->xPositive, pParms->yPositive, &rclBrush );
}
if( ( maskedROP3 != unmaskedROP3 ) && !(pParms->pMask) )
{
DEBUGMSG(GPE_ZONE_ERROR,(TEXT("Rop4 = %04x but pMask is NULL\r\n"), pParms->rop4 ));
return E_INVALIDARG;
}
if( pParms->pMask )
mask.InitPixelIterator( pParms->pMask, pParms->xPositive, pParms->yPositive, pParms->prclMask,
srcXStartSkip, srcYStartSkip );
else
mask.RowIncrement = 0;
if( ( maskedROP3 != unmaskedROP3 ) && !(mask.RowPtr) )
{
DEBUGMSG(GPE_ZONE_ERROR,(TEXT("Rop4 = %04x but mask.RowPtr is NULL\r\n"), pParms->rop4 ));
return E_INVALIDARG;
}
if( ( dst.Bpp = EGPEFormatToBpp[pParms->pDst->Format()] ) >= 8 )
{
quickWrite = 1;
if( !dstYPositive )
{
dst.RowIncrement = -pParms->pDst->Stride();
dst.RowPtr = (unsigned char *)pParms->pDst->Buffer() + pParms->pDst->Stride() * ( prclDst->bottom - 1 - dstYStartSkip );
}
else
{
dst.RowIncrement = pParms->pDst->Stride();
dst.RowPtr = (unsigned char *)pParms->pDst->Buffer() + pParms->pDst->Stride() * ( dstYStartSkip + prclDst->top );
}
if( !dstXPositive )
{
dst.BytesPerAccess = -dst.Bpp/8;
dst.RowPtr -= dst.BytesPerAccess * ( prclDst->right - 1 - dstXStartSkip );
}
else
{
dst.BytesPerAccess = dst.Bpp/8;
dst.RowPtr += dst.BytesPerAccess * ( dstXStartSkip + prclDst->left );
}
dst.Mask = ( 2 << (dst.Bpp - 1) ) - 1;
dst.CacheState=0; // so it is not marked as dirty
}
else
dst.InitPixelIterator( pParms->pDst, dstXPositive, dstYPositive, prclDst,
dstXStartSkip, dstYStartSkip );
if( yShrinkStretch )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -