Skip to content

Commit

Permalink
[d3d9] Reject Reset if there's any remaining DEFAULT resources
Browse files Browse the repository at this point in the history
  • Loading branch information
K0bin committed Jun 11, 2023
1 parent c585ea2 commit e1d063c
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 36 deletions.
5 changes: 5 additions & 0 deletions src/d3d9/d3d9_common_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ namespace dxvk {
m_dirtyRange = D3D9Range(0, m_desc.Size);
}

D3D9CommonBuffer::~D3D9CommonBuffer() {
if (m_desc.Pool == D3DPOOL_DEFAULT)
m_parent->DecrementLosableCounter();
}


HRESULT D3D9CommonBuffer::Lock(
UINT OffsetToLock,
Expand Down
2 changes: 2 additions & 0 deletions src/d3d9/d3d9_common_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ namespace dxvk {
D3D9DeviceEx* pDevice,
const D3D9_BUFFER_DESC* pDesc);

~D3D9CommonBuffer();

HRESULT Lock(
UINT OffsetToLock,
UINT SizeToLock,
Expand Down
3 changes: 3 additions & 0 deletions src/d3d9/d3d9_common_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ namespace dxvk {
m_device->ChangeReportedMemory(m_size);

m_device->RemoveMappedTexture(this);

if (m_desc.IsLosable)
m_device->DecrementLosableCounter();
}


Expand Down
1 change: 1 addition & 0 deletions src/d3d9/d3d9_common_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace dxvk {
bool IsBackBuffer;
bool IsAttachmentOnly;
bool IsLockable;
bool IsLosable;
};

struct D3D9ColorView {
Expand Down
90 changes: 89 additions & 1 deletion src/d3d9/d3d9_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,12 +412,29 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters) {
D3D9DeviceLock lock = LockDevice();

/*
* 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.
*/
if (unlikely(m_losableResourceCounter.load() != 0 && !IsExtended())) {
Logger::info("Device reset failed because device still has alive losable resources: Device not reset");
m_deviceLostState = D3D9DeviceLostState::NotReset;
return D3DERR_INVALIDCALL;
}

Logger::info("Device reset");
m_deviceLostState = D3D9DeviceLostState::Ok;

HRESULT hr = ResetSwapChain(pPresentationParameters, nullptr);
if (FAILED(hr))
if (FAILED(hr)) {
if (!IsExtended()) {
Logger::info("Device reset failed: Device not reset");
m_deviceLostState = D3D9DeviceLostState::NotReset;
}
return hr;
}

ResetState(pPresentationParameters);

Expand Down Expand Up @@ -516,6 +533,7 @@ namespace dxvk {
desc.MultisampleQuality = 0;
desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = FALSE;
desc.IsLosable = Pool == D3DPOOL_DEFAULT;
// Docs:
// Textures placed in the D3DPOOL_DEFAULT pool cannot be locked
// unless they are dynamic textures or they are private, FOURCC, driver formats.
Expand All @@ -542,6 +560,9 @@ namespace dxvk {
m_initializer->InitTexture(texture->GetCommonTexture(), initialData);
*ppTexture = texture.ref();

if (desc.IsLosable)
m_losableResourceCounter++;

return D3D_OK;
}
catch (const DxvkError& e) {
Expand Down Expand Up @@ -583,6 +604,7 @@ namespace dxvk {
desc.MultisampleQuality = 0;
desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = FALSE;
desc.IsLosable = Pool == D3DPOOL_DEFAULT;
// Docs:
// Textures placed in the D3DPOOL_DEFAULT pool cannot be locked
// unless they are dynamic textures or they are private, FOURCC, driver formats.
Expand All @@ -597,6 +619,9 @@ namespace dxvk {
const Com<D3D9Texture3D> texture = new D3D9Texture3D(this, &desc);
m_initializer->InitTexture(texture->GetCommonTexture());
*ppVolumeTexture = texture.ref();

if (desc.IsLosable)
m_losableResourceCounter++;

return D3D_OK;
}
Expand Down Expand Up @@ -637,6 +662,7 @@ namespace dxvk {
desc.MultisampleQuality = 0;
desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = FALSE;
desc.IsLosable = Pool == D3DPOOL_DEFAULT;
// Docs:
// Textures placed in the D3DPOOL_DEFAULT pool cannot be locked
// unless they are dynamic textures or they are private, FOURCC, driver formats.
Expand All @@ -651,6 +677,9 @@ namespace dxvk {
const Com<D3D9TextureCube> texture = new D3D9TextureCube(this, &desc);
m_initializer->InitTexture(texture->GetCommonTexture());
*ppCubeTexture = texture.ref();

if (desc.IsLosable)
m_losableResourceCounter++;

return D3D_OK;
}
Expand Down Expand Up @@ -691,6 +720,9 @@ namespace dxvk {
const Com<D3D9VertexBuffer> buffer = new D3D9VertexBuffer(this, &desc);
m_initializer->InitBuffer(buffer->GetCommonBuffer());
*ppVertexBuffer = buffer.ref();
if (desc.Pool == D3DPOOL_DEFAULT)
m_losableResourceCounter++;

return D3D_OK;
}
catch (const DxvkError & e) {
Expand Down Expand Up @@ -729,6 +761,9 @@ namespace dxvk {
const Com<D3D9IndexBuffer> buffer = new D3D9IndexBuffer(this, &desc);
m_initializer->InitBuffer(buffer->GetCommonBuffer());
*ppIndexBuffer = buffer.ref();
if (desc.Pool == D3DPOOL_DEFAULT)
m_losableResourceCounter++;

return D3D_OK;
}
catch (const DxvkError & e) {
Expand Down Expand Up @@ -2254,6 +2289,8 @@ namespace dxvk {
try {
const Com<D3D9StateBlock> sb = new D3D9StateBlock(this, ConvertStateBlockType(Type));
*ppSB = sb.ref();
m_losableResourceCounter++;

return D3D_OK;
}
catch (const DxvkError & e) {
Expand Down Expand Up @@ -2284,6 +2321,7 @@ namespace dxvk {
return D3DERR_INVALIDCALL;

*ppSB = m_recorder.ref();
m_losableResourceCounter++;
m_recorder = nullptr;

return D3D_OK;
Expand Down Expand Up @@ -3610,6 +3648,7 @@ namespace dxvk {
desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = TRUE;
desc.IsLockable = Lockable;
desc.IsLosable = TRUE;

if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
return D3DERR_INVALIDCALL;
Expand All @@ -3618,6 +3657,8 @@ namespace dxvk {
const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle);
m_initializer->InitTexture(surface->GetCommonTexture());
*ppSurface = surface.ref();
m_losableResourceCounter++;

return D3D_OK;
}
catch (const DxvkError& e) {
Expand Down Expand Up @@ -3654,6 +3695,7 @@ namespace dxvk {
desc.MultisampleQuality = 0;
desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = Pool == D3DPOOL_DEFAULT;
desc.IsLosable = Pool == D3DPOOL_DEFAULT;
// Docs: Off-screen plain surfaces are always lockable, regardless of their pool types.
desc.IsLockable = TRUE;

Expand All @@ -3667,6 +3709,10 @@ namespace dxvk {
const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle);
m_initializer->InitTexture(surface->GetCommonTexture());
*ppSurface = surface.ref();

if (desc.IsLosable)
m_losableResourceCounter++;

return D3D_OK;
}
catch (const DxvkError& e) {
Expand Down Expand Up @@ -3705,6 +3751,7 @@ namespace dxvk {
desc.MultisampleQuality = MultisampleQuality;
desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = TRUE;
desc.IsLosable = TRUE;
// Docs don't say anything, so just assume it's lockable.
desc.IsLockable = TRUE;

Expand All @@ -3715,6 +3762,8 @@ namespace dxvk {
const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle);
m_initializer->InitTexture(surface->GetCommonTexture());
*ppSurface = surface.ref();
m_losableResourceCounter++;

return D3D_OK;
}
catch (const DxvkError& e) {
Expand Down Expand Up @@ -3776,6 +3825,7 @@ namespace dxvk {
try {
auto* swapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
*ppSwapChain = ref(swapchain);
m_losableResourceCounter++;
}
catch (const DxvkError & e) {
Logger::err(e.message());
Expand Down Expand Up @@ -7453,6 +7503,7 @@ namespace dxvk {
desc.MultisampleQuality = pPresentationParameters->MultiSampleQuality;
desc.IsBackBuffer = FALSE;
desc.IsAttachmentOnly = TRUE;
desc.IsLosable = FALSE;
// Docs: Also note that - unlike textures - swap chain back buffers, render targets [..] can be locked
desc.IsLockable = TRUE;

Expand Down Expand Up @@ -7563,6 +7614,43 @@ namespace dxvk {
#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
////////////////////////////////////
Expand Down
36 changes: 6 additions & 30 deletions src/d3d9/d3d9_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -961,41 +961,16 @@ namespace dxvk {
void TouchMappedTexture(D3D9CommonTexture* pTexture);
void RemoveMappedTexture(D3D9CommonTexture* pTexture);

// Device Lost
bool IsDeviceLost() const {
return m_deviceLostState != D3D9DeviceLostState::Ok;
}

void NotifyFullscreen(HWND window, bool fullscreen) {
D3D9DeviceLock lock = LockDevice();
void NotifyFullscreen(HWND window, bool fullscreen);
void NotifyWindowActivated(HWND window, bool activated);

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 NotifyWindowActivated(HWND window, bool activated) {
D3D9DeviceLock lock = LockDevice();

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;
}
void DecrementLosableCounter() {
m_losableResourceCounter--;
}

private:
Expand Down Expand Up @@ -1366,6 +1341,7 @@ namespace dxvk {

D3D9DeviceLostState m_deviceLostState = D3D9DeviceLostState::Ok;
HWND m_fullscreenWindow = NULL;
std::atomic<uint32_t> m_losableResourceCounter = { 0 };

#ifdef D3D9_ALLOW_UNMAPPING
lru_list<D3D9CommonTexture*> m_mappedTextures;
Expand Down
4 changes: 2 additions & 2 deletions src/d3d9/d3d9_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ namespace dxvk {
this->deviceLocalConstantBuffers = config.getOption<bool> ("d3d9.deviceLocalConstantBuffers", false);
this->allowDirectBufferMapping = config.getOption<bool> ("d3d9.allowDirectBufferMapping", true);
this->seamlessCubes = config.getOption<bool> ("d3d9.seamlessCubes", false);
this->textureMemory = config.getOption<int32_t> ("d3d9.textureMemory", 100) << 20;
this->deviceLost = config.getOption<bool> ("d3d9.deviceLost", false);
this->textureMemory = config.getOption<int32_t> ("d3d9.textureMemory", 100) << 20;
this->deviceLossOnFocusLoss = config.getOption<bool> ("d3d9.deviceLossOnFocusLoss", false);

std::string floatEmulation = Config::toLower(config.getOption<std::string>("d3d9.floatEmulation", "auto"));
if (floatEmulation == "strict") {
Expand Down
2 changes: 1 addition & 1 deletion src/d3d9/d3d9_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ namespace dxvk {
std::string shaderDumpPath;

/// Enable emulation of device loss when a fullscreen app loses focus
bool deviceLost;
bool deviceLossOnFocusLoss;
};

}
3 changes: 3 additions & 0 deletions src/d3d9/d3d9_stateblock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ namespace dxvk {
CaptureType(Type);
}

D3D9StateBlock::~D3D9StateBlock() {
m_parent->DecrementLosableCounter();
}

HRESULT STDMETHODCALLTYPE D3D9StateBlock::QueryInterface(
REFIID riid,
Expand Down
2 changes: 2 additions & 0 deletions src/d3d9/d3d9_stateblock.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ namespace dxvk {

D3D9StateBlock(D3D9DeviceEx* pDevice, D3D9StateBlockType Type);

~D3D9StateBlock();

HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
void** ppvObject) final;
Expand Down
3 changes: 3 additions & 0 deletions src/d3d9/d3d9_swapchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ namespace dxvk {

m_device->waitForSubmission(&m_presentStatus);
m_device->waitForIdle();

m_parent->DecrementLosableCounter();
}


Expand Down Expand Up @@ -977,6 +979,7 @@ namespace dxvk {
desc.Discard = FALSE;
desc.IsBackBuffer = TRUE;
desc.IsAttachmentOnly = FALSE;
desc.IsLosable = TRUE;
// Docs: Also note that - unlike textures - swap chain back buffers, render targets [..] can be locked
desc.IsLockable = TRUE;

Expand Down
Loading

0 comments on commit e1d063c

Please sign in to comment.