1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-20 08:52:22 +01:00

[d3d9] Add present params validations on device creation and reset

This commit is contained in:
WinterSnowfall 2024-10-14 00:56:53 +03:00 committed by Robin Kertels
parent 35352b9c52
commit a7c2eb140e
5 changed files with 77 additions and 14 deletions

View File

@ -228,6 +228,13 @@ namespace dxvk {
if (unlikely(pPresentationParameters == nullptr))
return D3DERR_INVALIDCALL;
// D3DSWAPEFFECT_COPY can not be used with more than one back buffer.
// This is also technically true for D3DSWAPEFFECT_COPY_VSYNC, however
// RC Cars depends on it not being rejected.
if (unlikely(pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY
&& pPresentationParameters->BackBufferCount > 1))
return D3DERR_INVALIDCALL;
m_presentParams = *pPresentationParameters;
ResetState();

View File

@ -122,6 +122,13 @@ namespace dxvk
ppReturnedDeviceInterface == nullptr))
return D3DERR_INVALIDCALL;
// D3DSWAPEFFECT_COPY can not be used with more than one back buffer.
// This is also technically true for D3DSWAPEFFECT_COPY_VSYNC, however
// RC Cars depends on it not being rejected.
if (unlikely(pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY
&& pPresentationParameters->BackBufferCount > 1))
return D3DERR_INVALIDCALL;
Com<d3d9::IDirect3DDevice9> pDevice9 = nullptr;
d3d9::D3DPRESENT_PARAMETERS params = ConvertPresentParameters9(pPresentationParameters);
HRESULT res = m_d3d9->CreateDevice(

View File

@ -476,6 +476,11 @@ namespace dxvk {
Logger::info("Device reset");
m_deviceLostState = D3D9DeviceLostState::Ok;
HRESULT hr = m_parent->ValidatePresentationParameters(pPresentationParameters);
if (unlikely(FAILED(hr)))
return hr;
if (!IsExtended()) {
// The internal references are always cleared, regardless of whether the Reset call succeeds.
ResetState(pPresentationParameters);
@ -507,8 +512,8 @@ namespace dxvk {
return D3DERR_DEVICELOST;
}
HRESULT hr = ResetSwapChain(pPresentationParameters, nullptr);
if (FAILED(hr)) {
hr = ResetSwapChain(pPresentationParameters, nullptr);
if (unlikely(FAILED(hr))) {
if (!IsExtended()) {
Logger::warn("Device reset failed: Device not reset");
m_deviceLostState = D3D9DeviceLostState::NotReset;

View File

@ -350,16 +350,21 @@ namespace dxvk {
IDirect3DDevice9Ex** ppReturnedDeviceInterface) {
InitReturnPtr(ppReturnedDeviceInterface);
if (ppReturnedDeviceInterface == nullptr
|| pPresentationParameters == nullptr)
if (unlikely(ppReturnedDeviceInterface == nullptr
|| pPresentationParameters == nullptr))
return D3DERR_INVALIDCALL;
// creating a device with D3DCREATE_PUREDEVICE only works in conjunction
// with D3DCREATE_HARDWARE_VERTEXPROCESSING on native drivers
if (BehaviorFlags & D3DCREATE_PUREDEVICE &&
!(BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING))
// Creating a device with D3DCREATE_PUREDEVICE only works in conjunction
// with D3DCREATE_HARDWARE_VERTEXPROCESSING on native drivers.
if (unlikely(BehaviorFlags & D3DCREATE_PUREDEVICE &&
!(BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)))
return D3DERR_INVALIDCALL;
HRESULT hr = ValidatePresentationParameters(pPresentationParameters);
if (unlikely(FAILED(hr)))
return hr;
auto* adapter = GetAdapter(Adapter);
if (adapter == nullptr)
@ -378,9 +383,9 @@ namespace dxvk {
BehaviorFlags,
dxvkDevice);
HRESULT hr = device->InitialReset(pPresentationParameters, pFullscreenDisplayMode);
hr = device->InitialReset(pPresentationParameters, pFullscreenDisplayMode);
if (FAILED(hr))
if (unlikely(FAILED(hr)))
return hr;
*ppReturnedDeviceInterface = ref(device);

View File

@ -121,6 +121,49 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE GetAdapterLUID(UINT Adapter, LUID* pLUID);
HRESULT ValidatePresentationParameters(D3DPRESENT_PARAMETERS* pPresentationParameters) {
if (m_extended) {
// The swap effect value on a D3D9Ex device
// can not be higher than D3DSWAPEFFECT_FLIPEX.
if (unlikely(pPresentationParameters->SwapEffect > D3DSWAPEFFECT_FLIPEX))
return D3DERR_INVALIDCALL;
} else {
// The swap effect value on a non-Ex D3D9 device
// can not be higher than D3DSWAPEFFECT_COPY.
if (unlikely(pPresentationParameters->SwapEffect > D3DSWAPEFFECT_COPY))
return D3DERR_INVALIDCALL;
}
// The swap effect value can not be 0.
if (unlikely(!pPresentationParameters->SwapEffect))
return D3DERR_INVALIDCALL;
// D3DSWAPEFFECT_COPY can not be used with more than one back buffer.
// Allow D3DSWAPEFFECT_COPY to bypass this restriction in D3D8 compatibility
// mode, since it may be a remapping of D3DSWAPEFFECT_COPY_VSYNC and RC Cars
// depends on it not being validated.
if (unlikely(!IsD3D8Compatible()
&& pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY
&& pPresentationParameters->BackBufferCount > 1))
return D3DERR_INVALIDCALL;
// 3 is the highest supported back buffer count.
if (unlikely(pPresentationParameters->BackBufferCount > 3))
return D3DERR_INVALIDCALL;
// Valid fullscreen presentation intervals must be known values.
if (unlikely(!pPresentationParameters->Windowed
&& !(pPresentationParameters->PresentationInterval == D3DPRESENT_INTERVAL_DEFAULT
|| pPresentationParameters->PresentationInterval == D3DPRESENT_INTERVAL_ONE
|| pPresentationParameters->PresentationInterval == D3DPRESENT_INTERVAL_TWO
|| pPresentationParameters->PresentationInterval == D3DPRESENT_INTERVAL_THREE
|| pPresentationParameters->PresentationInterval == D3DPRESENT_INTERVAL_FOUR
|| pPresentationParameters->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE)))
return D3DERR_INVALIDCALL;
return D3D_OK;
}
const D3D9Options& GetOptions() { return m_d3d9Options; }
D3D9Adapter* GetAdapter(UINT Ordinal) {
@ -146,10 +189,6 @@ namespace dxvk {
private:
void CacheModes(D3D9Format Format);
static const char* GetDriverDllName(DxvkGpuVendor vendor);
Rc<DxvkInstance> m_instance;
DxvkD3D8InterfaceBridge m_d3d8Bridge;