summaryrefslogtreecommitdiff
path: root/src/video_core/dma_pusher.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2018-11-28 10:12:37 -0500
committerGravatar GitHub2018-11-28 10:12:37 -0500
commit6f849887c9e7fa51743809c3a4bcfd2e319dff8d (patch)
treeba26ea7fcb626dacab4b7997149ad52c21ba526c /src/video_core/dma_pusher.cpp
parentMerge pull request #1735 from FernandoS27/tex-spacing (diff)
parentdma_pushbuffer: Optimize to avoid loop and copy on Push. (diff)
downloadyuzu-6f849887c9e7fa51743809c3a4bcfd2e319dff8d.tar.gz
yuzu-6f849887c9e7fa51743809c3a4bcfd2e319dff8d.tar.xz
yuzu-6f849887c9e7fa51743809c3a4bcfd2e319dff8d.zip
Merge pull request #1792 from bunnei/dma-pusher
gpu: Rewrite GPU command list processing with DmaPusher class.
Diffstat (limited to 'src/video_core/dma_pusher.cpp')
-rw-r--r--src/video_core/dma_pusher.cpp123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
new file mode 100644
index 000000000..63a958f11
--- /dev/null
+++ b/src/video_core/dma_pusher.cpp
@@ -0,0 +1,123 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/microprofile.h"
6#include "core/core.h"
7#include "core/memory.h"
8#include "video_core/dma_pusher.h"
9#include "video_core/engines/maxwell_3d.h"
10#include "video_core/gpu.h"
11
12namespace Tegra {
13
14DmaPusher::DmaPusher(GPU& gpu) : gpu(gpu) {}
15
16DmaPusher::~DmaPusher() = default;
17
18MICROPROFILE_DEFINE(DispatchCalls, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
19
20void DmaPusher::DispatchCalls() {
21 MICROPROFILE_SCOPE(DispatchCalls);
22
23 // On entering GPU code, assume all memory may be touched by the ARM core.
24 gpu.Maxwell3D().dirty_flags.OnMemoryWrite();
25
26 dma_pushbuffer_subindex = 0;
27
28 while (Core::System::GetInstance().IsPoweredOn()) {
29 if (!Step()) {
30 break;
31 }
32 }
33}
34
35bool DmaPusher::Step() {
36 if (dma_get != dma_put) {
37 // Push buffer non-empty, read a word
38 const CommandHeader command_header{
39 Memory::Read32(*gpu.MemoryManager().GpuToCpuAddress(dma_get))};
40
41 dma_get += sizeof(u32);
42
43 if (!non_main) {
44 dma_mget = dma_get;
45 }
46
47 // now, see if we're in the middle of a command
48 if (dma_state.length_pending) {
49 // Second word of long non-inc methods command - method count
50 dma_state.length_pending = 0;
51 dma_state.method_count = command_header.method_count_;
52 } else if (dma_state.method_count) {
53 // Data word of methods command
54 CallMethod(command_header.argument);
55
56 if (!dma_state.non_incrementing) {
57 dma_state.method++;
58 }
59
60 if (dma_increment_once) {
61 dma_state.non_incrementing = true;
62 }
63
64 dma_state.method_count--;
65 } else {
66 // No command active - this is the first word of a new one
67 switch (command_header.mode) {
68 case SubmissionMode::Increasing:
69 SetState(command_header);
70 dma_state.non_incrementing = false;
71 dma_increment_once = false;
72 break;
73 case SubmissionMode::NonIncreasing:
74 SetState(command_header);
75 dma_state.non_incrementing = true;
76 dma_increment_once = false;
77 break;
78 case SubmissionMode::Inline:
79 dma_state.method = command_header.method;
80 dma_state.subchannel = command_header.subchannel;
81 CallMethod(command_header.arg_count);
82 dma_state.non_incrementing = true;
83 dma_increment_once = false;
84 break;
85 case SubmissionMode::IncreaseOnce:
86 SetState(command_header);
87 dma_state.non_incrementing = false;
88 dma_increment_once = true;
89 break;
90 }
91 }
92 } else if (ib_enable && !dma_pushbuffer.empty()) {
93 // Current pushbuffer empty, but we have more IB entries to read
94 const CommandList& command_list{dma_pushbuffer.front()};
95 const CommandListHeader& command_list_header{command_list[dma_pushbuffer_subindex++]};
96 dma_get = command_list_header.addr;
97 dma_put = dma_get + command_list_header.size * sizeof(u32);
98 non_main = command_list_header.is_non_main;
99
100 if (dma_pushbuffer_subindex >= command_list.size()) {
101 // We've gone through the current list, remove it from the queue
102 dma_pushbuffer.pop();
103 dma_pushbuffer_subindex = 0;
104 }
105 } else {
106 // Otherwise, pushbuffer empty and IB empty or nonexistent - nothing to do
107 return {};
108 }
109
110 return true;
111}
112
113void DmaPusher::SetState(const CommandHeader& command_header) {
114 dma_state.method = command_header.method;
115 dma_state.subchannel = command_header.subchannel;
116 dma_state.method_count = command_header.method_count;
117}
118
119void DmaPusher::CallMethod(u32 argument) const {
120 gpu.CallMethod({dma_state.method, argument, dma_state.subchannel, dma_state.method_count});
121}
122
123} // namespace Tegra