From c1f16d36bd35dd8fd57a40c46a4ce832ac5cf962 Mon Sep 17 00:00:00 2001
From: Philip Rebohle <philip.rebohle@tu-dortmund.de>
Date: Sat, 13 Jan 2018 22:18:32 +0100
Subject: [PATCH] [dxvk] Implemented local pipeline cache

---
 src/dxvk/dxvk_compute.cpp     |  9 +++++----
 src/dxvk/dxvk_compute.h       |  7 +++++--
 src/dxvk/dxvk_device.cpp      |  7 +++++--
 src/dxvk/dxvk_device.h        |  2 ++
 src/dxvk/dxvk_graphics.cpp    | 17 +++++++++--------
 src/dxvk/dxvk_graphics.h      | 20 +++++++++++++-------
 src/dxvk/dxvk_pipecache.cpp   | 27 +++++++++++++++++++++++++++
 src/dxvk/dxvk_pipecache.h     | 35 +++++++++++++++++++++++++++++++++++
 src/dxvk/dxvk_pipemanager.cpp | 22 +++++++++++++---------
 src/dxvk/dxvk_pipemanager.h   | 14 ++++++++------
 src/dxvk/meson.build          |  1 +
 11 files changed, 123 insertions(+), 38 deletions(-)
 create mode 100644 src/dxvk/dxvk_pipecache.cpp
 create mode 100644 src/dxvk/dxvk_pipecache.h

diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp
index f1a4e2c6..03d2703f 100644
--- a/src/dxvk/dxvk_compute.cpp
+++ b/src/dxvk/dxvk_compute.cpp
@@ -3,9 +3,10 @@
 namespace dxvk {
   
   DxvkComputePipeline::DxvkComputePipeline(
-    const Rc<vk::DeviceFn>& vkd,
-    const Rc<DxvkShader>&   cs)
-  : m_vkd(vkd) {
+    const Rc<vk::DeviceFn>&       vkd,
+    const Rc<DxvkPipelineCache>&  cache,
+    const Rc<DxvkShader>&         cs)
+  : m_vkd(vkd), m_cache(cache) {
     DxvkDescriptorSlotMapping slotMapping;
     cs->defineResourceSlots(slotMapping);
     
@@ -38,7 +39,7 @@ namespace dxvk {
     info.basePipelineIndex    = -1;
     
     if (m_vkd->vkCreateComputePipelines(m_vkd->device(),
-          VK_NULL_HANDLE, 1, &info, nullptr, &m_pipeline) != VK_SUCCESS)
+          m_cache->handle(), 1, &info, nullptr, &m_pipeline) != VK_SUCCESS)
       throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to compile pipeline");
   }
   
diff --git a/src/dxvk/dxvk_compute.h b/src/dxvk/dxvk_compute.h
index 2140fe7f..89b1dd46 100644
--- a/src/dxvk/dxvk_compute.h
+++ b/src/dxvk/dxvk_compute.h
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "dxvk_pipecache.h"
 #include "dxvk_pipelayout.h"
 #include "dxvk_resource.h"
 #include "dxvk_shader.h"
