summaryrefslogtreecommitdiff
path: root/src/video_core/macro
diff options
context:
space:
mode:
authorGravatar liamwhite2023-01-04 21:20:00 -0500
committerGravatar GitHub2023-01-04 21:20:00 -0500
commitb78328f19a54964ef6874281d1a4d6b6ad1c34d9 (patch)
tree239947ad53a4a06c3641d58c5d6b8daf5b3dc16a /src/video_core/macro
parentMerge pull request #9518 from gidoly/revert-9504-pg2 (diff)
parentyuzu-ui: Add setting for disabling macro HLE (diff)
downloadyuzu-b78328f19a54964ef6874281d1a4d6b6ad1c34d9.tar.gz
yuzu-b78328f19a54964ef6874281d1a4d6b6ad1c34d9.tar.xz
yuzu-b78328f19a54964ef6874281d1a4d6b6ad1c34d9.zip
Merge pull request #9501 from FernandoS27/yfc-rel-2
Yuzu Fried Chicken Part 1.5: MacroHLE Rework and Dynamic State
Diffstat (limited to 'src/video_core/macro')
-rw-r--r--src/video_core/macro/macro.cpp19
-rw-r--r--src/video_core/macro/macro.h1
-rw-r--r--src/video_core/macro/macro_hle.cpp648
-rw-r--r--src/video_core/macro/macro_hle.h5
4 files changed, 569 insertions, 104 deletions
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp
index 505d81c1e..82ad0477d 100644
--- a/src/video_core/macro/macro.cpp
+++ b/src/video_core/macro/macro.cpp
@@ -12,7 +12,9 @@
12#include "common/assert.h" 12#include "common/assert.h"
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/microprofile.h"
15#include "common/settings.h" 16#include "common/settings.h"
17#include "video_core/engines/maxwell_3d.h"
16#include "video_core/macro/macro.h" 18#include "video_core/macro/macro.h"
17#include "video_core/macro/macro_hle.h" 19#include "video_core/macro/macro_hle.h"
18#include "video_core/macro/macro_interpreter.h" 20#include "video_core/macro/macro_interpreter.h"
@@ -21,6 +23,8 @@
21#include "video_core/macro/macro_jit_x64.h" 23#include "video_core/macro/macro_jit_x64.h"
22#endif 24#endif
23 25
26MICROPROFILE_DEFINE(MacroHLE, "GPU", "Execute macro HLE", MP_RGB(128, 192, 192));
27
24namespace Tegra { 28namespace Tegra {
25 29
26static void Dump(u64 hash, std::span<const u32> code) { 30static void Dump(u64 hash, std::span<const u32> code) {
@@ -40,8 +44,8 @@ static void Dump(u64 hash, std::span<const u32> code) {
40 macro_file.write(reinterpret_cast<const char*>(code.data()), code.size_bytes()); 44 macro_file.write(reinterpret_cast<const char*>(code.data()), code.size_bytes());
41} 45}
42 46
43MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d) 47MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d_)
44 : hle_macros{std::make_unique<Tegra::HLEMacro>(maxwell3d)} {} 48 : hle_macros{std::make_unique<Tegra::HLEMacro>(maxwell3d_)}, maxwell3d{maxwell3d_} {}
45 49
46MacroEngine::~MacroEngine() = default; 50MacroEngine::~MacroEngine() = default;
47 51
@@ -59,8 +63,10 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
59 if (compiled_macro != macro_cache.end()) { 63 if (compiled_macro != macro_cache.end()) {
60 const auto& cache_info = compiled_macro->second; 64 const auto& cache_info = compiled_macro->second;
61 if (cache_info.has_hle_program) { 65 if (cache_info.has_hle_program) {
66 MICROPROFILE_SCOPE(MacroHLE);
62 cache_info.hle_program->Execute(parameters, method); 67 cache_info.hle_program->Execute(parameters, method);
63 } else { 68 } else {
69 maxwell3d.RefreshParameters();
64 cache_info.lle_program->Execute(parameters, method); 70 cache_info.lle_program->Execute(parameters, method);
65 } 71 }
66 } else { 72 } else {
@@ -101,12 +107,15 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
101 } 107 }
102 } 108 }
103 109
104 if (auto hle_program = hle_macros->GetHLEProgram(cache_info.hash)) { 110 auto hle_program = hle_macros->GetHLEProgram(cache_info.hash);
111 if (!hle_program || Settings::values.disable_macro_hle) {
112 maxwell3d.RefreshParameters();
113 cache_info.lle_program->Execute(parameters, method);
114 } else {
105 cache_info.has_hle_program = true; 115 cache_info.has_hle_program = true;
106 cache_info.hle_program = std::move(hle_program); 116 cache_info.hle_program = std::move(hle_program);
117 MICROPROFILE_SCOPE(MacroHLE);
107 cache_info.hle_program->Execute(parameters, method); 118 cache_info.hle_program->Execute(parameters, method);
108 } else {
109 cache_info.lle_program->Execute(parameters, method);
110 } 119 }
111 } 120 }
112} 121}
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
142std::unique_ptr<MacroEngine> GetMacroEngine(Engines::Maxwell3D& maxwell3d); 143std::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 8549db2e4..a5476e795 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -1,143 +1,593 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
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"
9#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
10#include "video_core/macro/macro.h" 11#include "video_core/macro/macro.h"
11#include "video_core/macro/macro_hle.h" 12#include "video_core/macro/macro_hle.h"
13#include "video_core/memory_manager.h"
12#include "video_core/rasterizer_interface.h" 14#include "video_core/rasterizer_interface.h"
13 15
14namespace Tegra { 16namespace Tegra {
15namespace {
16 17
17using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters); 18using Maxwell3D = Engines::Maxwell3D;
18 19
19// HLE'd functions 20namespace {
20void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
21 const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B);
22 maxwell3d.draw_manager->DrawIndex(
23 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff),
24 parameters[4], parameters[1], parameters[3], parameters[5], instance_count);
25}
26 21
27void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { 22bool IsTopologySafe(Maxwell3D::Regs::PrimitiveTopology topology) {
28 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); 23 switch (topology) {
29 maxwell3d.draw_manager->DrawArray( 24 case Maxwell3D::Regs::PrimitiveTopology::Points:
30 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]), 25 case Maxwell3D::Regs::PrimitiveTopology::Lines:
31 parameters[3], parameters[1], parameters[4], instance_count); 26 case Maxwell3D::Regs::PrimitiveTopology::LineLoop:
27 case Maxwell3D::Regs::PrimitiveTopology::LineStrip:
28 case Maxwell3D::Regs::PrimitiveTopology::Triangles:
29 case Maxwell3D::Regs::PrimitiveTopology::TriangleStrip:
30 case Maxwell3D::Regs::PrimitiveTopology::TriangleFan:
31 case Maxwell3D::Regs::PrimitiveTopology::LinesAdjacency:
32 case Maxwell3D::Regs::PrimitiveTopology::LineStripAdjacency:
33 case Maxwell3D::Regs::PrimitiveTopology::TrianglesAdjacency:
34 case Maxwell3D::Regs::PrimitiveTopology::TriangleStripAdjacency:
35 case Maxwell3D::Regs::PrimitiveTopology::Patches:
36 return true;
37 case Maxwell3D::Regs::PrimitiveTopology::Quads:
38 case Maxwell3D::Regs::PrimitiveTopology::QuadStrip:
39 case Maxwell3D::Regs::PrimitiveTopology::Polygon:
40 default:
41 return false;
42 }
32} 43}
33 44
34void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { 45class HLEMacroImpl : public CachedMacro {
35 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); 46public:
36 const u32 element_base = parameters[4]; 47 explicit HLEMacroImpl(Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} {}
37 const u32 base_instance = parameters[5];
38 maxwell3d.regs.vertex_id_base = element_base;
39 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
40 maxwell3d.CallMethod(0x8e3, 0x640, true);
41 maxwell3d.CallMethod(0x8e4, element_base, true);
42 maxwell3d.CallMethod(0x8e5, base_instance, true);
43
44 maxwell3d.draw_manager->DrawIndex(
45 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]),
46 parameters[3], parameters[1], element_base, base_instance, instance_count);
47
48 maxwell3d.regs.vertex_id_base = 0x0;
49 maxwell3d.CallMethod(0x8e3, 0x640, true);
50 maxwell3d.CallMethod(0x8e4, 0x0, true);
51 maxwell3d.CallMethod(0x8e5, 0x0, true);
52}
53 48
54// Multidraw Indirect 49protected:
55void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { 50 Maxwell3D& maxwell3d;
56 SCOPE_EXIT({ 51};
57 // Clean everything. 52
58 maxwell3d.regs.vertex_id_base = 0x0; 53class HLE_DrawArrays final : public HLEMacroImpl {
59 maxwell3d.CallMethod(0x8e3, 0x640, true); 54public:
60 maxwell3d.CallMethod(0x8e4, 0x0, true); 55 explicit HLE_DrawArrays(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
61 maxwell3d.CallMethod(0x8e5, 0x0, true); 56
57 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
58 maxwell3d.RefreshParameters();
59
60 auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
61 maxwell3d.draw_manager->DrawArray(topology, parameters[1], parameters[2],
62 maxwell3d.regs.global_base_instance_index, 1);
63 }
64};
65
66class HLE_DrawIndexed final : public HLEMacroImpl {
67public:
68 explicit HLE_DrawIndexed(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
69
70 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
71 maxwell3d.RefreshParameters();
72 maxwell3d.regs.index_buffer.start_addr_high = parameters[1];
73 maxwell3d.regs.index_buffer.start_addr_low = parameters[2];
74 maxwell3d.regs.index_buffer.format =
75 static_cast<Engines::Maxwell3D::Regs::IndexFormat>(parameters[3]);
62 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; 76 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
63 }); 77
64 const u32 start_indirect = parameters[0]; 78 auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
65 const u32 end_indirect = parameters[1]; 79 maxwell3d.draw_manager->DrawIndex(topology, 0, parameters[4],
66 if (start_indirect >= end_indirect) { 80 maxwell3d.regs.global_base_vertex_index,
67 // Nothing to do. 81 maxwell3d.regs.global_base_instance_index, 1);
68 return; 82 }
69 } 83};
70 const u32 padding = parameters[3]; 84
71 const std::size_t max_draws = parameters[4]; 85/*
72 86 * @note: these macros have two versions, a normal and extended version, with the extended version
73 const u32 indirect_words = 5 + padding; 87 * also assigning the base vertex/instance.
74 const std::size_t first_draw = start_indirect; 88 */
75 const std::size_t effective_draws = end_indirect - start_indirect; 89template <bool extended>
76 const std::size_t last_draw = start_indirect + std::min(effective_draws, max_draws); 90class HLE_DrawArraysIndirect final : public HLEMacroImpl {
77 91public:
78 for (std::size_t index = first_draw; index < last_draw; index++) { 92 explicit HLE_DrawArraysIndirect(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
79 const std::size_t base = index * indirect_words + 5; 93
80 const u32 base_vertex = parameters[base + 3]; 94 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
81 const u32 base_instance = parameters[base + 4]; 95 auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
82 maxwell3d.regs.vertex_id_base = base_vertex; 96 if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
83 maxwell3d.CallMethod(0x8e3, 0x640, true); 97 Fallback(parameters);
84 maxwell3d.CallMethod(0x8e4, base_vertex, true); 98 return;
85 maxwell3d.CallMethod(0x8e5, base_instance, true); 99 }
100
101 auto& params = maxwell3d.draw_manager->GetIndirectParams();
102 params.is_indexed = false;
103 params.include_count = false;
104 params.count_start_address = 0;
105 params.indirect_start_address = maxwell3d.GetMacroAddress(1);
106 params.buffer_size = 4 * sizeof(u32);
107 params.max_draw_counts = 1;
108 params.stride = 0;
109
110 if constexpr (extended) {
111 maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro;
112 maxwell3d.SetHLEReplacementAttributeType(
113 0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseInstance);
114 }
115
116 maxwell3d.draw_manager->DrawArrayIndirect(topology);
117
118 if constexpr (extended) {
119 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
120 maxwell3d.replace_table.clear();
121 }
122 }
123
124private:
125 void Fallback(const std::vector<u32>& parameters) {
126 SCOPE_EXIT({
127 if (extended) {
128 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
129 maxwell3d.replace_table.clear();
130 }
131 });
132 maxwell3d.RefreshParameters();
133 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
134
135 auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
136 const u32 vertex_first = parameters[3];
137 const u32 vertex_count = parameters[1];
138
139 if (!IsTopologySafe(topology) &&
140 static_cast<size_t>(maxwell3d.GetMaxCurrentVertices()) <
141 static_cast<size_t>(vertex_first) + static_cast<size_t>(vertex_count)) {
142 ASSERT_MSG(false, "Faulty draw!");
143 return;
144 }
145
146 const u32 base_instance = parameters[4];
147 if constexpr (extended) {
148 maxwell3d.regs.global_base_instance_index = base_instance;
149 maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro;
150 maxwell3d.SetHLEReplacementAttributeType(
151 0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseInstance);
152 }
153
154 maxwell3d.draw_manager->DrawArray(topology, vertex_first, vertex_count, base_instance,
155 instance_count);
156
157 if constexpr (extended) {
158 maxwell3d.regs.global_base_instance_index = 0;
159 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
160 maxwell3d.replace_table.clear();
161 }
162 }
163};
164
165/*
166 * @note: these macros have two versions, a normal and extended version, with the extended version
167 * also assigning the base vertex/instance.
168 */
169template <bool extended>
170class HLE_DrawIndexedIndirect final : public HLEMacroImpl {
171public:
172 explicit HLE_DrawIndexedIndirect(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
173
174 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
175 auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
176 if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
177 Fallback(parameters);
178 return;
179 }
180
181 const u32 estimate = static_cast<u32>(maxwell3d.EstimateIndexBufferSize());
182 const u32 element_base = parameters[4];
183 const u32 base_instance = parameters[5];
184 maxwell3d.regs.vertex_id_base = element_base;
185 maxwell3d.regs.global_base_vertex_index = element_base;
186 maxwell3d.regs.global_base_instance_index = base_instance;
187 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
188 if constexpr (extended) {
189 maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro;
190 maxwell3d.SetHLEReplacementAttributeType(
191 0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex);
192 maxwell3d.SetHLEReplacementAttributeType(
193 0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance);
194 }
195 auto& params = maxwell3d.draw_manager->GetIndirectParams();
196 params.is_indexed = true;
197 params.include_count = false;
198 params.count_start_address = 0;
199 params.indirect_start_address = maxwell3d.GetMacroAddress(1);
200 params.buffer_size = 5 * sizeof(u32);
201 params.max_draw_counts = 1;
202 params.stride = 0;
86 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; 203 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
204 maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, estimate);
205 maxwell3d.regs.vertex_id_base = 0x0;
206 maxwell3d.regs.global_base_vertex_index = 0x0;
207 maxwell3d.regs.global_base_instance_index = 0x0;
208 if constexpr (extended) {
209 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
210 maxwell3d.replace_table.clear();
211 }
212 }
213
214private:
215 void Fallback(const std::vector<u32>& parameters) {
216 maxwell3d.RefreshParameters();
217 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
218 const u32 element_base = parameters[4];
219 const u32 base_instance = parameters[5];
220 maxwell3d.regs.vertex_id_base = element_base;
221 maxwell3d.regs.global_base_vertex_index = element_base;
222 maxwell3d.regs.global_base_instance_index = base_instance;
223 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
224 if constexpr (extended) {
225 maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro;
226 maxwell3d.SetHLEReplacementAttributeType(
227 0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex);
228 maxwell3d.SetHLEReplacementAttributeType(
229 0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance);
230 }
231
87 maxwell3d.draw_manager->DrawIndex( 232 maxwell3d.draw_manager->DrawIndex(
88 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]), 233 static_cast<Tegra::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]), parameters[3],
89 parameters[base + 2], parameters[base], base_vertex, base_instance, 234 parameters[1], element_base, base_instance, instance_count);
90 parameters[base + 1]); 235
236 maxwell3d.regs.vertex_id_base = 0x0;
237 maxwell3d.regs.global_base_vertex_index = 0x0;
238 maxwell3d.regs.global_base_instance_index = 0x0;
239 if constexpr (extended) {
240 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
241 maxwell3d.replace_table.clear();
242 }
91 } 243 }
92} 244};
93 245
94// Multi-layer Clear 246class HLE_MultiLayerClear final : public HLEMacroImpl {
95void HLE_EAD26C3E2109B06B(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { 247public:
96 ASSERT(parameters.size() == 1); 248 explicit HLE_MultiLayerClear(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
97 249
98 const Engines::Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; 250 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
99 const u32 rt_index = clear_params.RT; 251 maxwell3d.RefreshParameters();
100 const u32 num_layers = maxwell3d.regs.rt[rt_index].depth; 252 ASSERT(parameters.size() == 1);
101 ASSERT(clear_params.layer == 0);
102 253
103 maxwell3d.regs.clear_surface.raw = clear_params.raw; 254 const Maxwell3D::Regs::ClearSurface clear_params{parameters[0]};
104 maxwell3d.draw_manager->Clear(num_layers); 255 const u32 rt_index = clear_params.RT;
105} 256 const u32 num_layers = maxwell3d.regs.rt[rt_index].depth;
257 ASSERT(clear_params.layer == 0);
106 258
107constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{ 259 maxwell3d.regs.clear_surface.raw = clear_params.raw;
108 {0x771BB18C62444DA0, &HLE_771BB18C62444DA0}, 260 maxwell3d.draw_manager->Clear(num_layers);
109 {0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD}, 261 }
110 {0x0217920100488FF7, &HLE_0217920100488FF7}, 262};
111 {0x3F5E74B9C9A50164, &HLE_3F5E74B9C9A50164}, 263
112 {0xEAD26C3E2109B06B, &HLE_EAD26C3E2109B06B}, 264class HLE_MultiDrawIndexedIndirectCount final : public HLEMacroImpl {
113}}; 265public:
266 explicit HLE_MultiDrawIndexedIndirectCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
267
268 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
269 const auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[2]);
270 if (!IsTopologySafe(topology)) {
271 Fallback(parameters);
272 return;
273 }
274
275 const u32 start_indirect = parameters[0];
276 const u32 end_indirect = parameters[1];
277 if (start_indirect >= end_indirect) {
278 // Nothing to do.
279 return;
280 }
281
282 const u32 padding = parameters[3]; // padding is in words
283
284 // size of each indirect segment
285 const u32 indirect_words = 5 + padding;
286 const u32 stride = indirect_words * sizeof(u32);
287 const std::size_t draw_count = end_indirect - start_indirect;
288 const u32 estimate = static_cast<u32>(maxwell3d.EstimateIndexBufferSize());
289 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
290 auto& params = maxwell3d.draw_manager->GetIndirectParams();
291 params.is_indexed = true;
292 params.include_count = true;
293 params.count_start_address = maxwell3d.GetMacroAddress(4);
294 params.indirect_start_address = maxwell3d.GetMacroAddress(5);
295 params.buffer_size = stride * draw_count;
296 params.max_draw_counts = draw_count;
297 params.stride = stride;
298 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
299 maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro;
300 maxwell3d.SetHLEReplacementAttributeType(
301 0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex);
302 maxwell3d.SetHLEReplacementAttributeType(
303 0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance);
304 maxwell3d.SetHLEReplacementAttributeType(0, 0x648,
305 Maxwell3D::HLEReplacementAttributeType::DrawID);
306 maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, estimate);
307 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
308 maxwell3d.replace_table.clear();
309 }
310
311private:
312 void Fallback(const std::vector<u32>& parameters) {
313 SCOPE_EXIT({
314 // Clean everything.
315 maxwell3d.regs.vertex_id_base = 0x0;
316 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
317 maxwell3d.replace_table.clear();
318 });
319 maxwell3d.RefreshParameters();
320 const u32 start_indirect = parameters[0];
321 const u32 end_indirect = parameters[1];
322 if (start_indirect >= end_indirect) {
323 // Nothing to do.
324 return;
325 }
326 const auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[2]);
327 const u32 padding = parameters[3];
328 const std::size_t max_draws = parameters[4];
329
330 const u32 indirect_words = 5 + padding;
331 const std::size_t first_draw = start_indirect;
332 const std::size_t effective_draws = end_indirect - start_indirect;
333 const std::size_t last_draw = start_indirect + std::min(effective_draws, max_draws);
334
335 for (std::size_t index = first_draw; index < last_draw; index++) {
336 const std::size_t base = index * indirect_words + 5;
337 const u32 base_vertex = parameters[base + 3];
338 const u32 base_instance = parameters[base + 4];
339 maxwell3d.regs.vertex_id_base = base_vertex;
340 maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro;
341 maxwell3d.SetHLEReplacementAttributeType(
342 0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex);
343 maxwell3d.SetHLEReplacementAttributeType(
344 0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance);
345 maxwell3d.CallMethod(0x8e3, 0x648, true);
346 maxwell3d.CallMethod(0x8e4, static_cast<u32>(index), true);
347 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
348 maxwell3d.draw_manager->DrawIndex(topology, parameters[base + 2], parameters[base],
349 base_vertex, base_instance, parameters[base + 1]);
350 }
351 }
352};
353
354class HLE_C713C83D8F63CCF3 final : public HLEMacroImpl {
355public:
356 explicit HLE_C713C83D8F63CCF3(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
357
358 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
359 maxwell3d.RefreshParameters();
360 const u32 offset = (parameters[0] & 0x3FFFFFFF) << 2;
361 const u32 address = maxwell3d.regs.shadow_scratch[24];
362 auto& const_buffer = maxwell3d.regs.const_buffer;
363 const_buffer.size = 0x7000;
364 const_buffer.address_high = (address >> 24) & 0xFF;
365 const_buffer.address_low = address << 8;
366 const_buffer.offset = offset;
367 }
368};
369
370class HLE_D7333D26E0A93EDE final : public HLEMacroImpl {
371public:
372 explicit HLE_D7333D26E0A93EDE(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
373
374 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
375 maxwell3d.RefreshParameters();
376 const size_t index = parameters[0];
377 const u32 address = maxwell3d.regs.shadow_scratch[42 + index];
378 const u32 size = maxwell3d.regs.shadow_scratch[47 + index];
379 auto& const_buffer = maxwell3d.regs.const_buffer;
380 const_buffer.size = size;
381 const_buffer.address_high = (address >> 24) & 0xFF;
382 const_buffer.address_low = address << 8;
383 }
384};
385
386class HLE_BindShader final : public HLEMacroImpl {
387public:
388 explicit HLE_BindShader(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
389
390 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
391 maxwell3d.RefreshParameters();
392 auto& regs = maxwell3d.regs;
393 const u32 index = parameters[0];
394 if ((parameters[1] - regs.shadow_scratch[28 + index]) == 0) {
395 return;
396 }
397
398 regs.pipelines[index & 0xF].offset = parameters[2];
399 maxwell3d.dirty.flags[VideoCommon::Dirty::Shaders] = true;
400 regs.shadow_scratch[28 + index] = parameters[1];
401 regs.shadow_scratch[34 + index] = parameters[2];
402
403 const u32 address = parameters[4];
404 auto& const_buffer = regs.const_buffer;
405 const_buffer.size = 0x10000;
406 const_buffer.address_high = (address >> 24) & 0xFF;
407 const_buffer.address_low = address << 8;
408
409 const size_t bind_group_id = parameters[3] & 0x7F;
410 auto& bind_group = regs.bind_groups[bind_group_id];
411 bind_group.raw_config = 0x11;
412 maxwell3d.ProcessCBBind(bind_group_id);
413 }
414};
114 415
115class HLEMacroImpl final : public CachedMacro { 416class HLE_SetRasterBoundingBox final : public HLEMacroImpl {
116public: 417public:
117 explicit HLEMacroImpl(Engines::Maxwell3D& maxwell3d_, HLEFunction func_) 418 explicit HLE_SetRasterBoundingBox(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
118 : maxwell3d{maxwell3d_}, func{func_} {}
119 419
120 void Execute(const std::vector<u32>& parameters, u32 method) override { 420 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
121 func(maxwell3d, parameters); 421 maxwell3d.RefreshParameters();
422 const u32 raster_mode = parameters[0];
423 auto& regs = maxwell3d.regs;
424 const u32 raster_enabled = maxwell3d.regs.conservative_raster_enable;
425 const u32 scratch_data = maxwell3d.regs.shadow_scratch[52];
426 regs.raster_bounding_box.raw = raster_mode & 0xFFFFF00F;
427 regs.raster_bounding_box.pad.Assign(scratch_data & raster_enabled);
428 }
429};
430
431template <size_t base_size>
432class HLE_ClearConstBuffer final : public HLEMacroImpl {
433public:
434 explicit HLE_ClearConstBuffer(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
435
436 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
437 maxwell3d.RefreshParameters();
438 static constexpr std::array<u32, base_size> zeroes{};
439 auto& regs = maxwell3d.regs;
440 regs.const_buffer.size = static_cast<u32>(base_size);
441 regs.const_buffer.address_high = parameters[0];
442 regs.const_buffer.address_low = parameters[1];
443 regs.const_buffer.offset = 0;
444 maxwell3d.ProcessCBMultiData(zeroes.data(), parameters[2] * 4);
445 }
446};
447
448class HLE_ClearMemory final : public HLEMacroImpl {
449public:
450 explicit HLE_ClearMemory(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
451
452 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
453 maxwell3d.RefreshParameters();
454
455 const u32 needed_memory = parameters[2] / sizeof(u32);
456 if (needed_memory > zero_memory.size()) {
457 zero_memory.resize(needed_memory, 0);
458 }
459 auto& regs = maxwell3d.regs;
460 regs.upload.line_length_in = parameters[2];
461 regs.upload.line_count = 1;
462 regs.upload.dest.address_high = parameters[0];
463 regs.upload.dest.address_low = parameters[1];
464 maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
465 maxwell3d.CallMultiMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)),
466 zero_memory.data(), needed_memory, needed_memory);
122 } 467 }
123 468
124private: 469private:
125 Engines::Maxwell3D& maxwell3d; 470 std::vector<u32> zero_memory;
126 HLEFunction func; 471};
472
473class HLE_TransformFeedbackSetup final : public HLEMacroImpl {
474public:
475 explicit HLE_TransformFeedbackSetup(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
476
477 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
478 maxwell3d.RefreshParameters();
479
480 auto& regs = maxwell3d.regs;
481 regs.transform_feedback_enabled = 1;
482 regs.transform_feedback.buffers[0].start_offset = 0;
483 regs.transform_feedback.buffers[1].start_offset = 0;
484 regs.transform_feedback.buffers[2].start_offset = 0;
485 regs.transform_feedback.buffers[3].start_offset = 0;
486
487 regs.upload.line_length_in = 4;
488 regs.upload.line_count = 1;
489 regs.upload.dest.address_high = parameters[0];
490 regs.upload.dest.address_low = parameters[1];
491 maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
492 maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)),
493 regs.transform_feedback.controls[0].stride, true);
494 }
127}; 495};
128 496
129} // Anonymous namespace 497} // Anonymous namespace
130 498
131HLEMacro::HLEMacro(Engines::Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} {} 499HLEMacro::HLEMacro(Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} {
500 builders.emplace(0xDD6A7FA92A7D2674ULL,
501 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
502 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
503 return std::make_unique<HLE_DrawArrays>(maxwell3d__);
504 }));
505 builders.emplace(0x0D61FC9FAAC9FCADULL,
506 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
507 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
508 return std::make_unique<HLE_DrawArraysIndirect<false>>(maxwell3d__);
509 }));
510 builders.emplace(0x8A4D173EB99A8603ULL,
511 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
512 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
513 return std::make_unique<HLE_DrawArraysIndirect<true>>(maxwell3d__);
514 }));
515 builders.emplace(0x2DB33AADB741839CULL,
516 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
517 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
518 return std::make_unique<HLE_DrawIndexed>(maxwell3d__);
519 }));
520 builders.emplace(0x771BB18C62444DA0ULL,
521 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
522 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
523 return std::make_unique<HLE_DrawIndexedIndirect<false>>(maxwell3d__);
524 }));
525 builders.emplace(0x0217920100488FF7ULL,
526 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
527 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
528 return std::make_unique<HLE_DrawIndexedIndirect<true>>(maxwell3d__);
529 }));
530 builders.emplace(0x3F5E74B9C9A50164ULL,
531 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
532 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
533 return std::make_unique<HLE_MultiDrawIndexedIndirectCount>(
534 maxwell3d__);
535 }));
536 builders.emplace(0xEAD26C3E2109B06BULL,
537 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
538 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
539 return std::make_unique<HLE_MultiLayerClear>(maxwell3d__);
540 }));
541 builders.emplace(0xC713C83D8F63CCF3ULL,
542 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
543 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
544 return std::make_unique<HLE_C713C83D8F63CCF3>(maxwell3d__);
545 }));
546 builders.emplace(0xD7333D26E0A93EDEULL,
547 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
548 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
549 return std::make_unique<HLE_D7333D26E0A93EDE>(maxwell3d__);
550 }));
551 builders.emplace(0xEB29B2A09AA06D38ULL,
552 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
553 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
554 return std::make_unique<HLE_BindShader>(maxwell3d__);
555 }));
556 builders.emplace(0xDB1341DBEB4C8AF7ULL,
557 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
558 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
559 return std::make_unique<HLE_SetRasterBoundingBox>(maxwell3d__);
560 }));
561 builders.emplace(0x6C97861D891EDf7EULL,
562 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
563 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
564 return std::make_unique<HLE_ClearConstBuffer<0x5F00>>(maxwell3d__);
565 }));
566 builders.emplace(0xD246FDDF3A6173D7ULL,
567 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
568 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
569 return std::make_unique<HLE_ClearConstBuffer<0x7000>>(maxwell3d__);
570 }));
571 builders.emplace(0xEE4D0004BEC8ECF4ULL,
572 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
573 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
574 return std::make_unique<HLE_ClearMemory>(maxwell3d__);
575 }));
576 builders.emplace(0xFC0CF27F5FFAA661ULL,
577 std::function<std::unique_ptr<CachedMacro>(Maxwell3D&)>(
578 [](Maxwell3D& maxwell3d__) -> std::unique_ptr<CachedMacro> {
579 return std::make_unique<HLE_TransformFeedbackSetup>(maxwell3d__);
580 }));
581}
582
132HLEMacro::~HLEMacro() = default; 583HLEMacro::~HLEMacro() = default;
133 584
134std::unique_ptr<CachedMacro> HLEMacro::GetHLEProgram(u64 hash) const { 585std::unique_ptr<CachedMacro> HLEMacro::GetHLEProgram(u64 hash) const {
135 const auto it = std::find_if(hle_funcs.cbegin(), hle_funcs.cend(), 586 const auto it = builders.find(hash);
136 [hash](const auto& pair) { return pair.first == hash; }); 587 if (it == builders.end()) {
137 if (it == hle_funcs.end()) {
138 return nullptr; 588 return nullptr;
139 } 589 }
140 return std::make_unique<HLEMacroImpl>(maxwell3d, it->second); 590 return it->second(maxwell3d);
141} 591}
142 592
143} // namespace Tegra 593} // 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
9namespace Tegra { 12namespace Tegra {
@@ -23,6 +26,8 @@ public:
23 26
24private: 27private:
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