summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar FengChen2022-10-21 15:38:50 +0800
committerGravatar FengChen2022-10-21 17:09:22 +0800
commit1f54cd4ac78dd1af48490dcc404bec4adf2876f3 (patch)
tree92b3ef5859262f2141e90344cd9179ed8895ec23
parentMerge pull request #9088 from Fdawgs/chore/images (diff)
downloadyuzu-1f54cd4ac78dd1af48490dcc404bec4adf2876f3.tar.gz
yuzu-1f54cd4ac78dd1af48490dcc404bec4adf2876f3.tar.xz
yuzu-1f54cd4ac78dd1af48490dcc404bec4adf2876f3.zip
video_coare: Reimplementing the maxwell drawing trigger mechanism
-rw-r--r--src/video_core/engines/maxwell_3d.cpp257
-rw-r--r--src/video_core/engines/maxwell_3d.h33
-rw-r--r--src/video_core/macro/macro_hle.cpp47
-rw-r--r--src/video_core/macro/macro_interpreter.cpp2
-rw-r--r--src/video_core/macro/macro_jit_x64.cpp2
-rw-r--r--src/video_core/rasterizer_interface.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h2
10 files changed, 139 insertions, 224 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 89a9d1f5a..b41aa6fc1 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -117,10 +117,15 @@ void Maxwell3D::InitializeRegisterDefaults() {
117 117
118 shadow_state = regs; 118 shadow_state = regs;
119 119
120 mme_inline[MAXWELL3D_REG_INDEX(draw.end)] = true; 120 draw_command[MAXWELL3D_REG_INDEX(draw.end)] = true;
121 mme_inline[MAXWELL3D_REG_INDEX(draw.begin)] = true; 121 draw_command[MAXWELL3D_REG_INDEX(draw.begin)] = true;
122 mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; 122 draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.first)] = true;
123 mme_inline[MAXWELL3D_REG_INDEX(index_buffer.count)] = true; 123 draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true;
124 draw_command[MAXWELL3D_REG_INDEX(index_buffer.first)] = true;
125 draw_command[MAXWELL3D_REG_INDEX(index_buffer.count)] = true;
126 draw_command[MAXWELL3D_REG_INDEX(index_buffer32_first)] = true;
127 draw_command[MAXWELL3D_REG_INDEX(index_buffer16_first)] = true;
128 draw_command[MAXWELL3D_REG_INDEX(index_buffer8_first)] = true;
124} 129}
125 130
126void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { 131void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
@@ -208,25 +213,6 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
208 return ProcessCBBind(3); 213 return ProcessCBBind(3);
209 case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): 214 case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config):
210 return ProcessCBBind(4); 215 return ProcessCBBind(4);
211 case MAXWELL3D_REG_INDEX(draw.end):
212 return DrawArrays();
213 case MAXWELL3D_REG_INDEX(index_buffer32_first):
214 regs.index_buffer.count = regs.index_buffer32_first.count;
215 regs.index_buffer.first = regs.index_buffer32_first.first;
216 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
217 return DrawArrays();
218 case MAXWELL3D_REG_INDEX(index_buffer16_first):
219 regs.index_buffer.count = regs.index_buffer16_first.count;
220 regs.index_buffer.first = regs.index_buffer16_first.first;
221 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
222 return DrawArrays();
223 case MAXWELL3D_REG_INDEX(index_buffer8_first):
224 regs.index_buffer.count = regs.index_buffer8_first.count;
225 regs.index_buffer.first = regs.index_buffer8_first.first;
226 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
227 // a macro calls this one over and over, should it increase instancing?
228 // Used by Hades and likely other Vulkan games.
229 return DrawArrays();
230 case MAXWELL3D_REG_INDEX(topology_override): 216 case MAXWELL3D_REG_INDEX(topology_override):
231 use_topology_override = true; 217 use_topology_override = true;
232 return; 218 return;
@@ -261,14 +247,13 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters)
261 247
262 // Execute the current macro. 248 // Execute the current macro.
263 macro_engine->Execute(macro_positions[entry], parameters); 249 macro_engine->Execute(macro_positions[entry], parameters);
264 if (mme_draw.current_mode != MMEDrawMode::Undefined) { 250
265 FlushMMEInlineDraw(); 251 ProcessDeferredDraw();
266 }
267} 252}
268 253
269void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { 254void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
270 // It is an error to write to a register other than the current macro's ARG register before it 255 // It is an error to write to a register other than the current macro's ARG register before
271 // has finished execution. 256 // it has finished execution.
272 if (executing_macro != 0) { 257 if (executing_macro != 0) {
273 ASSERT(method == executing_macro + 1); 258 ASSERT(method == executing_macro + 1);
274 } 259 }
@@ -283,9 +268,16 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
283 ASSERT_MSG(method < Regs::NUM_REGS, 268 ASSERT_MSG(method < Regs::NUM_REGS,
284 "Invalid Maxwell3D register, increase the size of the Regs structure"); 269 "Invalid Maxwell3D register, increase the size of the Regs structure");
285 270
286 const u32 argument = ProcessShadowRam(method, method_argument); 271 if (draw_command[method]) {
287 ProcessDirtyRegisters(method, argument); 272 regs.reg_array[method] = method_argument;
288 ProcessMethodCall(method, argument, method_argument, is_last_call); 273 deferred_draw_method.push_back(method);
274 } else {
275 ProcessDeferredDraw();
276
277 const u32 argument = ProcessShadowRam(method, method_argument);
278 ProcessDirtyRegisters(method, argument);
279 ProcessMethodCall(method, argument, method_argument, is_last_call);
280 }
289} 281}
290 282
291void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, 283void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
@@ -326,55 +318,6 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
326 } 318 }
327} 319}
328 320
329void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) {
330 if (mme_draw.current_mode == MMEDrawMode::Undefined) {
331 if (mme_draw.gl_begin_consume) {
332 mme_draw.current_mode = expected_mode;
333 mme_draw.current_count = count;
334 mme_draw.instance_count = 1;
335 mme_draw.gl_begin_consume = false;
336 mme_draw.gl_end_count = 0;
337 }
338 return;
339 } else {
340 if (mme_draw.current_mode == expected_mode && count == mme_draw.current_count &&
341 mme_draw.instance_mode && mme_draw.gl_begin_consume) {
342 mme_draw.instance_count++;
343 mme_draw.gl_begin_consume = false;
344 return;
345 } else {
346 FlushMMEInlineDraw();
347 }
348 }
349 // Tail call in case it needs to retry.
350 StepInstance(expected_mode, count);
351}
352
353void Maxwell3D::CallMethodFromMME(u32 method, u32 method_argument) {
354 if (mme_inline[method]) {
355 regs.reg_array[method] = method_argument;
356 if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count) ||
357 method == MAXWELL3D_REG_INDEX(index_buffer.count)) {
358 const MMEDrawMode expected_mode = method == MAXWELL3D_REG_INDEX(vertex_buffer.count)
359 ? MMEDrawMode::Array
360 : MMEDrawMode::Indexed;
361 StepInstance(expected_mode, method_argument);
362 } else if (method == MAXWELL3D_REG_INDEX(draw.begin)) {
363 mme_draw.instance_mode =
364 (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) ||
365 (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged);
366 mme_draw.gl_begin_consume = true;
367 } else {
368 mme_draw.gl_end_count++;
369 }
370 } else {
371 if (mme_draw.current_mode != MMEDrawMode::Undefined) {
372 FlushMMEInlineDraw();
373 }
374 CallMethod(method, method_argument, true);
375 }
376}
377
378void Maxwell3D::ProcessTopologyOverride() { 321void Maxwell3D::ProcessTopologyOverride() {
379 using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology; 322 using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology;
380 using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride; 323 using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride;
@@ -404,41 +347,6 @@ void Maxwell3D::ProcessTopologyOverride() {
404 } 347 }
405} 348}
406 349
407void Maxwell3D::FlushMMEInlineDraw() {
408 LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(),
409 regs.vertex_buffer.count);
410 ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?");
411 ASSERT(mme_draw.instance_count == mme_draw.gl_end_count);
412
413 // Both instance configuration registers can not be set at the same time.
414 ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First ||
415 regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged,
416 "Illegal combination of instancing parameters");
417
418 ProcessTopologyOverride();
419
420 const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed;
421 if (ShouldExecute()) {
422 rasterizer->Draw(is_indexed, true);
423 }
424
425 // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
426 // the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
427 // it's possible that it is incorrect and that there is some other register used to specify the
428 // drawing mode.
429 if (is_indexed) {
430 regs.index_buffer.count = 0;
431 } else {
432 regs.vertex_buffer.count = 0;
433 }
434 mme_draw.current_mode = MMEDrawMode::Undefined;
435 mme_draw.current_count = 0;
436 mme_draw.instance_count = 0;
437 mme_draw.instance_mode = false;
438 mme_draw.gl_begin_consume = false;
439 mme_draw.gl_end_count = 0;
440}
441
442void Maxwell3D::ProcessMacroUpload(u32 data) { 350void Maxwell3D::ProcessMacroUpload(u32 data) {
443 macro_engine->AddCode(regs.load_mme.instruction_ptr++, data); 351 macro_engine->AddCode(regs.load_mme.instruction_ptr++, data);
444} 352}
@@ -576,42 +484,6 @@ void Maxwell3D::ProcessSyncPoint() {
576 } 484 }
577} 485}
578 486
579void Maxwell3D::DrawArrays() {
580 LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(),
581 regs.vertex_buffer.count);
582 ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?");
583
584 // Both instance configuration registers can not be set at the same time.
585 ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First ||
586 regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged,
587 "Illegal combination of instancing parameters");
588
589 ProcessTopologyOverride();
590
591 if (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) {
592 // Increment the current instance *before* drawing.
593 state.current_instance++;
594 } else if (regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged) {
595 // Reset the current instance to 0.
596 state.current_instance = 0;
597 }
598
599 const bool is_indexed{regs.index_buffer.count && !regs.vertex_buffer.count};
600 if (ShouldExecute()) {
601 rasterizer->Draw(is_indexed, false);
602 }
603
604 // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
605 // the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
606 // it's possible that it is incorrect and that there is some other register used to specify the
607 // drawing mode.
608 if (is_indexed) {
609 regs.index_buffer.count = 0;
610 } else {
611 regs.vertex_buffer.count = 0;
612 }
613}
614
615std::optional<u64> Maxwell3D::GetQueryResult() { 487std::optional<u64> Maxwell3D::GetQueryResult() {
616 switch (regs.report_semaphore.query.report) { 488 switch (regs.report_semaphore.query.report) {
617 case Regs::ReportSemaphore::Report::Payload: 489 case Regs::ReportSemaphore::Report::Payload:
@@ -694,4 +566,87 @@ void Maxwell3D::ProcessClearBuffers() {
694 rasterizer->Clear(); 566 rasterizer->Clear();
695} 567}
696 568
569void Maxwell3D::ProcessDeferredDraw() {
570 auto method_count = deferred_draw_method.size();
571 if (method_count) {
572 enum class DrawMode {
573 Undefined,
574 General,
575 Instance,
576 };
577 DrawMode draw_mode{DrawMode::Undefined};
578 u32 instance_count = 1;
579
580 auto first_method = deferred_draw_method[0];
581 if (MAXWELL3D_REG_INDEX(draw.begin) == first_method) {
582 // The minimum number of methods for drawing must be greater than or equal to
583 // 3[draw.begin->vertex(index)count->draw.end] to avoid errors in index mode drawing
584 if (method_count < 3) {
585 return;
586 }
587 draw_mode =
588 (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) ||
589 (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged)
590 ? DrawMode::Instance
591 : DrawMode::General;
592 } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method ||
593 MAXWELL3D_REG_INDEX(index_buffer16_first) == first_method ||
594 MAXWELL3D_REG_INDEX(index_buffer8_first) == first_method) {
595 draw_mode = DrawMode::General;
596 }
597
598 // Drawing will only begin with draw.begin or index_buffer method, other methods directly
599 // clear
600 if (draw_mode == DrawMode::Undefined) {
601 deferred_draw_method.clear();
602 return;
603 }
604
605 if (draw_mode == DrawMode::Instance) {
606 ASSERT_MSG(deferred_draw_method.size() % 4 == 0, "Instance mode method size error");
607 instance_count = static_cast<u32>(deferred_draw_method.size()) / 4;
608 } else {
609 if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) {
610 regs.index_buffer.count = regs.index_buffer32_first.count;
611 regs.index_buffer.first = regs.index_buffer32_first.first;
612 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
613 } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) {
614 regs.index_buffer.count = regs.index_buffer16_first.count;
615 regs.index_buffer.first = regs.index_buffer16_first.first;
616 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
617 } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) {
618 regs.index_buffer.count = regs.index_buffer8_first.count;
619 regs.index_buffer.first = regs.index_buffer8_first.first;
620 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
621 }
622 }
623
624 LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(),
625 regs.vertex_buffer.count);
626
627 ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count),
628 "Both indexed and direct?");
629
630 // Both instance configuration registers can not be set at the same time.
631 ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First ||
632 regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged,
633 "Illegal combination of instancing parameters");
634
635 ProcessTopologyOverride();
636
637 const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count;
638 if (ShouldExecute()) {
639 rasterizer->Draw(is_indexed, instance_count);
640 }
641
642 if (is_indexed) {
643 regs.index_buffer.count = 0;
644 } else {
645 regs.vertex_buffer.count = 0;
646 }
647
648 deferred_draw_method.clear();
649 }
650}
651
697} // namespace Tegra::Engines 652} // namespace Tegra::Engines
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 75e3b868d..1472e8871 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -3048,8 +3048,6 @@ public:
3048 }; 3048 };
3049 3049
3050 std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages; 3050 std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages;
3051
3052 u32 current_instance = 0; ///< Current instance to be used to simulate instanced rendering.
3053 }; 3051 };
3054 3052
3055 State state{}; 3053 State state{};
@@ -3064,11 +3062,6 @@ public:
3064 void CallMultiMethod(u32 method, const u32* base_start, u32 amount, 3062 void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
3065 u32 methods_pending) override; 3063 u32 methods_pending) override;
3066 3064
3067 /// Write the value to the register identified by method.
3068 void CallMethodFromMME(u32 method, u32 method_argument);
3069
3070 void FlushMMEInlineDraw();
3071
3072 bool ShouldExecute() const { 3065 bool ShouldExecute() const {
3073 return execute_on; 3066 return execute_on;
3074 } 3067 }
@@ -3081,21 +3074,6 @@ public:
3081 return *rasterizer; 3074 return *rasterizer;
3082 } 3075 }
3083 3076
3084 enum class MMEDrawMode : u32 {
3085 Undefined,
3086 Array,
3087 Indexed,
3088 };
3089
3090 struct MMEDrawState {
3091 MMEDrawMode current_mode{MMEDrawMode::Undefined};
3092 u32 current_count{};
3093 u32 instance_count{};
3094 bool instance_mode{};
3095 bool gl_begin_consume{};
3096 u32 gl_end_count{};
3097 } mme_draw;
3098
3099 struct DirtyState { 3077 struct DirtyState {
3100 using Flags = std::bitset<std::numeric_limits<u8>::max()>; 3078 using Flags = std::bitset<std::numeric_limits<u8>::max()>;
3101 using Table = std::array<u8, Regs::NUM_REGS>; 3079 using Table = std::array<u8, Regs::NUM_REGS>;
@@ -3164,14 +3142,10 @@ private:
3164 /// Handles a write to the CB_BIND register. 3142 /// Handles a write to the CB_BIND register.
3165 void ProcessCBBind(size_t stage_index); 3143 void ProcessCBBind(size_t stage_index);
3166 3144
3167 /// Handles a write to the VERTEX_END_GL register, triggering a draw.
3168 void DrawArrays();
3169
3170 /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro) 3145 /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro)
3171 void ProcessTopologyOverride(); 3146 void ProcessTopologyOverride();
3172 3147
3173 // Handles a instance drawcall from MME 3148 void ProcessDeferredDraw();
3174 void StepInstance(MMEDrawMode expected_mode, u32 count);
3175 3149
3176 /// Returns a query's value or an empty object if the value will be deferred through a cache. 3150 /// Returns a query's value or an empty object if the value will be deferred through a cache.
3177 std::optional<u64> GetQueryResult(); 3151 std::optional<u64> GetQueryResult();
@@ -3184,8 +3158,6 @@ private:
3184 /// Start offsets of each macro in macro_memory 3158 /// Start offsets of each macro in macro_memory
3185 std::array<u32, 0x80> macro_positions{}; 3159 std::array<u32, 0x80> macro_positions{};
3186 3160
3187 std::array<bool, Regs::NUM_REGS> mme_inline{};
3188
3189 /// Macro method that is currently being executed / being fed parameters. 3161 /// Macro method that is currently being executed / being fed parameters.
3190 u32 executing_macro = 0; 3162 u32 executing_macro = 0;
3191 /// Parameters that have been submitted to the macro call so far. 3163 /// Parameters that have been submitted to the macro call so far.
@@ -3198,6 +3170,9 @@ private:
3198 3170
3199 bool execute_on{true}; 3171 bool execute_on{true};
3200 bool use_topology_override{false}; 3172 bool use_topology_override{false};
3173
3174 std::array<bool, Regs::NUM_REGS> draw_command{};
3175 std::vector<u32> deferred_draw_method;
3201}; 3176};
3202 3177
3203#define ASSERT_REG_POSITION(field_name, position) \ 3178#define ASSERT_REG_POSITION(field_name, position) \
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp
index 8a8adbb42..f896591bf 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -22,35 +22,29 @@ void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
22 maxwell3d.regs.draw.topology.Assign( 22 maxwell3d.regs.draw.topology.Assign(
23 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff)); 23 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff));
24 maxwell3d.regs.global_base_instance_index = parameters[5]; 24 maxwell3d.regs.global_base_instance_index = parameters[5];
25 maxwell3d.mme_draw.instance_count = instance_count;
26 maxwell3d.regs.global_base_vertex_index = parameters[3]; 25 maxwell3d.regs.global_base_vertex_index = parameters[3];
27 maxwell3d.regs.index_buffer.count = parameters[1]; 26 maxwell3d.regs.index_buffer.count = parameters[1];
28 maxwell3d.regs.index_buffer.first = parameters[4]; 27 maxwell3d.regs.index_buffer.first = parameters[4];
29 28
30 if (maxwell3d.ShouldExecute()) { 29 if (maxwell3d.ShouldExecute()) {
31 maxwell3d.Rasterizer().Draw(true, true); 30 maxwell3d.Rasterizer().Draw(true, instance_count);
32 } 31 }
33 maxwell3d.regs.index_buffer.count = 0; 32 maxwell3d.regs.index_buffer.count = 0;
34 maxwell3d.mme_draw.instance_count = 0;
35 maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
36} 33}
37 34
38void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { 35void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
39 const u32 count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); 36 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
40 37
41 maxwell3d.regs.vertex_buffer.first = parameters[3]; 38 maxwell3d.regs.vertex_buffer.first = parameters[3];
42 maxwell3d.regs.vertex_buffer.count = parameters[1]; 39 maxwell3d.regs.vertex_buffer.count = parameters[1];
43 maxwell3d.regs.global_base_instance_index = parameters[4]; 40 maxwell3d.regs.global_base_instance_index = parameters[4];
44 maxwell3d.regs.draw.topology.Assign( 41 maxwell3d.regs.draw.topology.Assign(
45 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); 42 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
46 maxwell3d.mme_draw.instance_count = count;
47 43
48 if (maxwell3d.ShouldExecute()) { 44 if (maxwell3d.ShouldExecute()) {
49 maxwell3d.Rasterizer().Draw(false, true); 45 maxwell3d.Rasterizer().Draw(false, instance_count);
50 } 46 }
51 maxwell3d.regs.vertex_buffer.count = 0; 47 maxwell3d.regs.vertex_buffer.count = 0;
52 maxwell3d.mme_draw.instance_count = 0;
53 maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
54} 48}
55 49
56void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { 50void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
@@ -63,24 +57,21 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
63 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; 57 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
64 maxwell3d.regs.global_base_vertex_index = element_base; 58 maxwell3d.regs.global_base_vertex_index = element_base;
65 maxwell3d.regs.global_base_instance_index = base_instance; 59 maxwell3d.regs.global_base_instance_index = base_instance;
66 maxwell3d.mme_draw.instance_count = instance_count; 60 maxwell3d.CallMethod(0x8e3, 0x640, true);
67 maxwell3d.CallMethodFromMME(0x8e3, 0x640); 61 maxwell3d.CallMethod(0x8e4, element_base, true);
68 maxwell3d.CallMethodFromMME(0x8e4, element_base); 62 maxwell3d.CallMethod(0x8e5, base_instance, true);
69 maxwell3d.CallMethodFromMME(0x8e5, base_instance);
70 maxwell3d.regs.draw.topology.Assign( 63 maxwell3d.regs.draw.topology.Assign(
71 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); 64 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
72 if (maxwell3d.ShouldExecute()) { 65 if (maxwell3d.ShouldExecute()) {
73 maxwell3d.Rasterizer().Draw(true, true); 66 maxwell3d.Rasterizer().Draw(true, instance_count);
74 } 67 }
75 maxwell3d.regs.vertex_id_base = 0x0; 68 maxwell3d.regs.vertex_id_base = 0x0;
76 maxwell3d.regs.index_buffer.count = 0; 69 maxwell3d.regs.index_buffer.count = 0;
77 maxwell3d.regs.global_base_vertex_index = 0x0; 70 maxwell3d.regs.global_base_vertex_index = 0x0;
78 maxwell3d.regs.global_base_instance_index = 0x0; 71 maxwell3d.regs.global_base_instance_index = 0x0;
79 maxwell3d.mme_draw.instance_count = 0; 72 maxwell3d.CallMethod(0x8e3, 0x640, true);
80 maxwell3d.CallMethodFromMME(0x8e3, 0x640); 73 maxwell3d.CallMethod(0x8e4, 0x0, true);
81 maxwell3d.CallMethodFromMME(0x8e4, 0x0); 74 maxwell3d.CallMethod(0x8e5, 0x0, true);
82 maxwell3d.CallMethodFromMME(0x8e5, 0x0);
83 maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
84} 75}
85 76
86// Multidraw Indirect 77// Multidraw Indirect
@@ -91,11 +82,9 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
91 maxwell3d.regs.index_buffer.count = 0; 82 maxwell3d.regs.index_buffer.count = 0;
92 maxwell3d.regs.global_base_vertex_index = 0x0; 83 maxwell3d.regs.global_base_vertex_index = 0x0;
93 maxwell3d.regs.global_base_instance_index = 0x0; 84 maxwell3d.regs.global_base_instance_index = 0x0;
94 maxwell3d.mme_draw.instance_count = 0; 85 maxwell3d.CallMethod(0x8e3, 0x640, true);
95 maxwell3d.CallMethodFromMME(0x8e3, 0x640); 86 maxwell3d.CallMethod(0x8e4, 0x0, true);
96 maxwell3d.CallMethodFromMME(0x8e4, 0x0); 87 maxwell3d.CallMethod(0x8e5, 0x0, true);
97 maxwell3d.CallMethodFromMME(0x8e5, 0x0);
98 maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
99 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; 88 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
100 }); 89 });
101 const u32 start_indirect = parameters[0]; 90 const u32 start_indirect = parameters[0];
@@ -127,15 +116,13 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
127 maxwell3d.regs.index_buffer.count = num_vertices; 116 maxwell3d.regs.index_buffer.count = num_vertices;
128 maxwell3d.regs.global_base_vertex_index = base_vertex; 117 maxwell3d.regs.global_base_vertex_index = base_vertex;
129 maxwell3d.regs.global_base_instance_index = base_instance; 118 maxwell3d.regs.global_base_instance_index = base_instance;
130 maxwell3d.mme_draw.instance_count = instance_count; 119 maxwell3d.CallMethod(0x8e3, 0x640, true);
131 maxwell3d.CallMethodFromMME(0x8e3, 0x640); 120 maxwell3d.CallMethod(0x8e4, base_vertex, true);
132 maxwell3d.CallMethodFromMME(0x8e4, base_vertex); 121 maxwell3d.CallMethod(0x8e5, base_instance, true);
133 maxwell3d.CallMethodFromMME(0x8e5, base_instance);
134 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; 122 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
135 if (maxwell3d.ShouldExecute()) { 123 if (maxwell3d.ShouldExecute()) {
136 maxwell3d.Rasterizer().Draw(true, true); 124 maxwell3d.Rasterizer().Draw(true, instance_count);
137 } 125 }
138 maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
139 } 126 }
140} 127}
141 128
diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp
index f670b1bca..c0d32c112 100644
--- a/src/video_core/macro/macro_interpreter.cpp
+++ b/src/video_core/macro/macro_interpreter.cpp
@@ -335,7 +335,7 @@ void MacroInterpreterImpl::SetMethodAddress(u32 address) {
335} 335}
336 336
337void MacroInterpreterImpl::Send(u32 value) { 337void MacroInterpreterImpl::Send(u32 value) {
338 maxwell3d.CallMethodFromMME(method_address.address, value); 338 maxwell3d.CallMethod(method_address.address, value, true);
339 // Increment the method address by the method increment. 339 // Increment the method address by the method increment.
340 method_address.address.Assign(method_address.address.Value() + 340 method_address.address.Assign(method_address.address.Value() +
341 method_address.increment.Value()); 341 method_address.increment.Value());
diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp
index a302a9603..25c1ce798 100644
--- a/src/video_core/macro/macro_jit_x64.cpp
+++ b/src/video_core/macro/macro_jit_x64.cpp
@@ -346,7 +346,7 @@ void MacroJITx64Impl::Compile_Read(Macro::Opcode opcode) {
346} 346}
347 347
348void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) { 348void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) {
349 maxwell3d->CallMethodFromMME(method_address.address, value); 349 maxwell3d->CallMethod(method_address.address, value, true);
350} 350}
351 351
352void MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) { 352void MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) {
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index d2d40884c..1cbfef090 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -40,7 +40,7 @@ public:
40 virtual ~RasterizerInterface() = default; 40 virtual ~RasterizerInterface() = default;
41 41
42 /// Dispatches a draw invocation 42 /// Dispatches a draw invocation
43 virtual void Draw(bool is_indexed, bool is_instanced) = 0; 43 virtual void Draw(bool is_indexed, u32 instance_count) = 0;
44 44
45 /// Clear the current framebuffer 45 /// Clear the current framebuffer
46 virtual void Clear() = 0; 46 virtual void Clear() = 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index e5c09a969..21bac6ebf 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -205,7 +205,7 @@ void RasterizerOpenGL::Clear() {
205 ++num_queued_commands; 205 ++num_queued_commands;
206} 206}
207 207
208void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { 208void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
209 MICROPROFILE_SCOPE(OpenGL_Drawing); 209 MICROPROFILE_SCOPE(OpenGL_Drawing);
210 210
211 SCOPE_EXIT({ gpu.TickWork(); }); 211 SCOPE_EXIT({ gpu.TickWork(); });
@@ -228,8 +228,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
228 BeginTransformFeedback(pipeline, primitive_mode); 228 BeginTransformFeedback(pipeline, primitive_mode);
229 229
230 const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index); 230 const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index);
231 const GLsizei num_instances = 231 const GLsizei num_instances = static_cast<GLsizei>(instance_count);
232 static_cast<GLsizei>(is_instanced ? maxwell3d->mme_draw.instance_count : 1);
233 if (is_indexed) { 232 if (is_indexed) {
234 const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.global_base_vertex_index); 233 const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.global_base_vertex_index);
235 const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_buffer.count); 234 const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_buffer.count);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 45131b785..c93ba3b42 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -68,7 +68,7 @@ public:
68 StateTracker& state_tracker_); 68 StateTracker& state_tracker_);
69 ~RasterizerOpenGL() override; 69 ~RasterizerOpenGL() override;
70 70
71 void Draw(bool is_indexed, bool is_instanced) override; 71 void Draw(bool is_indexed, u32 instance_count) override;
72 void Clear() override; 72 void Clear() override;
73 void DispatchCompute() override; 73 void DispatchCompute() override;
74 void ResetCounter(VideoCore::QueryType type) override; 74 void ResetCounter(VideoCore::QueryType type) override;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 47dfb45a1..9a7d90b2a 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -127,11 +127,10 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3
127 return scissor; 127 return scissor;
128} 128}
129 129
130DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_instanced, 130DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_indexed) {
131 bool is_indexed) {
132 DrawParams params{ 131 DrawParams params{
133 .base_instance = regs.global_base_instance_index, 132 .base_instance = regs.global_base_instance_index,
134 .num_instances = is_instanced ? num_instances : 1, 133 .num_instances = num_instances,
135 .base_vertex = is_indexed ? regs.global_base_vertex_index : regs.vertex_buffer.first, 134 .base_vertex = is_indexed ? regs.global_base_vertex_index : regs.vertex_buffer.first,
136 .num_vertices = is_indexed ? regs.index_buffer.count : regs.vertex_buffer.count, 135 .num_vertices = is_indexed ? regs.index_buffer.count : regs.vertex_buffer.count,
137 .first_index = is_indexed ? regs.index_buffer.first : 0, 136 .first_index = is_indexed ? regs.index_buffer.first : 0,
@@ -177,7 +176,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
177 176
178RasterizerVulkan::~RasterizerVulkan() = default; 177RasterizerVulkan::~RasterizerVulkan() = default;
179 178
180void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { 179void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
181 MICROPROFILE_SCOPE(Vulkan_Drawing); 180 MICROPROFILE_SCOPE(Vulkan_Drawing);
182 181
183 SCOPE_EXIT({ gpu.TickWork(); }); 182 SCOPE_EXIT({ gpu.TickWork(); });
@@ -199,8 +198,8 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
199 UpdateDynamicStates(); 198 UpdateDynamicStates();
200 199
201 const auto& regs{maxwell3d->regs}; 200 const auto& regs{maxwell3d->regs};
202 const u32 num_instances{maxwell3d->mme_draw.instance_count}; 201 const u32 num_instances{instance_count};
203 const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_instanced, is_indexed)}; 202 const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_indexed)};
204 scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { 203 scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
205 if (draw_params.is_indexed) { 204 if (draw_params.is_indexed) {
206 cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, 205 cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 4cde3c983..b3a182588 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -64,7 +64,7 @@ public:
64 StateTracker& state_tracker_, Scheduler& scheduler_); 64 StateTracker& state_tracker_, Scheduler& scheduler_);
65 ~RasterizerVulkan() override; 65 ~RasterizerVulkan() override;
66 66
67 void Draw(bool is_indexed, bool is_instanced) override; 67 void Draw(bool is_indexed, u32 instance_count) override;
68 void Clear() override; 68 void Clear() override;
69 void DispatchCompute() override; 69 void DispatchCompute() override;
70 void ResetCounter(VideoCore::QueryType type) override; 70 void ResetCounter(VideoCore::QueryType type) override;