@@ -19,8 +20,9 @@ namespace dxvk {
   public:
     
     DxvkComputePipeline(
-      const Rc<vk::DeviceFn>& vkd,
-      const Rc<DxvkShader>&   cs);
+      const Rc<vk::DeviceFn>&       vkd,
+      const Rc<DxvkPipelineCache>&  cache,
+      const Rc<DxvkShader>&         cs);
     ~DxvkComputePipeline();
     
     /**
@@ -46,6 +48,7 @@ namespace dxvk {
   private:
     
     Rc<vk::DeviceFn>      m_vkd;
+    Rc<DxvkPipelineCache> m_cache;
     Rc<DxvkBindingLayout> m_layout;
     Rc<DxvkShaderModule>  m_cs;
     
diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp
index cafb2887..dede436d 100644
--- a/src/dxvk/dxvk_device.cpp
+++ b/src/dxvk/dxvk_device.cpp
@@ -12,6 +12,7 @@ namespace dxvk {
     m_features        (features),
     m_memory          (new DxvkMemoryAllocator(adapter, vkd)),
     m_renderPassPool  (new DxvkRenderPassPool (vkd)),
+    m_pipelineCache   (new DxvkPipelineCache  (vkd)),
     m_pipelineManager (new DxvkPipelineManager(vkd)),
     m_submissionQueue (this) {
     m_vkd->vkGetDeviceQueue(m_vkd->device(),
@@ -161,7 +162,8 @@ namespace dxvk {
   
   Rc<DxvkComputePipeline> DxvkDevice::createComputePipeline(
     const Rc<DxvkShader>&           cs) {
-    return m_pipelineManager->createComputePipeline(cs);
+    return m_pipelineManager->createComputePipeline(
+      m_pipelineCache, cs);
   }
   
   
@@ -171,7 +173,8 @@ namespace dxvk {
     const Rc<DxvkShader>&           tes,
     const Rc<DxvkShader>&           gs,
     const Rc<DxvkShader>&           fs) {
-    return m_pipelineManager->createGraphicsPipeline(vs, tcs, tes, gs, fs);
+    return m_pipelineManager->createGraphicsPipeline(
+      m_pipelineCache, vs, tcs, tes, gs, fs);
   }
   
   
diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h
index fc042d9f..13e6870c 100644
--- a/src/dxvk/dxvk_device.h
+++ b/src/dxvk/dxvk_device.h
@@ -8,6 +8,7 @@
 #include "dxvk_framebuffer.h"
 #include "dxvk_image.h"
 #include "dxvk_memory.h"
+#include "dxvk_pipecache.h"
 #include "dxvk_pipemanager.h"
 #include "dxvk_queue.h"
 #include "dxvk_recycler.h"
@@ -303,6 +304,7 @@ namespace dxvk {
     
     Rc<DxvkMemoryAllocator>   m_memory;
     Rc<DxvkRenderPassPool>    m_renderPassPool;
+    Rc<DxvkPipelineCache>     m_pipelineCache;
     Rc<DxvkPipelineManager>   m_pipelineManager;
     
     std::mutex m_submissionLock;
diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp
index 0f092778..321d1c5a 100644
--- a/src/dxvk/dxvk_graphics.cpp
+++ b/src/dxvk/dxvk_graphics.cpp
@@ -33,13 +33,14 @@ namespace dxvk {
   
   
   DxvkGraphicsPipeline::DxvkGraphicsPipeline(
-      const Rc<vk::DeviceFn>& vkd,
-      const Rc<DxvkShader>&   vs,
-      const Rc<DxvkShader>&   tcs,
-      const Rc<DxvkShader>&   tes,
-      const Rc<DxvkShader>&   gs,
-      const Rc<DxvkShader>&   fs)
-  : m_vkd(vkd) {
+      const Rc<vk::DeviceFn>&       vkd,
+      const Rc<DxvkPipelineCache>&  cache,
+      const Rc<DxvkShader>&         vs,
+      const Rc<DxvkShader>&         tcs,
+      const Rc<DxvkShader>&         tes,
+      const Rc<DxvkShader>&         gs,
+      const Rc<DxvkShader>&         fs)
+  : m_vkd(vkd), m_cache(cache) {
     DxvkDescriptorSlotMapping slotMapping;
     if (vs  != nullptr) vs ->defineResourceSlots(slotMapping);
     if (tcs != nullptr) tcs->defineResourceSlots(slotMapping);
@@ -229,7 +230,7 @@ namespace dxvk {
     
     VkPipeline pipeline = VK_NULL_HANDLE;
     if (m_vkd->vkCreateGraphicsPipelines(m_vkd->device(),
-          VK_NULL_HANDLE, 1, &info, nullptr, &pipeline) != VK_SUCCESS)
+          m_cache->handle(), 1, &info, nullptr, &pipeline) != VK_SUCCESS)
       throw DxvkError("DxvkGraphicsPipeline::DxvkGraphicsPipeline: Failed to compile pipeline");
     return pipeline;
   }
diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h
index d664d48c..a3247aaf 100644
--- a/src/dxvk/dxvk_graphics.h
+++ b/src/dxvk/dxvk_graphics.h
@@ -5,7 +5,7 @@
 
 #include "dxvk_binding.h"
 #include "dxvk_constant_state.h"
-#include "dxvk_hash.h"
+#include "dxvk_pipecache.h"
 #include "dxvk_pipelayout.h"
 #include "dxvk_resource.h"
 #include "dxvk_shader.h"
@@ -88,12 +88,13 @@ namespace dxvk {
   public:
     
     DxvkGraphicsPipeline(
-      const Rc<vk::DeviceFn>& vkd,
-      const Rc<DxvkShader>&   vs,
-      const Rc<DxvkShader>&   tcs,
-      const Rc<DxvkShader>&   tes,
-      const Rc<DxvkShader>&   gs,
-      const Rc<DxvkShader>&   fs);
+      const Rc<vk::DeviceFn>&       vkd,
+      const Rc<DxvkPipelineCache>&  cache,
+      const Rc<DxvkShader>&         vs,
+      const Rc<DxvkShader>&         tcs,
+      const Rc<DxvkShader>&         tes,
+      const Rc<DxvkShader>&         gs,
+      const Rc<DxvkShader>&         fs);
     ~DxvkGraphicsPipeline();
     
     /**
@@ -110,6 +111,10 @@ namespace dxvk {
     
     /**
      * \brief Pipeline handle
+     * 
+     * Retrieves a pipeline handle for the given pipeline
+     * state. If necessary, a new pipeline will be created.
+     * \param [in] state Pipeline state vector
      * \returns Pipeline handle
      */
     VkPipeline getPipelineHandle(
@@ -123,6 +128,7 @@ namespace dxvk {
     };
     
     Rc<vk::DeviceFn>      m_vkd;
+    Rc<DxvkPipelineCache> m_cache;
     Rc<DxvkBindingLayout> m_layout;
     
     Rc<DxvkShaderModule>  m_vs;
diff --git a/src/dxvk/dxvk_pipecache.cpp b/src/dxvk/dxvk_pipecache.cpp
new file mode 100644
index 00000000..4d137dbd
--- /dev/null
+++ b/src/dxvk/dxvk_pipecache.cpp
@@ -0,0 +1,27 @@
+#include "dxvk_pipecache.h"
+
+namespace dxvk {
+  
+  DxvkPipelineCache::DxvkPipelineCache(
+    const Rc<vk::DeviceFn>& vkd)
+  : m_vkd(vkd) {
+    // TODO read pipeline cache from file
+    VkPipelineCacheCreateInfo info;
+    info.sType            = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+    info.pNext            = nullptr;
+    info.flags            = 0;
+    info.initialDataSize  = 0;
+    info.pInitialData     = nullptr;
+    
+    if (m_vkd->vkCreatePipelineCache(m_vkd->device(),
+        &info, nullptr, &m_handle) != VK_SUCCESS)
+      throw DxvkError("DxvkPipelineCache: Failed to create cache");
+  }
+  
+  
+  DxvkPipelineCache::~DxvkPipelineCache() {
+    m_vkd->vkDestroyPipelineCache(
+      m_vkd->device(), m_handle, nullptr);
+  }
+  
+}
\ No newline at end of file
diff --git a/src/dxvk/dxvk_pipecache.h b/src/dxvk/dxvk_pipecache.h
new file mode 100644
index 00000000..94dced12
--- /dev/null
+++ b/src/dxvk/dxvk_pipecache.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+  
+  /**
+   * \brief Pipeline cache
+   * 
+   * Allows the Vulkan implementation to
+   * re-use previously compiled pipelines.
+   */
+  class DxvkPipelineCache : public RcObject {
+    
+  public:
+    
+    DxvkPipelineCache(const Rc<vk::DeviceFn>& vkd);
+    ~DxvkPipelineCache();
+    
+    /**
+     * \brief Pipeline cache handle
+     * \returns Pipeline cache handle
+     */
+    VkPipelineCache handle() const {
+      return m_handle;
+    }
+    
+  private:
+    
+    Rc<vk::DeviceFn> m_vkd;
+    VkPipelineCache  m_handle;
+    
+  };
+  
+}
\ No newline at end of file
diff --git a/src/dxvk/dxvk_pipemanager.cpp b/src/dxvk/dxvk_pipemanager.cpp
index b4477c66..88a68d32 100644
--- a/src/dxvk/dxvk_pipemanager.cpp
+++ b/src/dxvk/dxvk_pipemanager.cpp
@@ -36,7 +36,9 @@ namespace dxvk {
   
   
   DxvkPipelineManager::DxvkPipelineManager(const Rc<vk::DeviceFn>& vkd)
-  : m_vkd(vkd) { }
+  : m_vkd(vkd) {
+    
+  }
   
   
   DxvkPipelineManager::~DxvkPipelineManager() {
@@ -45,7 +47,8 @@ namespace dxvk {
   
   
   Rc<DxvkComputePipeline> DxvkPipelineManager::createComputePipeline(
-    const Rc<DxvkShader>& cs) {
+    const Rc<DxvkPipelineCache>&  cache,
+    const Rc<DxvkShader>&         cs) {
     if (cs == nullptr)
       return nullptr;
     
@@ -59,18 +62,19 @@ namespace dxvk {
       return pair->second;
     
     const Rc<DxvkComputePipeline> pipeline
-      = new DxvkComputePipeline(m_vkd, cs);
+      = new DxvkComputePipeline(m_vkd, cache, cs);
     m_computePipelines.insert(std::make_pair(key, pipeline));
     return pipeline;
   }
   
   
   Rc<DxvkGraphicsPipeline> DxvkPipelineManager::createGraphicsPipeline(
-    const Rc<DxvkShader>& vs,
-    const Rc<DxvkShader>& tcs,
-    const Rc<DxvkShader>& tes,
-    const Rc<DxvkShader>& gs,
-    const Rc<DxvkShader>& fs) {
+    const Rc<DxvkPipelineCache>&  cache,
+    const Rc<DxvkShader>&         vs,
+    const Rc<DxvkShader>&         tcs,
+    const Rc<DxvkShader>&         tes,
+    const Rc<DxvkShader>&         gs,
+    const Rc<DxvkShader>&         fs) {
     if (vs == nullptr)
       return nullptr;
     
@@ -88,7 +92,7 @@ namespace dxvk {
       return pair->second;
     
     const Rc<DxvkGraphicsPipeline> pipeline
-      = new DxvkGraphicsPipeline(m_vkd, vs, tcs, tes, gs, fs);
+      = new DxvkGraphicsPipeline(m_vkd, cache, vs, tcs, tes, gs, fs);
     m_graphicsPipelines.insert(std::make_pair(key, pipeline));
     return pipeline;
   }
diff --git a/src/dxvk/dxvk_pipemanager.h b/src/dxvk/dxvk_pipemanager.h
index 003f9a13..9d438cd7 100644
--- a/src/dxvk/dxvk_pipemanager.h
+++ b/src/dxvk/dxvk_pipemanager.h
@@ -73,7 +73,8 @@ namespace dxvk {
      * \returns Compute pipeline object
      */
     Rc<DxvkComputePipeline> createComputePipeline(
-      const Rc<DxvkShader>& cs);
+      const Rc<DxvkPipelineCache>&  cache,
+      const Rc<DxvkShader>&         cs);
     
     /**
      * \brief Retrieves a graphics pipeline object
@@ -89,11 +90,12 @@ namespace dxvk {
      * \returns Graphics pipeline object
      */
     Rc<DxvkGraphicsPipeline> createGraphicsPipeline(
-      const Rc<DxvkShader>& vs,
-      const Rc<DxvkShader>& tcs,
-      const Rc<DxvkShader>& tes,
-      const Rc<DxvkShader>& gs,
-      const Rc<DxvkShader>& fs);
+      const Rc<DxvkPipelineCache>&  cache,
+      const Rc<DxvkShader>&         vs,
+      const Rc<DxvkShader>&         tcs,
+      const Rc<DxvkShader>&         tes,
+      const Rc<DxvkShader>&         gs,
+      const Rc<DxvkShader>&         fs);
     
   private:
     
diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build
index e240736d..2694bf88 100644
--- a/src/dxvk/meson.build
+++ b/src/dxvk/meson.build
@@ -22,6 +22,7 @@ dxvk_src = files([
   'dxvk_lifetime.cpp',
   'dxvk_main.cpp',
   'dxvk_memory.cpp',
+  'dxvk_pipecache.cpp',
   'dxvk_pipelayout.cpp',
   'dxvk_pipemanager.cpp',
   'dxvk_queue.cpp',