From b22d56ac06231beadd1ab2bd9af9b05fa248f4d0 Mon Sep 17 00:00:00 2001
From: Philip Rebohle <philip.rebohle@tu-dortmund.de>
Date: Wed, 10 Jan 2018 12:13:46 +0100
Subject: [PATCH] [dxvk] Implementing unbound resource handling (2/4)

Refactored pipeline binding and descriptor set updates so that
no descriptor info gets written for unbound resources.
---
 src/dxvk/dxvk_cmdlist.cpp | 35 ++++++++--------
 src/dxvk/dxvk_cmdlist.h   |  4 +-
 src/dxvk/dxvk_context.cpp | 84 +++++++++++++++++++++++++++------------
 src/dxvk/dxvk_context.h   | 10 +++++
 4 files changed, 90 insertions(+), 43 deletions(-)

diff --git a/src/dxvk/dxvk_cmdlist.cpp b/src/dxvk/dxvk_cmdlist.cpp
index 5018f5ab7..50bc387b1 100644
--- a/src/dxvk/dxvk_cmdlist.cpp
+++ b/src/dxvk/dxvk_cmdlist.cpp
@@ -94,33 +94,36 @@ namespace dxvk {
           VkDescriptorSetLayout   descriptorLayout,
           uint32_t                descriptorCount,
     const DxvkDescriptorSlot*     descriptorSlots,
-    const DxvkDescriptorInfo*     descriptorInfos) {
+    const DxvkDescriptorInfo*     descriptorInfos,
+    const DxvkBindingState&       bindingState) {
     
     // Allocate a new descriptor set
     VkDescriptorSet dset = m_descAlloc.alloc(descriptorLayout);
     
     // Write data to the descriptor set
     std::array<VkWriteDescriptorSet, MaxNumResourceSlots> descriptorWrites;
+    uint32_t writeId = 0;
     
     for (uint32_t i = 0; i < descriptorCount; i++) {
-      auto& curr    = descriptorWrites[i];
-      auto& binding = descriptorSlots[i];
-      
-      curr.sType            = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
-      curr.pNext            = nullptr;
-      curr.dstSet           = dset;
-      curr.dstBinding       = i;
-      curr.dstArrayElement  = 0;
-      curr.descriptorCount  = 1;
-      curr.descriptorType   = binding.type;
-      curr.pImageInfo       = &descriptorInfos[i].image;
-      curr.pBufferInfo      = &descriptorInfos[i].buffer;
-      curr.pTexelBufferView = &descriptorInfos[i].texelBuffer;
+      if (bindingState.isBound(i)) {
+        auto& curr    = descriptorWrites[writeId++];
+        auto& binding = descriptorSlots[i];
+        
+        curr.sType            = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+        curr.pNext            = nullptr;
+        curr.dstSet           = dset;
+        curr.dstBinding       = i;
+        curr.dstArrayElement  = 0;
+        curr.descriptorCount  = 1;
+        curr.descriptorType   = binding.type;
+        curr.pImageInfo       = &descriptorInfos[i].image;
+        curr.pBufferInfo      = &descriptorInfos[i].buffer;
+        curr.pTexelBufferView = &descriptorInfos[i].texelBuffer;
+      }
     }
     
     m_vkd->vkUpdateDescriptorSets(
-      m_vkd->device(),
-      descriptorCount,
+      m_vkd->device(), writeId,
       descriptorWrites.data(),
       0, nullptr);
     
diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h
index 390cbb437..4f6611a51 100644
--- a/src/dxvk/dxvk_cmdlist.h
+++ b/src/dxvk/dxvk_cmdlist.h
@@ -2,6 +2,7 @@
 
 #include <unordered_set>
 
+#include "dxvk_binding.h"
 #include "dxvk_descriptor.h"
 #include "dxvk_lifetime.h"
 #include "dxvk_limits.h"
@@ -87,7 +88,8 @@ namespace dxvk {
             VkDescriptorSetLayout   descriptorLayout,
             uint32_t                descriptorCount,
       const DxvkDescriptorSlot*     descriptorSlots,
-      const DxvkDescriptorInfo*     descriptorInfos);
+      const DxvkDescriptorInfo*     descriptorInfos,
+      const DxvkBindingState&       bindingState);
     
     void cmdBeginRenderPass(
       const VkRenderPassBeginInfo*  pRenderPassBegin,
diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp
index 75fb83d04..d12489a10 100644
--- a/src/dxvk/dxvk_context.cpp
+++ b/src/dxvk/dxvk_context.cpp
@@ -142,10 +142,12 @@ namespace dxvk {
       if (stage == VK_SHADER_STAGE_COMPUTE_BIT) {
         m_flags.set(
           DxvkContextFlag::CpDirtyPipeline,
+          DxvkContextFlag::CpDirtyPipelineState,
           DxvkContextFlag::CpDirtyResources);
       } else {
         m_flags.set(
           DxvkContextFlag::GpDirtyPipeline,
+          DxvkContextFlag::GpDirtyPipelineState,
           DxvkContextFlag::GpDirtyResources);
       }
     }
@@ -920,17 +922,22 @@ namespace dxvk {
   
   
   void DxvkContext::updateGraphicsPipeline() {
-    if (m_flags.any(DxvkContextFlag::GpDirtyPipeline, DxvkContextFlag::GpDirtyPipelineState)) {
-      m_flags.clr(DxvkContextFlag::GpDirtyPipelineState);
+    if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) {
+      m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
       
-      if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) {
-        m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
-        
-        m_state.gp.bs.clear();
-        m_state.gp.pipeline = m_device->createGraphicsPipeline(
-          m_state.gp.vs.shader, m_state.gp.tcs.shader, m_state.gp.tes.shader,
-          m_state.gp.gs.shader, m_state.gp.fs.shader);
-      }
+      m_state.gp.bs.clear();
+      m_state.gp.pipeline = m_device->createGraphicsPipeline(
+        m_state.gp.vs.shader, m_state.gp.tcs.shader, m_state.gp.tes.shader,
+        m_state.gp.gs.shader, m_state.gp.fs.shader);
+      
+      m_cmd->trackResource(m_state.gp.pipeline);
+    }
+  }
+  
+  
+  void DxvkContext::updateGraphicsPipelineState() {
+    if (m_flags.test(DxvkContextFlag::GpDirtyPipelineState)) {
+      m_flags.clr(DxvkContextFlag::GpDirtyPipelineState);
       
       DxvkGraphicsPipelineStateInfo gpState;
       gpState.bsBindingState = m_state.gp.bs;
@@ -1005,15 +1012,12 @@ namespace dxvk {
       
       m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS,
         m_state.gp.pipeline->getPipelineHandle(gpState));
-      m_cmd->trackResource(m_state.gp.pipeline);
     }
   }
   
   
   void DxvkContext::updateComputeShaderResources() {
     if (m_flags.test(DxvkContextFlag::CpDirtyResources)) {
-      m_flags.clr(DxvkContextFlag::CpDirtyResources);
-      
       this->updateShaderResources(
         VK_PIPELINE_BIND_POINT_COMPUTE,
         m_state.cp.pipeline->layout());
@@ -1021,12 +1025,34 @@ namespace dxvk {
   }
   
   
+  void DxvkContext::updateComputeShaderDescriptors() {
+    if (m_flags.test(DxvkContextFlag::CpDirtyResources)) {
+      m_flags.clr(DxvkContextFlag::CpDirtyResources);
+      
+      this->updateShaderDescriptors(
+        VK_PIPELINE_BIND_POINT_COMPUTE,
+        m_state.cp.bs,
+        m_state.cp.pipeline->layout());
+    }
+  }
+  
+  
   void DxvkContext::updateGraphicsShaderResources() {
+    if (m_flags.test(DxvkContextFlag::GpDirtyResources)) {
+      this->updateShaderResources(
+        VK_PIPELINE_BIND_POINT_GRAPHICS,
+        m_state.gp.pipeline->layout());
+    }
+  }
+  
+  
+  void DxvkContext::updateGraphicsShaderDescriptors() {
     if (m_flags.test(DxvkContextFlag::GpDirtyResources)) {
       m_flags.clr(DxvkContextFlag::GpDirtyResources);
       
-      this->updateShaderResources(
+      this->updateShaderDescriptors(
         VK_PIPELINE_BIND_POINT_GRAPHICS,
+        m_state.gp.bs,
         m_state.gp.pipeline->layout());
     }
   }
@@ -1059,7 +1085,6 @@ namespace dxvk {
             
             m_cmd->trackResource(res.sampler);
           } else {
-            Logger::err("DxvkContext: Unbound sampler descriptor");
             updatePipelineState |= bs.setUnbound(i);
             
             m_descriptors[i].image.sampler     = VK_NULL_HANDLE;
@@ -1069,7 +1094,7 @@ namespace dxvk {
         
         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
-          if (res.imageView != nullptr/* && res.imageView->type() != binding.view*/) {
+          if (res.imageView != nullptr && res.imageView->type() != binding.view) {
             updatePipelineState |= bs.setBound(i);
             
             m_descriptors[i].image.sampler     = VK_NULL_HANDLE;
@@ -1079,7 +1104,6 @@ namespace dxvk {
             m_cmd->trackResource(res.imageView);
             m_cmd->trackResource(res.imageView->image());
           } else {
-            Logger::err("DxvkContext: Unbound or incompatible image descriptor");
             updatePipelineState |= bs.setUnbound(i);
             
             m_descriptors[i].image.sampler     = VK_NULL_HANDLE;
@@ -1097,7 +1121,6 @@ namespace dxvk {
             m_cmd->trackResource(res.bufferView);
             m_cmd->trackResource(res.bufferView->buffer()->resource());
           } else {
-            Logger::err("DxvkContext: Unbound texel buffer");
             updatePipelineState |= bs.setUnbound(i);
             
             m_descriptors[i].texelBuffer = VK_NULL_HANDLE;
@@ -1111,7 +1134,6 @@ namespace dxvk {
             m_descriptors[i].buffer = res.bufferSlice.descriptorInfo();
             m_cmd->trackResource(res.bufferSlice.resource());
           } else {
-            Logger::err("DxvkContext: Unbound buffer");
             updatePipelineState |= bs.setUnbound(i);
             
             m_descriptors[i].buffer.buffer = VK_NULL_HANDLE;
@@ -1124,19 +1146,26 @@ namespace dxvk {
       }
     }
     
+    if (updatePipelineState) {
+      m_flags.set(bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
+        ? DxvkContextFlag::GpDirtyPipelineState
+        : DxvkContextFlag::CpDirtyPipelineState);
+    }
+  }
+  
+  
+  void DxvkContext::updateShaderDescriptors(
+          VkPipelineBindPoint     bindPoint,
+    const DxvkBindingState&       bindingState,
+    const Rc<DxvkBindingLayout>&  layout) {
     m_cmd->bindResourceDescriptors(
       bindPoint,
       layout->pipelineLayout(),
       layout->descriptorSetLayout(),
       layout->bindingCount(),
       layout->bindings(),
-      m_descriptors.data());
-    
-    if (updatePipelineState) {
-      m_flags.set(bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
-        ? DxvkContextFlag::GpDirtyPipelineState
-        : DxvkContextFlag::CpDirtyPipelineState);
-    }
+      m_descriptors.data(),
+      bindingState);
   }
   
   
@@ -1213,6 +1242,7 @@ namespace dxvk {
     this->renderPassEnd();
     this->updateComputePipeline();
     this->updateComputeShaderResources();
+    this->updateComputeShaderDescriptors();
   }
   
   
@@ -1223,6 +1253,8 @@ namespace dxvk {
     this->updateIndexBufferBinding();
     this->updateVertexBufferBindings();
     this->updateGraphicsShaderResources();
+    this->updateGraphicsPipelineState();
+    this->updateGraphicsShaderDescriptors();
   }
   
   
diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h
index ba903b419..fbb2a143a 100644
--- a/src/dxvk/dxvk_context.h
+++ b/src/dxvk/dxvk_context.h
@@ -492,15 +492,25 @@ namespace dxvk {
     void renderPassEnd();
     
     void updateComputePipeline();
+    
     void updateGraphicsPipeline();
+    void updateGraphicsPipelineState();
     
     void updateComputeShaderResources();
+    void updateComputeShaderDescriptors();
+    
     void updateGraphicsShaderResources();
+    void updateGraphicsShaderDescriptors();
     
     void updateShaderResources(
             VkPipelineBindPoint     bindPoint,
       const Rc<DxvkBindingLayout>&  layout);
     
+    void updateShaderDescriptors(
+            VkPipelineBindPoint     bindPoint,
+      const DxvkBindingState&       bindingState,
+      const Rc<DxvkBindingLayout>&  layout);
+    
     void updateDynamicState();
     void updateViewports();
     void updateBlendConstants();