From adb0f5e16b85623cd5b4409294f7df1007ac2209 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 18 Apr 2018 17:30:46 +0200 Subject: [PATCH] [dxgi] DxgiSwapchain: Check whether window is valid Fixes a GPU hang when closing Dark Souls 3 as well as similar undesired behaviour in other games that continue to use the DXGI swap chain after the window has been destroyed. --- src/dxgi/dxgi_swapchain.cpp | 38 ++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index 946148157..b8be17984 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -96,6 +96,9 @@ namespace dxvk { std::lock_guard lock(m_mutex); + if (!IsWindow(m_desc.OutputWindow)) + return DXGI_ERROR_INVALID_CALL; + if (Buffer > 0) { Logger::err("DxgiSwapChain::GetBuffer: Buffer > 0 not supported"); return DXGI_ERROR_INVALID_CALL; @@ -108,6 +111,11 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetContainingOutput(IDXGIOutput** ppOutput) { InitReturnPtr(ppOutput); + std::lock_guard lock(m_mutex); + + if (!IsWindow(m_desc.OutputWindow)) + return DXGI_ERROR_INVALID_CALL; + RECT windowRect = { 0, 0, 0, 0 }; ::GetWindowRect(m_desc.OutputWindow, &windowRect); @@ -121,20 +129,22 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) { + std::lock_guard lock(m_mutex); + if (pDesc == nullptr) return DXGI_ERROR_INVALID_CALL; - std::lock_guard lock(m_mutex); *pDesc = m_desc; return S_OK; } HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) { + std::lock_guard lock(m_mutex); + if (pStats == nullptr) return DXGI_ERROR_INVALID_CALL; - std::lock_guard lock(m_mutex); *pStats = m_stats; return S_OK; } @@ -145,6 +155,9 @@ namespace dxvk { IDXGIOutput** ppTarget) { std::lock_guard lock(m_mutex); + if (!IsWindow(m_desc.OutputWindow)) + return DXGI_ERROR_INVALID_CALL; + HRESULT hr = S_OK; if (pFullscreen != nullptr) @@ -162,10 +175,11 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetLastPresentCount(UINT* pLastPresentCount) { + std::lock_guard lock(m_mutex); + if (pLastPresentCount == nullptr) return DXGI_ERROR_INVALID_CALL; - std::lock_guard lock(m_mutex); *pLastPresentCount = m_stats.PresentCount; return S_OK; } @@ -174,6 +188,9 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) { std::lock_guard lock(m_mutex); + if (!IsWindow(m_desc.OutputWindow)) + return DXGI_ERROR_INVALID_CALL; + if (Flags & DXGI_PRESENT_TEST) return S_OK; @@ -223,6 +240,9 @@ namespace dxvk { UINT SwapChainFlags) { std::lock_guard lock(m_mutex); + if (!IsWindow(m_desc.OutputWindow)) + return DXGI_ERROR_INVALID_CALL; + const VkExtent2D windowSize = GetWindowSize(); m_desc.BufferDesc.Width = Width != 0 ? Width : windowSize.width; @@ -241,10 +261,13 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiSwapChain::ResizeTarget(const DXGI_MODE_DESC* pNewTargetParameters) { + std::lock_guard lock(m_mutex); + if (pNewTargetParameters == nullptr) return DXGI_ERROR_INVALID_CALL; - std::lock_guard lock(m_mutex); + if (!IsWindow(m_desc.OutputWindow)) + return DXGI_ERROR_INVALID_CALL; // TODO support fullscreen mode RECT newRect = { 0, 0, 0, 0 }; @@ -269,6 +292,9 @@ namespace dxvk { IDXGIOutput* pTarget) { std::lock_guard lock(m_mutex); + if (!IsWindow(m_desc.OutputWindow)) + return DXGI_ERROR_INVALID_CALL; + if (Fullscreen) Logger::warn("DxgiSwapChain: Display mode changes not implemented"); @@ -357,7 +383,9 @@ namespace dxvk { VkExtent2D DxgiSwapChain::GetWindowSize() const { RECT windowRect; - ::GetClientRect(m_desc.OutputWindow, &windowRect); + + if (!::GetClientRect(m_desc.OutputWindow, &windowRect)) + windowRect = RECT(); VkExtent2D result; result.width = windowRect.right;