mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Fixed incorrect z-buffer bit depths reported in D3DDEVICEDESC
Legacy DirectDraw interfaces specify the z-buffer format as a single bit depth number instead of as a DDPIXELFORMAT struct. DirectDraw seems to convert a legacy z-buffer bit depth of N into a DDPIXELFORMAT with dwFlags = DDPF_ZBUFFER, dwZBufferBitDepth = N and dwZBitMask set to 1s in the lowest N bits. Some drivers (so far noticed with AMD only) report the list of supported z-buffer bit depths incorrectly, resulting in a game potentially selecting a bit depth that can't actually be created via the legacy interfaces. For example, the driver may report 16 and 32 bits as supported whereas all 32 bit z-buffer pixel formats use only 24 bits for z-buffer (with the remaining bits unused or used as stencil buffer). Meanwhile the same driver doesn't report 24 bits as supported when it's actually supported. This fix overrides the set of supported z-buffer bit depths in D3DDEVICEDESC structs for HAL devices to align with the actually supported pixel formats. Fixes a startup issue in Rainbow Six mentioned in issue #2.
This commit is contained in:
parent
6aba3b6f39
commit
b9b4a2aafd
124
DDrawCompat/CompatDepthBuffer.cpp
Normal file
124
DDrawCompat/CompatDepthBuffer.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#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<uint64_t>(1) << lpDDPixFmt->dwZBufferBitDepth) - 1 == lpDDPixFmt->dwZBitMask)
|
||||
{
|
||||
DWORD& supportedBitDepths = *reinterpret_cast<DWORD*>(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 <typename TDirect3d>
|
||||
DWORD getSupportedZBufferBitDepths(CompatPtr<TDirect3d> 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<IDirectDraw7> 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<DeviceId> 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 <typename TDirect3d, typename TD3dDeviceDesc>
|
||||
void fixSupportedZBufferBitDepths(
|
||||
CompatPtr<TDirect3d> 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<IDirect3D3>, D3DDEVICEDESC&);
|
||||
template void fixSupportedZBufferBitDepths(CompatPtr<IDirect3D7>, D3DDEVICEDESC7&);
|
||||
}
|
11
DDrawCompat/CompatDepthBuffer.h
Normal file
11
DDrawCompat/CompatDepthBuffer.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <guiddef.h>
|
||||
|
||||
#include "CompatPtr.h"
|
||||
|
||||
namespace CompatDepthBuffer
|
||||
{
|
||||
template <typename TDirect3d, typename TD3dDeviceDesc>
|
||||
void fixSupportedZBufferBitDepths(CompatPtr<TDirect3d> d3d, TD3dDeviceDesc& desc);
|
||||
}
|
@ -1,8 +1,68 @@
|
||||
#include "CompatDepthBuffer.h"
|
||||
#include "CompatDirect3d.h"
|
||||
#include "CompatPtr.h"
|
||||
#include "Direct3dTypes.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename TDirect3d>
|
||||
struct EnumDevicesParams
|
||||
{
|
||||
CompatPtr<TDirect3d> d3d;
|
||||
typename Types<TDirect3d>::TD3dEnumDevicesCallback enumDevicesCallback;
|
||||
void* userArg;
|
||||
};
|
||||
|
||||
HRESULT CALLBACK d3dEnumDevicesCallback(
|
||||
GUID* lpGuid,
|
||||
LPSTR lpDeviceDescription,
|
||||
LPSTR lpDeviceName,
|
||||
LPD3DDEVICEDESC lpD3DHWDeviceDesc,
|
||||
LPD3DDEVICEDESC lpD3DHELDeviceDesc,
|
||||
LPVOID lpContext)
|
||||
{
|
||||
auto& params = *reinterpret_cast<EnumDevicesParams<IDirect3D3>*>(lpContext);
|
||||
CompatDepthBuffer::fixSupportedZBufferBitDepths<IDirect3D3>(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<EnumDevicesParams<IDirect3D7>*>(lpContext);
|
||||
CompatDepthBuffer::fixSupportedZBufferBitDepths<IDirect3D7>(params.d3d, *lpD3DDeviceDesc);
|
||||
return params.enumDevicesCallback(lpDeviceDescription, lpDeviceName,
|
||||
lpD3DDeviceDesc, params.userArg);
|
||||
}
|
||||
|
||||
template <typename TDirect3d, typename TD3dEnumDevicesCallback>
|
||||
HRESULT STDMETHODCALLTYPE enumDevices(
|
||||
TDirect3d* This, TD3dEnumDevicesCallback lpEnumDevicesCallback, LPVOID lpUserArg)
|
||||
{
|
||||
if (!lpEnumDevicesCallback)
|
||||
{
|
||||
return CompatVtableBase<TDirect3d>::s_origVtable.EnumDevices(
|
||||
This, lpEnumDevicesCallback, lpUserArg);
|
||||
}
|
||||
|
||||
typedef typename Types<TDirect3d>::TDirect3dHighest TDirect3dHighest;
|
||||
CompatPtr<TDirect3dHighest> d3d(Compat::queryInterface<TDirect3dHighest>(This));
|
||||
|
||||
EnumDevicesParams<TDirect3dHighest> params = { d3d, lpEnumDevicesCallback, lpUserArg };
|
||||
return CompatVtableBase<TDirect3d>::s_origVtable.EnumDevices(
|
||||
This, &d3dEnumDevicesCallback, ¶ms);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TDirect3d>
|
||||
void CompatDirect3d<TDirect3d>::setCompatVtable(Vtable<TDirect3d>& /*vtable*/)
|
||||
void CompatDirect3d<TDirect3d>::setCompatVtable(Vtable<TDirect3d>& vtable)
|
||||
{
|
||||
vtable.EnumDevices = &enumDevices;
|
||||
// No need to fix FindDevice since it uses EnumDevices
|
||||
}
|
||||
|
||||
template CompatDirect3d<IDirect3D>;
|
||||
|
@ -1,8 +1,44 @@
|
||||
#include "CompatDepthBuffer.h"
|
||||
#include "CompatDirect3dDevice.h"
|
||||
#include "CompatPtr.h"
|
||||
#include "CompatRef.h"
|
||||
#include "Direct3dTypes.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename TDirect3dDevice, typename TD3dDeviceDesc>
|
||||
void fixSupportedZBufferBitDepths(CompatRef<TDirect3dDevice> d3dDevice, TD3dDeviceDesc& desc)
|
||||
{
|
||||
typedef typename Types<TDirect3dDevice>::TDirect3d TDirect3d;
|
||||
CompatPtr<TDirect3d> d3d;
|
||||
if (SUCCEEDED(CompatVtableBase<TDirect3dDevice>::s_origVtable.GetDirect3D(
|
||||
&d3dDevice, &d3d.getRef())))
|
||||
{
|
||||
typedef typename Types<TDirect3dDevice>::TDirect3dHighest TDirect3dHighest;
|
||||
CompatDepthBuffer::fixSupportedZBufferBitDepths<TDirect3dHighest>(d3d, desc);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TDirect3dDevice, typename TD3dDeviceDesc, typename... Params>
|
||||
HRESULT STDMETHODCALLTYPE getCaps(
|
||||
TDirect3dDevice* This,
|
||||
TD3dDeviceDesc* lpD3DHWDevDesc,
|
||||
Params... params)
|
||||
{
|
||||
HRESULT result = CompatVtableBase<TDirect3dDevice>::s_origVtable.GetCaps(
|
||||
This, lpD3DHWDevDesc, params...);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
fixSupportedZBufferBitDepths<TDirect3dDevice>(*This, *lpD3DHWDevDesc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TDirect3dDevice>
|
||||
void CompatDirect3dDevice<TDirect3dDevice>::setCompatVtable(Vtable<TDirect3dDevice>& /*vtable*/)
|
||||
void CompatDirect3dDevice<TDirect3dDevice>::setCompatVtable(Vtable<TDirect3dDevice>& vtable)
|
||||
{
|
||||
vtable.GetCaps = &getCaps;
|
||||
}
|
||||
|
||||
template CompatDirect3dDevice<IDirect3DDevice>;
|
||||
|
@ -145,6 +145,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CompatActivateAppHandler.h" />
|
||||
<ClInclude Include="CompatDepthBuffer.h" />
|
||||
<ClInclude Include="CompatDirect3d.h" />
|
||||
<ClInclude Include="CompatDirect3dDevice.h" />
|
||||
<ClInclude Include="CompatDirectDrawPalette.h" />
|
||||
@ -179,6 +180,7 @@
|
||||
<ClInclude Include="DDrawVtableVisitor.h" />
|
||||
<ClInclude Include="CompatVtable.h" />
|
||||
<ClInclude Include="Direct3dDeviceVtblVisitor.h" />
|
||||
<ClInclude Include="Direct3dTypes.h" />
|
||||
<ClInclude Include="Direct3dVtblVisitor.h" />
|
||||
<ClInclude Include="DirectDrawPaletteVtblVisitor.h" />
|
||||
<ClInclude Include="DirectDrawSurfaceVtblVisitor.h" />
|
||||
@ -192,6 +194,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CompatActivateAppHandler.cpp" />
|
||||
<ClCompile Include="CompatDepthBuffer.cpp" />
|
||||
<ClCompile Include="CompatDirect3d.cpp" />
|
||||
<ClCompile Include="CompatDirect3dDevice.cpp" />
|
||||
<ClCompile Include="CompatDirectDraw.cpp" />
|
||||
|
@ -150,6 +150,12 @@
|
||||
<ClInclude Include="CompatDirect3dDevice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Direct3dTypes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompatDepthBuffer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="DllMain.cpp">
|
||||
@ -248,6 +254,9 @@
|
||||
<ClCompile Include="CompatDirect3dDevice.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompatDepthBuffer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="DDrawCompat.def">
|
||||
|
64
DDrawCompat/Direct3dTypes.h
Normal file
64
DDrawCompat/Direct3dTypes.h
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#define CINTERFACE
|
||||
|
||||
#include <d3d.h>
|
||||
|
||||
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 <typename Interface>
|
||||
struct Types;
|
||||
|
||||
#define D3D_CONCAT(x, y, ...) x##y
|
||||
|
||||
#define D3D_TYPES(Interface, ...) \
|
||||
template <> \
|
||||
struct Types<D3D_CONCAT(Interface, __VA_ARGS__)> : 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
|
Loading…
x
Reference in New Issue
Block a user