Przeglądaj źródła

shader: Mark SSBOs as written when they are

FernandoS27 5 lat temu
rodzic
commit
12f5f32098

+ 29 - 2
src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp

@@ -6,6 +6,7 @@
 #include <compare>
 #include <compare>
 #include <optional>
 #include <optional>
 #include <ranges>
 #include <ranges>
+#include <map>
 
 
 #include <boost/container/flat_set.hpp>
 #include <boost/container/flat_set.hpp>
 #include <boost/container/small_vector.hpp>
 #include <boost/container/small_vector.hpp>
@@ -45,6 +46,7 @@ using StorageBufferSet =
 using StorageInstVector = boost::container::small_vector<StorageInst, 24>;
 using StorageInstVector = boost::container::small_vector<StorageInst, 24>;
 using VisitedBlocks = boost::container::flat_set<IR::Block*, std::less<IR::Block*>,
 using VisitedBlocks = boost::container::flat_set<IR::Block*, std::less<IR::Block*>,
                                                  boost::container::small_vector<IR::Block*, 4>>;
                                                  boost::container::small_vector<IR::Block*, 4>>;
+using StorageWritesMap = std::map<StorageBufferAddr, bool>;
 
 
 /// Returns true when the instruction is a global memory instruction
 /// Returns true when the instruction is a global memory instruction
 bool IsGlobalMemory(const IR::Inst& inst) {
 bool IsGlobalMemory(const IR::Inst& inst) {
@@ -69,6 +71,22 @@ bool IsGlobalMemory(const IR::Inst& inst) {
     }
     }
 }
 }
 
 
+/// Returns true when the instruction is a global memory instruction
+bool IsGlobalMemoryWrite(const IR::Inst& inst) {
+    switch (inst.Opcode()) {
+    case IR::Opcode::WriteGlobalS8:
+    case IR::Opcode::WriteGlobalU8:
+    case IR::Opcode::WriteGlobalS16:
+    case IR::Opcode::WriteGlobalU16:
+    case IR::Opcode::WriteGlobal32:
+    case IR::Opcode::WriteGlobal64:
+    case IR::Opcode::WriteGlobal128:
+        return true;
+    default:
+        return false;
+    }
+}
+
 /// Converts a global memory opcode to its storage buffer equivalent
 /// Converts a global memory opcode to its storage buffer equivalent
 IR::Opcode GlobalToStorage(IR::Opcode opcode) {
 IR::Opcode GlobalToStorage(IR::Opcode opcode) {
     switch (opcode) {
     switch (opcode) {
@@ -248,7 +266,7 @@ std::optional<StorageBufferAddr> Track(IR::Block* block, const IR::Value& value,
 
 
 /// Collects the storage buffer used by a global memory instruction and the instruction itself
 /// Collects the storage buffer used by a global memory instruction and the instruction itself
 void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageBufferSet& storage_buffer_set,
 void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageBufferSet& storage_buffer_set,
-                           StorageInstVector& to_replace) {
+                           StorageInstVector& to_replace, StorageWritesMap& writes_map) {
     // NVN puts storage buffers in a specific range, we have to bias towards these addresses to
     // NVN puts storage buffers in a specific range, we have to bias towards these addresses to
     // avoid getting false positives
     // avoid getting false positives
     static constexpr Bias nvn_bias{
     static constexpr Bias nvn_bias{
@@ -277,6 +295,13 @@ void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageBufferSet& s
         }
         }
     }
     }
     // Collect storage buffer and the instruction
     // Collect storage buffer and the instruction
+    const bool is_a_write = IsGlobalMemoryWrite(inst);
+    auto it = writes_map.find(*storage_buffer);
+    if (it == writes_map.end()) {
+      writes_map[*storage_buffer] = is_a_write;
+    } else {
+      it->second = it->second || is_a_write;
+    }
     storage_buffer_set.insert(*storage_buffer);
     storage_buffer_set.insert(*storage_buffer);
     to_replace.push_back(StorageInst{
     to_replace.push_back(StorageInst{
         .storage_buffer{*storage_buffer},
         .storage_buffer{*storage_buffer},
@@ -350,13 +375,14 @@ void Replace(IR::Block& block, IR::Inst& inst, const IR::U32& storage_index,
 void GlobalMemoryToStorageBufferPass(IR::Program& program) {
 void GlobalMemoryToStorageBufferPass(IR::Program& program) {
     StorageBufferSet storage_buffers;
     StorageBufferSet storage_buffers;
     StorageInstVector to_replace;
     StorageInstVector to_replace;
+    StorageWritesMap writes_map;
 
 
     for (IR::Block* const block : program.post_order_blocks) {
     for (IR::Block* const block : program.post_order_blocks) {
         for (IR::Inst& inst : block->Instructions()) {
         for (IR::Inst& inst : block->Instructions()) {
             if (!IsGlobalMemory(inst)) {
             if (!IsGlobalMemory(inst)) {
                 continue;
                 continue;
             }
             }
-            CollectStorageBuffers(*block, inst, storage_buffers, to_replace);
+            CollectStorageBuffers(*block, inst, storage_buffers, to_replace, writes_map);
         }
         }
     }
     }
     Info& info{program.info};
     Info& info{program.info};
@@ -366,6 +392,7 @@ void GlobalMemoryToStorageBufferPass(IR::Program& program) {
             .cbuf_index{storage_buffer.index},
             .cbuf_index{storage_buffer.index},
             .cbuf_offset{storage_buffer.offset},
             .cbuf_offset{storage_buffer.offset},
             .count{1},
             .count{1},
+            .is_written{writes_map[storage_buffer]},
         });
         });
         ++storage_index;
         ++storage_index;
     }
     }

+ 1 - 0
src/shader_recompiler/shader_info.h

@@ -59,6 +59,7 @@ struct StorageBufferDescriptor {
     u32 cbuf_index;
     u32 cbuf_index;
     u32 cbuf_offset;
     u32 cbuf_offset;
     u32 count;
     u32 count;
+    bool is_written;
 };
 };
 
 
 struct Info {
 struct Info {

+ 1 - 1
src/video_core/renderer_vulkan/vk_compute_pipeline.cpp

@@ -75,7 +75,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
     size_t ssbo_index{};
     size_t ssbo_index{};
     for (const auto& desc : info.storage_buffers_descriptors) {
     for (const auto& desc : info.storage_buffers_descriptors) {
         ASSERT(desc.count == 1);
         ASSERT(desc.count == 1);
-        buffer_cache.BindComputeStorageBuffer(ssbo_index, desc.cbuf_index, desc.cbuf_offset, true);
+        buffer_cache.BindComputeStorageBuffer(ssbo_index, desc.cbuf_index, desc.cbuf_offset, desc.is_written);
         ++ssbo_index;
         ++ssbo_index;
     }
     }
     buffer_cache.UpdateComputeBuffers();
     buffer_cache.UpdateComputeBuffers();

+ 1 - 1
src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp

@@ -163,7 +163,7 @@ void GraphicsPipeline::Configure(bool is_indexed) {
         for (const auto& desc : info.storage_buffers_descriptors) {
         for (const auto& desc : info.storage_buffers_descriptors) {
             ASSERT(desc.count == 1);
             ASSERT(desc.count == 1);
             buffer_cache.BindGraphicsStorageBuffer(stage, index, desc.cbuf_index, desc.cbuf_offset,
             buffer_cache.BindGraphicsStorageBuffer(stage, index, desc.cbuf_index, desc.cbuf_offset,
-                                                   true);
+                                                   desc.is_written);
             ++index;
             ++index;
         }
         }
         const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers};
         const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers};