diff options
| author | 2022-03-05 08:01:13 +0100 | |
|---|---|---|
| committer | 2023-01-01 16:43:57 -0500 | |
| commit | c541559767c3912940ee3d73a122530b3edde9f1 (patch) | |
| tree | 9924302d2b8e383ce8824ccc219da42417bbc6d4 /src/video_core/macro | |
| parent | MacroHLE: Implement DrawIndexedIndirect & DrawArraysIndirect. (diff) | |
| download | yuzu-c541559767c3912940ee3d73a122530b3edde9f1.tar.gz yuzu-c541559767c3912940ee3d73a122530b3edde9f1.tar.xz yuzu-c541559767c3912940ee3d73a122530b3edde9f1.zip | |
MacroHLE: Refactor MacroHLE system.
Diffstat (limited to 'src/video_core/macro')
| -rw-r--r-- | src/video_core/macro/macro.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/macro/macro.h | 1 | ||||
| -rw-r--r-- | src/video_core/macro/macro_hle.cpp | 445 | ||||
| -rw-r--r-- | src/video_core/macro/macro_hle.h | 5 |
4 files changed, 345 insertions, 113 deletions
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp index 505d81c1e..01dd25f95 100644 --- a/src/video_core/macro/macro.cpp +++ b/src/video_core/macro/macro.cpp | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include "common/fs/fs.h" | 13 | #include "common/fs/fs.h" |
| 14 | #include "common/fs/path_util.h" | 14 | #include "common/fs/path_util.h" |
| 15 | #include "common/settings.h" | 15 | #include "common/settings.h" |
| 16 | #include "video_core/engines/maxwell_3d.h" | ||
| 16 | #include "video_core/macro/macro.h" | 17 | #include "video_core/macro/macro.h" |
| 17 | #include "video_core/macro/macro_hle.h" | 18 | #include "video_core/macro/macro_hle.h" |
| 18 | #include "video_core/macro/macro_interpreter.h" | 19 | #include "video_core/macro/macro_interpreter.h" |
| @@ -40,8 +41,8 @@ static void Dump(u64 hash, std::span<const u32> code) { | |||
| 40 | macro_file.write(reinterpret_cast<const char*>(code.data()), code.size_bytes()); | 41 | macro_file.write(reinterpret_cast<const char*>(code.data()), code.size_bytes()); |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d) | 44 | MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d_) |
| 44 | : hle_macros{std::make_unique<Tegra::HLEMacro>(maxwell3d)} {} | 45 | : hle_macros{std::make_unique<Tegra::HLEMacro>(maxwell3d_)}, maxwell3d{maxwell3d_} {} |
| 45 | 46 | ||
| 46 | MacroEngine::~MacroEngine() = default; | 47 | MacroEngine::~MacroEngine() = default; |
| 47 | 48 | ||
| @@ -61,6 +62,7 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { | |||
| 61 | if (cache_info.has_hle_program) { | 62 | if (cache_info.has_hle_program) { |
| 62 | cache_info.hle_program->Execute(parameters, method); | 63 | cache_info.hle_program->Execute(parameters, method); |
| 63 | } else { | 64 | } else { |
| 65 | maxwell3d.RefreshParameters(); | ||
| 64 | cache_info.lle_program->Execute(parameters, method); | 66 | cache_info.lle_program->Execute(parameters, method); |
| 65 | } | 67 | } |
| 66 | } else { | 68 | } else { |
| @@ -106,6 +108,7 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { | |||
| 106 | cache_info.hle_program = std::move(hle_program); | 108 | cache_info.hle_program = std::move(hle_program); |
| 107 | cache_info.hle_program->Execute(parameters, method); | 109 | cache_info.hle_program->Execute(parameters, method); |
| 108 | } else { | 110 | } else { |
| 111 | maxwell3d.RefreshParameters(); | ||
| 109 | cache_info.lle_program->Execute(parameters, method); | 112 | cache_info.lle_program->Execute(parameters, method); |
| 110 | } | 113 | } |
| 111 | } | 114 | } |
diff --git a/src/video_core/macro/macro.h b/src/video_core/macro/macro.h index 07d97ba39..737ced9a4 100644 --- a/src/video_core/macro/macro.h +++ b/src/video_core/macro/macro.h | |||
| @@ -137,6 +137,7 @@ private: | |||
| 137 | std::unordered_map<u32, CacheInfo> macro_cache; | 137 | std::unordered_map<u32, CacheInfo> macro_cache; |
| 138 | std::unordered_map<u32, std::vector<u32>> uploaded_macro_code; | 138 | std::unordered_map<u32, std::vector<u32>> uploaded_macro_code; |
| 139 | std::unique_ptr<HLEMacro> hle_macros; | 139 | std::unique_ptr<HLEMacro> hle_macros; |
| 140 | Engines::Maxwell3D& maxwell3d; | ||
| 140 | }; | 141 | }; |
| 141 | 142 | ||
| 142 | std::unique_ptr<MacroEngine> GetMacroEngine(Engines::Maxwell3D& maxwell3d); | 143 | std::unique_ptr<MacroEngine> GetMacroEngine(Engines::Maxwell3D& maxwell3d); |
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index da988cc0d..79fab96e1 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <array> | 4 | #include <array> |
| 5 | #include <vector> | 5 | #include <vector> |
| 6 | #include "common/assert.h" | ||
| 6 | #include "common/scope_exit.h" | 7 | #include "common/scope_exit.h" |
| 7 | #include "video_core/dirty_flags.h" | 8 | #include "video_core/dirty_flags.h" |
| 8 | #include "video_core/engines/draw_manager.h" | 9 | #include "video_core/engines/draw_manager.h" |
| @@ -15,143 +16,365 @@ | |||
| 15 | namespace Tegra { | 16 | namespace Tegra { |
| 16 | namespace { | 17 | namespace { |
| 17 | 18 | ||
| 18 | using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters); | 19 | bool IsTopologySafe(Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology topology) { |
| 19 | 20 | switch (topology) { | |
| 20 | // HLE'd functions | 21 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::Points: |
| 21 | void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | 22 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::Lines: |
| 22 | const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B); | 23 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::LineLoop: |
| 23 | maxwell3d.draw_manager->DrawIndex( | 24 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::LineStrip: |
| 24 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff), | 25 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::Triangles: |
| 25 | parameters[4], parameters[1], parameters[3], parameters[5], instance_count); | 26 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::TriangleStrip: |
| 27 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::TriangleFan: | ||
| 28 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::LinesAdjacency: | ||
| 29 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::LineStripAdjacency: | ||
| 30 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::TrianglesAdjacency: | ||
| 31 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::TriangleStripAdjacency: | ||
| 32 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::Patches: | ||
| 33 | return true; | ||
| 34 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::Quads: | ||
| 35 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::QuadStrip: | ||
| 36 | case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::Polygon: | ||
| 37 | default: | ||
| 38 | return false; | ||
| 39 | } | ||
| 26 | } | 40 | } |
| 27 | 41 | ||
| 28 | void HLE_DrawArraysIndirect(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | 42 | class HLEMacroImpl : public CachedMacro { |
| 29 | const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); | 43 | public: |
| 30 | maxwell3d.draw_manager->DrawArray( | 44 | explicit HLEMacroImpl(Engines::Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} {} |
| 31 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]), | ||
| 32 | parameters[3], parameters[1], parameters[4], instance_count); | ||
| 33 | } | ||
| 34 | 45 | ||
| 35 | void HLE_DrawIndexedIndirect(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | 46 | protected: |
| 36 | const u32 element_base = parameters[4]; | 47 | void advanceCheck() { |
| 37 | const u32 base_instance = parameters[5]; | 48 | current_value = (current_value + 1) % fibonacci_post; |
| 38 | maxwell3d.regs.vertex_id_base = element_base; | 49 | check_limit = current_value == 0; |
| 39 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | 50 | if (check_limit) { |
| 40 | maxwell3d.CallMethod(0x8e3, 0x640, true); | 51 | const u32 new_fibonacci = fibonacci_pre + fibonacci_post; |
| 41 | maxwell3d.CallMethod(0x8e4, element_base, true); | 52 | fibonacci_pre = fibonacci_post; |
| 42 | maxwell3d.CallMethod(0x8e5, base_instance, true); | 53 | fibonacci_post = new_fibonacci; |
| 43 | 54 | } | |
| 44 | auto& params = maxwell3d.draw_manager->GetIndirectParams(); | 55 | } |
| 45 | params.is_indexed = true; | 56 | |
| 46 | params.include_count = false; | 57 | Engines::Maxwell3D& maxwell3d; |
| 47 | params.count_start_address = 0; | 58 | u32 fibonacci_pre{89}; |
| 48 | params.indirect_start_address = maxwell3d.macro_addresses[1]; | 59 | u32 fibonacci_post{144}; |
| 49 | params.buffer_size = 5 * sizeof(u32); | 60 | u32 current_value{fibonacci_post - 1}; |
| 50 | params.max_draw_counts = 1; | 61 | bool check_limit{}; |
| 51 | params.stride = 0; | 62 | }; |
| 52 | 63 | ||
| 53 | maxwell3d.draw_manager->DrawIndexedIndirect( | 64 | class HLE_771BB18C62444DA0 final : public HLEMacroImpl { |
| 54 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]), 0, | 65 | public: |
| 55 | 1U << 18); | 66 | explicit HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} |
| 56 | |||
| 57 | maxwell3d.regs.vertex_id_base = 0x0; | ||
| 58 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 59 | maxwell3d.CallMethod(0x8e4, 0x0, true); | ||
| 60 | maxwell3d.CallMethod(0x8e5, 0x0, true); | ||
| 61 | } | ||
| 62 | 67 | ||
| 63 | // Multidraw Indixed Indirect | 68 | void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { |
| 64 | void HLE_MultiDrawIndexedIndirect(Engines::Maxwell3D& maxwell3d, | 69 | maxwell3d.RefreshParameters(); |
| 65 | const std::vector<u32>& parameters) { | 70 | const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B); |
| 66 | const u32 start_indirect = parameters[0]; | 71 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; |
| 67 | const u32 end_indirect = parameters[1]; | 72 | maxwell3d.draw_manager->DrawIndex( |
| 68 | if (start_indirect >= end_indirect) { | 73 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & |
| 69 | // Nothing to do. | 74 | 0x3ffffff), |
| 70 | return; | 75 | parameters[4], parameters[1], parameters[3], parameters[5], instance_count); |
| 71 | } | 76 | } |
| 72 | const auto topology = | 77 | }; |
| 73 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]); | 78 | |
| 74 | const u32 padding = parameters[3]; // padding is in words | 79 | class HLE_DrawArraysIndirect final : public HLEMacroImpl { |
| 75 | 80 | public: | |
| 76 | // size of each indirect segment | 81 | explicit HLE_DrawArraysIndirect(Engines::Maxwell3D& maxwell3d_, bool extended_ = false) |
| 77 | const u32 indirect_words = 5 + padding; | 82 | : HLEMacroImpl(maxwell3d_), extended(extended_) {} |
| 78 | const u32 stride = indirect_words * sizeof(u32); | 83 | |
| 79 | const std::size_t draw_count = end_indirect - start_indirect; | 84 | void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { |
| 80 | u32 lowest_first = std::numeric_limits<u32>::max(); | 85 | auto topology = |
| 81 | u32 highest_limit = std::numeric_limits<u32>::min(); | 86 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]); |
| 82 | for (std::size_t index = 0; index < draw_count; index++) { | 87 | if (!IsTopologySafe(topology)) { |
| 83 | const std::size_t base = index * indirect_words + 5; | 88 | Fallback(parameters); |
| 84 | const u32 count = parameters[base]; | 89 | return; |
| 85 | const u32 first_index = parameters[base + 2]; | 90 | } |
| 86 | lowest_first = std::min(lowest_first, first_index); | 91 | |
| 87 | highest_limit = std::max(highest_limit, first_index + count); | 92 | auto& params = maxwell3d.draw_manager->GetIndirectParams(); |
| 93 | params.is_indexed = false; | ||
| 94 | params.include_count = false; | ||
| 95 | params.count_start_address = 0; | ||
| 96 | params.indirect_start_address = maxwell3d.getMacroAddress(1); | ||
| 97 | params.buffer_size = 4 * sizeof(u32); | ||
| 98 | params.max_draw_counts = 1; | ||
| 99 | params.stride = 0; | ||
| 100 | |||
| 101 | if (extended) { | ||
| 102 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 103 | maxwell3d.CallMethod(0x8e4, parameters[4], true); | ||
| 104 | } | ||
| 105 | |||
| 106 | maxwell3d.draw_manager->DrawArrayIndirect(topology); | ||
| 107 | |||
| 108 | if (extended) { | ||
| 109 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 110 | maxwell3d.CallMethod(0x8e4, 0, true); | ||
| 111 | } | ||
| 112 | maxwell3d.regs.vertex_buffer.first = 0; | ||
| 113 | maxwell3d.regs.vertex_buffer.count = 0; | ||
| 88 | } | 114 | } |
| 89 | 115 | ||
| 90 | const u32 base_vertex = parameters[8]; | 116 | private: |
| 91 | const u32 base_instance = parameters[9]; | 117 | void Fallback(const std::vector<u32>& parameters) { |
| 92 | maxwell3d.regs.vertex_id_base = base_vertex; | 118 | SCOPE_EXIT({ |
| 93 | maxwell3d.CallMethod(0x8e3, 0x640, true); | 119 | if (extended) { |
| 94 | maxwell3d.CallMethod(0x8e4, base_vertex, true); | 120 | maxwell3d.CallMethod(0x8e3, 0x640, true); |
| 95 | maxwell3d.CallMethod(0x8e5, base_instance, true); | 121 | maxwell3d.CallMethod(0x8e4, 0, true); |
| 96 | auto& params = maxwell3d.draw_manager->GetIndirectParams(); | 122 | } |
| 97 | params.is_indexed = true; | 123 | }); |
| 98 | params.include_count = true; | 124 | maxwell3d.RefreshParameters(); |
| 99 | params.count_start_address = maxwell3d.macro_addresses[4]; | 125 | const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); |
| 100 | params.indirect_start_address = maxwell3d.macro_addresses[5]; | ||
| 101 | params.buffer_size = stride * draw_count; | ||
| 102 | params.max_draw_counts = draw_count; | ||
| 103 | params.stride = stride; | ||
| 104 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 105 | maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, highest_limit); | ||
| 106 | } | ||
| 107 | 126 | ||
| 108 | // Multi-layer Clear | 127 | const u32 vertex_first = parameters[3]; |
| 109 | void HLE_MultiLayerClear(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | 128 | const u32 vertex_count = parameters[1]; |
| 110 | ASSERT(parameters.size() == 1); | ||
| 111 | 129 | ||
| 112 | const Engines::Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; | 130 | if (maxwell3d.GetMaxCurrentVertices() < vertex_first + vertex_count) { |
| 113 | const u32 rt_index = clear_params.RT; | 131 | ASSERT_MSG(false, "Faulty draw!"); |
| 114 | const u32 num_layers = maxwell3d.regs.rt[rt_index].depth; | 132 | return; |
| 115 | ASSERT(clear_params.layer == 0); | 133 | } |
| 116 | 134 | ||
| 117 | maxwell3d.regs.clear_surface.raw = clear_params.raw; | 135 | const u32 base_instance = parameters[4]; |
| 118 | maxwell3d.draw_manager->Clear(num_layers); | 136 | if (extended) { |
| 119 | } | 137 | maxwell3d.CallMethod(0x8e3, 0x640, true); |
| 138 | maxwell3d.CallMethod(0x8e4, base_instance, true); | ||
| 139 | } | ||
| 140 | |||
| 141 | maxwell3d.draw_manager->DrawArray( | ||
| 142 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]), | ||
| 143 | vertex_first, vertex_count, base_instance, instance_count); | ||
| 144 | } | ||
| 120 | 145 | ||
| 121 | constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{ | 146 | bool extended; |
| 122 | {0x771BB18C62444DA0, &HLE_771BB18C62444DA0}, | 147 | }; |
| 123 | {0x0D61FC9FAAC9FCAD, &HLE_DrawArraysIndirect}, | ||
| 124 | {0x0217920100488FF7, &HLE_DrawIndexedIndirect}, | ||
| 125 | {0x3F5E74B9C9A50164, &HLE_MultiDrawIndexedIndirect}, | ||
| 126 | {0xEAD26C3E2109B06B, &HLE_MultiLayerClear}, | ||
| 127 | }}; | ||
| 128 | 148 | ||
| 129 | class HLEMacroImpl final : public CachedMacro { | 149 | class HLE_DrawIndexedIndirect final : public HLEMacroImpl { |
| 130 | public: | 150 | public: |
| 131 | explicit HLEMacroImpl(Engines::Maxwell3D& maxwell3d_, HLEFunction func_) | 151 | explicit HLE_DrawIndexedIndirect(Engines::Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} |
| 132 | : maxwell3d{maxwell3d_}, func{func_} {} | ||
| 133 | 152 | ||
| 134 | void Execute(const std::vector<u32>& parameters, u32 method) override { | 153 | void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { |
| 135 | func(maxwell3d, parameters); | 154 | auto topology = |
| 155 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]); | ||
| 156 | if (!IsTopologySafe(topology)) { | ||
| 157 | Fallback(parameters); | ||
| 158 | return; | ||
| 159 | } | ||
| 160 | |||
| 161 | advanceCheck(); | ||
| 162 | if (check_limit) { | ||
| 163 | maxwell3d.RefreshParameters(); | ||
| 164 | minimum_limit = std::max(parameters[3], minimum_limit); | ||
| 165 | } | ||
| 166 | |||
| 167 | const u32 base_vertex = parameters[8]; | ||
| 168 | const u32 base_instance = parameters[9]; | ||
| 169 | maxwell3d.regs.vertex_id_base = base_vertex; | ||
| 170 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 171 | maxwell3d.CallMethod(0x8e4, base_vertex, true); | ||
| 172 | maxwell3d.CallMethod(0x8e5, base_instance, true); | ||
| 173 | auto& params = maxwell3d.draw_manager->GetIndirectParams(); | ||
| 174 | params.is_indexed = true; | ||
| 175 | params.include_count = false; | ||
| 176 | params.count_start_address = 0; | ||
| 177 | params.indirect_start_address = maxwell3d.getMacroAddress(1); | ||
| 178 | params.buffer_size = 5 * sizeof(u32); | ||
| 179 | params.max_draw_counts = 1; | ||
| 180 | params.stride = 0; | ||
| 181 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 182 | maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, minimum_limit); | ||
| 183 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 184 | maxwell3d.CallMethod(0x8e4, 0x0, true); | ||
| 185 | maxwell3d.CallMethod(0x8e5, 0x0, true); | ||
| 136 | } | 186 | } |
| 137 | 187 | ||
| 138 | private: | 188 | private: |
| 139 | Engines::Maxwell3D& maxwell3d; | 189 | void Fallback(const std::vector<u32>& parameters) { |
| 140 | HLEFunction func; | 190 | maxwell3d.RefreshParameters(); |
| 191 | const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); | ||
| 192 | const u32 element_base = parameters[4]; | ||
| 193 | const u32 base_instance = parameters[5]; | ||
| 194 | maxwell3d.regs.vertex_id_base = element_base; | ||
| 195 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 196 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 197 | maxwell3d.CallMethod(0x8e4, element_base, true); | ||
| 198 | maxwell3d.CallMethod(0x8e5, base_instance, true); | ||
| 199 | |||
| 200 | maxwell3d.draw_manager->DrawIndex( | ||
| 201 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]), | ||
| 202 | parameters[3], parameters[1], element_base, base_instance, instance_count); | ||
| 203 | |||
| 204 | maxwell3d.regs.vertex_id_base = 0x0; | ||
| 205 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 206 | maxwell3d.CallMethod(0x8e4, 0x0, true); | ||
| 207 | maxwell3d.CallMethod(0x8e5, 0x0, true); | ||
| 208 | } | ||
| 209 | |||
| 210 | u32 minimum_limit{1 << 18}; | ||
| 211 | }; | ||
| 212 | |||
| 213 | class HLE_MultiLayerClear final : public HLEMacroImpl { | ||
| 214 | public: | ||
| 215 | explicit HLE_MultiLayerClear(Engines::Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} | ||
| 216 | |||
| 217 | void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { | ||
| 218 | maxwell3d.RefreshParameters(); | ||
| 219 | ASSERT(parameters.size() == 1); | ||
| 220 | |||
| 221 | const Engines::Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; | ||
| 222 | const u32 rt_index = clear_params.RT; | ||
| 223 | const u32 num_layers = maxwell3d.regs.rt[rt_index].depth; | ||
| 224 | ASSERT(clear_params.layer == 0); | ||
| 225 | |||
| 226 | maxwell3d.regs.clear_surface.raw = clear_params.raw; | ||
| 227 | maxwell3d.draw_manager->Clear(num_layers); | ||
| 228 | } | ||
| 229 | }; | ||
| 230 | |||
| 231 | class HLE_MultiDrawIndexedIndirectCount final : public HLEMacroImpl { | ||
| 232 | public: | ||
| 233 | explicit HLE_MultiDrawIndexedIndirectCount(Engines::Maxwell3D& maxwell3d_) | ||
| 234 | : HLEMacroImpl(maxwell3d_) {} | ||
| 235 | |||
| 236 | void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { | ||
| 237 | const auto topology = | ||
| 238 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]); | ||
| 239 | if (!IsTopologySafe(topology)) { | ||
| 240 | Fallback(parameters); | ||
| 241 | return; | ||
| 242 | } | ||
| 243 | |||
| 244 | advanceCheck(); | ||
| 245 | if (check_limit) { | ||
| 246 | maxwell3d.RefreshParameters(); | ||
| 247 | } | ||
| 248 | const u32 start_indirect = parameters[0]; | ||
| 249 | const u32 end_indirect = parameters[1]; | ||
| 250 | if (start_indirect >= end_indirect) { | ||
| 251 | // Nothing to do. | ||
| 252 | return; | ||
| 253 | } | ||
| 254 | |||
| 255 | maxwell3d.regs.draw.topology.Assign(topology); | ||
| 256 | const u32 padding = parameters[3]; // padding is in words | ||
| 257 | |||
| 258 | // size of each indirect segment | ||
| 259 | const u32 indirect_words = 5 + padding; | ||
| 260 | const u32 stride = indirect_words * sizeof(u32); | ||
| 261 | const std::size_t draw_count = end_indirect - start_indirect; | ||
| 262 | u32 lowest_first = std::numeric_limits<u32>::max(); | ||
| 263 | u32 highest_limit = std::numeric_limits<u32>::min(); | ||
| 264 | for (std::size_t index = 0; index < draw_count; index++) { | ||
| 265 | const std::size_t base = index * indirect_words + 5; | ||
| 266 | const u32 count = parameters[base]; | ||
| 267 | const u32 first_index = parameters[base + 2]; | ||
| 268 | lowest_first = std::min(lowest_first, first_index); | ||
| 269 | highest_limit = std::max(highest_limit, first_index + count); | ||
| 270 | } | ||
| 271 | if (check_limit) { | ||
| 272 | minimum_limit = std::max(highest_limit, minimum_limit); | ||
| 273 | } | ||
| 274 | |||
| 275 | maxwell3d.regs.index_buffer.first = 0; | ||
| 276 | maxwell3d.regs.index_buffer.count = std::max(highest_limit, minimum_limit); | ||
| 277 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 278 | auto& params = maxwell3d.draw_manager->GetIndirectParams(); | ||
| 279 | params.is_indexed = true; | ||
| 280 | params.include_count = true; | ||
| 281 | params.count_start_address = maxwell3d.getMacroAddress(4); | ||
| 282 | params.indirect_start_address = maxwell3d.getMacroAddress(5); | ||
| 283 | params.buffer_size = stride * draw_count; | ||
| 284 | params.max_draw_counts = draw_count; | ||
| 285 | params.stride = stride; | ||
| 286 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 287 | maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, highest_limit); | ||
| 288 | } | ||
| 289 | |||
| 290 | private: | ||
| 291 | void Fallback(const std::vector<u32>& parameters) { | ||
| 292 | SCOPE_EXIT({ | ||
| 293 | // Clean everything. | ||
| 294 | // Clean everything. | ||
| 295 | maxwell3d.regs.vertex_id_base = 0x0; | ||
| 296 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 297 | maxwell3d.CallMethod(0x8e4, 0x0, true); | ||
| 298 | maxwell3d.CallMethod(0x8e5, 0x0, true); | ||
| 299 | }); | ||
| 300 | maxwell3d.RefreshParameters(); | ||
| 301 | const u32 start_indirect = parameters[0]; | ||
| 302 | const u32 end_indirect = parameters[1]; | ||
| 303 | if (start_indirect >= end_indirect) { | ||
| 304 | // Nothing to do. | ||
| 305 | return; | ||
| 306 | } | ||
| 307 | const auto topology = | ||
| 308 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]); | ||
| 309 | maxwell3d.regs.draw.topology.Assign(topology); | ||
| 310 | const u32 padding = parameters[3]; | ||
| 311 | const std::size_t max_draws = parameters[4]; | ||
| 312 | |||
| 313 | const u32 indirect_words = 5 + padding; | ||
| 314 | const std::size_t first_draw = start_indirect; | ||
| 315 | const std::size_t effective_draws = end_indirect - start_indirect; | ||
| 316 | const std::size_t last_draw = start_indirect + std::min(effective_draws, max_draws); | ||
| 317 | |||
| 318 | for (std::size_t index = first_draw; index < last_draw; index++) { | ||
| 319 | const std::size_t base = index * indirect_words + 5; | ||
| 320 | const u32 base_vertex = parameters[base + 3]; | ||
| 321 | const u32 base_instance = parameters[base + 4]; | ||
| 322 | maxwell3d.regs.vertex_id_base = base_vertex; | ||
| 323 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 324 | maxwell3d.CallMethod(0x8e4, base_vertex, true); | ||
| 325 | maxwell3d.CallMethod(0x8e5, base_instance, true); | ||
| 326 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 327 | maxwell3d.draw_manager->DrawIndex(topology, parameters[base + 2], parameters[base], | ||
| 328 | base_vertex, base_instance, parameters[base + 1]); | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | u32 minimum_limit{1 << 12}; | ||
| 141 | }; | 333 | }; |
| 142 | 334 | ||
| 143 | } // Anonymous namespace | 335 | } // Anonymous namespace |
| 144 | 336 | ||
| 145 | HLEMacro::HLEMacro(Engines::Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} {} | 337 | HLEMacro::HLEMacro(Engines::Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} { |
| 338 | builders.emplace(0x771BB18C62444DA0ULL, | ||
| 339 | std::function<std::unique_ptr<CachedMacro>(Engines::Maxwell3D&)>( | ||
| 340 | [](Engines::Maxwell3D& maxwell3d) -> std::unique_ptr<CachedMacro> { | ||
| 341 | return std::make_unique<HLE_771BB18C62444DA0>(maxwell3d); | ||
| 342 | })); | ||
| 343 | builders.emplace(0x0D61FC9FAAC9FCADULL, | ||
| 344 | std::function<std::unique_ptr<CachedMacro>(Engines::Maxwell3D&)>( | ||
| 345 | [](Engines::Maxwell3D& maxwell3d) -> std::unique_ptr<CachedMacro> { | ||
| 346 | return std::make_unique<HLE_DrawArraysIndirect>(maxwell3d); | ||
| 347 | })); | ||
| 348 | builders.emplace(0x8A4D173EB99A8603ULL, | ||
| 349 | std::function<std::unique_ptr<CachedMacro>(Engines::Maxwell3D&)>( | ||
| 350 | [](Engines::Maxwell3D& maxwell3d) -> std::unique_ptr<CachedMacro> { | ||
| 351 | return std::make_unique<HLE_DrawArraysIndirect>(maxwell3d, true); | ||
| 352 | })); | ||
| 353 | builders.emplace(0x0217920100488FF7ULL, | ||
| 354 | std::function<std::unique_ptr<CachedMacro>(Engines::Maxwell3D&)>( | ||
| 355 | [](Engines::Maxwell3D& maxwell3d) -> std::unique_ptr<CachedMacro> { | ||
| 356 | return std::make_unique<HLE_DrawIndexedIndirect>(maxwell3d); | ||
| 357 | })); | ||
| 358 | builders.emplace(0x3F5E74B9C9A50164ULL, | ||
| 359 | std::function<std::unique_ptr<CachedMacro>(Engines::Maxwell3D&)>( | ||
| 360 | [](Engines::Maxwell3D& maxwell3d) -> std::unique_ptr<CachedMacro> { | ||
| 361 | return std::make_unique<HLE_MultiDrawIndexedIndirectCount>(maxwell3d); | ||
| 362 | })); | ||
| 363 | builders.emplace(0xEAD26C3E2109B06BULL, | ||
| 364 | std::function<std::unique_ptr<CachedMacro>(Engines::Maxwell3D&)>( | ||
| 365 | [](Engines::Maxwell3D& maxwell3d) -> std::unique_ptr<CachedMacro> { | ||
| 366 | return std::make_unique<HLE_MultiLayerClear>(maxwell3d); | ||
| 367 | })); | ||
| 368 | } | ||
| 369 | |||
| 146 | HLEMacro::~HLEMacro() = default; | 370 | HLEMacro::~HLEMacro() = default; |
| 147 | 371 | ||
| 148 | std::unique_ptr<CachedMacro> HLEMacro::GetHLEProgram(u64 hash) const { | 372 | std::unique_ptr<CachedMacro> HLEMacro::GetHLEProgram(u64 hash) const { |
| 149 | const auto it = std::find_if(hle_funcs.cbegin(), hle_funcs.cend(), | 373 | const auto it = builders.find(hash); |
| 150 | [hash](const auto& pair) { return pair.first == hash; }); | 374 | if (it == builders.end()) { |
| 151 | if (it == hle_funcs.end()) { | ||
| 152 | return nullptr; | 375 | return nullptr; |
| 153 | } | 376 | } |
| 154 | return std::make_unique<HLEMacroImpl>(maxwell3d, it->second); | 377 | return it->second(maxwell3d); |
| 155 | } | 378 | } |
| 156 | 379 | ||
| 157 | } // namespace Tegra | 380 | } // namespace Tegra |
diff --git a/src/video_core/macro/macro_hle.h b/src/video_core/macro/macro_hle.h index 625332c9d..33f92fab1 100644 --- a/src/video_core/macro/macro_hle.h +++ b/src/video_core/macro/macro_hle.h | |||
| @@ -3,7 +3,10 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <functional> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 8 | #include <unordered_map> | ||
| 9 | |||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | 11 | ||
| 9 | namespace Tegra { | 12 | namespace Tegra { |
| @@ -23,6 +26,8 @@ public: | |||
| 23 | 26 | ||
| 24 | private: | 27 | private: |
| 25 | Engines::Maxwell3D& maxwell3d; | 28 | Engines::Maxwell3D& maxwell3d; |
| 29 | std::unordered_map<u64, std::function<std::unique_ptr<CachedMacro>(Engines::Maxwell3D&)>> | ||
| 30 | builders; | ||
| 26 | }; | 31 | }; |
| 27 | 32 | ||
| 28 | } // namespace Tegra | 33 | } // namespace Tegra |