summaryrefslogtreecommitdiff
path: root/src/video_core/engines
diff options
context:
space:
mode:
authorGravatar FengChen2022-10-21 15:38:50 +0800
committerGravatar FengChen2022-10-21 17:09:22 +0800
commit1f54cd4ac78dd1af48490dcc404bec4adf2876f3 (patch)
tree92b3ef5859262f2141e90344cd9179ed8895ec23 /src/video_core/engines
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
Diffstat (limited to 'src/video_core/engines')
-rw-r--r--src/video_core/engines/maxwell_3d.cpp257
-rw-r--r--src/video_core/engines/maxwell_3d.h33
2 files changed, 110 insertions, 180 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) \