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

[d3d9] Reject Reset if there's any remaining DEFAULT resources

This commit is contained in:
Robin Kertels 2023-06-10 01:18:05 +02:00 committed by Joshie
parent a1a91dd766
commit 52ac271acb
13 changed files with 192 additions and 58 deletions

View File

@ -20,6 +20,11 @@ namespace dxvk {
m_dirtyRange = D3D9Range(0, m_desc.Size); m_dirtyRange = D3D9Range(0, m_desc.Size);
} }
D3D9CommonBuffer::~D3D9CommonBuffer() {
if (m_desc.Pool == D3DPOOL_DEFAULT)
m_parent->DecrementLosableCounter();
}
HRESULT D3D9CommonBuffer::Lock( HRESULT D3D9CommonBuffer::Lock(
UINT OffsetToLock, UINT OffsetToLock,

View File

@ -78,6 +78,8 @@ namespace dxvk {
D3D9DeviceEx* pDevice, D3D9DeviceEx* pDevice,
const D3D9_BUFFER_DESC* pDesc); const D3D9_BUFFER_DESC* pDesc);
~D3D9CommonBuffer();
HRESULT Lock( HRESULT Lock(
UINT OffsetToLock, UINT OffsetToLock,
UINT SizeToLock, UINT SizeToLock,

View File

@ -98,6 +98,9 @@ namespace dxvk {
m_device->ChangeReportedMemory(m_size); m_device->ChangeReportedMemory(m_size);
m_device->RemoveMappedTexture(this); m_device->RemoveMappedTexture(this);
if (m_desc.IsLosable)
m_device->DecrementLosableCounter();
} }

View File

@ -48,6 +48,7 @@ namespace dxvk {
bool IsBackBuffer; bool IsBackBuffer;
bool IsAttachmentOnly; bool IsAttachmentOnly;
bool IsLockable; bool IsLockable;
bool IsLosable;
}; };
struct D3D9ColorView { struct D3D9ColorView {

View File

@ -415,11 +415,42 @@ namespace dxvk {
Logger::info("Device reset"); Logger::info("Device reset");
m_deviceLostState = D3D9DeviceLostState::Ok; m_deviceLostState = D3D9DeviceLostState::Ok;
HRESULT hr = ResetSwapChain(pPresentationParameters, nullptr); if (!IsExtended()) {
if (FAILED(hr)) // The internal references are always cleared, regardless of whether the Reset call succeeds.
return hr;
ResetState(pPresentationParameters); ResetState(pPresentationParameters);
m_implicitSwapchain->DestroyBackBuffers();
m_autoDepthStencil = nullptr;
} else {
// Extended devices only reset the bound render targets
for (uint32_t i = 0; i < caps::MaxSimultaneousRenderTargets; i++) {
SetRenderTargetInternal(i, nullptr);
}
SetDepthStencilSurface(nullptr);
}
/*
* Before calling the IDirect3DDevice9::Reset method for a device,
* an application should release any explicit render targets,
* depth stencil surfaces, additional swap chains, state blocks,
* and D3DPOOL_DEFAULT resources associated with the device.
*
* We have to check after ResetState clears the references held by SetTexture, etc.
* This matches what Windows D3D9 does.
*/
if (unlikely(m_losableResourceCounter.load() != 0 && !IsExtended())) {
Logger::warn(str::format("Device reset failed because device still has alive losable resources: Device not reset. Remaining resources: ", m_losableResourceCounter.load()));
m_deviceLostState = D3D9DeviceLostState::NotReset;
return D3DERR_INVALIDCALL;
}
HRESULT hr = ResetSwapChain(pPresentationParameters, nullptr);
if (FAILED(hr)) {
if (!IsExtended()) {
Logger::warn("Device reset failed: Device not reset");
m_deviceLostState = D3D9DeviceLostState::NotReset;
}
return hr;
}
Flush(); Flush();
SynchronizeCsThread(DxvkCsThread::SynchronizeAll); SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
@ -516,6 +547,7 @@ namespace dxvk {
desc.MultisampleQuality = 0; desc.MultisampleQuality = 0;
desc.IsBackBuffer = FALSE; desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = FALSE; desc.IsAttachmentOnly = FALSE;
desc.IsLosable = Pool == D3DPOOL_DEFAULT;
// Docs: // Docs:
// Textures placed in the D3DPOOL_DEFAULT pool cannot be locked // Textures placed in the D3DPOOL_DEFAULT pool cannot be locked
// unless they are dynamic textures or they are private, FOURCC, driver formats. // unless they are dynamic textures or they are private, FOURCC, driver formats.
@ -542,6 +574,9 @@ namespace dxvk {
m_initializer->InitTexture(texture->GetCommonTexture(), initialData); m_initializer->InitTexture(texture->GetCommonTexture(), initialData);
*ppTexture = texture.ref(); *ppTexture = texture.ref();
if (desc.IsLosable)
m_losableResourceCounter++;
return D3D_OK; return D3D_OK;
} }
catch (const DxvkError& e) { catch (const DxvkError& e) {
@ -583,6 +618,7 @@ namespace dxvk {
desc.MultisampleQuality = 0; desc.MultisampleQuality = 0;
desc.IsBackBuffer = FALSE; desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = FALSE; desc.IsAttachmentOnly = FALSE;
desc.IsLosable = Pool == D3DPOOL_DEFAULT;
// Docs: // Docs:
// Textures placed in the D3DPOOL_DEFAULT pool cannot be locked // Textures placed in the D3DPOOL_DEFAULT pool cannot be locked
// unless they are dynamic textures or they are private, FOURCC, driver formats. // unless they are dynamic textures or they are private, FOURCC, driver formats.
@ -598,6 +634,9 @@ namespace dxvk {
m_initializer->InitTexture(texture->GetCommonTexture()); m_initializer->InitTexture(texture->GetCommonTexture());
*ppVolumeTexture = texture.ref(); *ppVolumeTexture = texture.ref();
if (desc.IsLosable)
m_losableResourceCounter++;
return D3D_OK; return D3D_OK;
} }
catch (const DxvkError& e) { catch (const DxvkError& e) {
@ -637,6 +676,7 @@ namespace dxvk {
desc.MultisampleQuality = 0; desc.MultisampleQuality = 0;
desc.IsBackBuffer = FALSE; desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = FALSE; desc.IsAttachmentOnly = FALSE;
desc.IsLosable = Pool == D3DPOOL_DEFAULT;
// Docs: // Docs:
// Textures placed in the D3DPOOL_DEFAULT pool cannot be locked // Textures placed in the D3DPOOL_DEFAULT pool cannot be locked
// unless they are dynamic textures or they are private, FOURCC, driver formats. // unless they are dynamic textures or they are private, FOURCC, driver formats.
@ -652,6 +692,9 @@ namespace dxvk {
m_initializer->InitTexture(texture->GetCommonTexture()); m_initializer->InitTexture(texture->GetCommonTexture());
*ppCubeTexture = texture.ref(); *ppCubeTexture = texture.ref();
if (desc.IsLosable)
m_losableResourceCounter++;
return D3D_OK; return D3D_OK;
} }
catch (const DxvkError& e) { catch (const DxvkError& e) {
@ -691,6 +734,9 @@ namespace dxvk {
const Com<D3D9VertexBuffer> buffer = new D3D9VertexBuffer(this, &desc); const Com<D3D9VertexBuffer> buffer = new D3D9VertexBuffer(this, &desc);
m_initializer->InitBuffer(buffer->GetCommonBuffer()); m_initializer->InitBuffer(buffer->GetCommonBuffer());
*ppVertexBuffer = buffer.ref(); *ppVertexBuffer = buffer.ref();
if (desc.Pool == D3DPOOL_DEFAULT)
m_losableResourceCounter++;
return D3D_OK; return D3D_OK;
} }
catch (const DxvkError & e) { catch (const DxvkError & e) {
@ -729,6 +775,9 @@ namespace dxvk {
const Com<D3D9IndexBuffer> buffer = new D3D9IndexBuffer(this, &desc); const Com<D3D9IndexBuffer> buffer = new D3D9IndexBuffer(this, &desc);
m_initializer->InitBuffer(buffer->GetCommonBuffer()); m_initializer->InitBuffer(buffer->GetCommonBuffer());
*ppIndexBuffer = buffer.ref(); *ppIndexBuffer = buffer.ref();
if (desc.Pool == D3DPOOL_DEFAULT)
m_losableResourceCounter++;
return D3D_OK; return D3D_OK;
} }
catch (const DxvkError & e) { catch (const DxvkError & e) {
@ -1311,14 +1360,22 @@ namespace dxvk {
0); 0);
} }
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetRenderTarget( HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetRenderTarget(
DWORD RenderTargetIndex, DWORD RenderTargetIndex,
IDirect3DSurface9* pRenderTarget) { IDirect3DSurface9* pRenderTarget) {
D3D9DeviceLock lock = LockDevice(); D3D9DeviceLock lock = LockDevice();
if (unlikely(RenderTargetIndex >= caps::MaxSimultaneousRenderTargets if (unlikely((pRenderTarget == nullptr && RenderTargetIndex == 0)))
|| (pRenderTarget == nullptr && RenderTargetIndex == 0))) return D3DERR_INVALIDCALL;
return SetRenderTargetInternal(RenderTargetIndex, pRenderTarget);
}
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetRenderTargetInternal(
DWORD RenderTargetIndex,
IDirect3DSurface9* pRenderTarget) {
if (unlikely(RenderTargetIndex >= caps::MaxSimultaneousRenderTargets))
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
D3D9Surface* rt = static_cast<D3D9Surface*>(pRenderTarget); D3D9Surface* rt = static_cast<D3D9Surface*>(pRenderTarget);
@ -1330,21 +1387,28 @@ namespace dxvk {
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
if (RenderTargetIndex == 0) { if (RenderTargetIndex == 0) {
auto rtSize = rt->GetSurfaceExtent();
D3DVIEWPORT9 viewport; D3DVIEWPORT9 viewport;
viewport.X = 0; viewport.X = 0;
viewport.Y = 0; viewport.Y = 0;
viewport.Width = rtSize.width;
viewport.Height = rtSize.height;
viewport.MinZ = 0.0f; viewport.MinZ = 0.0f;
viewport.MaxZ = 1.0f; viewport.MaxZ = 1.0f;
RECT scissorRect; RECT scissorRect;
scissorRect.left = 0; scissorRect.left = 0;
scissorRect.top = 0; scissorRect.top = 0;
if (likely(rt != nullptr)) {
auto rtSize = rt->GetSurfaceExtent();
viewport.Width = rtSize.width;
viewport.Height = rtSize.height;
scissorRect.right = rtSize.width; scissorRect.right = rtSize.width;
scissorRect.bottom = rtSize.height; scissorRect.bottom = rtSize.height;
} else {
viewport.Width = 0;
viewport.Height = 0;
scissorRect.right = 0;
scissorRect.bottom = 0;
}
if (m_state.viewport != viewport) { if (m_state.viewport != viewport) {
m_flags.set(D3D9DeviceFlag::DirtyFFViewport); m_flags.set(D3D9DeviceFlag::DirtyFFViewport);
@ -1389,6 +1453,7 @@ namespace dxvk {
m_flags.set(D3D9DeviceFlag::DirtyBlendState); m_flags.set(D3D9DeviceFlag::DirtyBlendState);
if (RenderTargetIndex == 0) { if (RenderTargetIndex == 0) {
if (likely(texInfo != nullptr)) {
bool validSampleMask = texInfo->Desc()->MultiSample > D3DMULTISAMPLE_NONMASKABLE; bool validSampleMask = texInfo->Desc()->MultiSample > D3DMULTISAMPLE_NONMASKABLE;
if (validSampleMask != m_flags.test(D3D9DeviceFlag::ValidSampleMask)) { if (validSampleMask != m_flags.test(D3D9DeviceFlag::ValidSampleMask)) {
@ -1398,6 +1463,10 @@ namespace dxvk {
m_flags.set(D3D9DeviceFlag::DirtyMultiSampleState); m_flags.set(D3D9DeviceFlag::DirtyMultiSampleState);
} }
} else {
m_flags.clr(D3D9DeviceFlag::ValidSampleMask);
m_flags.set(D3D9DeviceFlag::DirtyMultiSampleState);
}
} }
return D3D_OK; return D3D_OK;
@ -2254,6 +2323,8 @@ namespace dxvk {
try { try {
const Com<D3D9StateBlock> sb = new D3D9StateBlock(this, ConvertStateBlockType(Type)); const Com<D3D9StateBlock> sb = new D3D9StateBlock(this, ConvertStateBlockType(Type));
*ppSB = sb.ref(); *ppSB = sb.ref();
m_losableResourceCounter++;
return D3D_OK; return D3D_OK;
} }
catch (const DxvkError & e) { catch (const DxvkError & e) {
@ -2284,6 +2355,7 @@ namespace dxvk {
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
*ppSB = m_recorder.ref(); *ppSB = m_recorder.ref();
m_losableResourceCounter++;
m_recorder = nullptr; m_recorder = nullptr;
return D3D_OK; return D3D_OK;
@ -3613,6 +3685,7 @@ namespace dxvk {
desc.IsBackBuffer = FALSE; desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = TRUE; desc.IsAttachmentOnly = TRUE;
desc.IsLockable = Lockable; desc.IsLockable = Lockable;
desc.IsLosable = TRUE;
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc))) if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
@ -3621,6 +3694,8 @@ namespace dxvk {
const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle); const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle);
m_initializer->InitTexture(surface->GetCommonTexture()); m_initializer->InitTexture(surface->GetCommonTexture());
*ppSurface = surface.ref(); *ppSurface = surface.ref();
m_losableResourceCounter++;
return D3D_OK; return D3D_OK;
} }
catch (const DxvkError& e) { catch (const DxvkError& e) {
@ -3657,6 +3732,7 @@ namespace dxvk {
desc.MultisampleQuality = 0; desc.MultisampleQuality = 0;
desc.IsBackBuffer = FALSE; desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = Pool == D3DPOOL_DEFAULT; desc.IsAttachmentOnly = Pool == D3DPOOL_DEFAULT;
desc.IsLosable = Pool == D3DPOOL_DEFAULT;
// Docs: Off-screen plain surfaces are always lockable, regardless of their pool types. // Docs: Off-screen plain surfaces are always lockable, regardless of their pool types.
desc.IsLockable = TRUE; desc.IsLockable = TRUE;
@ -3670,6 +3746,10 @@ namespace dxvk {
const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle); const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle);
m_initializer->InitTexture(surface->GetCommonTexture()); m_initializer->InitTexture(surface->GetCommonTexture());
*ppSurface = surface.ref(); *ppSurface = surface.ref();
if (desc.IsLosable)
m_losableResourceCounter++;
return D3D_OK; return D3D_OK;
} }
catch (const DxvkError& e) { catch (const DxvkError& e) {
@ -3708,6 +3788,7 @@ namespace dxvk {
desc.MultisampleQuality = MultisampleQuality; desc.MultisampleQuality = MultisampleQuality;
desc.IsBackBuffer = FALSE; desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = TRUE; desc.IsAttachmentOnly = TRUE;
desc.IsLosable = TRUE;
// Docs don't say anything, so just assume it's lockable. // Docs don't say anything, so just assume it's lockable.
desc.IsLockable = TRUE; desc.IsLockable = TRUE;
@ -3718,6 +3799,8 @@ namespace dxvk {
const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle); const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle);
m_initializer->InitTexture(surface->GetCommonTexture()); m_initializer->InitTexture(surface->GetCommonTexture());
*ppSurface = surface.ref(); *ppSurface = surface.ref();
m_losableResourceCounter++;
return D3D_OK; return D3D_OK;
} }
catch (const DxvkError& e) { catch (const DxvkError& e) {
@ -3779,6 +3862,7 @@ namespace dxvk {
try { try {
auto* swapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode); auto* swapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
*ppSwapChain = ref(swapchain); *ppSwapChain = ref(swapchain);
m_losableResourceCounter++;
} }
catch (const DxvkError & e) { catch (const DxvkError & e) {
Logger::err(e.message()); Logger::err(e.message());
@ -7171,11 +7255,10 @@ namespace dxvk {
void D3D9DeviceEx::ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters) { void D3D9DeviceEx::ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters) {
if (!pPresentationParameters->EnableAutoDepthStencil)
SetDepthStencilSurface(nullptr); SetDepthStencilSurface(nullptr);
for (uint32_t i = 1; i < caps::MaxSimultaneousRenderTargets; i++) for (uint32_t i = 0; i < caps::MaxSimultaneousRenderTargets; i++)
SetRenderTarget(i, nullptr); SetRenderTargetInternal(i, nullptr);
auto& rs = m_state.renderStates; auto& rs = m_state.renderStates;
@ -7358,8 +7441,9 @@ namespace dxvk {
for (uint32_t i = 0; i < caps::MaxStreams; i++) for (uint32_t i = 0; i < caps::MaxStreams; i++)
m_state.streamFreq[i] = 1; m_state.streamFreq[i] = 1;
for (uint32_t i = 0; i < m_state.textures->size(); i++) for (uint32_t i = 0; i < m_state.textures->size(); i++) {
SetStateTexture(i, nullptr); SetStateTexture(i, nullptr);
}
EmitCs([ EmitCs([
cSize = m_state.textures->size() cSize = m_state.textures->size()
@ -7465,6 +7549,7 @@ namespace dxvk {
desc.MultisampleQuality = pPresentationParameters->MultiSampleQuality; desc.MultisampleQuality = pPresentationParameters->MultiSampleQuality;
desc.IsBackBuffer = FALSE; desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = TRUE; desc.IsAttachmentOnly = TRUE;
desc.IsLosable = TRUE;
// 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;
@ -7474,6 +7559,7 @@ namespace dxvk {
m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr, nullptr); m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr, nullptr);
m_initializer->InitTexture(m_autoDepthStencil->GetCommonTexture()); m_initializer->InitTexture(m_autoDepthStencil->GetCommonTexture());
SetDepthStencilSurface(m_autoDepthStencil.ptr()); SetDepthStencilSurface(m_autoDepthStencil.ptr());
m_losableResourceCounter++;
} }
SetRenderTarget(0, m_implicitSwapchain->GetBackBuffer(0)); SetRenderTarget(0, m_implicitSwapchain->GetBackBuffer(0));
@ -7575,6 +7661,43 @@ namespace dxvk {
#endif #endif
} }
////////////////////////////////////
// D3D9 Device Lost
////////////////////////////////////
void D3D9DeviceEx::NotifyFullscreen(HWND window, bool fullscreen) {
D3D9DeviceLock lock = LockDevice();
if (fullscreen) {
if (unlikely(window != m_fullscreenWindow && m_fullscreenWindow != NULL)) {
Logger::warn("Multiple fullscreen windows detected.");
}
m_fullscreenWindow = window;
} else {
if (unlikely(m_fullscreenWindow != window)) {
Logger::warn("Window was not fullscreen in the first place.");
} else {
m_fullscreenWindow = 0;
}
}
}
void D3D9DeviceEx::NotifyWindowActivated(HWND window, bool activated) {
D3D9DeviceLock lock = LockDevice();
if (likely(!m_d3d9Options.deviceLossOnFocusLoss || IsExtended()))
return;
if (activated && m_deviceLostState == D3D9DeviceLostState::Lost) {
Logger::info("Device not reset");
m_deviceLostState = D3D9DeviceLostState::NotReset;
} else if (!activated && m_deviceLostState != D3D9DeviceLostState::Lost && m_fullscreenWindow == window) {
Logger::info("Device lost");
m_deviceLostState = D3D9DeviceLostState::Lost;
m_fullscreenWindow = NULL;
}
}
//////////////////////////////////// ////////////////////////////////////
// D3D9 Device Specialization State // D3D9 Device Specialization State
//////////////////////////////////// ////////////////////////////////////

View File

@ -879,6 +879,10 @@ namespace dxvk {
void MarkTextureBindingDirty(IDirect3DBaseTexture9* texture); void MarkTextureBindingDirty(IDirect3DBaseTexture9* texture);
HRESULT STDMETHODCALLTYPE SetRenderTargetInternal(
DWORD RenderTargetIndex,
IDirect3DSurface9* pRenderTarget);
D3D9DrawInfo GenerateDrawInfo( D3D9DrawInfo GenerateDrawInfo(
D3DPRIMITIVETYPE PrimitiveType, D3DPRIMITIVETYPE PrimitiveType,
UINT PrimitiveCount, UINT PrimitiveCount,
@ -961,41 +965,20 @@ namespace dxvk {
void TouchMappedTexture(D3D9CommonTexture* pTexture); void TouchMappedTexture(D3D9CommonTexture* pTexture);
void RemoveMappedTexture(D3D9CommonTexture* pTexture); void RemoveMappedTexture(D3D9CommonTexture* pTexture);
// Device Lost
bool IsDeviceLost() const { bool IsDeviceLost() const {
return m_deviceLostState != D3D9DeviceLostState::Ok; return m_deviceLostState != D3D9DeviceLostState::Ok;
} }
void NotifyFullscreen(HWND window, bool fullscreen) { void NotifyFullscreen(HWND window, bool fullscreen);
D3D9DeviceLock lock = LockDevice(); void NotifyWindowActivated(HWND window, bool activated);
if (fullscreen) { void IncrementLosableCounter() {
if (unlikely(window != m_fullscreenWindow && m_fullscreenWindow != NULL)) { m_losableResourceCounter++;
Logger::warn("Multiple fullscreen windows detected.");
}
m_fullscreenWindow = window;
} else {
if (unlikely(m_fullscreenWindow != window)) {
Logger::warn("Window was not fullscreen in the first place.");
} else {
m_fullscreenWindow = 0;
}
}
} }
void NotifyWindowActivated(HWND window, bool activated) { void DecrementLosableCounter() {
D3D9DeviceLock lock = LockDevice(); m_losableResourceCounter--;
if (likely(!m_d3d9Options.deviceLost || IsExtended()))
return;
if (activated && m_deviceLostState == D3D9DeviceLostState::Lost) {
Logger::info("Device not reset");
m_deviceLostState = D3D9DeviceLostState::NotReset;
} else if (!activated && m_deviceLostState != D3D9DeviceLostState::Lost && m_fullscreenWindow == window) {
Logger::info("Device lost");
m_deviceLostState = D3D9DeviceLostState::Lost;
m_fullscreenWindow = NULL;
}
} }
bool CanOnlySWVP() const { bool CanOnlySWVP() const {
@ -1369,6 +1352,7 @@ namespace dxvk {
D3D9DeviceLostState m_deviceLostState = D3D9DeviceLostState::Ok; D3D9DeviceLostState m_deviceLostState = D3D9DeviceLostState::Ok;
HWND m_fullscreenWindow = NULL; HWND m_fullscreenWindow = NULL;
std::atomic<uint32_t> m_losableResourceCounter = { 0 };
#ifdef D3D9_ALLOW_UNMAPPING #ifdef D3D9_ALLOW_UNMAPPING
lru_list<D3D9CommonTexture*> m_mappedTextures; lru_list<D3D9CommonTexture*> m_mappedTextures;

View File

@ -71,7 +71,7 @@ namespace dxvk {
this->allowDirectBufferMapping = config.getOption<bool> ("d3d9.allowDirectBufferMapping", true); this->allowDirectBufferMapping = config.getOption<bool> ("d3d9.allowDirectBufferMapping", true);
this->seamlessCubes = config.getOption<bool> ("d3d9.seamlessCubes", false); this->seamlessCubes = config.getOption<bool> ("d3d9.seamlessCubes", false);
this->textureMemory = config.getOption<int32_t> ("d3d9.textureMemory", 100) << 20; this->textureMemory = config.getOption<int32_t> ("d3d9.textureMemory", 100) << 20;
this->deviceLost = config.getOption<bool> ("d3d9.deviceLost", false); this->deviceLossOnFocusLoss = config.getOption<bool> ("d3d9.deviceLossOnFocusLoss", false);
std::string floatEmulation = Config::toLower(config.getOption<std::string>("d3d9.floatEmulation", "auto")); std::string floatEmulation = Config::toLower(config.getOption<std::string>("d3d9.floatEmulation", "auto"));
if (floatEmulation == "strict") { if (floatEmulation == "strict") {

View File

@ -143,7 +143,7 @@ namespace dxvk {
std::string shaderDumpPath; std::string shaderDumpPath;
/// Enable emulation of device loss when a fullscreen app loses focus /// Enable emulation of device loss when a fullscreen app loses focus
bool deviceLost; bool deviceLossOnFocusLoss;
}; };
} }

View File

@ -17,6 +17,9 @@ namespace dxvk {
CaptureType(Type); CaptureType(Type);
} }
D3D9StateBlock::~D3D9StateBlock() {
m_parent->DecrementLosableCounter();
}
HRESULT STDMETHODCALLTYPE D3D9StateBlock::QueryInterface( HRESULT STDMETHODCALLTYPE D3D9StateBlock::QueryInterface(
REFIID riid, REFIID riid,

View File

@ -89,6 +89,8 @@ namespace dxvk {
D3D9StateBlock(D3D9DeviceEx* pDevice, D3D9StateBlockType Type); D3D9StateBlock(D3D9DeviceEx* pDevice, D3D9StateBlockType Type);
~D3D9StateBlock();
HRESULT STDMETHODCALLTYPE QueryInterface( HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid, REFIID riid,
void** ppvObject) final; void** ppvObject) final;

View File

@ -71,6 +71,8 @@ namespace dxvk {
m_device->waitForSubmission(&m_presentStatus); m_device->waitForSubmission(&m_presentStatus);
m_device->waitForIdle(); m_device->waitForIdle();
m_parent->DecrementLosableCounter();
} }
@ -436,6 +438,13 @@ namespace dxvk {
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
} }
if (m_backBuffers.empty()) {
// The backbuffers were destroyed and not recreated.
// This can happen when a call to Reset fails.
*ppBackBuffer = nullptr;
return D3D_OK;
}
*ppBackBuffer = ref(m_backBuffers[iBackBuffer].ptr()); *ppBackBuffer = ref(m_backBuffers[iBackBuffer].ptr());
return D3D_OK; return D3D_OK;
} }
@ -977,6 +986,7 @@ namespace dxvk {
desc.Discard = FALSE; desc.Discard = FALSE;
desc.IsBackBuffer = TRUE; desc.IsBackBuffer = TRUE;
desc.IsAttachmentOnly = FALSE; desc.IsAttachmentOnly = FALSE;
desc.IsLosable = TRUE;
// 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;
@ -984,6 +994,7 @@ namespace dxvk {
D3D9Surface* surface; D3D9Surface* surface;
try { try {
surface = new D3D9Surface(m_parent, &desc, this, nullptr); surface = new D3D9Surface(m_parent, &desc, this, nullptr);
m_parent->IncrementLosableCounter();
} catch (const DxvkError& e) { } catch (const DxvkError& e) {
DestroyBackBuffers(); DestroyBackBuffers();
Logger::err(e.message()); Logger::err(e.message());

View File

@ -120,6 +120,8 @@ namespace dxvk {
bool HasFormatsUnlocked() const { return m_unlockAdditionalFormats; } bool HasFormatsUnlocked() const { return m_unlockAdditionalFormats; }
void DestroyBackBuffers();
private: private:
enum BindingIds : uint32_t { enum BindingIds : uint32_t {
@ -189,8 +191,6 @@ namespace dxvk {
void CreateRenderTargetViews(); void CreateRenderTargetViews();
void DestroyBackBuffers();
HRESULT CreateBackBuffers( HRESULT CreateBackBuffers(
uint32_t NumBackBuffers); uint32_t NumBackBuffers);

View File

@ -500,7 +500,7 @@ namespace dxvk {
{ "d3d9.customVendorId", "1002" }, { "d3d9.customVendorId", "1002" },
{ "dxgi.emulateUMA", "True" }, { "dxgi.emulateUMA", "True" },
{ "d3d9.supportDFFormats", "False" }, { "d3d9.supportDFFormats", "False" },
{ "d3d9.deviceLost", "True" }, { "d3d9.deviceLostOnFocusLoss", "True" },
}} }, }} },
/* Battlefield 2 (bad z-pass) */ /* Battlefield 2 (bad z-pass) */
{ R"(\\BF2\.exe$)", {{ { R"(\\BF2\.exe$)", {{
@ -754,7 +754,7 @@ namespace dxvk {
/* DC Universe Online * /* DC Universe Online *
* Freezes after alt tabbing */ * Freezes after alt tabbing */
{ R"(\\DCGAME\.EXE$)", {{ { R"(\\DCGAME\.EXE$)", {{
{ "d3d9.deviceLost", "True" }, { "d3d9.deviceLostOnFocusLoss", "True" },
}} }, }} },
/* Halo Online * /* Halo Online *
* Black textures */ * Black textures */