From 669276e10a7fc9975831bd9d719db67127b8a306 Mon Sep 17 00:00:00 2001
From: Philip Rebohle <philip.rebohle@tu-dortmund.de>
Date: Wed, 15 Jan 2025 19:02:50 +0100
Subject: [PATCH] [d3d9] Rework device reset detection

More robust.
---
 src/d3d9/d3d9_device.cpp    |  2 +-
 src/d3d9/d3d9_device.h      |  8 ++++----
 src/d3d9/d3d9_swapchain.cpp | 14 +++++++++++++-
 src/d3d9/d3d9_swapchain.h   |  4 ++++
 4 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp
index 5679c1a3d..80bdcf88f 100644
--- a/src/d3d9/d3d9_device.cpp
+++ b/src/d3d9/d3d9_device.cpp
@@ -539,7 +539,7 @@ namespace dxvk {
     SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
 
     if (m_d3d9Options.deferSurfaceCreation)
-      m_deviceHasBeenReset = true;
+      m_resetCtr++;
 
     return D3D_OK;
   }
diff --git a/src/d3d9/d3d9_device.h b/src/d3d9/d3d9_device.h
index c307036a4..7fd4ab70a 100644
--- a/src/d3d9/d3d9_device.h
+++ b/src/d3d9/d3d9_device.h
@@ -1143,12 +1143,12 @@ namespace dxvk {
     }
 
     /**
-     * \brief Returns whether the device has been reset and marks it as true.
+     * \brief Queries current reset counter
      * Used for the deferred surface creation workaround.
      * (Device Reset detection for D3D9SwapChainEx::Present)
      */
-    bool IsDeviceReset() {
-      return std::exchange(m_deviceHasBeenReset, false);
+    uint32_t GetResetCounter() {
+      return m_resetCtr;
     }
 
     template <bool Synchronize9On12>
@@ -1513,7 +1513,7 @@ namespace dxvk {
     VkImageLayout                   m_hazardLayout = VK_IMAGE_LAYOUT_GENERAL;
 
     bool                            m_usingGraphicsPipelines = false;
-    bool                            m_deviceHasBeenReset = false;
+    uint32_t                        m_resetCtr = 0u;
 
     DxvkDepthBiasRepresentation     m_depthBiasRepresentation = { VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, false };
     float                           m_depthBiasScale  = 0.0f;
diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp
index db590d725..0c47db2a0 100644
--- a/src/d3d9/d3d9_swapchain.cpp
+++ b/src/d3d9/d3d9_swapchain.cpp
@@ -151,7 +151,7 @@ namespace dxvk {
     if (!UpdateWindowCtx())
       return D3D_OK;
 
-    if (options->deferSurfaceCreation && m_parent->IsDeviceReset())
+    if (options->deferSurfaceCreation && IsDeviceReset(m_wctx))
       m_wctx->presenter->invalidateSurface();
 
     m_wctx->presenter->setSyncInterval(presentInterval);
@@ -1272,6 +1272,18 @@ namespace dxvk {
     return this->GetParent()->IsExtended() ? "D3D9Ex" : "D3D9";
   }
 
+
+  bool D3D9SwapChainEx::IsDeviceReset(D3D9WindowContext* wctx) {
+    uint32_t counter = m_parent->GetResetCounter();
+
+    if (counter == wctx->deviceResetCounter)
+      return false;
+
+    wctx->deviceResetCounter = counter;
+    return true;
+  }
+
+
   D3D9VkExtSwapchain::D3D9VkExtSwapchain(D3D9SwapChainEx *pSwapChain)
     : m_swapchain(pSwapChain) {
 
diff --git a/src/d3d9/d3d9_swapchain.h b/src/d3d9/d3d9_swapchain.h
index fd08508f3..9ab394975 100644
--- a/src/d3d9/d3d9_swapchain.h
+++ b/src/d3d9/d3d9_swapchain.h
@@ -55,6 +55,8 @@ namespace dxvk {
 
     uint64_t                       frameId = D3D9DeviceEx::MaxFrameLatency;
     Rc<sync::Fence>                frameLatencySignal;
+
+    uint32_t                       deviceResetCounter = 0u;
   };
 
   using D3D9SwapChainExBase = D3D9DeviceChild<IDirect3DSwapChain9Ex>;
@@ -228,6 +230,8 @@ namespace dxvk {
 
     std::string GetApiName();
 
+    bool IsDeviceReset(D3D9WindowContext* wctx);
+
     const Com<D3D9Surface, false>& GetFrontBuffer() const {
       return m_backBuffers.back();
     }