summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/engines/maxwell_3d.cpp285
-rw-r--r--src/video_core/engines/maxwell_3d.h46
-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.cpp17
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp26
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h4
10 files changed, 203 insertions, 232 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);
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..1590b21de 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(); });
@@ -222,14 +222,15 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
222 pipeline->SetEngine(maxwell3d, gpu_memory); 222 pipeline->SetEngine(maxwell3d, gpu_memory);
223 pipeline->Configure(is_indexed); 223 pipeline->Configure(is_indexed);
224 224
225 BindInlineIndexBuffer();
226
225 SyncState(); 227 SyncState();
226 228
227 const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology); 229 const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology);
228 BeginTransformFeedback(pipeline, primitive_mode); 230 BeginTransformFeedback(pipeline, primitive_mode);
229 231
230 const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index); 232 const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index);
231 const GLsizei num_instances = 233 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) { 234 if (is_indexed) {
234 const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.global_base_vertex_index); 235 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); 236 const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_buffer.count);
@@ -1129,6 +1130,16 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) {
1129 query_cache.EraseChannel(channel_id); 1130 query_cache.EraseChannel(channel_id);
1130} 1131}
1131 1132
1133void RasterizerOpenGL::BindInlineIndexBuffer() {
1134 if (maxwell3d->inline_index_draw_indexes.empty()) {
1135 return;
1136 }
1137 const auto data_count = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size());
1138 auto buffer = Buffer(buffer_cache_runtime, *this, 0, data_count);
1139 buffer.ImmediateUpload(0, maxwell3d->inline_index_draw_indexes);
1140 buffer_cache_runtime.BindIndexBuffer(buffer, 0, data_count);
1141}
1142
1132AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {} 1143AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {}
1133 1144
1134bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) { 1145bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 45131b785..793e0d608 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;
@@ -199,6 +199,8 @@ private:
199 /// End a transform feedback 199 /// End a transform feedback
200 void EndTransformFeedback(); 200 void EndTransformFeedback();
201 201
202 void BindInlineIndexBuffer();
203
202 Tegra::GPU& gpu; 204 Tegra::GPU& gpu;
203 205
204 const Device& device; 206 const Device& device;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 47dfb45a1..9f05a7a18 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(); });
@@ -194,13 +193,15 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
194 pipeline->SetEngine(maxwell3d, gpu_memory); 193 pipeline->SetEngine(maxwell3d, gpu_memory);
195 pipeline->Configure(is_indexed); 194 pipeline->Configure(is_indexed);
196 195
196 BindInlineIndexBuffer();
197
197 BeginTransformFeedback(); 198 BeginTransformFeedback();
198 199
199 UpdateDynamicStates(); 200 UpdateDynamicStates();
200 201
201 const auto& regs{maxwell3d->regs}; 202 const auto& regs{maxwell3d->regs};
202 const u32 num_instances{maxwell3d->mme_draw.instance_count}; 203 const u32 num_instances{instance_count};
203 const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_instanced, is_indexed)}; 204 const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_indexed)};
204 scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { 205 scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
205 if (draw_params.is_indexed) { 206 if (draw_params.is_indexed) {
206 cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, 207 cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
@@ -1009,4 +1010,17 @@ void RasterizerVulkan::ReleaseChannel(s32 channel_id) {
1009 query_cache.EraseChannel(channel_id); 1010 query_cache.EraseChannel(channel_id);
1010} 1011}
1011 1012
1013void RasterizerVulkan::BindInlineIndexBuffer() {
1014 if (maxwell3d->inline_index_draw_indexes.empty()) {
1015 return;
1016 }
1017 const auto data_count = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size());
1018 auto buffer = buffer_cache_runtime.UploadStagingBuffer(data_count);
1019 std::memcpy(buffer.mapped_span.data(), maxwell3d->inline_index_draw_indexes.data(), data_count);
1020 buffer_cache_runtime.BindIndexBuffer(
1021 maxwell3d->regs.draw.topology, maxwell3d->regs.index_buffer.format,
1022 maxwell3d->regs.index_buffer.first, maxwell3d->regs.index_buffer.count, buffer.buffer,
1023 static_cast<u32>(buffer.offset), data_count);
1024}
1025
1012} // namespace Vulkan 1026} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 4cde3c983..e2fdc7611 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;
@@ -141,6 +141,8 @@ private:
141 141
142 void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); 142 void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs);
143 143
144 void BindInlineIndexBuffer();
145
144 Tegra::GPU& gpu; 146 Tegra::GPU& gpu;
145 147
146 ScreenInfo& screen_info; 148 ScreenInfo& screen_info;