File dxvk-gplasync-2.4-1.patch of Package dxvk-gplasync-x86-64-v3

From 4e5658e97b6cbdf1b196ff062ce76fc1811b6b45 Mon Sep 17 00:00:00 2001
From: Ph42oN <julle.ys.57@gmail.com>
Date: Sun, 9 Jun 2024 21:32:28 +0300
Subject: [PATCH] update

---
 meson.build                |  2 +-
 src/dxvk/dxvk_context.cpp  | 20 +++++++++++++++++---
 src/dxvk/dxvk_context.h    |  4 +++-
 src/dxvk/dxvk_graphics.cpp | 36 +++++++++++++++++++++++++++++-------
 src/dxvk/dxvk_graphics.h   |  9 ++++++++-
 src/dxvk/dxvk_image.h      | 33 +++++++++++++++++++++++++++++++++
 src/dxvk/dxvk_options.cpp  | 10 ++++++++++
 src/dxvk/dxvk_options.h    |  6 ++++++
 8 files changed, 107 insertions(+), 13 deletions(-)

diff --git a/meson.build b/meson.build
index cfa841a6..e6c96d5b 100644
--- a/meson.build
+++ b/meson.build
@@ -182,7 +182,7 @@ glsl_generator = generator(
 )
 
 dxvk_version = vcs_tag(
-  command: ['git', 'describe', '--dirty=+'],
+  command: ['git', 'describe', '--dirty=-1-gplasync'],
   input:  'version.h.in',
   output: 'version.h',
 )
diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp
index c63dce53..4f7d1761 100644
--- a/src/dxvk/dxvk_context.cpp
+++ b/src/dxvk/dxvk_context.cpp
@@ -5089,7 +5089,8 @@ namespace dxvk {
       : DxvkContextFlag::GpDirtyRasterizerState);
 
     // Retrieve and bind actual Vulkan pipeline handle
-    auto pipelineInfo = m_state.gp.pipeline->getPipelineHandle(m_state.gp.state);
+    auto pipelineInfo = m_state.gp.pipeline->getPipelineHandle(
+      m_state.gp.state, this->checkAsyncCompilationCompat());
 
     if (unlikely(!pipelineInfo.first))
       return false;
@@ -5446,7 +5447,7 @@ namespace dxvk {
   }
 
 
-  void DxvkContext::updateFramebuffer() {
+  void DxvkContext::updateFramebuffer(bool isDraw) {
     if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) {
       m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer);
 
@@ -5470,6 +5471,11 @@ namespace dxvk {
         m_state.gp.state.omSwizzle[i] = DxvkOmAttachmentSwizzle(mapping);
       }
 
+      if (isDraw) {
+        for (uint32_t i = 0; i < fbInfo.numAttachments(); i++)
+          fbInfo.getAttachment(i).view->setRtBindingFrameId(m_device->getCurrentFrameId());
+      }
+
       m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
     }
   }
@@ -5973,7 +5979,7 @@ namespace dxvk {
     }
     
     if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer))
-      this->updateFramebuffer();
+      this->updateFramebuffer(true);
 
     if (!m_flags.test(DxvkContextFlag::GpRenderPassBound))
       this->startRenderPass();
@@ -6392,6 +6398,14 @@ namespace dxvk {
     return true;
   }
   
