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:
parent
20356148af
commit
f140d2de0d
@ -7363,8 +7363,9 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
if (m_implicitSwapchain != nullptr) {
|
||||
if (FAILED(m_implicitSwapchain->Reset(pPresentationParameters, pFullscreenDisplayMode)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
HRESULT hr = m_implicitSwapchain->Reset(pPresentationParameters, pFullscreenDisplayMode);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
else
|
||||
m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
|
||||
|
@ -43,7 +43,9 @@ namespace dxvk {
|
||||
RecreateSwapChain(false);
|
||||
}
|
||||
|
||||
CreateBackBuffers(m_presentParams.BackBufferCount);
|
||||
if (FAILED(CreateBackBuffers(m_presentParams.BackBufferCount)))
|
||||
throw DxvkError("D3D9: Failed to create swapchain backbuffers");
|
||||
|
||||
CreateBlitter();
|
||||
CreateHud();
|
||||
|
||||
@ -101,6 +103,14 @@ namespace dxvk {
|
||||
DWORD dwFlags) {
|
||||
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;
|
||||
|
||||
// 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) {
|
||||
D3D9DeviceLock lock = m_parent->LockDevice();
|
||||
|
||||
HRESULT hr = D3D_OK;
|
||||
|
||||
this->SynchronizePresent();
|
||||
this->NormalizePresentParameters(pPresentParams);
|
||||
|
||||
@ -529,15 +541,17 @@ namespace dxvk {
|
||||
}
|
||||
else {
|
||||
if (changeFullscreen) {
|
||||
if (FAILED(this->EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
hr = this->EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
|
||||
D3D9WindowMessageFilter filter(m_window);
|
||||
|
||||
if (!changeFullscreen) {
|
||||
if (FAILED(ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
hr = ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
wsi::updateFullscreenWindow(m_monitor, m_window, true);
|
||||
}
|
||||
@ -548,7 +562,9 @@ namespace dxvk {
|
||||
if (changeFullscreen)
|
||||
SetGammaRamp(0, &m_ramp);
|
||||
|
||||
CreateBackBuffers(m_presentParams.BackBufferCount);
|
||||
hr = CreateBackBuffers(m_presentParams.BackBufferCount);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
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
|
||||
// creating a new one to free up resources
|
||||
DestroyBackBuffers();
|
||||
|
||||
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
|
||||
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
|
||||
desc.IsLockable = TRUE;
|
||||
|
||||
for (uint32_t i = 0; i < m_backBuffers.size(); i++)
|
||||
m_backBuffers[i] = new D3D9Surface(m_parent, &desc, this, nullptr);
|
||||
for (uint32_t i = 0; i < NumBuffers; i++) {
|
||||
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();
|
||||
|
||||
@ -973,6 +1001,8 @@ namespace dxvk {
|
||||
m_device->submitCommandList(
|
||||
m_context->endRecording(),
|
||||
nullptr);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -150,7 +150,7 @@ namespace dxvk {
|
||||
|
||||
void DestroyBackBuffers();
|
||||
|
||||
void CreateBackBuffers(
|
||||
HRESULT CreateBackBuffers(
|
||||
uint32_t NumBackBuffers);
|
||||
|
||||
void CreateBlitter();
|
||||
|
Loading…
Reference in New Issue
Block a user