📄 blt.c
字号:
// DrvTransparentBlt
// This function peforms a GDI BitBlt. It is capable of only SRCCOPY blits,
// with color conversion, clipping, stretching, and a source color key.
// Other ROPs, masked blits, brushes and alpha blending are not expressable.
// Local variables.
PERM3_BLT_PARAM Parameters;
PERM3_SURFACE Dest;
RECT LocalDestRect;
PERM3_SURFACE Source;
RECT LocalSourceRect;
BOOL FnRetVal; // Return value for this function.
ENUMRECTS * ClipperRects = NULL;
ULONG SizeofClipperRects;
ULONG ClipperSortDirection = CD_ANY;
COLOR_SPACE ColorKey;
// Check parameters.
Assert(sizeof(SIZE) == sizeof(SIZEL));
Assert(sizeof(RECT) == sizeof(RECTL));
Assert(sizeof(POINT) == sizeof(POINTL));
// !TODO! Change this once we return something real from DrvEnablePDEV.
Assert((ULONG)DestSurface->dhpdev == 123);
Enter(L"DrvTransparentBlt");
memset(&Parameters, 0, sizeof(PERM3_BLT_PARAM));
// Fill in Parameters.
Parameters.Rop = 0x0000CCCC; // SRCCOPY
// SRCCOPY must have source.
Assert(SourceSurface != NULL);
// Destination surface details.
SurfobjToPerm3Surface(&Dest,
DestSurface,
Xlate,
FALSE);
Parameters.Destination = (const SURFACE *)&Dest;
if (DestRect != NULL) {
// We know that RECT and RECL are really the same thing. The assert above
// protects this.
Parameters.DestRect = (RECT *)DestRect;
}
else {
LocalDestRect.left = 0;
LocalDestRect.top = 0;
LocalDestRect.right = Dest.Size.cx;
LocalDestRect.bottom = Dest.Size.cy;
Parameters.DestRect = &LocalDestRect;
}
// Reject blits that have no height or width.
if (Parameters.DestRect->top == Parameters.DestRect->bottom ||
Parameters.DestRect->left == Parameters.DestRect->right) {
return TRUE;
}
// Source surface details.
SurfobjToPerm3Surface(&Source,
SourceSurface,
Xlate,
TRUE);
Parameters.Source = (const SURFACE *)&Source;
if (SourceRect != NULL) {
// We know that RECT and RECL are really the same thing. The assert above
// protects this.
Parameters.SourceRect = (RECT *)SourceRect;
}
else {
LocalSourceRect.left = 0;
LocalSourceRect.top = 0;
LocalSourceRect.right = Source.Size.cx;
LocalSourceRect.bottom = Source.Size.cy;
Parameters.SourceRect = &LocalSourceRect;
}
// Check for an overlap, and set the blitting direction appropriately.
if (Source.Ptr == Dest.Ptr) {
if (Parameters.SourceRect->bottom > Parameters.DestRect->top &&
Parameters.SourceRect->top < Parameters.DestRect->bottom &&
Parameters.SourceRect->right > Parameters.DestRect->left &&
Parameters.SourceRect->left < Parameters.DestRect->right) {
if (Parameters.SourceRect->top == Parameters.DestRect->top) {
// Horizontal blt, just set ScanXPositive appropriately.
Parameters.ScanXPositive = (BOOL)(Parameters.SourceRect->left >= Parameters.DestRect->left);
}
else {
// Non horizontal blts, just set ScanYPositive appropriately.
Parameters.ScanYPositive = (BOOL)(Parameters.SourceRect->top >= Parameters.DestRect->top);
}
// Might need particular clipping rectangles sort order.
if (Clipper) {
if (Parameters.SourceRect->top > Parameters.DestRect->top) {
ClipperSortDirection = (Parameters.SourceRect->left > Parameters.DestRect->left) ? CD_RIGHTDOWN : CD_LEFTDOWN;
}
else {
ClipperSortDirection = (Parameters.SourceRect->left > Parameters.DestRect->left) ? CD_RIGHTUP : CD_LEFTUP;
}
}
}
}
if (Clipper && Clipper->iDComplexity != DC_TRIVIAL) {
if (Clipper->iDComplexity == DC_RECT) {
Parameters.ClipRectCount = 1;
Parameters.ClipRect = (const RECT *)&(Clipper->rclBounds);
}
else if (Clipper->iDComplexity == DC_COMPLEX) {
// Extract all of the rectangles from GDI.
Parameters.ClipRectCount = CLIPOBJ_cEnumStart(Clipper,
TRUE,
CT_RECTANGLES,
ClipperSortDirection,
0);
// The ENUMRECTS strcuture already contains space for 1 rectangle.
SizeofClipperRects = sizeof(ENUMRECTS) +
sizeof(RECT) * (Parameters.ClipRectCount - 1);
ClipperRects = SystemAlloc(SizeofClipperRects);
if (ClipperRects) {
CLIPOBJ_bEnum(Clipper,
SizeofClipperRects,
(ULONG *)ClipperRects);
Assert(ClipperRects->c == Parameters.ClipRectCount);
Parameters.ClipRect = (const RECT *)ClipperRects->arcl;
}
else {
Error(L"System memory allocation failure.\n");
}
}
else {
Error(L"Unknown clipping complexity.\n");
}
}
// Setup the color key.
Parameters.ColorKeyType = SourceColorKey;
ColorKey.LowValue = TransColor;
ColorKey.HighValue = TransColor;
Parameters.SourceColorKey = &ColorKey;
// Call the Blt with our newly constructed parameter block.
FnRetVal = TryBothBlt(&Parameters);
FreeSurfobjDerivedPerm3Surface(&Dest);
FreeSurfobjDerivedPerm3Surface(&Source);
if (ClipperRects) {
SystemFree(ClipperRects);
}
Exit(L"DrvTransparentBlt");
return FnRetVal;
}
BOOL
TryBothBlt(
PERM3_BLT_PARAM * Parameters
)
{
// TryBothBlt
// This function attempts a hardware blt to fulfill the given parameter
// block, and if that fails, attempts a software fallover.
// Local variables.
BOOL FnRetVal = FALSE; // Return value for this function.
ULONG i;
ULONG ClipRectCount;
// Check parameters.
// !TODO!
Enter(L"TryBothBlt");
ClipRectCount = Parameters->ClipRectCount;
if (ClipRectCount == 0 || ClipRectCount == 1) {
if (!(FnRetVal = HardwareBlt(Parameters))) {
FnRetVal = SoftwareBlt(Parameters);
}
}
else {
Parameters->ClipRectCount = 1;
for (i = 0; i < ClipRectCount; i++) {
if (!(FnRetVal = HardwareBlt(Parameters))) {
FnRetVal = SoftwareBlt(Parameters);
}
if (!FnRetVal) break;
((RECT *)Parameters->ClipRect)++;
}
}
Exit(L"TryBothBlt");
return FnRetVal;
}
BOOL
HardwareBlt(
PERM3_BLT_PARAM * Parameters
)
{
// HardwareBlt
// This function attempts to execute the blit specified in the parameters
// block using the Permedia3 display hardware. It fails blits that it
// doesn't support by returning FALSE. This allows us an attempt with the
// software fallover.
// Local constants.
// These are used to index into the flags arrays for which surfaces are
// needed (according to the ROP,) for a particular blit.
const ULONG Foreground = 0;
const ULONG Background = 1;
// Local variables.
BOOL FnRetVal = FALSE; // Return value for this function.
ULONG DestRectHeight;
ULONG DestRectWidth;
// Source surface offset in memory. Computed from the source and destination
// positions.
ULONG SourceOffset;
// The first bit to consume from the first 32 bit value in the bit mask.
ULONG BitMaskOffset;
// We accumulate the bits we will write into the Config2D and Render2D
// registers here.
ULONG Config2D;
ULONG Render2D;
// Foreground and background Permedia3 logicops.
USHORT Logicop[2];
// Flags that we compute concerning the nature of the blit.
BOOL NeedMask;
BOOL NeedSource[2];
BOOL NeedDestRead[2];
BOOL NeedPattern[2];
// Did we turn on clipping?
BOOL ResetClipping = FALSE;
// Did we turn on chromakeying?
BOOL ResetChromaKey = FALSE;
// Need to compute color format to program chromkeying.
ULONG ColorFormat;
// Foreground and background ROP3s.
BYTE Rop3[2];
// Check parameters.
Assert(Parameters != NULL);
Assert(Parameters->Destination != NULL);
// !TODO! Finish parameters checks...
Enter(L"HardwareBlt");
// Save pointer derefrences by caching values from the parameters structure.
Assert((Parameters->Rop >> 16) == 0);
Rop3[Foreground] = (BYTE)Parameters->Rop;
Rop3[Background] = (BYTE)(Parameters->Rop >> 8);
// Save us some computations.
DestRectWidth = RectWidth(Parameters->DestRect);
DestRectHeight = RectHeight(Parameters->DestRect);
// Blitting is a multipart task. Each blit is composed of several different,
// hardware chores, which are shared. For example, destination rectangles
// and surface setup is the same for nearly every blit, so the code can be
// shared.
Config2D = 0;
Render2D = b_Render2D_SpanOperation;
// The first job is to discover some information about the nature of the
// blit we are performing by checking out the ROP.
NeedMask = (BOOL)(Rop3[Foreground] != Rop3[Background]);
NeedDestRead[Foreground] = (BOOL)((((Rop3[Foreground] >> 1) ^ Rop3[Foreground]) & 0x55) != 0);
NeedSource[Foreground] = (BOOL)((((Rop3[Foreground] >> 2) ^ Rop3[Foreground]) & 0x33) != 0);
NeedPattern[Foreground] = (BOOL)((((Rop3[Foreground] >> 4) ^ Rop3[Foreground]) & 0x0F) != 0);
if (NeedMask) {
NeedDestRead[Background] = (BOOL)((((Rop3[Background] >> 1) ^ Rop3[Background]) & 0x55) != 0);
NeedSource[Background] = (BOOL)((((Rop3[Background] >> 2) ^ Rop3[Background]) & 0x33) != 0);
NeedPattern[Background] = (BOOL)((((Rop3[Background] >> 4) ^ Rop3[Background]) & 0x0F) != 0);
}
else {
NeedDestRead[Background] = FALSE;
NeedSource[Background] = FALSE;
NeedPattern[Background] = FALSE;
}
// Determine the logic-op(s). The nature of the Permedia3 span hardware will
// only allow us destination readback along with another surface (could be
// source, constant color, or LUT pattern data.)
Logicop[Foreground] = LookupLogicop(Rop3[Foreground]);
if (Logicop[Foreground] == NO_APPROPRIATE_OP) {
// Bail. We cannot accelerate this ROP.
return FALSE;
}
Assert((NeedSource[Foreground] & NeedPattern[Foreground]) != 1);
Config2D |= b_Config2D_ForegroundLogicalOpEnable;
Config2D |= (Logicop[Foreground] << 7);
if (NeedMask) {
Logicop[Background] = LookupLogicop(Rop3[Background]);
if ((Logicop[Background] == NO_APPROPRIATE_OP) ||
(NeedSource[Foreground] & NeedPattern[Background]) ||
(NeedPattern[Foreground] & NeedSource[Background])) {
// Bail we cannot accelerate this ROP.
return FALSE;
}
Assert((NeedSource[Background] & NeedPattern[Background]) != 1);
Config2D |= b_Config2D_BackgroundLogicalOpEnable;
Config2D |= (Logicop[Background] << 12);
}
// Check the remaining restrictions on this functions capability. Punt
// anything we can't handle.
if (Parameters->Destination->Type != VideoMemory) return FALSE;
if (!IsSameFormat(Parameters->Destination->Format,
(const FORMAT *)GetDisplayModeFormat(GetCurrentMode()))) return FALSE;
if (Parameters->Source) {
if (Parameters->Source->Type != VideoMemory) return FALSE;
if (!IsSameFormat(Parameters->Source->Format,
Parameters->Destination->Format)) return FALSE;
if (RectWidth(Parameters->SourceRect) != RectWidth(Parameters->DestRect)) return FALSE;
if (RectHeight(Parameters->SourceRect) != RectHeight(Parameters->DestRect)) return FALSE;
}
if (Parameters->Mask) {
if (Parameters->Mask->Format->BitsPerPixel != 1) return FALSE;
}
if (Parameters->ColorKeyType == SourceAndDestColorKey) return FALSE;
if (Parameters->Brush) {
if (Parameters->Brush->Size.cx != 8 ||
Parameters->Brush->Size.cy != 8) {
return FALSE;
}
if (!IsSameFormat(Parameters->Brush->Format,
(const FORMAT *)GetDisplayModeFormat(GetCurrentMode()))) return FALSE;
}
// Make sure we are in the 2D rendering context.
Restore2DContext();
// The next step is to setup the hardware for a masked blit, if necessary.
if (NeedMask) {
Assert(Parameters->Mask != NULL);
// Specifies that we need to use the opaque spans (background ROPS.)
// Bit mask consumption order is specified as part of the 2D context.
Config2D |= b_Config2D_OpaqueSpan;
Render2D |= (2 << 12); // SyncOnBitMask
// Compute which bit needs to be consumed first in the first ulong.
// !TODO! How is this impacted by mirroring the bit mask?
BitMaskOffset = (Parameters->MaskRect->left & 0x0000001F);
WriteRegUlong(r_RasterizerMode,
b_RasterizerMode_MirrorBitMask |
(3 << 7) | // byteswap bitmasks ABCD => DCBA
(BitMaskOffset << 10) |
b_RasterizerMode_BitMaskPacking |
b_RasterizerMode_YLimitsEnable |
b_RasterizerMode_OpaqueSpans);
}
else {
Assert(Parameters->Mask == NULL);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -