diff --git a/DDrawCompat/Common/Comparison.h b/DDrawCompat/Common/Comparison.h index 651a29c..974a486 100644 --- a/DDrawCompat/Common/Comparison.h +++ b/DDrawCompat/Common/Comparison.h @@ -23,6 +23,12 @@ std::enable_if_t && std::is_trivial_v, bool> operator<(con return toTuple(left) < toTuple(right); } +inline auto toTuple(const GUID& guid) +{ + const auto data4 = *reinterpret_cast(&guid.Data4); + return std::make_tuple(guid.Data1, guid.Data2, guid.Data3, data4); +} + inline auto toTuple(const LUID& luid) { return std::make_tuple(luid.LowPart, luid.HighPart); @@ -38,6 +44,11 @@ inline auto toTuple(const RGBQUAD& q) return std::make_tuple(q.rgbBlue, q.rgbGreen, q.rgbRed, q.rgbReserved); } +inline auto toTuple(const RECT& rect) +{ + return std::make_tuple(rect.left, rect.top, rect.right, rect.bottom); +} + inline auto toTuple(const SIZE& size) { return std::make_tuple(size.cx, size.cy); diff --git a/DDrawCompat/Config/Config.cpp b/DDrawCompat/Config/Config.cpp index d3989dc..5c5e436 100644 --- a/DDrawCompat/Config/Config.cpp +++ b/DDrawCompat/Config/Config.cpp @@ -23,6 +23,7 @@ namespace Config Settings::RemoveBorders removeBorders; Settings::RenderColorDepth renderColorDepth; Settings::ResolutionScale resolutionScale; + Settings::SoftwareDevice softwareDevice; Settings::SpriteDetection spriteDetection; Settings::SpriteFilter spriteFilter; Settings::SpriteTexCoord spriteTexCoord; diff --git a/DDrawCompat/Config/Config.h b/DDrawCompat/Config/Config.h index 60f644c..948627e 100644 --- a/DDrawCompat/Config/Config.h +++ b/DDrawCompat/Config/Config.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ namespace Config extern Settings::RemoveBorders removeBorders; extern Settings::RenderColorDepth renderColorDepth; extern Settings::ResolutionScale resolutionScale; + extern Settings::SoftwareDevice softwareDevice; extern Settings::SpriteDetection spriteDetection; extern Settings::SpriteFilter spriteFilter; extern Settings::SpriteTexCoord spriteTexCoord; diff --git a/DDrawCompat/Config/Settings/SoftwareDevice.h b/DDrawCompat/Config/Settings/SoftwareDevice.h new file mode 100644 index 0000000..1e7cde4 --- /dev/null +++ b/DDrawCompat/Config/Settings/SoftwareDevice.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include + +namespace Config +{ + namespace Settings + { + class SoftwareDevice : public MappedSetting + { + public: + SoftwareDevice() + : MappedSetting("SoftwareDevice", "rgb", { + {"app", nullptr}, + {"hal", &IID_IDirect3DHALDevice}, + {"ref", &IID_IDirect3DRefDevice}, + {"rgb", &IID_IDirect3DRGBDevice} + }) + { + } + }; + } +} diff --git a/DDrawCompat/D3dDdi/Adapter.cpp b/DDrawCompat/D3dDdi/Adapter.cpp index 9cc516a..194f98f 100644 --- a/DDrawCompat/D3dDdi/Adapter.cpp +++ b/DDrawCompat/D3dDdi/Adapter.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace @@ -55,12 +56,17 @@ namespace D3dDdi info.formatOps = getFormatOps(); info.supportedZBufferBitDepths = getSupportedZBufferBitDepths(info.formatOps); + info.isMsaaDepthResolveSupported = + info.formatOps.find(FOURCC_RESZ) != info.formatOps.end() && + info.formatOps.find(FOURCC_INTZ) != info.formatOps.end() && + info.formatOps.find(FOURCC_NULL) != info.formatOps.end(); + LOG_INFO << "Supported z-buffer bit depths: " << bitDepthsToString(info.supportedZBufferBitDepths); LOG_INFO << "Supported MSAA modes: " << getSupportedMsaaModes(info.formatOps); - LOG_DEBUG << "Supported resource formats:"; + LOG_INFO << "Supported resource formats:"; for (const auto& formatOp : info.formatOps) { - LOG_DEBUG << " " << formatOp.second; + LOG_INFO << " " << formatOp.second; } return info; diff --git a/DDrawCompat/D3dDdi/Adapter.h b/DDrawCompat/D3dDdi/Adapter.h index 1d4d11f..97a78e8 100644 --- a/DDrawCompat/D3dDdi/Adapter.h +++ b/DDrawCompat/D3dDdi/Adapter.h @@ -20,6 +20,7 @@ namespace D3dDdi D3DNTHAL_D3DEXTENDEDCAPS d3dExtendedCaps; std::map formatOps; DWORD supportedZBufferBitDepths; + bool isMsaaDepthResolveSupported; }; Adapter(const D3DDDIARG_OPENADAPTER& data); diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index d4ea847..383de9c 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -28,6 +28,7 @@ namespace D3dDdi , m_adapter(adapter) , m_device(device) , m_eventQuery(nullptr) + , m_depthStencil(nullptr) , m_renderTarget(nullptr) , m_renderTargetSubResourceIndex(0) , m_sharedPrimary(nullptr) @@ -107,12 +108,21 @@ namespace D3dDdi void Device::prepareForGpuWrite() { + if (m_depthStencil) + { + m_depthStencil->prepareForGpuWrite(0); + } if (m_renderTarget) { m_renderTarget->prepareForGpuWrite(m_renderTargetSubResourceIndex); } } + void Device::setDepthStencil(HANDLE resource) + { + m_depthStencil = getResource(resource); + } + void Device::setGdiResourceHandle(HANDLE resource) { LOG_FUNC("Device::setGdiResourceHandle", resource); @@ -166,19 +176,16 @@ namespace D3dDdi HRESULT Device::pfnClear(const D3DDDIARG_CLEAR* data, UINT numRect, const RECT* rect) { flushPrimitives(); - if (data->Flags & D3DCLEAR_TARGET) - { - setRenderTarget(m_state.getAppState().renderTarget); - prepareForGpuWrite(); - } + prepareForGpuWrite(); m_state.flush(); - if (m_renderTarget && rect) + if ((m_renderTarget || m_depthStencil) && rect) { std::vector scaledRect(rect, rect + numRect); + auto resource = m_renderTarget ? m_renderTarget : m_depthStencil; for (UINT i = 0; i < numRect; ++i) { - m_renderTarget->scaleRect(scaledRect[i]); + resource->scaleRect(scaledRect[i]); } return m_origVtable.pfnClear(m_device, data, numRect, scaledRect.data()); } @@ -188,6 +195,7 @@ namespace D3dDdi HRESULT Device::pfnColorFill(const D3DDDIARG_COLORFILL* data) { + flushPrimitives(); auto it = m_resources.find(data->hResource); if (it != m_resources.end()) { @@ -226,6 +234,30 @@ namespace D3dDdi } } + HRESULT Device::pfnDepthFill(const D3DDDIARG_DEPTHFILL* data) + { + flushPrimitives(); + auto resource = getResource(data->hResource); + auto customResource = resource->getCustomResource(); + auto fi = getFormatInfo(resource->getFixedDesc().Format); + resource->prepareForGpuWrite(0); + + m_state.setTempDepthStencil({ customResource ? *customResource : *resource }); + + RECT rect = data->DstRect; + resource->scaleRect(rect); + + D3DDDIARG_CLEAR clear = {}; + clear.Flags = D3DCLEAR_ZBUFFER; + clear.FillDepth = getComponentAsFloat(data->Depth, fi.depth); + if (0 != fi.stencil.bitCount) + { + clear.Flags |= D3DCLEAR_STENCIL; + clear.FillStencil = getComponent(data->Depth, fi.stencil); + } + return m_origVtable.pfnClear(m_device, &clear, 1, &rect); + } + HRESULT Device::pfnDestroyDevice() { auto device = m_device; @@ -247,6 +279,15 @@ namespace D3dDdi D3DKMTReleaseProcessVidPnSourceOwners(GetCurrentProcess()); } + if (m_renderTarget && resource == *m_renderTarget) + { + m_renderTarget = nullptr; + } + else if (m_depthStencil && resource == *m_depthStencil) + { + m_depthStencil = nullptr; + } + HRESULT result = m_origVtable.pfnDestroyResource(m_device, resource); if (SUCCEEDED(result)) { @@ -373,7 +414,7 @@ namespace D3dDdi auto it = m_resources.find(data->hResource); if (it != m_resources.end()) { - it->second->setPaletteHandle(data->PaletteHandle); + it->second->setPaletteHandle(data->PaletteHandle); } return S_OK; } diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h index 78f137d..ac7bac8 100644 --- a/DDrawCompat/D3dDdi/Device.h +++ b/DDrawCompat/D3dDdi/Device.h @@ -35,6 +35,7 @@ namespace D3dDdi HRESULT pfnColorFill(const D3DDDIARG_COLORFILL* data); HRESULT pfnCreateResource(D3DDDIARG_CREATERESOURCE* data); HRESULT pfnCreateResource2(D3DDDIARG_CREATERESOURCE2* data); + HRESULT pfnDepthFill(const D3DDDIARG_DEPTHFILL* data); HRESULT pfnDestroyDevice(); HRESULT pfnDestroyResource(HANDLE resource); HRESULT pfnDrawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2* data, @@ -61,6 +62,7 @@ namespace D3dDdi HRESULT createPrivateResource(D3DDDIARG_CREATERESOURCE2& data); void flushPrimitives() { m_drawPrimitive.flushPrimitives(); } void prepareForGpuWrite(); + void setDepthStencil(HANDLE resource); void setRenderTarget(const D3DDDIARG_SETRENDERTARGET& data); void updateConfig(); void waitForIdle(); @@ -83,6 +85,7 @@ namespace D3dDdi HANDLE m_device; HANDLE m_eventQuery; std::map> m_resources; + Resource* m_depthStencil; Resource* m_renderTarget; UINT m_renderTargetSubResourceIndex; HANDLE m_sharedPrimary; diff --git a/DDrawCompat/D3dDdi/DeviceFuncs.cpp b/DDrawCompat/D3dDdi/DeviceFuncs.cpp index 6ee6830..955564e 100644 --- a/DDrawCompat/D3dDdi/DeviceFuncs.cpp +++ b/DDrawCompat/D3dDdi/DeviceFuncs.cpp @@ -54,6 +54,7 @@ namespace SET_DEVICE_FUNC(pfnColorFill); SET_DEVICE_FUNC(pfnCreateResource); SET_DEVICE_FUNC(pfnCreateResource2); + SET_DEVICE_FUNC(pfnDepthFill); SET_DEVICE_FUNC(pfnDestroyDevice); SET_DEVICE_FUNC(pfnDestroyResource); SET_DEVICE_FUNC(pfnDrawIndexedPrimitive2); @@ -94,7 +95,6 @@ namespace SET_FLUSH_PRIMITIVES_FUNC(pfnBufBlt); SET_FLUSH_PRIMITIVES_FUNC(pfnBufBlt1); - SET_FLUSH_PRIMITIVES_FUNC(pfnDepthFill); SET_FLUSH_PRIMITIVES_FUNC(pfnDiscard); SET_FLUSH_PRIMITIVES_FUNC(pfnGenerateMipSubLevels); SET_FLUSH_PRIMITIVES_FUNC(pfnSetClipPlane); diff --git a/DDrawCompat/D3dDdi/DeviceState.cpp b/DDrawCompat/D3dDdi/DeviceState.cpp index 56a0d6f..a999d09 100644 --- a/DDrawCompat/D3dDdi/DeviceState.cpp +++ b/DDrawCompat/D3dDdi/DeviceState.cpp @@ -432,6 +432,7 @@ namespace D3dDdi { m_app.depthStencil = *data; m_changedStates |= CS_RENDER_TARGET; + m_device.setDepthStencil(data->hZBuffer); return S_OK; } @@ -469,6 +470,7 @@ namespace D3dDdi { m_app.renderTarget = *data; m_changedStates |= CS_RENDER_TARGET; + m_device.setRenderTarget(*data); return S_OK; } @@ -751,7 +753,6 @@ namespace D3dDdi void DeviceState::setTempRenderTarget(const D3DDDIARG_SETRENDERTARGET& renderTarget) { setRenderTarget(renderTarget); - m_device.setRenderTarget({}); m_changedStates |= CS_RENDER_TARGET; } @@ -958,7 +959,6 @@ namespace D3dDdi } setRenderTarget(renderTarget); - m_device.setRenderTarget(m_app.renderTarget); setDepthStencil(depthStencil); setViewport(vp); diff --git a/DDrawCompat/D3dDdi/DeviceState.h b/DDrawCompat/D3dDdi/DeviceState.h index bdc8835..004855d 100644 --- a/DDrawCompat/D3dDdi/DeviceState.h +++ b/DDrawCompat/D3dDdi/DeviceState.h @@ -127,6 +127,7 @@ namespace D3dDdi void disableTextureClamp(UINT stage); void flush(); const State& getAppState() const { return m_app; } + const State& getCurrentState() const { return m_current; } Resource* getTextureResource(UINT stage); const VertexDecl& getVertexDecl() const; HANDLE getVertexFixupDecl() const { return m_vsVertexFixup.get(); } diff --git a/DDrawCompat/D3dDdi/DrawPrimitive.cpp b/DDrawCompat/D3dDdi/DrawPrimitive.cpp index 5a10e57..bad0a12 100644 --- a/DDrawCompat/D3dDdi/DrawPrimitive.cpp +++ b/DDrawCompat/D3dDdi/DrawPrimitive.cpp @@ -454,14 +454,10 @@ namespace D3dDdi HRESULT DrawPrimitive::draw(D3DDDIARG_DRAWPRIMITIVE data, const UINT* flagBuffer) { auto& state = m_device.getState(); - if (!state.isLocked()) - { - state.updateStreamSource(); - } - auto vertexCount = getVertexCount(data.PrimitiveType, data.PrimitiveCount); if (!state.isLocked()) { + state.updateStreamSource(); if (m_streamSource.vertices && data.PrimitiveType >= D3DPT_TRIANGLELIST) { bool spriteMode = isSprite(data.VStart, 0, 1, 2); @@ -475,7 +471,6 @@ namespace D3dDdi { state.setSpriteMode(false); } - m_device.setRenderTarget(state.getAppState().renderTarget); m_device.prepareForGpuWrite(); state.flush(); } @@ -533,7 +528,6 @@ namespace D3dDdi { state.setSpriteMode(false); } - m_device.setRenderTarget(state.getAppState().renderTarget); m_device.prepareForGpuWrite(); state.flush(); } @@ -644,7 +638,10 @@ namespace D3dDdi } LOG_DEBUG << "Flushing " << m_batched.primitiveCount << " primitives of type " << m_batched.primitiveType; - m_device.prepareForGpuWrite(); + if (!m_device.getState().isLocked()) + { + m_device.prepareForGpuWrite(); + } return m_batched.indices.empty() ? flush(flagBuffer) : flushIndexed(flagBuffer); } diff --git a/DDrawCompat/D3dDdi/FormatInfo.cpp b/DDrawCompat/D3dDdi/FormatInfo.cpp index a1d83a4..f82239a 100644 --- a/DDrawCompat/D3dDdi/FormatInfo.cpp +++ b/DDrawCompat/D3dDdi/FormatInfo.cpp @@ -15,8 +15,8 @@ namespace RgbFormatInfo(BYTE unusedBitCount, BYTE alphaBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount) : FormatInfo(unusedBitCount, alphaBitCount, redBitCount, greenBitCount, blueBitCount) { - redPos = greenBitCount + blueBitCount; - greenPos = blueBitCount; + red.pos = greenBitCount + blueBitCount; + green.pos = blueBitCount; } }; @@ -25,37 +25,67 @@ namespace BgrFormatInfo(BYTE unusedBitCount, BYTE alphaBitCount, BYTE blueBitCount, BYTE greenBitCount, BYTE redBitCount) : FormatInfo(unusedBitCount, alphaBitCount, redBitCount, greenBitCount, blueBitCount) { - greenPos = redBitCount; - bluePos = redBitCount + greenBitCount; + green.pos = redBitCount; + blue.pos = redBitCount + greenBitCount; } }; - float getComponent(D3DCOLOR color, BYTE bitCount, BYTE pos) + struct DxsFormatInfo : D3dDdi::FormatInfo { - if (0 == bitCount) + DxsFormatInfo(BYTE depthBitCount, BYTE unusedBitCount, BYTE stencilBitCount) + : FormatInfo(unusedBitCount, depthBitCount, stencilBitCount) { - return 0; + depth.pos = unusedBitCount + stencilBitCount; + unused.pos = stencilBitCount; } - const UINT max = (1 << bitCount) - 1; - const UINT mask = max << pos; - return static_cast((color & mask) >> pos) / max; + }; + + struct XsdFormatInfo : D3dDdi::FormatInfo + { + XsdFormatInfo(BYTE unusedBitCount, BYTE stencilBitCount, BYTE depthBitCount) + : FormatInfo(unusedBitCount, depthBitCount, stencilBitCount) + { + unused.pos = stencilBitCount + depthBitCount; + stencil.pos = depthBitCount; + } + }; + + DWORD getMask(const D3dDdi::FormatInfo::Component& component) + { + return ((1 << component.bitCount) - 1) << component.pos; } } namespace D3dDdi { + FormatInfo::FormatInfo() + { + memset(this, 0, sizeof(*this)); + } + FormatInfo::FormatInfo(BYTE unusedBitCount, BYTE alphaBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount) : bitsPerPixel(unusedBitCount + alphaBitCount + redBitCount + greenBitCount + blueBitCount) , bytesPerPixel((bitsPerPixel + 7) / 8) - , unusedBitCount(unusedBitCount) - , alphaBitCount(alphaBitCount) - , alphaPos(redBitCount + greenBitCount + blueBitCount) - , redBitCount(redBitCount) - , redPos(0) - , greenBitCount(greenBitCount) - , greenPos(0) - , blueBitCount(blueBitCount) - , bluePos(0) + , unused{ unusedBitCount, static_cast(alphaBitCount + redBitCount + greenBitCount + blueBitCount) } + , alpha{ alphaBitCount, static_cast(redBitCount + greenBitCount + blueBitCount) } + , red{ redBitCount, 0 } + , green{ greenBitCount, 0 } + , blue{ blueBitCount, 0 } + , depth{} + , stencil{} + { + } + + FormatInfo::FormatInfo(BYTE unusedBitCount, BYTE depthBitCount, BYTE stencilBitCount) + : bitsPerPixel(unusedBitCount + depthBitCount + stencilBitCount) + , bytesPerPixel((bitsPerPixel + 7) / 8) + , unused{ unusedBitCount, 0 } + , alpha{} + , red{} + , green{} + , blue{} + , depth{ depthBitCount, 0 } + , stencil{ stencilBitCount, 0 } { } @@ -63,27 +93,43 @@ namespace D3dDdi { auto& src = *reinterpret_cast(&srcColor); - BYTE alpha = src.alpha >> (8 - dstFormatInfo.alphaBitCount); - BYTE red = src.red >> (8 - dstFormatInfo.redBitCount); - BYTE green = src.green >> (8 - dstFormatInfo.greenBitCount); - BYTE blue = src.blue >> (8 - dstFormatInfo.blueBitCount); + BYTE alpha = src.alpha >> (8 - dstFormatInfo.alpha.bitCount); + BYTE red = src.red >> (8 - dstFormatInfo.red.bitCount); + BYTE green = src.green >> (8 - dstFormatInfo.green.bitCount); + BYTE blue = src.blue >> (8 - dstFormatInfo.blue.bitCount); - return (alpha << dstFormatInfo.alphaPos) | - (red << dstFormatInfo.redPos) | - (green << dstFormatInfo.greenPos) | - (blue << dstFormatInfo.bluePos); + return (alpha << dstFormatInfo.alpha.pos) | + (red << dstFormatInfo.red.pos) | + (green << dstFormatInfo.green.pos) | + (blue << dstFormatInfo.blue.pos); } DeviceState::ShaderConstF convertToShaderConst(const FormatInfo& srcFormatInfo, D3DCOLOR srcColor) { return { - getComponent(srcColor, srcFormatInfo.redBitCount, srcFormatInfo.redPos), - getComponent(srcColor, srcFormatInfo.greenBitCount, srcFormatInfo.greenPos), - getComponent(srcColor, srcFormatInfo.blueBitCount, srcFormatInfo.bluePos), - getComponent(srcColor, srcFormatInfo.alphaBitCount, srcFormatInfo.alphaPos) + getComponentAsFloat(srcColor, srcFormatInfo.red), + getComponentAsFloat(srcColor, srcFormatInfo.green), + getComponentAsFloat(srcColor, srcFormatInfo.blue), + getComponentAsFloat(srcColor, srcFormatInfo.alpha) }; } + DWORD getComponent(D3DCOLOR color, const D3dDdi::FormatInfo::Component& component) + { + return (color & getMask(component)) >> component.pos; + } + + float getComponentAsFloat(D3DCOLOR color, const D3dDdi::FormatInfo::Component& component) + { + if (0 == component.bitCount) + { + return 0; + } + const UINT max = (1 << component.bitCount) - 1; + const UINT mask = max << component.pos; + return static_cast((color & mask) >> component.pos) / max; + } + FormatInfo getFormatInfo(D3DDDIFORMAT format) { switch (format) @@ -109,6 +155,17 @@ namespace D3dDdi case D3DDDIFMT_A8B8G8R8: return BgrFormatInfo(0, 8, 8, 8, 8); case D3DDDIFMT_X8B8G8R8: return BgrFormatInfo(8, 0, 8, 8, 8); + case D3DDDIFMT_D32: return DxsFormatInfo(32, 0, 0); + case D3DDDIFMT_D15S1: return DxsFormatInfo(15, 0, 1); + case D3DDDIFMT_D24S8: return DxsFormatInfo(24, 0, 8); + case D3DDDIFMT_D24X8: return DxsFormatInfo(24, 8, 0); + case D3DDDIFMT_D24X4S4: return DxsFormatInfo(24, 4, 4); + case D3DDDIFMT_D16: return DxsFormatInfo(16, 0, 0); + case D3DDDIFMT_S1D15: return XsdFormatInfo(0, 1, 15); + case D3DDDIFMT_S8D24: return XsdFormatInfo(0, 8, 24); + case D3DDDIFMT_X8D24: return XsdFormatInfo(8, 0, 24); + case D3DDDIFMT_X4S4D24: return XsdFormatInfo(4, 4, 24); + default: return FormatInfo(); } @@ -124,18 +181,34 @@ namespace D3dDdi DDPIXELFORMAT pf = {}; pf.dwSize = sizeof(pf); - pf.dwRGBBitCount = info.bitsPerPixel; - if (0 != pf.dwRGBBitCount) + if (0 != info.depth.bitCount) { - pf.dwFlags = DDPF_RGB; - pf.dwRBitMask = (0xFF >> (8 - info.redBitCount)) << info.redPos; - pf.dwGBitMask = (0xFF >> (8 - info.greenBitCount)) << info.greenPos; - pf.dwBBitMask = (0xFF >> (8 - info.blueBitCount)) << info.bluePos; + pf.dwFlags = DDPF_ZBUFFER; + pf.dwZBufferBitDepth = info.depth.bitCount; + pf.dwZBitMask = getMask(info.depth); + if (0 != info.stencil.bitCount) + { + pf.dwFlags |= DDPF_STENCILBUFFER; + pf.dwZBufferBitDepth += info.stencil.bitCount; + pf.dwStencilBitDepth = info.stencil.bitCount; + pf.dwStencilBitMask = getMask(info.stencil); + } } - if (0 != info.alphaBitCount) + else { - pf.dwFlags |= (0 == pf.dwFlags) ? DDPF_ALPHA : DDPF_ALPHAPIXELS; - pf.dwRGBAlphaBitMask = (0xFF >> (8 - info.alphaBitCount)) << info.alphaPos; + pf.dwRGBBitCount = info.bitsPerPixel; + if (info.bitsPerPixel > info.alpha.bitCount) + { + pf.dwFlags = DDPF_RGB; + pf.dwRBitMask = getMask(info.red);; + pf.dwGBitMask = getMask(info.green); + pf.dwBBitMask = getMask(info.blue); + } + if (0 != info.alpha.bitCount) + { + pf.dwFlags |= (0 == pf.dwFlags) ? DDPF_ALPHA : DDPF_ALPHAPIXELS; + pf.dwRGBAlphaBitMask = getMask(info.alpha); + } } return pf; } diff --git a/DDrawCompat/D3dDdi/FormatInfo.h b/DDrawCompat/D3dDdi/FormatInfo.h index 8061a9f..cf4c48a 100644 --- a/DDrawCompat/D3dDdi/FormatInfo.h +++ b/DDrawCompat/D3dDdi/FormatInfo.h @@ -7,26 +7,37 @@ namespace D3dDdi { + static const auto FOURCC_RESZ = static_cast(MAKEFOURCC('R', 'E', 'S', 'Z')); + static const auto FOURCC_INTZ = static_cast(MAKEFOURCC('I', 'N', 'T', 'Z')); + static const auto FOURCC_NULL = static_cast(MAKEFOURCC('N', 'U', 'L', 'L')); + struct FormatInfo { + struct Component + { + BYTE bitCount; + BYTE pos; + }; + BYTE bitsPerPixel; BYTE bytesPerPixel; - BYTE unusedBitCount; - BYTE alphaBitCount; - BYTE alphaPos; - BYTE redBitCount; - BYTE redPos; - BYTE greenBitCount; - BYTE greenPos; - BYTE blueBitCount; - BYTE bluePos; + Component unused; + Component alpha; + Component red; + Component green; + Component blue; + Component depth; + Component stencil; - FormatInfo(BYTE unusedBitCount = 0, BYTE alphaBitCount = 0, - BYTE redBitCount = 0, BYTE greenBitCount = 0, BYTE blueBitCount = 0); + FormatInfo(); + FormatInfo(BYTE unusedBitCount, BYTE alphaBitCount, BYTE redBitCount, BYTE greenBitCount, BYTE blueBitCount); + FormatInfo(BYTE unusedBitCount, BYTE depthBitCount, BYTE stencilBitCount); }; D3DCOLOR convertFrom32Bit(const FormatInfo& dstFormatInfo, D3DCOLOR srcColor); DeviceState::ShaderConstF convertToShaderConst(const FormatInfo& srcFormatInfo, D3DCOLOR srcColor); + DWORD getComponent(D3DCOLOR color, const D3dDdi::FormatInfo::Component& component); + float getComponentAsFloat(D3DCOLOR color, const D3dDdi::FormatInfo::Component& component); FormatInfo getFormatInfo(D3DDDIFORMAT format); DDPIXELFORMAT getPixelFormat(D3DDDIFORMAT format); } diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp index f06caf5..31568ae 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp @@ -110,6 +110,15 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATEVERTEXSHADERDEC << val.ShaderHandle; } +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DEPTHFILL& val) +{ + return Compat::LogStruct(os) + << val.hResource + << val.SubResourceIndex + << val.DstRect + << Compat::hex(val.Depth); +} + std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWINDEXEDPRIMITIVE& val) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h index e410e91..bb94a7f 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h @@ -16,6 +16,7 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_COLORFILL& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATERESOURCE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATERESOURCE2& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATEVERTEXSHADERDECL& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DEPTHFILL& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWINDEXEDPRIMITIVE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWPRIMITIVE& val); diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 167daee..6f44947 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -94,6 +94,12 @@ namespace { HeapFree(GetProcessHeap(), 0, p); } + + void logUnsupportedMsaaDepthBufferResolve() + { + LOG_ONCE("Warning: Resolving multisampled depth buffers is not supported by the GPU. " + "Disable antialiasing if experiencing visual glitches."); + } } namespace D3dDdi @@ -115,6 +121,7 @@ namespace D3dDdi , m_lockRefSurface{} , m_msaaSurface{} , m_msaaResolvedSurface{} + , m_nullSurface{} , m_formatConfig(D3DDDIFMT_UNKNOWN) , m_multiSampleConfig{ D3DDDIMULTISAMPLE_NONE, 0 } , m_scaledSize{} @@ -153,8 +160,18 @@ namespace D3dDdi updateConfig(); - if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool && - 0 != m_formatInfo.bytesPerPixel) + if (D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool && m_origData.Flags.ZBuffer) + { + m_lockData.resize(m_origData.SurfCount); + for (UINT i = 0; i < m_origData.SurfCount; ++i) + { + m_lockData[i].isSysMemUpToDate = true; + m_lockData[i].isVidMemUpToDate = true; + m_lockData[i].isMsaaUpToDate = m_msaaSurface.resource; + m_lockData[i].isMsaaResolvedUpToDate = m_msaaResolvedSurface.resource; + } + } + else if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool && 0 != m_formatInfo.bytesPerPixel) { m_lockData.resize(m_origData.SurfCount); for (UINT i = 0; i < m_origData.SurfCount; ++i) @@ -190,6 +207,13 @@ namespace D3dDdi HRESULT Resource::blt(D3DDDIARG_BLT data) { + if (m_fixedData.Flags.ZBuffer && m_msaaSurface.resource && + !m_device.getAdapter().getInfo().isMsaaDepthResolveSupported) + { + logUnsupportedMsaaDepthBufferResolve(); + return S_OK; + } + if (!isValidRect(data.DstSubResourceIndex, data.DstRect)) { return S_OK; @@ -350,6 +374,11 @@ namespace D3dDdi HRESULT Resource::bltViaGpu(D3DDDIARG_BLT data, Resource& srcResource) { + if (srcResource.m_lockResource) + { + srcResource.loadFromLockRefResource(data.SrcSubResourceIndex); + } + Resource* srcRes = &srcResource; if (m_msaaResolvedSurface.resource && srcResource.m_msaaResolvedSurface.resource && (srcResource.m_lockData[data.SrcSubResourceIndex].isMsaaResolvedUpToDate || @@ -359,7 +388,10 @@ namespace D3dDdi srcRes = srcResource.m_msaaResolvedSurface.resource; data.hSrcResource = *srcRes; srcResource.scaleRect(data.SrcRect); - loadMsaaResolvedResource(data.DstSubResourceIndex); + if (!m_lockData[data.DstSubResourceIndex].isMsaaUpToDate) + { + loadMsaaResolvedResource(data.DstSubResourceIndex); + } } else { @@ -369,7 +401,9 @@ namespace D3dDdi Resource& dstRes = prepareForBltDst(data); if (D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool && - (m_fixedData.Flags.RenderTarget || data.Flags.SrcColorKey || data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown) && + (m_fixedData.Flags.ZBuffer && &dstRes == m_msaaSurface.resource && m_nullSurface.resource || + m_fixedData.Flags.RenderTarget || data.Flags.SrcColorKey || + data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown) && SUCCEEDED(shaderBlt(data, dstRes, *srcRes))) { return S_OK; @@ -634,37 +668,27 @@ namespace D3dDdi m_isClampable = false; } - bool Resource::downscale(Resource*& rt, LONG& srcWidth, LONG& srcHeight, LONG dstWidth, LONG dstHeight) + void Resource::downscale(Resource*& rt, LONG& srcWidth, LONG& srcHeight, LONG dstWidth, LONG dstHeight, bool dryRun) { - LONG newSrcWidth = (srcWidth + 1) / 2; - if (newSrcWidth <= dstWidth) + while (srcWidth > 2 * dstWidth || srcHeight > 2 * dstHeight) { - newSrcWidth = srcWidth; - } + const LONG newSrcWidth = max(dstWidth, (srcWidth + 1) / 2); + const LONG newSrcHeight = max(dstHeight, (srcHeight + 1) / 2); + auto& nextRt = getNextRenderTarget(rt, newSrcWidth, newSrcHeight); + if (!nextRt.resource) + { + return; + } - LONG newSrcHeight = (srcHeight + 1) / 2; - if (newSrcHeight <= dstHeight) - { - newSrcHeight = srcHeight; + if (!dryRun) + { + m_device.getShaderBlitter().textureBlt(*nextRt.resource, 0, { 0, 0, newSrcWidth, newSrcHeight }, + *rt, 0, { 0, 0, srcWidth, srcHeight }, D3DTEXF_LINEAR); + } + rt = nextRt.resource; + srcWidth = newSrcWidth; + srcHeight = newSrcHeight; } - - if (newSrcWidth == srcWidth && newSrcHeight == srcHeight) - { - return false; - } - - auto& nextRt = getNextRenderTarget(rt, newSrcWidth, newSrcHeight); - if (!nextRt.resource) - { - return false; - } - - m_device.getShaderBlitter().textureBlt(*nextRt.resource, 0, { 0, 0, newSrcWidth, newSrcHeight }, - *rt, 0, { 0, 0, srcWidth, srcHeight }, D3DTEXF_LINEAR); - rt = nextRt.resource; - srcWidth = newSrcWidth; - srcHeight = newSrcHeight; - return true; } void Resource::fixResourceData() @@ -686,6 +710,10 @@ namespace D3dDdi if (D3DDDIFMT_UNKNOWN != g_formatOverride) { m_fixedData.Format = g_formatOverride; + if (m_fixedData.Flags.ZBuffer) + { + m_fixedData.Flags.Texture = 1; + } } if (D3DDDIMULTISAMPLE_NONE != g_msaaOverride.first) @@ -744,10 +772,10 @@ namespace D3dDdi const SurfaceRepository::Surface& Resource::getNextRenderTarget(Resource* currentRt, DWORD width, DWORD height) { auto& repo = SurfaceRepository::get(m_device.getAdapter()); - auto nextRt = &repo.getTempRenderTarget(width, height, 1); + auto nextRt = &repo.getTempRenderTarget(width, height, 0); if (nextRt->resource == currentRt) { - nextRt = &repo.getTempRenderTarget(width, height, 0); + nextRt = &repo.getTempRenderTarget(width, height, 1); } return *nextRt; } @@ -814,7 +842,19 @@ namespace D3dDdi if (m_msaaResolvedSurface.resource) { loadMsaaResolvedResource(subResourceIndex); - copySubResource(*m_msaaSurface.resource, *m_msaaResolvedSurface.resource, subResourceIndex); + if (m_fixedData.Flags.ZBuffer) + { + if (m_nullSurface.resource) + { + RECT r = m_msaaResolvedSurface.resource->getRect(0); + m_device.getShaderBlitter().depthBlt( + *m_msaaSurface.resource, r, *m_msaaResolvedSurface.resource, r, *m_nullSurface.resource); + } + } + else + { + copySubResource(*m_msaaSurface.resource, *m_msaaResolvedSurface.resource, subResourceIndex); + } } else { @@ -828,19 +868,35 @@ namespace D3dDdi void Resource::loadMsaaResolvedResource(UINT subResourceIndex) { loadFromLockRefResource(subResourceIndex); - if (!m_lockData[subResourceIndex].isMsaaResolvedUpToDate) + if (m_lockData[subResourceIndex].isMsaaResolvedUpToDate) { - if (m_lockData[subResourceIndex].isMsaaUpToDate) + return; + } + + if (m_lockData[subResourceIndex].isMsaaUpToDate) + { + if (m_fixedData.Flags.ZBuffer) { - copySubResource(*m_msaaResolvedSurface.resource, *m_msaaSurface.resource, subResourceIndex); + if (m_device.getAdapter().getInfo().isMsaaDepthResolveSupported) + { + resolveMsaaDepthBuffer(); + } + else + { + logUnsupportedMsaaDepthBufferResolve(); + } } else { - loadVidMemResource(subResourceIndex); - copySubResource(*m_msaaResolvedSurface.resource, *this, subResourceIndex); + copySubResource(*m_msaaResolvedSurface.resource, *m_msaaSurface.resource, subResourceIndex); } - m_lockData[subResourceIndex].isMsaaResolvedUpToDate = true; } + else + { + loadVidMemResource(subResourceIndex); + copySubResource(*m_msaaResolvedSurface.resource, *this, subResourceIndex); + } + m_lockData[subResourceIndex].isMsaaResolvedUpToDate = true; } void Resource::loadSysMemResource(UINT subResourceIndex) @@ -856,20 +912,59 @@ namespace D3dDdi void Resource::loadVidMemResource(UINT subResourceIndex) { - if (!m_lockData[subResourceIndex].isVidMemUpToDate) + if (m_lockData[subResourceIndex].isVidMemUpToDate) { - if (m_lockData[subResourceIndex].isMsaaUpToDate || m_lockData[subResourceIndex].isMsaaResolvedUpToDate) + return; + } + m_lockData[subResourceIndex].isVidMemUpToDate = true; + + if (m_lockData[subResourceIndex].isMsaaUpToDate || m_lockData[subResourceIndex].isMsaaResolvedUpToDate) + { + loadMsaaResolvedResource(subResourceIndex); + if (!m_fixedData.Flags.RenderTarget) { - loadMsaaResolvedResource(subResourceIndex); copySubResource(*this, *m_msaaResolvedSurface.resource, subResourceIndex); + return; + } + + auto src = m_msaaResolvedSurface.resource; + auto srcRect = src->getRect(subResourceIndex); + auto dstRect = getRect(subResourceIndex); + + SurfaceRepository::enableSurfaceCheck(false); + downscale(src, srcRect.right, srcRect.bottom, dstRect.right, dstRect.bottom); + auto srcIndex = src == m_msaaResolvedSurface.resource ? subResourceIndex : 0; + + if (dstRect != srcRect && + !(m_device.getAdapter().getInfo().formatOps.at(m_fixedData.Format).Operations & FORMATOP_SRGBWRITE)) + { + auto nextRt = getNextRenderTarget(src, dstRect.right, dstRect.bottom).resource; + if (nextRt) + { + m_device.getShaderBlitter().textureBlt(*nextRt, 0, dstRect, + *src, srcIndex, srcRect, D3DTEXF_LINEAR); + src = nextRt; + srcRect = dstRect; + srcIndex = 0; + } + } + SurfaceRepository::enableSurfaceCheck(true); + + if (dstRect == srcRect) + { + copySubResourceRegion(m_handle, subResourceIndex, dstRect, *src, srcIndex, srcRect); } else { - copySubResource(*this, m_lockResource.get(), subResourceIndex); - notifyLock(subResourceIndex); - m_lockData[subResourceIndex].isRefLocked = false; + m_device.getShaderBlitter().textureBlt(*this, subResourceIndex, dstRect, + *src, srcIndex, srcRect, D3DTEXF_LINEAR); } - m_lockData[subResourceIndex].isVidMemUpToDate = true; + } + else + { + copySubResource(*this, m_lockResource.get(), subResourceIndex); + notifyLock(subResourceIndex); + m_lockData[subResourceIndex].isRefLocked = false; } } @@ -896,6 +991,16 @@ namespace D3dDdi { m_isPalettizedTextureUpToDate = false; } + + if (m_fixedData.Flags.ZBuffer && m_msaaResolvedSurface.resource) + { + loadVidMemResource(0); + if (!data.Flags.ReadOnly) + { + m_lockData[0].isMsaaUpToDate = false; + m_lockData[0].isMsaaResolvedUpToDate = false; + } + } return m_device.getOrigVtable().pfnLock(m_device, &data); } @@ -926,7 +1031,7 @@ namespace D3dDdi Resource& Resource::prepareForBltSrc(const D3DDDIARG_BLT& data) { - if (m_lockResource) + if (m_lockResource || m_msaaResolvedSurface.resource) { loadVidMemResource(data.SrcSubResourceIndex); } @@ -941,7 +1046,7 @@ namespace D3dDdi Resource& Resource::prepareForBltDst(HANDLE& resource, UINT subResourceIndex, RECT& rect) { m_isPalettizedTextureUpToDate = false; - if (m_lockResource) + if (m_lockResource || m_msaaResolvedSurface.resource) { loadFromLockRefResource(subResourceIndex); if (m_lockData[subResourceIndex].isMsaaUpToDate) @@ -1000,6 +1105,7 @@ namespace D3dDdi { if (m_lockResource) { + loadFromLockRefResource(subResourceIndex); if (m_msaaResolvedSurface.resource) { loadMsaaResolvedResource(subResourceIndex); @@ -1015,7 +1121,7 @@ namespace D3dDdi void Resource::prepareForGpuWrite(UINT subResourceIndex) { - if (m_lockResource) + if (m_lockResource || m_msaaResolvedSurface.resource) { if (m_msaaSurface.resource) { @@ -1113,9 +1219,7 @@ namespace D3dDdi const LONG dstWidth = data.DstRect.right - data.DstRect.left; const LONG dstHeight = data.DstRect.bottom - data.DstRect.top; - while (downscale(rt, data.SrcRect.right, data.SrcRect.bottom, dstWidth, dstHeight)) - { - } + downscale(rt, data.SrcRect.right, data.SrcRect.bottom, dstWidth, dstHeight); const SurfaceRepository::Surface* rtGamma = nullptr; if (!ShaderBlitter::isGammaRampDefault() && @@ -1214,6 +1318,17 @@ namespace D3dDdi } } + void Resource::resolveMsaaDepthBuffer() + { + LOG_FUNC("Resource::resolveMsaaDepthBuffer"); + auto& state = m_device.getState(); + state.setTempDepthStencil({ *m_msaaSurface.resource }); + state.setTempTexture(0, *m_msaaResolvedSurface.resource); + + const UINT RESZ_CODE = 0x7fa05000; + state.setTempRenderState({ D3DDDIRS_POINTSIZE, RESZ_CODE }); + } + void Resource::scaleRect(RECT& rect) { const LONG origWidth = m_fixedData.pSurfList[0].Width; @@ -1310,13 +1425,15 @@ namespace D3dDdi { DWORD width = data.SrcRect.right - data.SrcRect.left; DWORD height = data.SrcRect.bottom - data.SrcRect.top; - auto& texture = repo.getTempTexture(width, height, getPixelFormat(srcResource.m_fixedData.Format)); - if (!texture.resource) + auto texture = m_fixedData.Flags.ZBuffer + ? m_msaaResolvedSurface.resource + : repo.getTempTexture(width, height, getPixelFormat(srcResource.m_fixedData.Format)).resource; + if (!texture) { return LOG_RESULT(E_OUTOFMEMORY); } - srcRes = texture.resource; + srcRes = texture; srcIndex = 0; srcRect = { 0, 0, static_cast(width), static_cast(height) }; @@ -1371,8 +1488,15 @@ namespace D3dDdi auto ck = data.Flags.SrcColorKey ? convertToShaderConst(srcResource.m_formatInfo, data.ColorKey) : DeviceState::ShaderConstF{}; - m_device.getShaderBlitter().textureBlt(*dstRes, dstIndex, dstRect, *srcRes, srcIndex, srcRect, - D3DTEXF_POINT, data.Flags.SrcColorKey ? &ck : nullptr); + if (m_fixedData.Flags.ZBuffer) + { + m_device.getShaderBlitter().depthBlt(*dstRes, dstRect, *srcRes, srcRect, *m_nullSurface.resource); + } + else + { + m_device.getShaderBlitter().textureBlt(*dstRes, dstIndex, dstRect, *srcRes, srcIndex, srcRect, + D3DTEXF_POINT, data.Flags.SrcColorKey ? &ck : nullptr); + } if (!m_fixedData.Flags.RenderTarget) { @@ -1413,8 +1537,7 @@ namespace D3dDdi m_formatConfig = formatConfig; m_scaledSize = scaledSize; - if ((m_fixedData.Flags.RenderTarget || m_isPrimary) && - (m_msaaSurface.resource || m_msaaResolvedSurface.resource)) + if (m_msaaSurface.resource || m_msaaResolvedSurface.resource) { for (UINT i = 0; i < m_lockData.size(); ++i) { @@ -1430,55 +1553,65 @@ namespace D3dDdi m_msaaSurface = {}; m_msaaResolvedSurface = {}; + m_nullSurface = {}; m_lockRefSurface = {}; - if (D3DDDIMULTISAMPLE_NONE != msaa.first || m_fixedData.Format != formatConfig || - static_cast(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx || - static_cast(m_fixedData.pSurfList[0].Height) != m_scaledSize.cy) + const bool isScaled = static_cast(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx || + static_cast(m_fixedData.pSurfList[0].Height) != m_scaledSize.cy; + if (D3DDDIMULTISAMPLE_NONE != msaa.first || m_fixedData.Format != formatConfig || isScaled) { - if (m_fixedData.Flags.ZBuffer) + const DWORD caps = (m_fixedData.Flags.ZBuffer ? DDSCAPS_ZBUFFER : DDSCAPS_3DDEVICE) | DDSCAPS_VIDEOMEMORY; + if (D3DDDIMULTISAMPLE_NONE != msaa.first) { - DDPIXELFORMAT pf = {}; - pf.dwSize = sizeof(pf); - pf.dwFlags = DDPF_ZBUFFER; - pf.dwZBufferBitDepth = 16; - pf.dwZBitMask = 0xFFFF; - - g_formatOverride = formatConfig; g_msaaOverride = msaa; SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaSurface, - scaledSize.cx, scaledSize.cy, pf, - DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); - g_formatOverride = D3DDDIFMT_UNKNOWN; + scaledSize.cx, scaledSize.cy, getPixelFormat(formatConfig), caps, m_fixedData.SurfCount); g_msaaOverride = {}; } - else + + if (m_fixedData.Flags.ZBuffer && m_msaaSurface.resource && + m_device.getAdapter().getInfo().isMsaaDepthResolveSupported) { - if (D3DDDIMULTISAMPLE_NONE != msaa.first) - { - g_msaaOverride = msaa; - SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaSurface, - scaledSize.cx, scaledSize.cy, getPixelFormat(formatConfig), - DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); - g_msaaOverride = {}; - } - - SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaResolvedSurface, - scaledSize.cx, scaledSize.cy, getPixelFormat(formatConfig), + g_formatOverride = FOURCC_NULL; + g_msaaOverride = msaa; + SurfaceRepository::get(m_device.getAdapter()).getSurface(m_nullSurface, + scaledSize.cx, scaledSize.cy, getPixelFormat(D3DDDIFMT_X8R8G8B8), DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); - if (!m_msaaResolvedSurface.resource && m_msaaSurface.resource) - { - m_msaaSurface = {}; - SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaResolvedSurface, - scaledSize.cx, scaledSize.cy, getPixelFormat(formatConfig), - DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); - } + g_msaaOverride = {}; + g_formatOverride = m_nullSurface.resource ? FOURCC_INTZ : D3DDDIFMT_UNKNOWN; + } + auto msaaResolvedSurfaceCaps = caps | ((m_fixedData.Flags.ZBuffer || !isScaled) ? 0 : DDSCAPS_TEXTURE); + auto msaaResolvedSurfaceFormat = + (m_fixedData.Flags.ZBuffer || !isScaled) ? getPixelFormat(formatConfig) : getPixelFormat(D3DDDIFMT_A8R8G8B8); + SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaResolvedSurface, + scaledSize.cx, scaledSize.cy, msaaResolvedSurfaceFormat, msaaResolvedSurfaceCaps, m_fixedData.SurfCount); + g_formatOverride = D3DDDIFMT_UNKNOWN; - if (m_msaaResolvedSurface.resource) + if (!m_msaaResolvedSurface.resource && m_msaaSurface.resource) + { + m_msaaSurface = {}; + SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaResolvedSurface, + scaledSize.cx, scaledSize.cy, msaaResolvedSurfaceFormat, msaaResolvedSurfaceCaps, m_fixedData.SurfCount); + } + + if (!m_fixedData.Flags.ZBuffer && m_msaaResolvedSurface.resource) + { + SurfaceRepository::get(m_device.getAdapter()).getSurface(m_lockRefSurface, + m_fixedData.pSurfList[0].Width, m_fixedData.pSurfList[0].Height, getPixelFormat(m_fixedData.Format), + DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); + + if (isScaled) { - SurfaceRepository::get(m_device.getAdapter()).getSurface(m_lockRefSurface, - m_fixedData.pSurfList[0].Width, m_fixedData.pSurfList[0].Height, getPixelFormat(m_fixedData.Format), - DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); + Resource* rt = m_msaaResolvedSurface.resource; + auto srcRect = rt->getRect(0); + auto dstRect = getRect(0); + const bool dryRun = true; + downscale(rt, srcRect.right, srcRect.bottom, dstRect.right, dstRect.bottom, dryRun); + if (dstRect != srcRect && + !(m_device.getAdapter().getInfo().formatOps.at(m_fixedData.Format).Operations & FORMATOP_SRGBWRITE)) + { + getNextRenderTarget(rt, dstRect.right, dstRect.bottom); + } } } } diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index a047c15..16225c9 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -84,6 +84,8 @@ namespace D3dDdi bool isMsaaUpToDate; bool isMsaaResolvedUpToDate; bool isRefLocked; + + LockData() { memset(this, 0, sizeof(*this)); } }; HRESULT bltLock(D3DDDIARG_LOCK& data); @@ -100,7 +102,7 @@ namespace D3dDdi void createGdiLockResource(); void createLockResource(); void createSysMemResource(const std::vector& surfaceInfo); - bool downscale(Resource*& rt, LONG& srcWidth, LONG& srcHeight, LONG dstWidth, LONG dstHeight); + void downscale(Resource*& rt, LONG& srcWidth, LONG& srcHeight, LONG dstWidth, LONG dstHeight, bool dryRun = false); void fixResourceData(); D3DDDIFORMAT getFormatConfig(); std::pair getMultisampleConfig(); @@ -115,6 +117,7 @@ namespace D3dDdi void loadVidMemResource(UINT subResourceIndex); void notifyLock(UINT subResourceIndex); void presentLayeredWindows(Resource& dst, UINT dstSubResourceIndex, const RECT& dstRect); + void resolveMsaaDepthBuffer(); HRESULT shaderBlt(D3DDDIARG_BLT& data, Resource& dstResource, Resource& srcResource); Device& m_device; @@ -128,6 +131,7 @@ namespace D3dDdi SurfaceRepository::Surface m_lockRefSurface; SurfaceRepository::Surface m_msaaSurface; SurfaceRepository::Surface m_msaaResolvedSurface; + SurfaceRepository::Surface m_nullSurface; D3DDDIFORMAT m_formatConfig; std::pair m_multiSampleConfig; SIZE m_scaledSize; diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index b912ebe..7014494 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ namespace D3dDdi ShaderBlitter::ShaderBlitter(Device& device) : m_device(device) , m_psColorKey(createPixelShader(g_psColorKey)) + , m_psDepthBlt(createPixelShader(g_psDepthBlt)) , m_psDrawCursor(createPixelShader(g_psDrawCursor)) , m_psGamma(createPixelShader(g_psGamma)) , m_psGenBilinear(createPixelShader(g_psGenBilinear)) @@ -74,7 +76,7 @@ namespace D3dDdi HANDLE pixelShader, UINT filter, UINT flags, const BYTE* alpha, const Gdi::Region& srcRgn) { LOG_FUNC("ShaderBlitter::blt", static_cast(dstResource), dstSubResourceIndex, dstRect, - static_cast(srcResource), srcRect, srcSubResourceIndex, pixelShader, filter, + static_cast(srcResource), srcSubResourceIndex, srcRect, pixelShader, filter, Compat::hex(flags), alpha, static_cast(srcRgn)); if (!m_vertexShaderDecl || !pixelShader) @@ -95,14 +97,14 @@ namespace D3dDdi auto& state = m_device.getState(); state.setSpriteMode(false); - state.setTempRenderState({ D3DDDIRS_SCENECAPTURE, TRUE }); - state.setTempVertexShaderDecl(m_vertexShaderDecl.get()); - state.setTempPixelShader(pixelShader); state.setTempRenderTarget({ 0, dstResource, dstSubResourceIndex }); state.setTempDepthStencil({ nullptr }); state.setTempViewport({ 0, 0, dstSurface.Width, dstSurface.Height }); state.setTempZRange({ 0, 1 }); + state.setTempPixelShader(pixelShader); + state.setTempVertexShaderDecl(m_vertexShaderDecl.get()); + state.setTempRenderState({ D3DDDIRS_SCENECAPTURE, TRUE }); state.setTempRenderState({ D3DDDIRS_ZENABLE, D3DZB_FALSE }); state.setTempRenderState({ D3DDDIRS_FILLMODE, D3DFILL_SOLID }); state.setTempRenderState({ D3DDDIRS_ZWRITEENABLE, FALSE }); @@ -261,6 +263,56 @@ namespace D3dDdi } } + void ShaderBlitter::depthBlt(const Resource& dstResource, const RECT& dstRect, + const Resource& srcResource, const RECT& srcRect, const Resource& nullResource) + { + LOG_FUNC("ShaderBlitter::depthBlt", static_cast(dstResource), dstRect, + static_cast(srcResource), srcRect, static_cast(nullResource)); + + const auto& srcSurface = srcResource.getFixedDesc().pSurfList[0]; + const auto& dstSurface = dstResource.getFixedDesc().pSurfList[0]; + + auto& state = m_device.getState(); + state.setSpriteMode(false); + state.setTempRenderTarget({ 0, nullResource, 0 }); + state.setTempDepthStencil({ dstResource }); + state.setTempViewport({ 0, 0, dstSurface.Width, dstSurface.Height }); + state.setTempZRange({ 0, 1 }); + state.setTempPixelShader(m_psDepthBlt.get()); + state.setTempVertexShaderDecl(m_vertexShaderDecl.get()); + + state.setTempRenderState({ D3DDDIRS_SCENECAPTURE, TRUE }); + state.setTempRenderState({ D3DDDIRS_ZENABLE, D3DZB_TRUE }); + state.setTempRenderState({ D3DDDIRS_ZFUNC, D3DCMP_ALWAYS }); + state.setTempRenderState({ D3DDDIRS_FILLMODE, D3DFILL_SOLID }); + state.setTempRenderState({ D3DDDIRS_ZWRITEENABLE, TRUE }); + state.setTempRenderState({ D3DDDIRS_ALPHATESTENABLE, FALSE }); + state.setTempRenderState({ D3DDDIRS_CULLMODE, D3DCULL_NONE }); + state.setTempRenderState({ D3DDDIRS_DITHERENABLE, FALSE }); + state.setTempRenderState({ D3DDDIRS_ALPHABLENDENABLE, TRUE }); + state.setTempRenderState({ D3DDDIRS_FOGENABLE, FALSE }); + state.setTempRenderState({ D3DDDIRS_COLORKEYENABLE, FALSE }); + state.setTempRenderState({ D3DDDIRS_STENCILENABLE, FALSE }); + state.setTempRenderState({ D3DDDIRS_CLIPPING, FALSE }); + state.setTempRenderState({ D3DDDIRS_CLIPPLANEENABLE, 0 }); + state.setTempRenderState({ D3DDDIRS_MULTISAMPLEANTIALIAS, FALSE }); + state.setTempRenderState({ D3DDDIRS_COLORWRITEENABLE, 0 }); + + const UINT D3DBLEND_ZERO = 1; + const UINT D3DBLEND_ONE = 2; + state.setTempRenderState({ D3DDDIRS_SRCBLEND, D3DBLEND_ZERO }); + state.setTempRenderState({ D3DDDIRS_DESTBLEND, D3DBLEND_ONE }); + + setTempTextureStage(0, srcResource, srcRect, D3DTEXF_POINT); + state.setTempTextureStageState({ 0, D3DDDITSS_SRGBTEXTURE, FALSE }); + + state.setTempStreamSourceUm({ 0, sizeof(Vertex) }, m_vertices.data()); + + DeviceState::TempStateLock lock(state); + drawRect(srcRect, Rect::toRectF(dstRect), srcSurface.Width, srcSurface.Height); + m_device.flushPrimitives(); + } + void ShaderBlitter::drawRect(const RECT& srcRect, const RectF& dstRect, UINT srcWidth, UINT srcHeight) { m_vertices[0].xy = { dstRect.left - 0.5f, dstRect.top - 0.5f }; diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h index 90c63bc..8be90a5 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.h +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -26,6 +26,8 @@ namespace D3dDdi void cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, HCURSOR cursor, POINT pt); + void depthBlt(const Resource& dstResource, const RECT& dstRect, + const Resource& srcResource, const RECT& srcRect, const Resource& nullResource); void gammaBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, const RECT& srcRect); void genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, @@ -73,6 +75,7 @@ namespace D3dDdi Device& m_device; std::unique_ptr m_psColorKey; + std::unique_ptr m_psDepthBlt; std::unique_ptr m_psDrawCursor; std::unique_ptr m_psGamma; std::unique_ptr m_psGenBilinear; diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.cpp b/DDrawCompat/D3dDdi/SurfaceRepository.cpp index aa2520d..ec7de67 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.cpp +++ b/DDrawCompat/D3dDdi/SurfaceRepository.cpp @@ -16,6 +16,7 @@ namespace { std::map g_repositories; + bool g_enableSurfaceCheck = true; } namespace D3dDdi @@ -66,6 +67,11 @@ namespace D3dDdi return surface; } + void SurfaceRepository::enableSurfaceCheck(bool enable) + { + g_enableSurfaceCheck = enable; + } + SurfaceRepository& SurfaceRepository::get(const Adapter& adapter) { auto it = g_repositories.find(adapter.getLuid()); @@ -215,6 +221,11 @@ namespace D3dDdi SurfaceRepository::Surface& SurfaceRepository::getSurface(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount) { + if (!g_enableSurfaceCheck) + { + return surface; + } + if (surface.surface && (surface.width != width || surface.height != height || 0 != memcmp(&surface.pixelFormat, &pf, sizeof(pf)) || isLost(surface))) { diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.h b/DDrawCompat/D3dDdi/SurfaceRepository.h index 5504e27..8afb47a 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.h +++ b/DDrawCompat/D3dDdi/SurfaceRepository.h @@ -51,6 +51,7 @@ namespace D3dDdi static SurfaceRepository& get(const Adapter& adapter); static bool inCreateSurface() { return s_inCreateSurface; } + static void enableSurfaceCheck(bool enable); private: SurfaceRepository(const Adapter& adapter); diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index 831a698..7d4155c 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -34,19 +35,41 @@ namespace { return DDraw::PrimarySurface::create(*This, *lpDDSurfaceDesc, *lplpDDSurface); } - else if (Config::palettizedTextures.get() && - (lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_TEXTURE) && - !(lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && - (lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) && - (DDPF_RGB | DDPF_PALETTEINDEXED8) == lpDDSurfaceDesc->ddpfPixelFormat.dwFlags) + + TSurfaceDesc desc = *lpDDSurfaceDesc; + if (!D3dDdi::SurfaceRepository::inCreateSurface()) { - return DDraw::PalettizedTexture::create(*This, *lpDDSurfaceDesc, *lplpDDSurface); - } - else - { - return DDraw::Surface::create( - *This, *lpDDSurfaceDesc, *lplpDDSurface, std::make_unique(lpDDSurfaceDesc->ddsCaps.dwCaps)); + if (&IID_IDirect3DHALDevice == Config::softwareDevice.get()) + { + if ((desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && + !(desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) && + (desc.dwFlags & DDSD_PIXELFORMAT) && + (DDPF_RGB | DDPF_PALETTEINDEXED8) == desc.ddpfPixelFormat.dwFlags) + { + desc.ddsCaps.dwCaps |= DDSCAPS_TEXTURE; + desc.ddsCaps.dwCaps &= ~DDSCAPS_OFFSCREENPLAIN; + } + + if (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY && + (desc.ddsCaps.dwCaps & (DDSCAPS_TEXTURE | DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER))) + { + desc.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; + desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + } + } + + if (Config::palettizedTextures.get() && + (desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE) && + !(desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && + (desc.dwFlags & DDSD_PIXELFORMAT) && + (DDPF_RGB | DDPF_PALETTEINDEXED8) == desc.ddpfPixelFormat.dwFlags) + { + return DDraw::PalettizedTexture::create(*This, desc, *lplpDDSurface); + } } + + return DDraw::Surface::create( + *This, desc, *lplpDDSurface, std::make_unique(desc.ddsCaps.dwCaps)); } template diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index 837a292..9157634 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -217,14 +218,18 @@ namespace DDraw template HRESULT SurfaceImpl::QueryInterface(TSurface* This, REFIID riid, LPVOID* obp) { - auto iid = (IID_IDirect3DRampDevice == riid) ? &IID_IDirect3DRGBDevice : &riid; - HRESULT result = getOrigVtable(This).QueryInterface(This, *iid, obp); + auto& iid = Direct3d::replaceDevice(riid);; + HRESULT result = getOrigVtable(This).QueryInterface(This, iid, obp); if (DDERR_INVALIDOBJECT == result) { m_data->setSizeOverride(1, 1); - result = getOrigVtable(This).QueryInterface(This, *iid, obp); + result = getOrigVtable(This).QueryInterface(This, iid, obp); m_data->setSizeOverride(0, 0); } + if (SUCCEEDED(result)) + { + Direct3d::onCreateDevice(iid, *m_data->m_surface); + } return result; } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 725c1a8..e7e605b 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -180,6 +180,7 @@ + @@ -423,6 +424,9 @@ Pixel + + Pixel + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index a6f2bed..df60137 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -597,6 +597,9 @@ Header Files\Config\Settings + + Header Files\Config\Settings + @@ -974,6 +977,9 @@ Shaders + + Shaders + diff --git a/DDrawCompat/Direct3d/Direct3d.cpp b/DDrawCompat/Direct3d/Direct3d.cpp index 5716d34..001578d 100644 --- a/DDrawCompat/Direct3d/Direct3d.cpp +++ b/DDrawCompat/Direct3d/Direct3d.cpp @@ -1,8 +1,10 @@ #include -#include #include #include +#include +#include +#include #include #include #include @@ -20,25 +22,26 @@ namespace TDirect3dDevice** lplpD3DDevice, Params... params) { - auto iid = (IID_IDirect3DRampDevice == rclsid) ? &IID_IDirect3DRGBDevice : &rclsid; - HRESULT result = getOrigVtable(This).CreateDevice(This, *iid, lpDDS, lplpD3DDevice, params...); + auto& iid = Direct3d::replaceDevice(rclsid); + HRESULT result = getOrigVtable(This).CreateDevice(This, iid, lpDDS, lplpD3DDevice, params...); if (DDERR_INVALIDOBJECT == result && lpDDS) { auto surface = DDraw::Surface::getSurface(*lpDDS); if (surface) { surface->setSizeOverride(1, 1); - result = getOrigVtable(This).CreateDevice(This, *iid, lpDDS, lplpD3DDevice, params...); + result = getOrigVtable(This).CreateDevice(This, iid, lpDDS, lplpD3DDevice, params...); surface->setSizeOverride(0, 0); } } - if constexpr (std::is_same_v) + if (SUCCEEDED(result)) { - if (SUCCEEDED(result)) + if constexpr (std::is_same_v) { Direct3d::Direct3dDevice::hookVtable(*(*lplpD3DDevice)->lpVtbl); } + Direct3d::onCreateDevice(iid, *CompatPtr::from(lpDDS)); } return result; } @@ -74,6 +77,52 @@ namespace namespace Direct3d { + void onCreateDevice(const IID& iid, IDirectDrawSurface7& surface) + { + if (IID_IDirect3DHALDevice == iid || IID_IDirect3DTnLHalDevice == iid) + { + auto device = D3dDdi::Device::findDeviceByResource( + DDraw::DirectDrawSurface::getDriverResourceHandle(surface)); + if (device) + { + device->getState().flush(); + } + } + } + + const IID& replaceDevice(const IID& iid) + { + if (IID_IDirect3DRampDevice != iid && + IID_IDirect3DRGBDevice != iid && + IID_IDirect3DHALDevice != iid && + IID_IDirect3DMMXDevice != iid && + IID_IDirect3DRefDevice != iid && + IID_IDirect3DNullDevice != iid && + IID_IDirect3DTnLHalDevice != iid) + { + return iid; + } + + auto mappedDeviceType = &iid; + if (Config::softwareDevice.get() && + (IID_IDirect3DRampDevice == iid || IID_IDirect3DMMXDevice == iid || IID_IDirect3DRGBDevice == iid)) + { + mappedDeviceType = Config::softwareDevice.get(); + } + + static std::set usedDeviceTypes; + if (usedDeviceTypes.insert(iid).second) + { + Compat::Log log(Config::Settings::LogLevel::INFO); + log << "Using Direct3D device type: " << iid; + if (iid != *mappedDeviceType) + { + log << " (mapped to " << *mappedDeviceType << ')'; + } + } + return *mappedDeviceType; + } + namespace Direct3d { template diff --git a/DDrawCompat/Direct3d/Direct3d.h b/DDrawCompat/Direct3d/Direct3d.h index c2e625a..1666b6f 100644 --- a/DDrawCompat/Direct3d/Direct3d.h +++ b/DDrawCompat/Direct3d/Direct3d.h @@ -1,9 +1,14 @@ #pragma once +#include + #include namespace Direct3d { + void onCreateDevice(const IID& iid, IDirectDrawSurface7& surface); + const IID& replaceDevice(const IID& iid); + namespace Direct3d { template diff --git a/DDrawCompat/Shaders/DepthBlt.hlsl b/DDrawCompat/Shaders/DepthBlt.hlsl new file mode 100644 index 0000000..fa78535 --- /dev/null +++ b/DDrawCompat/Shaders/DepthBlt.hlsl @@ -0,0 +1,15 @@ +sampler2D s_texture : register(s0); + +struct PS_OUT +{ + float4 color : COLOR0; + float depth : DEPTH0; +}; + +PS_OUT main(float2 texCoord : TEXCOORD0) +{ + PS_OUT result; + result.color = 0; + result.depth = tex2D(s_texture, texCoord).r; + return result; +}