📄 blt.c
字号:
// Setup clipping (scissoring, technically)
if (Parameters->ClipRectCount == 1) {
ResetClipping = TRUE;
// Setup scissor coordinates.
WriteRegUlong(r_ScissorMinXY,
PackXY(Parameters->ClipRect->left,
Parameters->ClipRect->top));
WriteRegUlong(r_ScissorMaxXY,
PackXY(Parameters->ClipRect->right,
Parameters->ClipRect->bottom));
// Enable scissoring.
Config2D |= b_Config2D_UserScissorEnable;
}
// Setup the blit destination, possibly with readback and overlap.
// !TODO! System memory destiantions?
Assert(Parameters->Destination->Type == VideoMemory);
Config2D |= b_Config2D_FBWriteEnable;
Render2D |= PackXY(DestRectWidth, DestRectHeight);
WriteRegUlong(r_RectanglePosition,
PackXY(Parameters->DestRect->left, Parameters->DestRect->top));
WriteRegUlong(r_FBWriteBufferAddr0,
VirtualToOffset(Parameters->Destination->Ptr));
WriteRegUlong(r_FBWriteBufferWidth0,
Parameters->Destination->Size.cx);
// Handle destination readback. This is different than overlap, which is
// when the source and destination surfaces are the same and the rectangles
// overlap. Here, we need to read the destination pixel as it is a component
// in the formula which will determine the value we write back. This is
// known as read-modify-write.
if (NeedDestRead[Foreground] || NeedDestRead[Background]) {
Config2D |= b_Config2D_FBDestReadEnable;
WriteRegUlong(r_FBDestReadBufferAddr0,
VirtualToOffset(Parameters->Destination->Ptr));
WriteRegUlong(r_FBDestReadBufferWidth0,
Parameters->Destination->Size.cx);
WriteRegUlong(r_FBDestReadMode,
b_FBDestReadMode_ReadEnable |
b_FBDestReadMode_Enable0);
}
// Setup the blit source.
if (NeedSource[Foreground] || NeedSource[Background]) {
Render2D |= b_Render2D_FBReadSourceEnable;
Assert(Parameters->Source != NULL);
// !TODO! System memory sources?
Assert(Parameters->Source->Type == VideoMemory);
WriteRegUlong(r_FBSourceReadMode,
b_FBSourceReadMode_ReadEnable);
WriteRegUlong(r_FBSourceReadBufferAddr,
VirtualToOffset(Parameters->Source->Ptr));
WriteRegUlong(r_FBSourceReadBufferWidth,
Parameters->Source->Size.cx);
// This is the packed offset the memory needs to be moved if you view
// the entriety of video memory as a single surface.
SourceOffset = PackXY((Parameters->SourceRect->left - Parameters->DestRect->left),
(Parameters->SourceRect->top - Parameters->DestRect->top));
WriteRegUlong(r_FBSourceReadBufferOffset, SourceOffset);
// !TODO! bottom-up bitmaps.
if (Parameters->ScanXPositive) {
Render2D |= b_Render2D_IncreasingXWhenSet;
}
if (Parameters->ScanYPositive) {
Render2D |= b_Render2D_IncreasingYWhenSet;
}
// We need to do a blocking blit if the horizontal overlap is less than
// a single span apart.
if (Abs(Parameters->SourceRect->left - Parameters->DestRect->right) < 64) {
Config2D |= b_Config2D_Blocking;
}
}
else {
Assert(Parameters->Source == NULL);
// With no source, there can be no overlap.
// !TODO! bottom-up bitmaps?
Render2D |= (b_Render2D_IncreasingXWhenSet |
b_Render2D_IncreasingYWhenSet);
}
// Setup the blit pattern.
if (NeedPattern[Foreground] || NeedPattern[Background]) {
if (Parameters->PatternType == SolidPattern) {
// It's a solid brush, just set the color in. While the Permedia allows
// us the potential of a different solid color for foreground and
// background, GDI does not.
WriteRegUlong(r_ForegroundColor,
Parameters->FillValue);
WriteRegUlong(r_BackgroundColor,
Parameters->FillValue);
Config2D |= b_Config2D_UseConstantSource;
}
else if (Parameters->PatternType == BitmapPattern) {
// Load the bitmap brush into the hardware LUT.
HwBrush(Parameters);
Config2D |= b_Config2D_LUTModeEnable;
}
}
// Setup hardware color keying.
// We punt blits that have both source and destination color keys
// above.
if (Parameters->ColorKeyType != NoColorKey) {
// Color keying shared some bits with the alpha blending unit. We do not
// enable alpha blending, only set the relevant bits.
WriteRegUlong(r_AlphaBlendAlphaMode,
(1 << 14)); // AlphaConversion = Shift
// Set color format and order and conversion to shift. This is slightly
// hacky, but we know that the primary will always use the
// l_PixelTable, which is actually PERM3_FORMATs.
switch (((const PERM3_FORMAT *)GetPrimarySurface()->Format)->RDColorFormat) {
case 64: ColorFormat = 0; break;
case 65: ColorFormat = 2; break;
case 66: ColorFormat = 1; break;
case 80: ColorFormat = 3; break;
case 96: ColorFormat = 16; break;
case 97: ColorFormat = 18; break;
case 98: ColorFormat = 17; break;
case 112: ColorFormat = 19; break;
default:
Error(L"Unknown RDColorFormat!\n");
ColorFormat = 0;
break;
}
WriteRegUlong(r_AlphaBlendColorMode,
(ColorFormat << 12) |
(1 << 17));
if (Parameters->ColorKeyType == SourceColorKey) {
ResetChromaKey = TRUE;
WriteRegUlong(r_ChromaUpper,
Parameters->SourceColorKey->HighValue);
WriteRegUlong(r_ChromaLower,
Parameters->SourceColorKey->LowValue);
// Setup colors come from FBSourceData, if the color matches it is
// rejected. If it fails the test, it is passed.
WriteRegUlong(r_ChromaTestMode,
b_ChromaTestMode_Enable |
(1 << 3)); // Reject passed colors
}
else if (Parameters->ColorKeyType == DestColorKey) {
ResetChromaKey = TRUE;
WriteRegUlong(r_ChromaUpper,
Parameters->DestColorKey->HighValue);
WriteRegUlong(r_ChromaLower,
Parameters->DestColorKey->LowValue);
// Setup colors come from FBData, if the color matches it is
// passed. If it fails the test, it is rejected.
WriteRegUlong(r_ChromaTestMode,
b_ChromaTestMode_Enable |
(1 << 1) | // Source = FBData
(1 << 5)); // Reject failed colors
}
}
WriteRegUlong(r_Config2D, Config2D);
WriteRegUlong(r_Render2D, Render2D);
if (NeedMask) {
// Load the bit mask into the hardware.
UploadBitMask((const PERM3_SURFACE *)Parameters->Mask,
Parameters->MaskRect);
}
if (ResetClipping) {
// Turn off scissoring.
WriteRegUlong(r_ScissorModeAnd,
!b_ScissorModeAnd_UserScissorEnable);
}
if (ResetChromaKey) {
// Turn off chromakeying.
WriteRegUlong(r_ChromaTestModeAnd,
!b_ChromaTestModeAnd_Enable);
}
FnRetVal = TRUE;
Exit(L"HardwareBlt");
return FnRetVal;
}
USHORT
LookupLogicop(
BYTE Rop3
)
{
// LookupLogicop
// This function returns the appropriate Permedia3 logicop for a given
// raster operation. It returns an error code if no logicop can be used
// for the given ROP.
USHORT Logicop;
Enter(L"LookupLogicop");
switch (Rop3) {
case 0x00 : // 0
Logicop = 0x0; // Clear
break;
case 0x88 : // DSa
case 0xA0 : // DPa
Logicop = 0x1; // And
break;
case 0x44 : // SDna
case 0x50 : // PDna
Logicop = 0x2; // AndReverse
break;
case 0xCC : // S
case 0xF0 : // P
Logicop = 0x3; // Copy
break;
case 0x0A : // DPna
case 0x22 : // DSna
Logicop = 0x4; // AndInvert
break;
case 0xAA : // D
Logicop = 0x5; // Noop
break;
case 0x5A : // DPx
case 0x66 : // DSx
Logicop = 0x6; // Xor
break;
case 0xEE : // DSo
case 0xFA : // DPo
Logicop = 0x7; // Or
break;
case 0x05 : // DPon
case 0x11 : // DSon
Logicop = 0x8; // Nor
break;
case 0x99 : // DSxn
case 0xA5 : // DPxn
Logicop = 0x9; // Equiv
break;
case 0x55 : // Dn
Logicop = 0xA; // Invert
break;
case 0xDD : // SDno
case 0xF5 : // PDno
Logicop = 0xB; // OrReverse
break;
case 0x0F : // Pn
case 0x33 : // Sn
Logicop = 0xC; // CopyInvert
break;
case 0xAF : // DPno
case 0xBB : // DSno
Logicop = 0xD; // OrInvert
break;
case 0x5F : // DPan
case 0x77 : // DSan
Logicop = 0xE; // Nand
break;
case 0xFF : // 1
Logicop = 0xF; // Set
break;
default :
Logicop = NO_APPROPRIATE_OP;
break;
}
Exit(L"LookupLogicop");
return Logicop;
}
void
UploadBitMask(
const PERM3_SURFACE * Mask,
const RECT * Rect
)
{
// UploadBitMask
// This function sends a bit mask, as given by the pointer, stride and rect
// parameters to the hardware.
// A note on the organization of 1bpp surfaces:
// 1 bpp surfaces are organized as an array of lines, where each line's
// size (in bytes, always,) is given by the stride. Within the line, the
// top-left pixel is in bit 7 of the first byte and filled down so that
// pixel (7,0) is in bit 0 of the first byte. Pixel (8,0) is then bit 7
// of the 2nd byte.
// Local variables.
BYTE * Scanline;
BYTE * InScanline;
ULONG ScanlineCount;
ULONG CurrentBytesInScanline;
ULONG i;
union u_UlongWithByteAccess {
ULONG Ulong;
struct {
BYTE Byte1; // Bits 0-7
BYTE Byte2; // Bits 8-15
BYTE Byte3; // Bits 16-23
BYTE Byte4; // Bits 24-31
};
} TransferValue;
// Check parameters.
// !TODO!
Enter(L"UploadBitMask");
// We need to determine the byte that contains the first bits in the line.
Scanline = ((BYTE *)Mask->Ptr + (Rect->top * Mask->Stride) + (Rect->left / 8)); // !TODO! >> 3
ScanlineCount = RectHeight(Rect);
for (i = 0; i < ScanlineCount; i++) {
CurrentBytesInScanline = Mask->Stride;
InScanline = Scanline;
do {
TransferValue.Ulong = 0;
if (CurrentBytesInScanline >= 4) {
// We have at least a whole ulong left, so just transfer it.
WriteRegUlong(r_BitMaskPattern, *((ULONG UNALIGNED *)InScanline));
InScanline += 4;
CurrentBytesInScanline -= 4;
}
else if (CurrentBytesInScanline == 3) {
TransferValue.Byte1 = *InScanline++;
TransferValue.Byte2 = *InScanline++;
TransferValue.Byte3 = *InScanline++;
WriteRegUlong(r_BitMaskPattern, TransferValue.Ulong);
CurrentBytesInScanline -= 3;
}
else if (CurrentBytesInScanline == 2) {
TransferValue.Byte1 = *InScanline++;
TransferValue.Byte2 = *InScanline++;
WriteRegUlong(r_BitMaskPattern, TransferValue.Ulong);
CurrentBytesInScanline -= 2;
}
else if (CurrentBytesInScanline == 1) {
TransferValue.Byte1 = *InScanline++;
WriteRegUlong(r_BitMaskPattern, TransferValue.Ulong);
CurrentBytesInScanline -= 1;
}
} while (CurrentBytesInScanline > 0);
Scanline += Mask->Stride;
}
Exit(L"UploadBitMask");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -