From d23904afd22e9f94e4b73fbefefbf966fff303b3 Mon Sep 17 00:00:00 2001 From: narzoul Date: Fri, 26 Jul 2019 00:26:44 +0200 Subject: [PATCH] Prefer color fills in system memory --- DDrawCompat/D3dDdi/Device.cpp | 5 ++ DDrawCompat/D3dDdi/FormatInfo.cpp | 111 ++++++++++++++++++++++++ DDrawCompat/D3dDdi/FormatInfo.h | 25 ++++++ DDrawCompat/D3dDdi/Resource.cpp | 76 +++++++--------- DDrawCompat/D3dDdi/Resource.h | 5 +- DDrawCompat/DDraw/Blitter.cpp | 38 ++++++++ DDrawCompat/DDraw/Blitter.h | 1 + DDrawCompat/DDrawCompat.vcxproj | 2 + DDrawCompat/DDrawCompat.vcxproj.filters | 6 ++ 9 files changed, 225 insertions(+), 44 deletions(-) create mode 100644 DDrawCompat/D3dDdi/FormatInfo.cpp create mode 100644 DDrawCompat/D3dDdi/FormatInfo.h diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index 711c6e7..f0ed921 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -82,6 +82,11 @@ namespace D3dDdi HRESULT Device::colorFill(const D3DDDIARG_COLORFILL& data) { + auto it = m_resources.find(data.hResource); + if (it != m_resources.end()) + { + return it->second.colorFill(data); + } RenderGuard renderGuard(*this, Gdi::ACCESS_WRITE, data.hResource, data.SubResourceIndex); return m_origVtable.pfnColorFill(m_device, &data); } diff --git a/DDrawCompat/D3dDdi/FormatInfo.cpp b/DDrawCompat/D3dDdi/FormatInfo.cpp new file mode 100644 index 0000000..096c6d6 --- /dev/null +++ b/DDrawCompat/D3dDdi/FormatInfo.cpp @@ -0,0 +1,111 @@ +#include "D3dDdi/FormatInfo.h" + +namespace +{ + struct ArgbFormatInfo : D3dDdi::FormatInfo + { + ArgbFormatInfo(BYTE alphaBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount) + : FormatInfo(alphaBitCount, redBitCount, greenBitCount, blueBitCount) + { + redPos = greenBitCount + blueBitCount; + greenPos = blueBitCount; + } + }; + + struct AbgrFormatInfo : D3dDdi::FormatInfo + { + AbgrFormatInfo(BYTE alphaBitCount, BYTE blueBitCount, BYTE greenBitCount, BYTE redBitCount) + : FormatInfo(alphaBitCount, redBitCount, greenBitCount, blueBitCount) + { + bluePos = redBitCount + greenBitCount; + greenPos = redBitCount; + } + }; + + struct XrgbFormatInfo : ArgbFormatInfo + { + XrgbFormatInfo(BYTE unusedBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount) + : ArgbFormatInfo(0, redBitCount, greenBitCount, blueBitCount) + { + bytesPerPixel = (unusedBitCount + redBitCount + greenBitCount + blueBitCount + 7) / 8; + } + }; + + struct XbgrFormatInfo : AbgrFormatInfo + { + XbgrFormatInfo(BYTE unusedBitCount, BYTE blueBitCount, BYTE greenBitCount, BYTE redBitCount) + : AbgrFormatInfo(0, redBitCount, greenBitCount, blueBitCount) + { + bytesPerPixel = (unusedBitCount + redBitCount + greenBitCount + blueBitCount + 7) / 8; + } + }; +} + +namespace D3dDdi +{ + FormatInfo::FormatInfo(BYTE alphaBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount) + : bytesPerPixel((alphaBitCount + redBitCount + greenBitCount + blueBitCount + 7) / 8) + , alphaBitCount(alphaBitCount) + , alphaPos(redBitCount + greenBitCount + blueBitCount) + , redBitCount(redBitCount) + , redPos(0) + , greenBitCount(greenBitCount) + , greenPos(0) + , blueBitCount(blueBitCount) + , bluePos(0) + { + } + + D3DCOLOR colorConvert(const FormatInfo& dstFormatInfo, D3DCOLOR srcRgbaColor) + { + struct ArgbColor + { + BYTE blue; + BYTE green; + BYTE red; + BYTE alpha; + }; + + auto& srcColor = *reinterpret_cast(&srcRgbaColor); + + BYTE alpha = srcColor.alpha >> (8 - dstFormatInfo.alphaBitCount); + BYTE red = srcColor.red >> (8 - dstFormatInfo.redBitCount); + BYTE green = srcColor.green >> (8 - dstFormatInfo.greenBitCount); + BYTE blue = srcColor.blue >> (8 - dstFormatInfo.blueBitCount); + + return (alpha << dstFormatInfo.alphaPos) | + (red << dstFormatInfo.redPos) | + (green << dstFormatInfo.greenPos) | + (blue << dstFormatInfo.bluePos); + } + + FormatInfo getFormatInfo(D3DDDIFORMAT format) + { + switch (format) + { + case D3DDDIFMT_R3G3B2: return ArgbFormatInfo(0, 3, 3, 2); + case D3DDDIFMT_A8: return ArgbFormatInfo(8, 0, 0, 0); + case D3DDDIFMT_P8: return ArgbFormatInfo(0, 0, 0, 8); + case D3DDDIFMT_R8: return ArgbFormatInfo(0, 8, 0, 0); + + case D3DDDIFMT_R5G6B5: return ArgbFormatInfo(0, 5, 6, 5); + case D3DDDIFMT_X1R5G5B5: return XrgbFormatInfo(1, 5, 5, 5); + case D3DDDIFMT_A1R5G5B5: return ArgbFormatInfo(1, 5, 5, 5); + case D3DDDIFMT_A4R4G4B4: return ArgbFormatInfo(4, 4, 4, 4); + case D3DDDIFMT_A8R3G3B2: return ArgbFormatInfo(8, 3, 3, 2); + case D3DDDIFMT_X4R4G4B4: return XrgbFormatInfo(4, 4, 4, 4); + case D3DDDIFMT_A8P8: return ArgbFormatInfo(8, 0, 0, 8); + case D3DDDIFMT_G8R8: return AbgrFormatInfo(0, 0, 8, 8); + + case D3DDDIFMT_R8G8B8: return ArgbFormatInfo(0, 8, 8, 8); + + case D3DDDIFMT_A8R8G8B8: return ArgbFormatInfo(8, 8, 8, 8); + case D3DDDIFMT_X8R8G8B8: return XrgbFormatInfo(8, 8, 8, 8); + case D3DDDIFMT_A8B8G8R8: return AbgrFormatInfo(8, 8, 8, 8); + case D3DDDIFMT_X8B8G8R8: return XbgrFormatInfo(8, 8, 8, 8); + + default: + return FormatInfo(); + } + } +} diff --git a/DDrawCompat/D3dDdi/FormatInfo.h b/DDrawCompat/D3dDdi/FormatInfo.h new file mode 100644 index 0000000..f4e08e7 --- /dev/null +++ b/DDrawCompat/D3dDdi/FormatInfo.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace D3dDdi +{ + struct FormatInfo + { + BYTE bytesPerPixel; + BYTE alphaBitCount; + BYTE alphaPos; + BYTE redBitCount; + BYTE redPos; + BYTE greenBitCount; + BYTE greenPos; + BYTE blueBitCount; + BYTE bluePos; + + FormatInfo(BYTE alphaBitCount = 0, BYTE redBitCount = 0, BYTE greenBitCount = 0, BYTE blueBitCount = 0); + }; + + D3DCOLOR colorConvert(const FormatInfo& dstFormatInfo, D3DCOLOR srcRgbaColor); + FormatInfo getFormatInfo(D3DDDIFORMAT format); +} diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 7891891..5c1dc22 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -11,7 +11,6 @@ namespace { - UINT getBytesPerPixel(D3DDDIFORMAT format); D3DDDI_RESOURCEFLAGS getResourceTypeFlags(); void splitToTiles(D3DDDIARG_CREATERESOURCE& data, const UINT tileWidth, const UINT tileHeight); @@ -34,7 +33,7 @@ namespace (isOffScreenPlain || data.Flags.Texture) && 1 == data.SurfCount && 0 == data.pSurfList[0].Depth && - 0 != getBytesPerPixel(data.Format)) + 0 != D3dDdi::getFormatInfo(data.Format).bytesPerPixel) { const auto& caps = device.getAdapter().getD3dExtendedCaps(); const auto& surfaceInfo = data.pSurfList[0]; @@ -46,40 +45,6 @@ namespace } } - UINT getBytesPerPixel(D3DDDIFORMAT format) - { - switch (format) - { - case D3DDDIFMT_R3G3B2: - case D3DDDIFMT_A8: - case D3DDDIFMT_P8: - case D3DDDIFMT_R8: - return 1; - - case D3DDDIFMT_R5G6B5: - case D3DDDIFMT_X1R5G5B5: - case D3DDDIFMT_A1R5G5B5: - case D3DDDIFMT_A4R4G4B4: - case D3DDDIFMT_A8R3G3B2: - case D3DDDIFMT_X4R4G4B4: - case D3DDDIFMT_A8P8: - case D3DDDIFMT_G8R8: - return 2; - - case D3DDDIFMT_R8G8B8: - return 3; - - case D3DDDIFMT_A8R8G8B8: - case D3DDDIFMT_X8R8G8B8: - case D3DDDIFMT_A8B8G8R8: - case D3DDDIFMT_X8B8G8R8: - return 4; - - default: - return 0; - } - } - D3DDDI_RESOURCEFLAGS getResourceTypeFlags() { D3DDDI_RESOURCEFLAGS flags = {}; @@ -109,7 +74,7 @@ namespace static std::vector tiles; tiles.clear(); - const UINT bytesPerPixel = getBytesPerPixel(data.Format); + const UINT bytesPerPixel = D3dDdi::getFormatInfo(data.Format).bytesPerPixel; for (UINT y = 0; y < data.pSurfList[0].Height; y += tileHeight) { @@ -216,7 +181,6 @@ namespace D3dDdi : m_device(device) , m_handle(nullptr) , m_origData(data) - , m_bytesPerPixel(0) , m_rootSurface(nullptr) , m_lockResource(nullptr) { @@ -279,7 +243,7 @@ namespace D3dDdi unsigned char* ptr = static_cast(lockData.data); if (data.Flags.AreaValid) { - ptr += data.Area.top * lockData.pitch + data.Area.left * m_bytesPerPixel; + ptr += data.Area.top * lockData.pitch + data.Area.left * m_formatInfo.bytesPerPixel; } data.pSurfData = ptr; @@ -303,6 +267,32 @@ namespace D3dDdi return LOG_RESULT(S_OK); } + HRESULT Resource::colorFill(const D3DDDIARG_COLORFILL& data) + { + LOG_FUNC("Resource::colorFill", data); + if (data.SubResourceIndex < m_lockData.size() && 0 != m_formatInfo.bytesPerPixel) + { + auto& lockData = m_lockData[data.SubResourceIndex]; + if (lockData.isSysMemUpToDate) + { + auto dstBuf = static_cast(lockData.data) + + data.DstRect.top * lockData.pitch + data.DstRect.left * m_formatInfo.bytesPerPixel; + + DDraw::Blitter::colorFill(dstBuf, lockData.pitch, + data.DstRect.right - data.DstRect.left, data.DstRect.bottom - data.DstRect.top, + m_formatInfo.bytesPerPixel, colorConvert(m_formatInfo, data.Color)); + + if (lockData.isVidMemUpToDate) + { + setVidMemUpToDate(data.SubResourceIndex, false); + } + return LOG_RESULT(S_OK); + } + } + prepareForRendering(data.SubResourceIndex, false); + return LOG_RESULT(m_device.getOrigVtable().pfnColorFill(m_device, &data)); + } + HRESULT Resource::copySubResource(Resource& dstResource, Resource& srcResource, UINT subResourceIndex) { RECT rect = {}; @@ -344,7 +334,7 @@ namespace D3dDdi Arg origData = data; fixResourceData(device, reinterpret_cast(data)); resource.m_fixedData = data; - resource.m_bytesPerPixel = getBytesPerPixel(data.Format); + resource.m_formatInfo = getFormatInfo(data.Format); HRESULT result = createResourceFunc(device, &data); if (FAILED(result)) @@ -625,9 +615,9 @@ namespace D3dDdi if (dstGuard.data) { auto dstBuf = static_cast(dstGuard.data) + - data.DstRect.top * dstGuard.pitch + data.DstRect.left * m_bytesPerPixel; + data.DstRect.top * dstGuard.pitch + data.DstRect.left * m_formatInfo.bytesPerPixel; auto srcBuf = static_cast(srcGuard.data) + - data.SrcRect.top * srcGuard.pitch + data.SrcRect.left * m_bytesPerPixel; + data.SrcRect.top * srcGuard.pitch + data.SrcRect.left * m_formatInfo.bytesPerPixel; DDraw::Blitter::blt( dstBuf, @@ -638,7 +628,7 @@ namespace D3dDdi srcGuard.pitch, (1 - 2 * data.Flags.MirrorLeftRight) * (data.SrcRect.right - data.SrcRect.left), (1 - 2 * data.Flags.MirrorUpDown) * (data.SrcRect.bottom - data.SrcRect.top), - m_bytesPerPixel, + m_formatInfo.bytesPerPixel, data.Flags.DstColorKey ? reinterpret_cast(&data.ColorKey) : nullptr, data.Flags.SrcColorKey ? reinterpret_cast(&data.ColorKey) : nullptr); diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 39e358c..bb88945 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -6,6 +6,8 @@ #include #include +#include "D3dDdi/FormatInfo.h" + namespace DDraw { class Surface; @@ -24,6 +26,7 @@ namespace D3dDdi operator HANDLE() const { return m_handle; } HRESULT blt(D3DDDIARG_BLT data); + HRESULT colorFill(const D3DDDIARG_COLORFILL& data); void destroy(); HRESULT lock(D3DDDIARG_LOCK& data); void prepareForRendering(UINT subResourceIndex, bool isReadOnly); @@ -92,7 +95,7 @@ namespace D3dDdi HANDLE m_handle; Data m_origData; Data m_fixedData; - UINT m_bytesPerPixel; + FormatInfo m_formatInfo; DDraw::Surface* m_rootSurface; Resource* m_lockResource; std::vector m_lockData; diff --git a/DDrawCompat/DDraw/Blitter.cpp b/DDrawCompat/DDraw/Blitter.cpp index 86fc84d..6903dcb 100644 --- a/DDrawCompat/DDraw/Blitter.cpp +++ b/DDrawCompat/DDraw/Blitter.cpp @@ -636,6 +636,33 @@ namespace vectorizedBltFunc(dst, dstPitch, dstWidth, dstHeight, src, srcPitch, offsetX, deltaX, offsetY, deltaY, dstCk, srcCk); } + + template + void colorFill(BYTE* dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight, DWORD color) + { + DWORD c = 0; + memset(&c, color, sizeof(Pixel)); + if (c == color) + { + for (DWORD i = dstHeight; i != 0; --i) + { + memset(dst, color, dstWidth * sizeof(Pixel)); + dst += dstPitch; + } + return; + } + + for (DWORD i = 0; i < dstWidth; ++i) + { + reinterpret_cast(dst)[i] = static_cast(color); + } + + for (DWORD i = dstHeight - 1; i != 0; --i) + { + memcpy(dst + dstPitch, dst, dstWidth * sizeof(Pixel)); + dst += dstPitch; + } + } } namespace DDraw @@ -650,5 +677,16 @@ namespace DDraw static_cast(src), srcPitch, srcWidth, srcHeight, bytesPerPixel, dstColorKey, srcColorKey); } + + void colorFill(void* dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight, DWORD bytesPerPixel, DWORD color) + { + switch (bytesPerPixel) + { + case 1: return ::colorFill(static_cast(dst), dstPitch, dstWidth, dstHeight, color); + case 2: return ::colorFill(static_cast(dst), dstPitch, dstWidth, dstHeight, color); + case 3: return ::colorFill(static_cast(dst), dstPitch, dstWidth, dstHeight, color); + case 4: return ::colorFill(static_cast(dst), dstPitch, dstWidth, dstHeight, color); + } + } } } diff --git a/DDrawCompat/DDraw/Blitter.h b/DDrawCompat/DDraw/Blitter.h index 09417c8..9e4edff 100644 --- a/DDrawCompat/DDraw/Blitter.h +++ b/DDrawCompat/DDraw/Blitter.h @@ -11,5 +11,6 @@ namespace DDraw void blt(void* dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight, const void* src, DWORD srcPitch, LONG srcWidth, LONG srcHeight, DWORD bytesPerPixel, const DWORD* dstColorKey, const DWORD* srcColorKey); + void colorFill(void* dst, DWORD dstPitch, DWORD dstWidth, DWORD dstHeight, DWORD bytesPerPixel, DWORD color); } } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index a379819..8c70a30 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -157,6 +157,7 @@ + @@ -234,6 +235,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 3920133..3aa7edf 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -351,6 +351,9 @@ Header Files\DDraw + + Header Files\D3dDdi + @@ -533,6 +536,9 @@ Source Files\DDraw + + Source Files\D3dDdi +