summaryrefslogtreecommitdiff
path: root/src/video_core/dma_pusher.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2018-11-23 23:20:56 -0500
committerGravatar bunnei2018-11-26 23:14:01 -0500
commitabea6fa90c901d0b47487ed38d44511b18f0addf (patch)
tree65ba9fc6ff7609ea569ea1e3d05f91caa56ffa14 /src/video_core/dma_pusher.cpp
parentMerge pull request #1805 from lioncash/resource (diff)
downloadyuzu-abea6fa90c901d0b47487ed38d44511b18f0addf.tar.gz
yuzu-abea6fa90c901d0b47487ed38d44511b18f0addf.tar.xz
yuzu-abea6fa90c901d0b47487ed38d44511b18f0addf.zip
gpu: Rewrite GPU command list processing with DmaPusher class.
- More accurate impl., fixes Undertale (among other games).
Diffstat (limited to 'src/video_core/dma_pusher.cpp')
-rw-r--r--src/video_core/dma_pusher.cpp110
1 files changed, 110 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..9f85a7aca
--- /dev/null
+++ b/src/video_core/dma_pusher.cpp
@@ -0,0 +1,110 @@
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 "core/core.h"
6#include "core/memory.h"
7#include "video_core/dma_pusher.h"
8#include "video_core/engines/maxwell_3d.h"
9#include "video_core/gpu.h"
10
11namespace Tegra {
12
13DmaPusher::DmaPusher(GPU& gpu) : gpu(gpu) {}
14
15DmaPusher::~DmaPusher() = default;
16
17void DmaPusher::DispatchCalls() {
18 // On entering GPU code, assume all memory may be touched by the ARM core.
19 gpu.Maxwell3D().dirty_flags.OnMemoryWrite();
20
21 while (Core::System::GetInstance().IsPoweredOn()) {
22 if (!Step()) {
23 break;
24 }
25 }
26}
27
28bool DmaPusher::Step() {
29 if (dma_get != dma_put) {
30 // Push buffer non-empty, read a word
31 const CommandHeader command_header{
32 Memory::Read32(*gpu.MemoryManager().GpuToCpuAddress(dma_get))};
33
34 dma_get += sizeof(u32);
35
36 if (!non_main) {
37 dma_mget = dma_get;
38 }
39
40 // now, see if we're in the middle of a command
41 if (dma_state.length_pending) {
42 // Second word of long non-inc methods command - method count
43 dma_state.length_pending = 0;
44 dma_state.method_count = command_header.method_count_;
45 } else if (dma_state.method_count) {
46 // Data word of methods command
47 CallMethod(command_header.argument);
48
49 if (!dma_state.non_incrementing) {
50 dma_state.method++;
51 }
52
53 if (dma_increment_once) {
54 dma_state.non_incrementing = true;
55 }
56
57 dma_state.method_count--;
58 } else {
59 // No command active - this is the first word of a new one
60 switch (command_header.mode) {
61 case SubmissionMode::Increasing:
62 SetState(command_header);
63 dma_state.non_incrementing = false;
64 dma_increment_once = false;
65 break;
66 case SubmissionMode::NonIncreasing:
67 SetState(command_header);
68 dma_state.non_incrementing = true;
69 dma_increment_once = false;
70 break;
71 case SubmissionMode::Inline:
72 dma_state.method = command_header.method;
73 dma_state.subchannel = command_header.subchannel;
74 CallMethod(command_header.arg_count);
75 dma_state.non_incrementing = true;
76 dma_increment_once = false;
77 break;
78 case SubmissionMode::IncreaseOnce:
79 SetState(command_header);
80 dma_state.non_incrementing = false;
81 dma_increment_once = true;
82 break;
83 }
84 }
85 } else if (ib_enable && !dma_pushbuffer.empty()) {
86 // Current pushbuffer empty, but we have more IB entries to read
87 const CommandListHeader& command_list_header{dma_pushbuffer.front()};
88 dma_get = command_list_header.addr;
89 dma_put = dma_get + command_list_header.size * sizeof(u32);
90 non_main = command_list_header.is_non_main;
91 dma_pushbuffer.pop();
92 } else {
93 // Otherwise, pushbuffer empty and IB empty or nonexistent - nothing to do
94 return {};
95 }
96
97 return true;
98}
99
100void DmaPusher::SetState(const CommandHeader& command_header) {
101 dma_state.method = command_header.method;
102 dma_state.subchannel = command_header.subchannel;
103 dma_state.method_count = command_header.method_count;
104}
105
106void DmaPusher::CallMethod(u32 argument) const {
107 gpu.CallMethod({dma_state.method, argument, dma_state.subchannel, dma_state.method_count});
108}
109
110} // namespace Tegra