1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-12 13:08:50 +01:00

[d3d9] Handle swapchain OOM and other errors more gracefully

Supercedes: #2964
This commit is contained in:
Joshua Ashton 2023-05-03 12:34:37 +01:00 committed by Joshie
parent 20356148af
commit f140d2de0d
3 changed files with 44 additions and 13 deletions

View File

@ -7363,8 +7363,9 @@ namespace dxvk {
} }
if (m_implicitSwapchain != nullptr) { if (m_implicitSwapchain != nullptr) {
if (FAILED(m_implicitSwapchain->Reset(pPresentationParameters, pFullscreenDisplayMode))) HRESULT hr = m_implicitSwapchain->Reset(pPresentationParameters, pFullscreenDisplayMode);
return D3DERR_INVALIDCALL; if (FAILED(hr))
return hr;
} }
else else
m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode); m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);

View File

@ -43,7 +43,9 @@ namespace dxvk {
RecreateSwapChain(false); RecreateSwapChain(false);
} }
CreateBackBuffers(m_presentParams.BackBufferCount); if (FAILED(CreateBackBuffers(m_presentParams.BackBufferCount)))
throw DxvkError("D3D9: Failed to create swapchain backbuffers");
CreateBlitter(); CreateBlitter();
CreateHud(); CreateHud();
@ -101,6 +103,14 @@ namespace dxvk {
DWORD dwFlags) { DWORD dwFlags) {
D3D9DeviceLock lock = m_parent->LockDevice(); D3D9DeviceLock lock = m_parent->LockDevice();
// If we have no backbuffers, error out.
// This handles the case where a ::Reset failed due to OOM
// or whatever.
// I am not sure what the actual HRESULT returned here is
// or should be, but it is better than crashing... probably!
if (m_backBuffers.empty())
return D3D_OK;
uint32_t presentInterval = m_presentParams.PresentationInterval; uint32_t presentInterval = m_presentParams.PresentationInterval;
// This is not true directly in d3d9 to to timing differences that don't matter for us. // This is not true directly in d3d9 to to timing differences that don't matter for us.
@ -515,6 +525,8 @@ namespace dxvk {
D3DDISPLAYMODEEX* pFullscreenDisplayMode) { D3DDISPLAYMODEEX* pFullscreenDisplayMode) {
D3D9DeviceLock lock = m_parent->LockDevice(); D3D9DeviceLock lock = m_parent->LockDevice();
HRESULT hr = D3D_OK;
this->SynchronizePresent(); this->SynchronizePresent();
this->NormalizePresentParameters(pPresentParams); this->NormalizePresentParameters(pPresentParams);
@ -529,15 +541,17 @@ namespace dxvk {
} }
else { else {
if (changeFullscreen) { if (changeFullscreen) {
if (FAILED(this->EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode))) hr = this->EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode);
return D3DERR_INVALIDCALL; if (FAILED(hr))
return hr;
} }
D3D9WindowMessageFilter filter(m_window); D3D9WindowMessageFilter filter(m_window);
if (!changeFullscreen) { if (!changeFullscreen) {
if (FAILED(ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode))) hr = ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode);
return D3DERR_INVALIDCALL; if (FAILED(hr))
return hr;
wsi::updateFullscreenWindow(m_monitor, m_window, true); wsi::updateFullscreenWindow(m_monitor, m_window, true);
} }
@ -548,7 +562,9 @@ namespace dxvk {
if (changeFullscreen) if (changeFullscreen)
SetGammaRamp(0, &m_ramp); SetGammaRamp(0, &m_ramp);
CreateBackBuffers(m_presentParams.BackBufferCount); hr = CreateBackBuffers(m_presentParams.BackBufferCount);
if (FAILED(hr))
return hr;
return D3D_OK; return D3D_OK;
} }
@ -921,13 +937,15 @@ namespace dxvk {
} }
void D3D9SwapChainEx::CreateBackBuffers(uint32_t NumBackBuffers) { HRESULT D3D9SwapChainEx::CreateBackBuffers(uint32_t NumBackBuffers) {
// Explicitly destroy current swap image before // Explicitly destroy current swap image before
// creating a new one to free up resources // creating a new one to free up resources
DestroyBackBuffers(); DestroyBackBuffers();
int NumFrontBuffer = m_parent->GetOptions()->noExplicitFrontBuffer ? 0 : 1; int NumFrontBuffer = m_parent->GetOptions()->noExplicitFrontBuffer ? 0 : 1;
m_backBuffers.resize(NumBackBuffers + NumFrontBuffer); const uint32_t NumBuffers = NumBackBuffers + NumFrontBuffer;
m_backBuffers.reserve(NumBuffers);
// Create new back buffer // Create new back buffer
D3D9_COMMON_TEXTURE_DESC desc; D3D9_COMMON_TEXTURE_DESC desc;
@ -947,8 +965,18 @@ namespace dxvk {
// Docs: Also note that - unlike textures - swap chain back buffers, render targets [..] can be locked // Docs: Also note that - unlike textures - swap chain back buffers, render targets [..] can be locked
desc.IsLockable = TRUE; desc.IsLockable = TRUE;
for (uint32_t i = 0; i < m_backBuffers.size(); i++) for (uint32_t i = 0; i < NumBuffers; i++) {
m_backBuffers[i] = new D3D9Surface(m_parent, &desc, this, nullptr); D3D9Surface* surface;
try {
surface = new D3D9Surface(m_parent, &desc, this, nullptr);
} catch (const DxvkError& e) {
DestroyBackBuffers();
Logger::err(e.message());
return D3DERR_OUTOFVIDEOMEMORY;
}
m_backBuffers.emplace_back(surface);
}
auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage(); auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
@ -973,6 +1001,8 @@ namespace dxvk {
m_device->submitCommandList( m_device->submitCommandList(
m_context->endRecording(), m_context->endRecording(),
nullptr); nullptr);
return D3D_OK;
} }

View File

@ -150,7 +150,7 @@ namespace dxvk {
void DestroyBackBuffers(); void DestroyBackBuffers();
void CreateBackBuffers( HRESULT CreateBackBuffers(
uint32_t NumBackBuffers); uint32_t NumBackBuffers);
void CreateBlitter(); void CreateBlitter();