From b7d8be25f1a07c63d041c45cd3caea83eeaa15ae Mon Sep 17 00:00:00 2001
From: Philip Rebohle <philip.rebohle@tu-dortmund.de>
Date: Sun, 9 Sep 2018 19:07:41 +0200
Subject: [PATCH] [dxgi] Use DXGI back buffer count for the Vulkan swap chain

---
 src/dxgi/dxgi_presenter.cpp |  4 +++-
 src/dxgi/dxgi_presenter.h   |  4 +++-
 src/dxgi/dxgi_swapchain.cpp |  8 ++++++--
 src/dxvk/dxvk_surface.cpp   | 11 +++++++----
 src/dxvk/dxvk_surface.h     |  4 +++-
 src/dxvk/dxvk_swapchain.cpp |  2 +-
 src/dxvk/dxvk_swapchain.h   |  1 +
 7 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp
index 260324da..c1a8db85 100644
--- a/src/dxgi/dxgi_presenter.cpp
+++ b/src/dxgi/dxgi_presenter.cpp
@@ -25,6 +25,7 @@ namespace dxvk {
     m_options.preferredSurfaceFormat = { VK_FORMAT_UNDEFINED, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
     m_options.preferredPresentMode   = VK_PRESENT_MODE_FIFO_KHR;
     m_options.preferredBufferSize    = { 0u, 0u };
+    m_options.preferredBufferCount   = 0;
     
     // Samplers for presentation. We'll create one with point sampling that will
     // be used when the back buffer resolution matches the output resolution, and
@@ -293,7 +294,7 @@ namespace dxvk {
   }
   
   
-  void DxgiVkPresenter::RecreateSwapchain(DXGI_FORMAT Format, BOOL Vsync, VkExtent2D WindowSize) {
+  void DxgiVkPresenter::RecreateSwapchain(DXGI_FORMAT Format, BOOL Vsync, VkExtent2D WindowSize, UINT BufferCount) {
     if (m_surface == nullptr)
       m_surface = CreateSurface();
     
@@ -301,6 +302,7 @@ namespace dxvk {
     options.preferredSurfaceFormat  = PickSurfaceFormat(Format);
     options.preferredPresentMode    = PickPresentMode(Vsync);
     options.preferredBufferSize     = WindowSize;
+    options.preferredBufferCount    = BufferCount;
     
     const bool doRecreate =
          options.preferredSurfaceFormat.format      != m_options.preferredSurfaceFormat.format
diff --git a/src/dxgi/dxgi_presenter.h b/src/dxgi/dxgi_presenter.h
index 73e4e239..ca2918f5 100644
--- a/src/dxgi/dxgi_presenter.h
+++ b/src/dxgi/dxgi_presenter.h
@@ -105,11 +105,13 @@ namespace dxvk {
      * \param [in] Format New surface format
      * \param [in] Vsync Enable vertical sync
      * \param [in] WindowSize Window size
+     * \param [in] BufferCount Swap image count
      */
     void RecreateSwapchain(
             DXGI_FORMAT       Format,
             BOOL              Vsync,
-            VkExtent2D        WindowSize);
+            VkExtent2D        WindowSize,
+            UINT              BufferCount);
     
     /**
      * \brief Sets gamma curve
diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp
index a9245d7c..999b0d35 100644
--- a/src/dxgi/dxgi_swapchain.cpp
+++ b/src/dxgi/dxgi_swapchain.cpp
@@ -272,12 +272,16 @@ namespace dxvk {
     std::lock_guard<std::mutex> lockWin(m_lockWindow);
     std::lock_guard<std::mutex> lockBuf(m_lockBuffer);
 
+    // Retrieve the number of back buffers. If this option
+    // was defined by the user, it overrides app settings.
+    uint32_t bufferCount = m_desc.BufferCount;
+
     // Higher values are not allowed according to the Microsoft documentation:
     // 
     //   "1 through 4 - Synchronize presentation after the nth vertical blank."
     //   https://msdn.microsoft.com/en-us/library/windows/desktop/bb174576(v=vs.85).aspx
     SyncInterval = std::min<UINT>(SyncInterval, 4);
-    
+
     try {
       // If in fullscreen mode, apply any updated gamma curve
       // if it has been changed since the last present call.
@@ -298,7 +302,7 @@ namespace dxvk {
       // up vertical synchronization properly, but also apply
       // changes that were made to the window size even if the
       // Vulkan swap chain itself remains valid.
-      m_presenter->RecreateSwapchain(m_desc.Format, SyncInterval != 0, GetWindowSize());
+      m_presenter->RecreateSwapchain(m_desc.Format, SyncInterval != 0, GetWindowSize(), bufferCount);
       m_presenter->PresentImage(SyncInterval, m_device->GetFrameSyncEvent());
       return S_OK;
     } catch (const DxvkError& err) {
diff --git a/src/dxvk/dxvk_surface.cpp b/src/dxvk/dxvk_surface.cpp
index 20dc456b..f9f80b1a 100644
--- a/src/dxvk/dxvk_surface.cpp
+++ b/src/dxvk/dxvk_surface.cpp
@@ -87,12 +87,15 @@ namespace dxvk {
   
   uint32_t DxvkSurface::pickImageCount(
     const VkSurfaceCapabilitiesKHR& caps,
-          VkPresentModeKHR          mode) const {
+          VkPresentModeKHR          mode,
+          uint32_t                  preferred) const {
     uint32_t count = caps.minImageCount;
     
-    if (mode == VK_PRESENT_MODE_MAILBOX_KHR
-     || mode == VK_PRESENT_MODE_FIFO_KHR)
-      count += 1;
+    if (mode != VK_PRESENT_MODE_IMMEDIATE_KHR)
+      count = caps.minImageCount + 1;
+    
+    if (count < preferred)
+      count = preferred;
     
     if (count > caps.maxImageCount && caps.maxImageCount != 0)
       count = caps.maxImageCount;
diff --git a/src/dxvk/dxvk_surface.h b/src/dxvk/dxvk_surface.h
index 252f29b4..683be9fb 100644
--- a/src/dxvk/dxvk_surface.h
+++ b/src/dxvk/dxvk_surface.h
@@ -65,11 +65,13 @@ namespace dxvk {
      * 
      * \param [in] caps Surface capabilities
      * \param [in] mode The present mode
+     * \param [in] preferred Preferred image count
      * \returns Suitable image count
      */
     uint32_t pickImageCount(
       const VkSurfaceCapabilitiesKHR& caps,
-            VkPresentModeKHR          mode) const;
+            VkPresentModeKHR          mode,
+            uint32_t                  preferred) const;
     
     /**
      * \brief Picks a suitable image size for a swap chain
diff --git a/src/dxvk/dxvk_swapchain.cpp b/src/dxvk/dxvk_swapchain.cpp
index 25a80956..048d9b00 100644
--- a/src/dxvk/dxvk_swapchain.cpp
+++ b/src/dxvk/dxvk_swapchain.cpp
@@ -117,7 +117,7 @@ namespace dxvk {
     swapInfo.pNext                  = nullptr;
     swapInfo.flags                  = 0;
     swapInfo.surface                = m_surface->handle();
-    swapInfo.minImageCount          = m_surface->pickImageCount(caps, mode);
+    swapInfo.minImageCount          = m_surface->pickImageCount(caps, mode, m_properties.preferredBufferCount);
     swapInfo.imageFormat            = fmt.format;
     swapInfo.imageColorSpace        = fmt.colorSpace;
     swapInfo.imageExtent            = m_surface->pickImageExtent(caps, m_properties.preferredBufferSize);
diff --git a/src/dxvk/dxvk_swapchain.h b/src/dxvk/dxvk_swapchain.h
index 97661d47..cf46b3e2 100644
--- a/src/dxvk/dxvk_swapchain.h
+++ b/src/dxvk/dxvk_swapchain.h
@@ -28,6 +28,7 @@ namespace dxvk {
     VkSurfaceFormatKHR preferredSurfaceFormat;
     VkPresentModeKHR   preferredPresentMode;
     VkExtent2D         preferredBufferSize;
+    uint32_t           preferredBufferCount;
   };