From aa40decc23f27bcb25bd8e61a76c032fd99ada59 Mon Sep 17 00:00:00 2001
From: Philip Rebohle <philip.rebohle@tu-dortmund.de>
Date: Sun, 15 Dec 2019 11:33:17 +0100
Subject: [PATCH] [d3d11] Don't present if the presenter has no swap chain.

Also fixes DXGI_PRESENT_TEST handling for zero-sized windows.
---
 src/d3d11/d3d11_swapchain.cpp | 72 ++++++++++++++++++++++-------------
 src/d3d11/d3d11_swapchain.h   |  2 +-
 src/dxgi/dxgi_swapchain.cpp   |  3 --
 3 files changed, 46 insertions(+), 31 deletions(-)

diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp
index c14fc53f..6577331c 100644
--- a/src/d3d11/d3d11_swapchain.cpp
+++ b/src/d3d11/d3d11_swapchain.cpp
@@ -208,11 +208,25 @@ namespace dxvk {
     if (m_presenter == nullptr)
       CreatePresenter();
 
+    HRESULT hr = S_OK;
+
+    if (!m_presenter->hasSwapChain()) {
+      RecreateSwapChain(vsync);
+      m_dirty = false;
+    }
+
+    if (!m_presenter->hasSwapChain())
+      hr = DXGI_STATUS_OCCLUDED;
+
+    if (m_device->getDeviceStatus() != VK_SUCCESS)
+      hr = DXGI_ERROR_DEVICE_RESET;
+
+    if ((PresentFlags & DXGI_PRESENT_TEST) || hr != S_OK)
+      return hr;
+
     if (std::exchange(m_dirty, false))
       RecreateSwapChain(vsync);
     
-    HRESULT hr = S_OK;
-
     try {
       PresentImage(SyncInterval);
     } catch (const DxvkError& e) {
@@ -220,14 +234,11 @@ namespace dxvk {
       hr = E_FAIL;
     }
 
-    if (m_device->getDeviceStatus() != VK_SUCCESS)
-      hr = DXGI_ERROR_DEVICE_RESET;
-
     return hr;
   }
 
 
-  void D3D11SwapChain::PresentImage(UINT SyncInterval) {
+  HRESULT D3D11SwapChain::PresentImage(UINT SyncInterval) {
     Com<ID3D11DeviceContext> deviceContext = nullptr;
     m_parent->GetImmediateContext(&deviceContext);
 
@@ -242,11 +253,36 @@ namespace dxvk {
     for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
       SynchronizePresent();
 
+      if (!m_presenter->hasSwapChain())
+        return DXGI_STATUS_OCCLUDED;
+
+      // Presentation semaphores and WSI swap chain image
+      vk::PresenterInfo info = m_presenter->info();
+      vk::PresenterSync sync = m_presenter->getSyncSemaphores();
+
+      uint32_t imageIndex = 0;
+
+      VkResult status = m_presenter->acquireNextImage(
+        sync.acquire, VK_NULL_HANDLE, imageIndex);
+
+      while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
+        RecreateSwapChain(m_vsync);
+
+        if (!m_presenter->hasSwapChain())
+          return DXGI_STATUS_OCCLUDED;
+        
+        info = m_presenter->info();
+        sync = m_presenter->getSyncSemaphores();
+
+        status = m_presenter->acquireNextImage(
+          sync.acquire, VK_NULL_HANDLE, imageIndex);
+      }
+
+      // Resolve back buffer if it is multisampled. We
+      // only have to do it only for the first frame.
       m_context->beginRecording(
         m_device->createCommandList());
       
-      // Resolve back buffer if it is multisampled. We
-      // only have to do it only for the first frame.
       if (m_swapImageResolve != nullptr && i == 0) {
         VkImageSubresourceLayers resolveSubresource;
         resolveSubresource.aspectMask      = VK_IMAGE_ASPECT_COLOR_BIT;
@@ -266,25 +302,6 @@ namespace dxvk {
           resolveRegion, VK_FORMAT_UNDEFINED);
       }
       
-      // Presentation semaphores and WSI swap chain image
-      vk::PresenterInfo info = m_presenter->info();
-      vk::PresenterSync sync = m_presenter->getSyncSemaphores();
-
-      uint32_t imageIndex = 0;
-
-      VkResult status = m_presenter->acquireNextImage(
-        sync.acquire, VK_NULL_HANDLE, imageIndex);
-
-      while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
-        RecreateSwapChain(m_vsync);
-        
-        info = m_presenter->info();
-        sync = m_presenter->getSyncSemaphores();
-
-        status = m_presenter->acquireNextImage(
-          sync.acquire, VK_NULL_HANDLE, imageIndex);
-      }
-
       // Use an appropriate texture filter depending on whether
       // the back buffer size matches the swap image size
       bool fitSize = m_swapImage->info().extent.width  == info.imageExtent.width
@@ -341,6 +358,7 @@ namespace dxvk {
     }
 
     SignalFrameLatencyEvent();
+    return S_OK;
   }
 
 
diff --git a/src/d3d11/d3d11_swapchain.h b/src/d3d11/d3d11_swapchain.h
index 11b6a437..30cc13aa 100644
--- a/src/d3d11/d3d11_swapchain.h
+++ b/src/d3d11/d3d11_swapchain.h
@@ -135,7 +135,7 @@ namespace dxvk {
     bool                    m_dirty = true;
     bool                    m_vsync = true;
 
-    void PresentImage(UINT SyncInterval);
+    HRESULT PresentImage(UINT SyncInterval);
 
     void SubmitPresent(
             D3D11ImmediateContext*  pContext,
diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp
index be385a2e..9e21d92e 100644
--- a/src/dxgi/dxgi_swapchain.cpp
+++ b/src/dxgi/dxgi_swapchain.cpp
@@ -258,9 +258,6 @@ namespace dxvk {
     if (SyncInterval > 4)
       return DXGI_ERROR_INVALID_CALL;
 
-    if (PresentFlags & DXGI_PRESENT_TEST)
-      return S_OK;
-    
     std::lock_guard<std::recursive_mutex> lockWin(m_lockWindow);
     std::lock_guard<std::mutex> lockBuf(m_lockBuffer);