diff --git a/src/d3d8/d3d8_device.cpp b/src/d3d8/d3d8_device.cpp index f56fb80d7..f0315d8c0 100644 --- a/src/d3d8/d3d8_device.cpp +++ b/src/d3d8/d3d8_device.cpp @@ -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(); diff --git a/src/d3d8/d3d8_interface.cpp b/src/d3d8/d3d8_interface.cpp index 6324946b6..a5550d532 100644 --- a/src/d3d8/d3d8_interface.cpp +++ b/src/d3d8/d3d8_interface.cpp @@ -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 pDevice9 = nullptr; d3d9::D3DPRESENT_PARAMETERS params = ConvertPresentParameters9(pPresentationParameters); HRESULT res = m_d3d9->CreateDevice( diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 5818a39a4..8413e6cd6 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -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; diff --git a/src/d3d9/d3d9_interface.cpp b/src/d3d9/d3d9_interface.cpp index be302bced..d30aa148b 100644 --- a/src/d3d9/d3d9_interface.cpp +++ b/src/d3d9/d3d9_interface.cpp @@ -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); diff --git a/src/d3d9/d3d9_interface.h b/src/d3d9/d3d9_interface.h index 2bb0e0a82..2449694b2 100644 --- a/src/d3d9/d3d9_interface.h +++ b/src/d3d9/d3d9_interface.h @@ -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 m_instance; DxvkD3D8InterfaceBridge m_d3d8Bridge;