diff --git a/DDrawCompat/CompatDepthBuffer.cpp b/DDrawCompat/CompatDepthBuffer.cpp new file mode 100644 index 0000000..a008cad --- /dev/null +++ b/DDrawCompat/CompatDepthBuffer.cpp @@ -0,0 +1,124 @@ +#include +#include + +#include "CompatDepthBuffer.h" + +namespace +{ + std::string bitDepthsToString(DWORD bitDepths) + { + std::string result; + if (bitDepths & DDBD_8) { result += ", 8"; } + if (bitDepths & DDBD_16) { result += ", 16"; } + if (bitDepths & DDBD_24) { result += ", 24"; } + if (bitDepths & DDBD_32) { result += ", 32"; } + result = '"' + result.substr(2) + '"'; + return result; + } + + HRESULT CALLBACK enumZBufferFormatsCallback(LPDDPIXELFORMAT lpDDPixFmt, LPVOID lpContext) + { + Compat::LogEnter("CompatDepthBuffer::enumZBufferFormatsCallback", lpDDPixFmt, lpContext); + if (DDPF_ZBUFFER == lpDDPixFmt->dwFlags && + (static_cast(1) << lpDDPixFmt->dwZBufferBitDepth) - 1 == lpDDPixFmt->dwZBitMask) + { + DWORD& supportedBitDepths = *reinterpret_cast(lpContext); + switch (lpDDPixFmt->dwZBufferBitDepth) + { + case 8: supportedBitDepths |= DDBD_8; break; + case 16: supportedBitDepths |= DDBD_16; break; + case 24: supportedBitDepths |= DDBD_24; break; + case 32: supportedBitDepths |= DDBD_32; break; + } + } + Compat::LogLeave("CompatDepthBuffer::enumZBufferFormatsCallback", + lpDDPixFmt, lpContext) << D3DENUMRET_OK; + return D3DENUMRET_OK; + } + + GUID getDeviceGuid(const D3DDEVICEDESC& /*desc*/) + { + return IID_IDirect3DHALDevice; + } + + GUID getDeviceGuid(const D3DDEVICEDESC7& desc) + { + return desc.deviceGUID; + } + + template + DWORD getSupportedZBufferBitDepths(CompatPtr d3d, const GUID& deviceGuid) + { + DWORD supportedBitDepths = 0; + if (d3d) + { + d3d->EnumZBufferFormats(d3d, deviceGuid, &enumZBufferFormatsCallback, &supportedBitDepths); + } + return supportedBitDepths; + } + + bool isHardwareZBufferSupported(const D3DDEVICEDESC& desc) + { + return (desc.dwFlags & D3DDD_DEVICEZBUFFERBITDEPTH) && 0 != desc.dwDeviceZBufferBitDepth; + } + + bool isHardwareZBufferSupported(const D3DDEVICEDESC7& desc) + { + return 0 != desc.dwDeviceZBufferBitDepth && + (IID_IDirect3DHALDevice == desc.deviceGUID || IID_IDirect3DTnLHalDevice == desc.deviceGUID); + } + + void logSupportedZBufferBitDepthsChanged( + CompatPtr dd, const GUID& d3dGuid, DWORD oldBitDepths, DWORD newBitDepths) + { + struct DeviceId + { + GUID directDrawGuid; + GUID direct3dGuid; + + bool operator==(const DeviceId& rhs) const + { + return directDrawGuid == rhs.directDrawGuid && direct3dGuid == rhs.direct3dGuid; + } + }; + + DDDEVICEIDENTIFIER2 deviceIdentifier = {}; + dd->GetDeviceIdentifier(dd, &deviceIdentifier, 0); + const DeviceId deviceId = { deviceIdentifier.guidDeviceIdentifier, d3dGuid }; + + static std::vector loggedDevices; + if (loggedDevices.end() != std::find(loggedDevices.begin(), loggedDevices.end(), deviceId)) + { + return; + } + loggedDevices.push_back(deviceId); + + Compat::Log() << "Incorrect z-buffer bit depth capabilities detected for \"" << + deviceIdentifier.szDescription << "\" / " << + (IID_IDirect3DTnLHalDevice == d3dGuid ? "Direct3D T&L HAL" : "Direct3D HAL") << ','; + Compat::Log() << " changed supported z-buffer bit depths from " << + bitDepthsToString(oldBitDepths) << " to " << bitDepthsToString(newBitDepths); + } +} + +namespace CompatDepthBuffer +{ + template + void fixSupportedZBufferBitDepths( + CompatPtr d3d, TD3dDeviceDesc& desc) + { + if (isHardwareZBufferSupported(desc)) + { + const DWORD supportedBitDepths = getSupportedZBufferBitDepths(d3d, getDeviceGuid(desc)); + if (0 != supportedBitDepths && supportedBitDepths != desc.dwDeviceZBufferBitDepth) + { + logSupportedZBufferBitDepthsChanged( + d3d, getDeviceGuid(desc), desc.dwDeviceZBufferBitDepth, supportedBitDepths); + desc.dwDeviceZBufferBitDepth = supportedBitDepths; + } + } + } + + template void fixSupportedZBufferBitDepths(CompatPtr, D3DDEVICEDESC&); + template void fixSupportedZBufferBitDepths(CompatPtr, D3DDEVICEDESC7&); +} diff --git a/DDrawCompat/CompatDepthBuffer.h b/DDrawCompat/CompatDepthBuffer.h new file mode 100644 index 0000000..bc596f1 --- /dev/null +++ b/DDrawCompat/CompatDepthBuffer.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include "CompatPtr.h" + +namespace CompatDepthBuffer +{ + template + void fixSupportedZBufferBitDepths(CompatPtr d3d, TD3dDeviceDesc& desc); +} diff --git a/DDrawCompat/CompatDirect3d.cpp b/DDrawCompat/CompatDirect3d.cpp index c15695f..d728c54 100644 --- a/DDrawCompat/CompatDirect3d.cpp +++ b/DDrawCompat/CompatDirect3d.cpp @@ -1,8 +1,68 @@ +#include "CompatDepthBuffer.h" #include "CompatDirect3d.h" +#include "CompatPtr.h" +#include "Direct3dTypes.h" + +namespace +{ + template + struct EnumDevicesParams + { + CompatPtr d3d; + typename Types::TD3dEnumDevicesCallback enumDevicesCallback; + void* userArg; + }; + + HRESULT CALLBACK d3dEnumDevicesCallback( + GUID* lpGuid, + LPSTR lpDeviceDescription, + LPSTR lpDeviceName, + LPD3DDEVICEDESC lpD3DHWDeviceDesc, + LPD3DDEVICEDESC lpD3DHELDeviceDesc, + LPVOID lpContext) + { + auto& params = *reinterpret_cast*>(lpContext); + CompatDepthBuffer::fixSupportedZBufferBitDepths(params.d3d, *lpD3DHWDeviceDesc); + return params.enumDevicesCallback(lpGuid, lpDeviceDescription, lpDeviceName, + lpD3DHWDeviceDesc, lpD3DHELDeviceDesc, params.userArg); + } + + HRESULT CALLBACK d3dEnumDevicesCallback( + LPSTR lpDeviceDescription, + LPSTR lpDeviceName, + LPD3DDEVICEDESC7 lpD3DDeviceDesc, + LPVOID lpContext) + { + auto& params = *reinterpret_cast*>(lpContext); + CompatDepthBuffer::fixSupportedZBufferBitDepths(params.d3d, *lpD3DDeviceDesc); + return params.enumDevicesCallback(lpDeviceDescription, lpDeviceName, + lpD3DDeviceDesc, params.userArg); + } + + template + HRESULT STDMETHODCALLTYPE enumDevices( + TDirect3d* This, TD3dEnumDevicesCallback lpEnumDevicesCallback, LPVOID lpUserArg) + { + if (!lpEnumDevicesCallback) + { + return CompatVtableBase::s_origVtable.EnumDevices( + This, lpEnumDevicesCallback, lpUserArg); + } + + typedef typename Types::TDirect3dHighest TDirect3dHighest; + CompatPtr d3d(Compat::queryInterface(This)); + + EnumDevicesParams params = { d3d, lpEnumDevicesCallback, lpUserArg }; + return CompatVtableBase::s_origVtable.EnumDevices( + This, &d3dEnumDevicesCallback, ¶ms); + } +} template -void CompatDirect3d::setCompatVtable(Vtable& /*vtable*/) +void CompatDirect3d::setCompatVtable(Vtable& vtable) { + vtable.EnumDevices = &enumDevices; + // No need to fix FindDevice since it uses EnumDevices } template CompatDirect3d; diff --git a/DDrawCompat/CompatDirect3dDevice.cpp b/DDrawCompat/CompatDirect3dDevice.cpp index 38299b4..bc39d24 100644 --- a/DDrawCompat/CompatDirect3dDevice.cpp +++ b/DDrawCompat/CompatDirect3dDevice.cpp @@ -1,8 +1,44 @@ +#include "CompatDepthBuffer.h" #include "CompatDirect3dDevice.h" +#include "CompatPtr.h" +#include "CompatRef.h" +#include "Direct3dTypes.h" + +namespace +{ + template + void fixSupportedZBufferBitDepths(CompatRef d3dDevice, TD3dDeviceDesc& desc) + { + typedef typename Types::TDirect3d TDirect3d; + CompatPtr d3d; + if (SUCCEEDED(CompatVtableBase::s_origVtable.GetDirect3D( + &d3dDevice, &d3d.getRef()))) + { + typedef typename Types::TDirect3dHighest TDirect3dHighest; + CompatDepthBuffer::fixSupportedZBufferBitDepths(d3d, desc); + } + } + + template + HRESULT STDMETHODCALLTYPE getCaps( + TDirect3dDevice* This, + TD3dDeviceDesc* lpD3DHWDevDesc, + Params... params) + { + HRESULT result = CompatVtableBase::s_origVtable.GetCaps( + This, lpD3DHWDevDesc, params...); + if (SUCCEEDED(result)) + { + fixSupportedZBufferBitDepths(*This, *lpD3DHWDevDesc); + } + return result; + } +} template -void CompatDirect3dDevice::setCompatVtable(Vtable& /*vtable*/) +void CompatDirect3dDevice::setCompatVtable(Vtable& vtable) { + vtable.GetCaps = &getCaps; } template CompatDirect3dDevice; diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index a64e8fe..3a4e8d9 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -145,6 +145,7 @@ + @@ -179,6 +180,7 @@ + @@ -192,6 +194,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index a272343..37a3805 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -150,6 +150,12 @@ Header Files + + Header Files + + + Header Files + @@ -248,6 +254,9 @@ Source Files + + Source Files + diff --git a/DDrawCompat/Direct3dTypes.h b/DDrawCompat/Direct3dTypes.h new file mode 100644 index 0000000..a9be937 --- /dev/null +++ b/DDrawCompat/Direct3dTypes.h @@ -0,0 +1,64 @@ +#pragma once + +#define CINTERFACE + +#include + +struct Direct3dTypes +{ + typedef IDirect3D TDirect3d; + typedef IDirect3D3 TDirect3dHighest; + typedef IDirect3DDevice TDirect3dDevice; + typedef D3DDEVICEDESC TD3dDeviceDesc; + typedef LPD3DENUMDEVICESCALLBACK TD3dEnumDevicesCallback; +}; + +struct Direct3dTypes2 +{ + typedef IDirect3D2 TDirect3d; + typedef IDirect3D3 TDirect3dHighest; + typedef IDirect3DDevice2 TDirect3dDevice; + typedef D3DDEVICEDESC TD3dDeviceDesc; + typedef LPD3DENUMDEVICESCALLBACK TD3dEnumDevicesCallback; +}; + +struct Direct3dTypes3 +{ + typedef IDirect3D3 TDirect3d; + typedef IDirect3D3 TDirect3dHighest; + typedef IDirect3DDevice3 TDirect3dDevice; + typedef D3DDEVICEDESC TD3dDeviceDesc; + typedef LPD3DENUMDEVICESCALLBACK TD3dEnumDevicesCallback; +}; + +struct Direct3dTypes7 +{ + typedef IDirect3D7 TDirect3d; + typedef IDirect3D7 TDirect3dHighest; + typedef IDirect3DDevice7 TDirect3dDevice; + typedef D3DDEVICEDESC7 TD3dDeviceDesc; + typedef LPD3DENUMDEVICESCALLBACK7 TD3dEnumDevicesCallback; +}; + +template +struct Types; + +#define D3D_CONCAT(x, y, ...) x##y + +#define D3D_TYPES(Interface, ...) \ + template <> \ + struct Types : D3D_CONCAT(Direct3dTypes, __VA_ARGS__) \ + {} + +D3D_TYPES(IDirect3D); +D3D_TYPES(IDirect3D, 2); +D3D_TYPES(IDirect3D, 3); +D3D_TYPES(IDirect3D, 7); + +D3D_TYPES(IDirect3DDevice); +D3D_TYPES(IDirect3DDevice, 2); +D3D_TYPES(IDirect3DDevice, 3); +D3D_TYPES(IDirect3DDevice, 7); + +#undef D3D_TYPES +#undef D3D_CONCAT