summaryrefslogtreecommitdiff
path: root/src/video_core/engines
diff options
context:
space:
mode:
authorGravatar liamwhite2022-10-25 09:42:59 -0400
committerGravatar GitHub2022-10-25 09:42:59 -0400
commitfa913a702f94818fcddf4ffd3aaded41a41b3a3b (patch)
treea4a994e1c91ce2fa862b681daee252e16a28159d /src/video_core/engines
parentMerge pull request #9119 from liamwhite/shutdown-barrier (diff)
parentvideo_core: Implement maxwell inline_index method (diff)
downloadyuzu-fa913a702f94818fcddf4ffd3aaded41a41b3a3b.tar.gz
yuzu-fa913a702f94818fcddf4ffd3aaded41a41b3a3b.tar.xz
yuzu-fa913a702f94818fcddf4ffd3aaded41a41b3a3b.zip
Merge pull request #9112 from vonchenplus/deferred_draw
video_core: Reimplementing the maxwell drawing trigger mechanism
Diffstat (limited to 'src/video_core/engines')
-rw-r--r--src/video_core/engines/maxwell_3d.cpp285
-rw-r--r--src/video_core/engines/maxwell_3d.h46
2 files changed, 143 insertions, 188 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index b1a22b76c..5208bea75 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -117,10 +117,18 @@ 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;
129 draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true;
130 draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true;
131 draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true;
124} 132}
125 133
126void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { 134void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
@@ -208,25 +216,6 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
208 return ProcessCBBind(3); 216 return ProcessCBBind(3);
209 case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): 217 case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config):
210 return ProcessCBBind(4); 218 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): 219 case MAXWELL3D_REG_INDEX(topology_override):
231 use_topology_override = true; 220 use_topology_override = true;
232 return; 221 return;
@@ -261,14 +250,13 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters)
261 250
262 // Execute the current macro. 251 // Execute the current macro.
263 macro_engine->Execute(macro_positions[entry], parameters); 252 macro_engine->Execute(macro_positions[entry], parameters);
264 if (mme_draw.current_mode != MMEDrawMode::Undefined) { 253
265 FlushMMEInlineDraw(); 254 ProcessDeferredDraw();
266 }
267} 255}
268 256
269void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { 257void 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 258 // It is an error to write to a register other than the current macro's ARG register before
271 // has finished execution. 259 // it has finished execution.
272 if (executing_macro != 0) { 260 if (executing_macro != 0) {
273 ASSERT(method == executing_macro + 1); 261 ASSERT(method == executing_macro + 1);
274 } 262 }
@@ -283,9 +271,33 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
283 ASSERT_MSG(method < Regs::NUM_REGS, 271 ASSERT_MSG(method < Regs::NUM_REGS,
284 "Invalid Maxwell3D register, increase the size of the Regs structure"); 272 "Invalid Maxwell3D register, increase the size of the Regs structure");
285 273
286 const u32 argument = ProcessShadowRam(method, method_argument); 274 if (draw_command[method]) {
287 ProcessDirtyRegisters(method, argument); 275 regs.reg_array[method] = method_argument;
288 ProcessMethodCall(method, argument, method_argument, is_last_call); 276 deferred_draw_method.push_back(method);
277 auto u32_to_u8 = [&](const u32 argument) {
278 inline_index_draw_indexes.push_back(static_cast<u8>(argument & 0x000000ff));
279 inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0x0000ff00) >> 8));
280 inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0x00ff0000) >> 16));
281 inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0xff000000) >> 24));
282 };
283 if (MAXWELL3D_REG_INDEX(draw_inline_index) == method) {
284 u32_to_u8(method_argument);
285 } else if (MAXWELL3D_REG_INDEX(inline_index_2x16.even) == method) {
286 u32_to_u8(regs.inline_index_2x16.even);
287 u32_to_u8(regs.inline_index_2x16.odd);
288 } else if (MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == method) {
289 u32_to_u8(regs.inline_index_4x8.index0);
290 u32_to_u8(regs.inline_index_4x8.index1);
291 u32_to_u8(regs.inline_index_4x8.index2);
292 u32_to_u8(regs.inline_index_4x8.index3);
293 }
294 } else {
295 ProcessDeferredDraw();
296
297 const u32 argument = ProcessShadowRam(method, method_argument);
298 ProcessDirtyRegisters(method, argument);
299 ProcessMethodCall(method, argument, method_argument, is_last_call);
300 }
289} 301}
290 302
291void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, 303void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
@@ -326,55 +338,6 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
326 } 338 }
327} 339}
328 340
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() { 341void Maxwell3D::ProcessTopologyOverride() {
379 using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology; 342 using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology;
380 using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride; 343 using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride;
@@ -404,41 +367,6 @@ void Maxwell3D::ProcessTopologyOverride() {
404 } 367 }
405} 368}
406 369
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) { 370void Maxwell3D::ProcessMacroUpload(u32 data) {
443 macro_engine->AddCode(regs.load_mme.instruction_ptr++, data); 371 macro_engine->AddCode(regs.load_mme.instruction_ptr++, data);
444} 372}
@@ -573,42 +501,6 @@ void Maxwell3D::ProcessSyncPoint() {
573 rasterizer->SignalSyncPoint(sync_point); 501 rasterizer->SignalSyncPoint(sync_point);
574} 502}
575 503
576void Maxwell3D::DrawArrays() {
577 LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(),
578 regs.vertex_buffer.count);
579 ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?");
580
581 // Both instance configuration registers can not be set at the same time.
582 ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First ||
583 regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged,
584 "Illegal combination of instancing parameters");
585
586 ProcessTopologyOverride();
587
588 if (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) {
589 // Increment the current instance *before* drawing.
590 state.current_instance++;
591 } else if (regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged) {
592 // Reset the current instance to 0.
593 state.current_instance = 0;
594 }
595
596 const bool is_indexed{regs.index_buffer.count && !regs.vertex_buffer.count};
597 if (ShouldExecute()) {
598 rasterizer->Draw(is_indexed, false);
599 }
600
601 // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
602 // the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
603 // it's possible that it is incorrect and that there is some other register used to specify the
604 // drawing mode.
605 if (is_indexed) {
606 regs.index_buffer.count = 0;
607 } else {
608 regs.vertex_buffer.count = 0;
609 }
610}
611
612std::optional<u64> Maxwell3D::GetQueryResult() { 504std::optional<u64> Maxwell3D::GetQueryResult() {
613 switch (regs.report_semaphore.query.report) { 505 switch (regs.report_semaphore.query.report) {
614 case Regs::ReportSemaphore::Report::Payload: 506 case Regs::ReportSemaphore::Report::Payload:
@@ -691,4 +583,95 @@ void Maxwell3D::ProcessClearBuffers() {
691 rasterizer->Clear(); 583 rasterizer->Clear();
692} 584}
693 585
586void Maxwell3D::ProcessDeferredDraw() {
587 if (deferred_draw_method.empty()) {
588 return;
589 }
590
591 enum class DrawMode {
592 Undefined,
593 General,
594 Instance,
595 };
596 DrawMode draw_mode{DrawMode::Undefined};
597 u32 instance_count = 1;
598
599 auto first_method = deferred_draw_method[0];
600 if (MAXWELL3D_REG_INDEX(draw.begin) == first_method) {
601 // The minimum number of methods for drawing must be greater than or equal to
602 // 3[draw.begin->vertex(index)count->draw.end] to avoid errors in index mode drawing
603 if (deferred_draw_method.size() < 3) {
604 return;
605 }
606 draw_mode = (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) ||
607 (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged)
608 ? DrawMode::Instance
609 : DrawMode::General;
610 } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method ||
611 MAXWELL3D_REG_INDEX(index_buffer16_first) == first_method ||
612 MAXWELL3D_REG_INDEX(index_buffer8_first) == first_method) {
613 draw_mode = DrawMode::General;
614 }
615
616 // Drawing will only begin with draw.begin or index_buffer method, other methods directly
617 // clear
618 if (draw_mode == DrawMode::Undefined) {
619 deferred_draw_method.clear();
620 return;
621 }
622
623 if (draw_mode == DrawMode::Instance) {
624 ASSERT_MSG(deferred_draw_method.size() % 4 == 0, "Instance mode method size error");
625 instance_count = static_cast<u32>(deferred_draw_method.size()) / 4;
626 } else {
627 if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) {
628 regs.index_buffer.count = regs.index_buffer32_first.count;
629 regs.index_buffer.first = regs.index_buffer32_first.first;
630 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
631 } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) {
632 regs.index_buffer.count = regs.index_buffer16_first.count;
633 regs.index_buffer.first = regs.index_buffer16_first.first;
634 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
635 } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) {
636 regs.index_buffer.count = regs.index_buffer8_first.count;
637 regs.index_buffer.first = regs.index_buffer8_first.first;
638 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
639 } else {
640 auto second_method = deferred_draw_method[1];
641 if (MAXWELL3D_REG_INDEX(draw_inline_index) == second_method ||
642 MAXWELL3D_REG_INDEX(inline_index_2x16.even) == second_method ||
643 MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == second_method) {
644 regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4);
645 regs.index_buffer.format = Regs::IndexFormat::UnsignedInt;
646 }
647 }
648 }
649
650 LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(),
651 regs.vertex_buffer.count);
652
653 ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?");
654
655 // Both instance configuration registers can not be set at the same time.
656 ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First ||
657 regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged,
658 "Illegal combination of instancing parameters");
659
660 ProcessTopologyOverride();
661
662 const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count;
663 if (ShouldExecute()) {
664 rasterizer->Draw(is_indexed, instance_count);
665 }
666
667 if (is_indexed) {
668 regs.index_buffer.count = 0;
669 } else {
670 regs.vertex_buffer.count = 0;
671 }
672
673 deferred_draw_method.clear();
674 inline_index_draw_indexes.clear();
675}
676
694} // namespace Tegra::Engines 677} // namespace Tegra::Engines
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 75e3b868d..bd23ebc12 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -1739,14 +1739,11 @@ public:
1739 Footprint_1x1_Virtual = 2, 1739 Footprint_1x1_Virtual = 2,
1740 }; 1740 };
1741 1741
1742 struct InlineIndex4x8Align { 1742 struct InlineIndex4x8 {
1743 union { 1743 union {
1744 BitField<0, 30, u32> count; 1744 BitField<0, 30, u32> count;
1745 BitField<30, 2, u32> start; 1745 BitField<30, 2, u32> start;
1746 }; 1746 };
1747 };
1748
1749 struct InlineIndex4x8Index {
1750 union { 1747 union {
1751 BitField<0, 8, u32> index0; 1748 BitField<0, 8, u32> index0;
1752 BitField<8, 8, u32> index1; 1749 BitField<8, 8, u32> index1;
@@ -2836,8 +2833,7 @@ public:
2836 u32 depth_write_enabled; ///< 0x12E8 2833 u32 depth_write_enabled; ///< 0x12E8
2837 u32 alpha_test_enabled; ///< 0x12EC 2834 u32 alpha_test_enabled; ///< 0x12EC
2838 INSERT_PADDING_BYTES_NOINIT(0x10); 2835 INSERT_PADDING_BYTES_NOINIT(0x10);
2839 InlineIndex4x8Align inline_index_4x8_align; ///< 0x1300 2836 InlineIndex4x8 inline_index_4x8; ///< 0x1300
2840 InlineIndex4x8Index inline_index_4x8_index; ///< 0x1304
2841 D3DCullMode d3d_cull_mode; ///< 0x1308 2837 D3DCullMode d3d_cull_mode; ///< 0x1308
2842 ComparisonOp depth_test_func; ///< 0x130C 2838 ComparisonOp depth_test_func; ///< 0x130C
2843 f32 alpha_test_ref; ///< 0x1310 2839 f32 alpha_test_ref; ///< 0x1310
@@ -3048,8 +3044,6 @@ public:
3048 }; 3044 };
3049 3045
3050 std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages; 3046 std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages;
3051
3052 u32 current_instance = 0; ///< Current instance to be used to simulate instanced rendering.
3053 }; 3047 };
3054 3048
3055 State state{}; 3049 State state{};
@@ -3064,11 +3058,6 @@ public:
3064 void CallMultiMethod(u32 method, const u32* base_start, u32 amount, 3058 void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
3065 u32 methods_pending) override; 3059 u32 methods_pending) override;
3066 3060
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 { 3061 bool ShouldExecute() const {
3073 return execute_on; 3062 return execute_on;
3074 } 3063 }
@@ -3081,21 +3070,6 @@ public:
3081 return *rasterizer; 3070 return *rasterizer;
3082 } 3071 }
3083 3072
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 { 3073 struct DirtyState {
3100 using Flags = std::bitset<std::numeric_limits<u8>::max()>; 3074 using Flags = std::bitset<std::numeric_limits<u8>::max()>;
3101 using Table = std::array<u8, Regs::NUM_REGS>; 3075 using Table = std::array<u8, Regs::NUM_REGS>;
@@ -3105,6 +3079,8 @@ public:
3105 Tables tables{}; 3079 Tables tables{};
3106 } dirty; 3080 } dirty;
3107 3081
3082 std::vector<u8> inline_index_draw_indexes;
3083
3108private: 3084private:
3109 void InitializeRegisterDefaults(); 3085 void InitializeRegisterDefaults();
3110 3086
@@ -3164,14 +3140,10 @@ private:
3164 /// Handles a write to the CB_BIND register. 3140 /// Handles a write to the CB_BIND register.
3165 void ProcessCBBind(size_t stage_index); 3141 void ProcessCBBind(size_t stage_index);
3166 3142
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) 3143 /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro)
3171 void ProcessTopologyOverride(); 3144 void ProcessTopologyOverride();
3172 3145
3173 // Handles a instance drawcall from MME 3146 void ProcessDeferredDraw();
3174 void StepInstance(MMEDrawMode expected_mode, u32 count);
3175 3147
3176 /// Returns a query's value or an empty object if the value will be deferred through a cache. 3148 /// Returns a query's value or an empty object if the value will be deferred through a cache.
3177 std::optional<u64> GetQueryResult(); 3149 std::optional<u64> GetQueryResult();
@@ -3184,8 +3156,6 @@ private:
3184 /// Start offsets of each macro in macro_memory 3156 /// Start offsets of each macro in macro_memory
3185 std::array<u32, 0x80> macro_positions{}; 3157 std::array<u32, 0x80> macro_positions{};
3186 3158
3187 std::array<bool, Regs::NUM_REGS> mme_inline{};
3188
3189 /// Macro method that is currently being executed / being fed parameters. 3159 /// Macro method that is currently being executed / being fed parameters.
3190 u32 executing_macro = 0; 3160 u32 executing_macro = 0;
3191 /// Parameters that have been submitted to the macro call so far. 3161 /// Parameters that have been submitted to the macro call so far.
@@ -3198,6 +3168,9 @@ private:
3198 3168
3199 bool execute_on{true}; 3169 bool execute_on{true};
3200 bool use_topology_override{false}; 3170 bool use_topology_override{false};
3171
3172 std::array<bool, Regs::NUM_REGS> draw_command{};
3173 std::vector<u32> deferred_draw_method;
3201}; 3174};
3202 3175
3203#define ASSERT_REG_POSITION(field_name, position) \ 3176#define ASSERT_REG_POSITION(field_name, position) \
@@ -3402,8 +3375,7 @@ ASSERT_REG_POSITION(alpha_to_coverage_dither, 0x12E0);
3402ASSERT_REG_POSITION(blend_per_target_enabled, 0x12E4); 3375ASSERT_REG_POSITION(blend_per_target_enabled, 0x12E4);
3403ASSERT_REG_POSITION(depth_write_enabled, 0x12E8); 3376ASSERT_REG_POSITION(depth_write_enabled, 0x12E8);
3404ASSERT_REG_POSITION(alpha_test_enabled, 0x12EC); 3377ASSERT_REG_POSITION(alpha_test_enabled, 0x12EC);
3405ASSERT_REG_POSITION(inline_index_4x8_align, 0x1300); 3378ASSERT_REG_POSITION(inline_index_4x8, 0x1300);
3406ASSERT_REG_POSITION(inline_index_4x8_index, 0x1304);
3407ASSERT_REG_POSITION(d3d_cull_mode, 0x1308); 3379ASSERT_REG_POSITION(d3d_cull_mode, 0x1308);
3408ASSERT_REG_POSITION(depth_test_func, 0x130C); 3380ASSERT_REG_POSITION(depth_test_func, 0x130C);
3409ASSERT_REG_POSITION(alpha_test_ref, 0x1310); 3381ASSERT_REG_POSITION(alpha_test_ref, 0x1310);