+  bool DxvkContext::checkAsyncCompilationCompat() {
+    bool fbCompat = true;
+    for (uint32_t i = 0; fbCompat && i < m_state.om.framebufferInfo.numAttachments(); i++) {
+      const auto& attachment = m_state.om.framebufferInfo.getAttachment(i);
+      fbCompat &= attachment.view->getRtBindingAsyncCompilationCompat();
+    }
+    return fbCompat;
+  }
 
   DxvkGraphicsPipeline* DxvkContext::lookupGraphicsPipeline(
     const DxvkGraphicsPipelineShaders&  shaders) {
diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h
index 3b61d474..e8c0c2fe 100644
--- a/src/dxvk/dxvk_context.h
+++ b/src/dxvk/dxvk_context.h
@@ -1639,7 +1639,7 @@ namespace dxvk {
     DxvkFramebufferInfo makeFramebufferInfo(
       const DxvkRenderTargets&      renderTargets);
 
-    void updateFramebuffer();
+    void updateFramebuffer(bool isDraw = false);
     
     void applyRenderTargetLoadLayouts();
 
@@ -1722,6 +1722,8 @@ namespace dxvk {
       const Rc<DxvkBuffer>&           buffer,
             VkDeviceSize              copySize);
 
+    bool checkAsyncCompilationCompat();
+
     DxvkGraphicsPipeline* lookupGraphicsPipeline(
       const DxvkGraphicsPipelineShaders&  shaders);
 
diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp
index 3092f350..1a3206b2 100644
--- a/src/dxvk/dxvk_graphics.cpp
+++ b/src/dxvk/dxvk_graphics.cpp
@@ -931,6 +931,7 @@ namespace dxvk {
     m_vsIn  = m_shaders.vs != nullptr ? m_shaders.vs->info().inputMask  : 0;
     m_fsOut = m_shaders.fs != nullptr ? m_shaders.fs->info().outputMask : 0;
     m_specConstantMask = this->computeSpecConstantMask();
+    gplAsyncCache = m_device->config().gplAsyncCache;
 
     if (m_shaders.gs != nullptr) {
       if (m_shaders.gs->flags().test(DxvkShaderFlag::HasTransformFeedback)) {
@@ -979,7 +980,8 @@ namespace dxvk {
 
 
   std::pair<VkPipeline, DxvkGraphicsPipelineType> DxvkGraphicsPipeline::getPipelineHandle(
-    const DxvkGraphicsPipelineStateInfo& state) {
+    const DxvkGraphicsPipelineStateInfo& state,
+          bool                           async) {
     DxvkGraphicsPipelineInstance* instance = this->findInstance(state);
 
     if (unlikely(!instance)) {
@@ -987,11 +989,22 @@ namespace dxvk {
       if (!this->validatePipelineState(state, true))
         return std::make_pair(VK_NULL_HANDLE, DxvkGraphicsPipelineType::FastPipeline);
 
-      // Prevent other threads from adding new instances and check again
-      std::unique_lock<dxvk::mutex> lock(m_mutex);
-      instance = this->findInstance(state);
+    bool useAsync = m_device->config().enableAsync && async;
+
+    // Prevent other threads from adding new instances and check again
+    std::unique_lock<dxvk::mutex> lock(useAsync ? m_asyncMutex : m_mutex);
+    instance = this->findInstance(state);
+
+    if (!instance) {
+      if (useAsync) {
+        m_async = true;
+        lock.unlock();
+
+        m_workers->compileGraphicsPipeline(this, state, DxvkPipelinePriority::High);
+
+        return std::make_pair(VK_NULL_HANDLE, DxvkGraphicsPipelineType::FastPipeline);
+      } else {
 
-      if (!instance) {
         // Keep pipeline object locked, at worst we're going to stall
         // a state cache worker and the current thread needs priority.
         bool canCreateBasePipeline = this->canCreateBasePipeline(state);
@@ -1011,6 +1024,7 @@ namespace dxvk {
           this->writePipelineStateToCache(state);
       }
     }
+  }
 
     // Find a pipeline handle to use. If no optimized pipeline has
     // been compiled yet, use the slower base pipeline instead.
@@ -1038,7 +1052,7 @@ namespace dxvk {
 
       // Do not compile if this pipeline can be fast linked. This essentially
       // disables the state cache for pipelines that do not benefit from it.
-      if (this->canCreateBasePipeline(state))
+      if (!gplAsyncCache && !m_async && this->canCreateBasePipeline(state))
         return;
 
       // Prevent other threads from adding new instances and check again
@@ -1059,8 +1073,14 @@ namespace dxvk {
     instance->fastHandle.store(pipeline, std::memory_order_release);
 
     // Log pipeline state on error
-    if (!pipeline)
+    if (!pipeline) {
       this->logPipelineState(LogLevel::Error, state);
+      return;
+    }
+
+    //Write pipeline to state cache
+    if (gplAsyncCache)
+      this->writePipelineStateToCache(state);
   }
 
 
@@ -1287,6 +1307,8 @@ namespace dxvk {
 
     if (handle)
       m_fastPipelines.insert({ key, handle });
+    
+    m_async = false;
 
     return handle;
   }
diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h
index 4f618f78..dba7236d 100644
--- a/src/dxvk/dxvk_graphics.h
+++ b/src/dxvk/dxvk_graphics.h
@@ -530,11 +530,14 @@ namespace dxvk {
      * Retrieves a pipeline handle for the given pipeline
      * state. If necessary, a new pipeline will be created.
      * \param [in] state Pipeline state vector
+     * \param [in] async Compile asynchronously
      * \returns Pipeline handle and handle type
      */
     std::pair<VkPipeline, DxvkGraphicsPipelineType> getPipelineHandle(
-      const DxvkGraphicsPipelineStateInfo&    state);
+      const DxvkGraphicsPipelineStateInfo&    state,
+            bool                              async);
     
+    void asyncPipeline(const DxvkGraphicsPipelineStateInfo& state);
     /**
      * \brief Compiles a pipeline
      * 
@@ -585,6 +588,10 @@ namespace dxvk {
 
     alignas(CACHE_LINE_SIZE)
     dxvk::mutex                                   m_mutex;
+    alignas(CACHE_LINE_SIZE)
+    dxvk::mutex                                   m_asyncMutex;
+    bool                                          m_async = false;
+    bool                                          gplAsyncCache;
     sync::List<DxvkGraphicsPipelineInstance>      m_pipelines;
     uint32_t                                      m_useCount = 0;
 
diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h
index 3a09302b..c9f7615d 100644
--- a/src/dxvk/dxvk_image.h
+++ b/src/dxvk/dxvk_image.h
@@ -548,6 +548,36 @@ namespace dxvk {
         this->imageSubresources(),
         view->imageSubresources());
     }
+    /**
+     * \brief Sets render target usage frame number
+     *
+     * The image view will track internally when
+     * it was last used as a render target. This
+     * info is used for async shader compilation.
+     * \param [in] frameId Frame number
+     */
+    void setRtBindingFrameId(uint32_t frameId) {
+      if (frameId != m_rtBindingFrameId) {
+        if (frameId == m_rtBindingFrameId + 1)
+          m_rtBindingFrameCount += 1;
+        else
+          m_rtBindingFrameCount = 0;
+
+        m_rtBindingFrameId = frameId;
+      }
+    }
+
+    /**
+     * \brief Checks for async pipeline compatibility
+     *
+     * Asynchronous pipeline compilation may be enabled if the
+     * render target has been drawn to in the previous frames.
+     * \param [in] frameId Current frame ID
+     * \returns \c true if async compilation is supported
+     */
+    bool getRtBindingAsyncCompilationCompat() const {
+      return m_rtBindingFrameCount >= 5;
+    }
 
   private:
     
@@ -557,6 +587,9 @@ namespace dxvk {
     DxvkImageViewCreateInfo m_info;
     VkImageView             m_views[ViewCount];
 
+    uint32_t m_rtBindingFrameId    = 0;
+    uint32_t m_rtBindingFrameCount = 0;
+
     void createView(VkImageViewType type, uint32_t numLayers);
     
   };
diff --git a/src/dxvk/dxvk_options.cpp b/src/dxvk/dxvk_options.cpp
index d84f08a6..f2eebf8b 100644
--- a/src/dxvk/dxvk_options.cpp
+++ b/src/dxvk/dxvk_options.cpp
@@ -3,6 +3,16 @@
 namespace dxvk {
 
   DxvkOptions::DxvkOptions(const Config& config) {
+    if (env::getEnvVar("DXVK_GPLASYNCCACHE") == "1")
+      gplAsyncCache = true;
+    else
+      gplAsyncCache = config.getOption<bool>("dxvk.gplAsyncCache", false);
+    
+    if (env::getEnvVar("DXVK_ASYNC") == "0")
+      enableAsync = false;
+    else
+      enableAsync = config.getOption<bool>("dxvk.enableAsync", true);
+    
     enableDebugUtils      = config.getOption<bool>    ("dxvk.enableDebugUtils",       false);
     enableStateCache      = config.getOption<bool>    ("dxvk.enableStateCache",       true);
     numCompilerThreads    = config.getOption<int32_t> ("dxvk.numCompilerThreads",     0);
diff --git a/src/dxvk/dxvk_options.h b/src/dxvk/dxvk_options.h
index ac63bc10..dde008bb 100644
--- a/src/dxvk/dxvk_options.h
+++ b/src/dxvk/dxvk_options.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "../util/config/config.h"
+#include "dxvk_include.h"
 
 namespace dxvk {
 
@@ -24,6 +25,11 @@ namespace dxvk {
     /// Enables pipeline lifetime tracking
     Tristate trackPipelineLifetime;
 
+    // Enable async pipelines
+    bool enableAsync;
+    // Enable state cache with gpl and fixes for async
+    bool gplAsyncCache;
+
     /// Shader-related options
     Tristate useRawSsbo;
 
-- 
2.44.2

openSUSE Build Service is sponsored by