From 757be61b700c56c49f7ba32545a3b1f464e2d2bd Mon Sep 17 00:00:00 2001
From: Philip Rebohle <philip.rebohle@tu-dortmund.de>
Date: Sun, 6 May 2018 13:12:30 +0200
Subject: [PATCH] [dxgi] Use per-adapter format lookup tables

Allows Nvidia cards to use 24-bit depth buffers.
---
 src/dxgi/dxgi_adapter.cpp |  5 ++--
 src/dxgi/dxgi_adapter.h   | 10 +++----
 src/dxgi/dxgi_format.cpp  | 63 +++++++++++++++++++++++++++++----------
 src/dxgi/dxgi_format.h    | 47 ++++++++++++++++++++++++-----
 4 files changed, 94 insertions(+), 31 deletions(-)

diff --git a/src/dxgi/dxgi_adapter.cpp b/src/dxgi/dxgi_adapter.cpp
index f38e3604..a562133f 100644
--- a/src/dxgi/dxgi_adapter.cpp
+++ b/src/dxgi/dxgi_adapter.cpp
@@ -18,7 +18,8 @@ namespace dxvk {
           DxgiFactory*      factory,
     const Rc<DxvkAdapter>&  adapter)
   : m_factory (factory),
-    m_adapter (adapter) {
+    m_adapter (adapter),
+    m_formats (adapter) {
     
   }
   
@@ -191,7 +192,7 @@ namespace dxvk {
   DXGI_VK_FORMAT_INFO STDMETHODCALLTYPE DxgiAdapter::LookupFormat(
           DXGI_FORMAT               Format,
           DXGI_VK_FORMAT_MODE       Mode) {
-    return GetDXGIFormatInfo(Format, Mode);
+    return m_formats.GetFormatInfo(Format, Mode);
   }
   
   
diff --git a/src/dxgi/dxgi_adapter.h b/src/dxgi/dxgi_adapter.h
index 0976544a..3bdd0bcb 100644
--- a/src/dxgi/dxgi_adapter.h
+++ b/src/dxgi/dxgi_adapter.h
@@ -1,13 +1,9 @@
 #pragma once
 
-#include <initializer_list>
-#include <memory>
+#include <mutex>
 #include <unordered_map>
-#include <vector>
-#include <string>
-
-#include <dxvk_adapter.h>
 
+#include "dxgi_format.h"
 #include "dxgi_interfaces.h"
 #include "dxgi_output.h"
 
@@ -77,6 +73,8 @@ namespace dxvk {
     Com<DxgiFactory>  m_factory;
     Rc<DxvkAdapter>   m_adapter;
     
+    DXGIVkFormatTable m_formats;
+    
     std::mutex        m_outputMutex;
     OutputMap         m_outputData;
     
diff --git a/src/dxgi/dxgi_format.cpp b/src/dxgi/dxgi_format.cpp
index b18e1ce1..6c01da25 100644
--- a/src/dxgi/dxgi_format.cpp
+++ b/src/dxgi/dxgi_format.cpp
@@ -216,21 +216,21 @@ namespace dxvk {
       VK_IMAGE_ASPECT_COLOR_BIT },
     // DXGI_FORMAT_R24G8_TYPELESS
     { VK_FORMAT_UNDEFINED,
-      VK_FORMAT_D32_SFLOAT_S8_UINT,
+      VK_FORMAT_D24_UNORM_S8_UINT,
       VK_FORMAT_UNDEFINED },
     // DXGI_FORMAT_D24_UNORM_S8_UINT
     { VK_FORMAT_UNDEFINED,
-      VK_FORMAT_D32_SFLOAT_S8_UINT,
+      VK_FORMAT_D24_UNORM_S8_UINT,
       VK_FORMAT_UNDEFINED,
       0, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT },
     // DXGI_FORMAT_R24_UNORM_X8_TYPELESS
     { VK_FORMAT_UNDEFINED,
-      VK_FORMAT_D32_SFLOAT_S8_UINT,
+      VK_FORMAT_D24_UNORM_S8_UINT,
       VK_FORMAT_UNDEFINED,
       0, VK_IMAGE_ASPECT_DEPTH_BIT },
     // DXGI_FORMAT_X24_TYPELESS_G8_UINT
     { VK_FORMAT_UNDEFINED,
-      VK_FORMAT_D32_SFLOAT_S8_UINT,
+      VK_FORMAT_D24_UNORM_S8_UINT,
       VK_FORMAT_UNDEFINED,
       0, VK_IMAGE_ASPECT_STENCIL_BIT },
     // DXGI_FORMAT_R8G8_TYPELESS
@@ -533,21 +533,36 @@ namespace dxvk {
   }};
   
   
-  const DXGI_VK_FORMAT_MAPPING& GetDXGIFormatMapping(
-          DXGI_FORMAT         Format) {
-    const size_t formatId = size_t(Format);
-    
-    return formatId < g_dxgiFormats.size()
-      ? g_dxgiFormats[formatId]
-      : g_dxgiFormats[0];
+  DXGIVkFormatTable::DXGIVkFormatTable(const Rc<DxvkAdapter>& adapter)
+  : m_dxgiFormats(g_dxgiFormats) {
+    // AMD do not support 24-bit depth buffers on Vulkan,
+    // so we have to fall back to a 32-bit depth format.
+    if (!CheckImageFormatSupport(adapter, VK_FORMAT_D24_UNORM_S8_UINT,
+          VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
+          VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
+      Logger::warn("DXGI: VK_FORMAT_D24_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT");
+      RemapDepthFormat(DXGI_FORMAT_R24G8_TYPELESS,        VK_FORMAT_D32_SFLOAT_S8_UINT);
+      RemapDepthFormat(DXGI_FORMAT_R24_UNORM_X8_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT);
+      RemapDepthFormat(DXGI_FORMAT_X24_TYPELESS_G8_UINT,  VK_FORMAT_D32_SFLOAT_S8_UINT);
+      RemapDepthFormat(DXGI_FORMAT_D24_UNORM_S8_UINT,     VK_FORMAT_D32_SFLOAT_S8_UINT);
+    }
   }
   
   
-  DXGI_VK_FORMAT_INFO GetDXGIFormatInfo(
+  DXGIVkFormatTable::~DXGIVkFormatTable() {
+    
+  }
+  
+  
+  DXGI_VK_FORMAT_INFO DXGIVkFormatTable::GetFormatInfo(
           DXGI_FORMAT         Format,
-          DXGI_VK_FORMAT_MODE Mode) {
+          DXGI_VK_FORMAT_MODE Mode) const {
+    const size_t formatId = size_t(Format);
+    
     const DXGI_VK_FORMAT_MAPPING& mapping
-      = GetDXGIFormatMapping(Format);
+      = formatId < m_dxgiFormats.size()
+        ? m_dxgiFormats[formatId]
+        : m_dxgiFormats[0];
     
     switch (Mode) {
       case DXGI_VK_FORMAT_MODE_ANY:
@@ -565,8 +580,26 @@ namespace dxvk {
         return { mapping.FormatRaw, mapping.AspectColor };
     }
     
-    Logger::err("DXGI: GetDXGIFormatInfo: Internal error");
+    Logger::err("DXGI: GetFormatInfo: Internal error");
     return DXGI_VK_FORMAT_INFO();
   }
   
+  
+  bool DXGIVkFormatTable::CheckImageFormatSupport(
+    const Rc<DxvkAdapter>&      Adapter,
+          VkFormat              Format,
+          VkFormatFeatureFlags  Features) const {
+    VkFormatProperties supported = Adapter->formatProperties(VK_FORMAT_D24_UNORM_S8_UINT);
+    
+    return (supported.linearTilingFeatures  & Features) == Features
+        || (supported.optimalTilingFeatures & Features) == Features;
+  }
+  
+  
+  void DXGIVkFormatTable::RemapDepthFormat(
+          DXGI_FORMAT         Format,
+          VkFormat            Target) {
+    m_dxgiFormats[uint32_t(Format)].FormatDepth = Target;
+  }
+  
 }
\ No newline at end of file
diff --git a/src/dxgi/dxgi_format.h b/src/dxgi/dxgi_format.h
index 86e6ee6b..0e96cf35 100644
--- a/src/dxgi/dxgi_format.h
+++ b/src/dxgi/dxgi_format.h
@@ -2,7 +2,7 @@
 
 #include "dxgi_include.h"
 
-#include "../dxvk/dxvk_include.h"
+#include "../dxvk/dxvk_adapter.h"
 
 namespace dxvk {
   
@@ -53,15 +53,46 @@ namespace dxvk {
     DXGI_VK_FORMAT_MODE_RAW   = 3,  ///< Unsigned integer format
   };
   
+  
   /**
-   * \brief Retrieves info for a given DXGI format
+   * \brief Format table
    * 
-   * \param [in] Format The DXGI format to look up
-   * \param [in] Mode the format lookup mode
-   * \returns Format info
+   * Initializes a format table for a specific
+   * device and provides methods to look up
+   * formats.
    */
-  DXGI_VK_FORMAT_INFO GetDXGIFormatInfo(
-          DXGI_FORMAT         Format,
-          DXGI_VK_FORMAT_MODE Mode);
+  class DXGIVkFormatTable {
+    
+  public:
+    
+    DXGIVkFormatTable(
+      const Rc<DxvkAdapter>& adapter);
+    ~DXGIVkFormatTable();
+    
+    /**
+     * \brief Retrieves info for a given DXGI format
+     * 
+     * \param [in] Format The DXGI format to look up
+     * \param [in] Mode the format lookup mode
+     * \returns Format info
+     */
+    DXGI_VK_FORMAT_INFO GetFormatInfo(
+            DXGI_FORMAT         Format,
+            DXGI_VK_FORMAT_MODE Mode) const;
+    
+  private:
+    
+    std::array<DXGI_VK_FORMAT_MAPPING, 133> m_dxgiFormats;
+    
+    bool CheckImageFormatSupport(
+      const Rc<DxvkAdapter>&      Adapter,
+            VkFormat              Format,
+            VkFormatFeatureFlags  Features) const;
+    
+    void RemapDepthFormat(
+            DXGI_FORMAT           Format,
+            VkFormat              Target);
+        
+  };
   
 };
\ No newline at end of file