diff options
Diffstat (limited to 'src/shader_recompiler/ir_opt/texture_pass.cpp')
| -rw-r--r-- | src/shader_recompiler/ir_opt/texture_pass.cpp | 68 |
1 files changed, 22 insertions, 46 deletions
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index da8977b76..bcb94ce4d 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -2,13 +2,14 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 5 | #include <optional> | 6 | #include <optional> |
| 6 | 7 | ||
| 7 | #include <boost/container/flat_set.hpp> | ||
| 8 | #include <boost/container/small_vector.hpp> | 8 | #include <boost/container/small_vector.hpp> |
| 9 | 9 | ||
| 10 | #include "shader_recompiler/environment.h" | 10 | #include "shader_recompiler/environment.h" |
| 11 | #include "shader_recompiler/frontend/ir/basic_block.h" | 11 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 12 | #include "shader_recompiler/frontend/ir/breadth_first_search.h" | ||
| 12 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | 13 | #include "shader_recompiler/frontend/ir/ir_emitter.h" |
| 13 | #include "shader_recompiler/ir_opt/passes.h" | 14 | #include "shader_recompiler/ir_opt/passes.h" |
| 14 | #include "shader_recompiler/shader_info.h" | 15 | #include "shader_recompiler/shader_info.h" |
| @@ -28,9 +29,6 @@ struct TextureInst { | |||
| 28 | 29 | ||
| 29 | using TextureInstVector = boost::container::small_vector<TextureInst, 24>; | 30 | using TextureInstVector = boost::container::small_vector<TextureInst, 24>; |
| 30 | 31 | ||
| 31 | using VisitedBlocks = boost::container::flat_set<IR::Block*, std::less<IR::Block*>, | ||
| 32 | boost::container::small_vector<IR::Block*, 2>>; | ||
| 33 | |||
| 34 | IR::Opcode IndexedInstruction(const IR::Inst& inst) { | 32 | IR::Opcode IndexedInstruction(const IR::Inst& inst) { |
| 35 | switch (inst.Opcode()) { | 33 | switch (inst.Opcode()) { |
| 36 | case IR::Opcode::BindlessImageSampleImplicitLod: | 34 | case IR::Opcode::BindlessImageSampleImplicitLod: |
| @@ -101,57 +99,35 @@ bool IsTextureInstruction(const IR::Inst& inst) { | |||
| 101 | return IndexedInstruction(inst) != IR::Opcode::Void; | 99 | return IndexedInstruction(inst) != IR::Opcode::Void; |
| 102 | } | 100 | } |
| 103 | 101 | ||
| 104 | std::optional<ConstBufferAddr> Track(IR::Block* block, const IR::Value& value, | 102 | std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { |
| 105 | VisitedBlocks& visited) { | 103 | if (inst->Opcode() != IR::Opcode::GetCbufU32) { |
| 106 | if (value.IsImmediate()) { | ||
| 107 | // Immediates can't be a storage buffer | ||
| 108 | return std::nullopt; | 104 | return std::nullopt; |
| 109 | } | 105 | } |
| 110 | const IR::Inst* const inst{value.InstRecursive()}; | 106 | const IR::Value index{inst->Arg(0)}; |
| 111 | if (inst->Opcode() == IR::Opcode::GetCbufU32) { | 107 | const IR::Value offset{inst->Arg(1)}; |
| 112 | const IR::Value index{inst->Arg(0)}; | 108 | if (!index.IsImmediate()) { |
| 113 | const IR::Value offset{inst->Arg(1)}; | 109 | // Reading a bindless texture from variable indices is valid |
| 114 | if (!index.IsImmediate()) { | 110 | // but not supported here at the moment |
| 115 | // Reading a bindless texture from variable indices is valid | 111 | return std::nullopt; |
| 116 | // but not supported here at the moment | ||
| 117 | return std::nullopt; | ||
| 118 | } | ||
| 119 | if (!offset.IsImmediate()) { | ||
| 120 | // TODO: Support arrays of textures | ||
| 121 | return std::nullopt; | ||
| 122 | } | ||
| 123 | return ConstBufferAddr{ | ||
| 124 | .index{index.U32()}, | ||
| 125 | .offset{offset.U32()}, | ||
| 126 | }; | ||
| 127 | } | 112 | } |
| 128 | // Reversed loops are more likely to find the right result | 113 | if (!offset.IsImmediate()) { |
| 129 | for (size_t arg = inst->NumArgs(); arg--;) { | 114 | // TODO: Support arrays of textures |
| 130 | IR::Block* inst_block{block}; | 115 | return std::nullopt; |
| 131 | if (inst->Opcode() == IR::Opcode::Phi) { | ||
| 132 | // If we are going through a phi node, mark the current block as visited | ||
| 133 | visited.insert(block); | ||
| 134 | // and skip already visited blocks to avoid looping forever | ||
| 135 | IR::Block* const phi_block{inst->PhiBlock(arg)}; | ||
| 136 | if (visited.contains(phi_block)) { | ||
| 137 | // Already visited, skip | ||
| 138 | continue; | ||
| 139 | } | ||
| 140 | inst_block = phi_block; | ||
| 141 | } | ||
| 142 | const std::optional storage_buffer{Track(inst_block, inst->Arg(arg), visited)}; | ||
| 143 | if (storage_buffer) { | ||
| 144 | return *storage_buffer; | ||
| 145 | } | ||
| 146 | } | 116 | } |
| 147 | return std::nullopt; | 117 | return ConstBufferAddr{ |
| 118 | .index{index.U32()}, | ||
| 119 | .offset{offset.U32()}, | ||
| 120 | }; | ||
| 121 | } | ||
| 122 | |||
| 123 | std::optional<ConstBufferAddr> Track(const IR::Value& value) { | ||
| 124 | return IR::BreadthFirstSearch(value, TryGetConstBuffer); | ||
| 148 | } | 125 | } |
| 149 | 126 | ||
| 150 | TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { | 127 | TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { |
| 151 | ConstBufferAddr addr; | 128 | ConstBufferAddr addr; |
| 152 | if (IsBindless(inst)) { | 129 | if (IsBindless(inst)) { |
| 153 | VisitedBlocks visited; | 130 | const std::optional<ConstBufferAddr> track_addr{Track(inst.Arg(0))}; |
| 154 | const std::optional<ConstBufferAddr> track_addr{Track(block, inst.Arg(0), visited)}; | ||
| 155 | if (!track_addr) { | 131 | if (!track_addr) { |
| 156 | throw NotImplementedException("Failed to track bindless texture constant buffer"); | 132 | throw NotImplementedException("Failed to track bindless texture constant buffer"); |
| 157 | } | 133 | } |