summaryrefslogtreecommitdiff
path: root/src/video_core/gpu_thread.h
diff options
context:
space:
mode:
authorGravatar bunnei2019-01-23 22:17:55 -0500
committerGravatar bunnei2019-03-06 21:48:57 -0500
commit7b574f406b25c02a0e0efd8b7ec13d68ecb55497 (patch)
tree375d4637d49ffe506129ce9cb679b5902328106a /src/video_core/gpu_thread.h
parentbootmanager: Ensure that we have a context for shader loading. (diff)
downloadyuzu-7b574f406b25c02a0e0efd8b7ec13d68ecb55497.tar.gz
yuzu-7b574f406b25c02a0e0efd8b7ec13d68ecb55497.tar.xz
yuzu-7b574f406b25c02a0e0efd8b7ec13d68ecb55497.zip
gpu: Move command processing to another thread.
Diffstat (limited to 'src/video_core/gpu_thread.h')
-rw-r--r--src/video_core/gpu_thread.h135
1 files changed, 135 insertions, 0 deletions
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
new file mode 100644
index 000000000..ad9f9462b
--- /dev/null
+++ b/src/video_core/gpu_thread.h
@@ -0,0 +1,135 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <atomic>
9#include <condition_variable>
10#include <memory>
11#include <mutex>
12#include <optional>
13#include <thread>
14#include <variant>
15
16namespace Tegra {
17struct FramebufferConfig;
18class DmaPusher;
19} // namespace Tegra
20
21namespace VideoCore {
22class RendererBase;
23} // namespace VideoCore
24
25namespace VideoCommon::GPUThread {
26
27/// Command to signal to the GPU thread that a command list is ready for processing
28struct SubmitListCommand final {
29 explicit SubmitListCommand(Tegra::CommandList&& entries) : entries{std::move(entries)} {}
30
31 Tegra::CommandList entries;
32};
33
34/// Command to signal to the GPU thread that a swap buffers is pending
35struct SwapBuffersCommand final {
36 explicit SwapBuffersCommand(std::optional<const Tegra::FramebufferConfig> framebuffer)
37 : framebuffer{std::move(framebuffer)} {}
38
39 std::optional<const Tegra::FramebufferConfig> framebuffer;
40};
41
42/// Command to signal to the GPU thread to flush a region
43struct FlushRegionCommand final {
44 explicit constexpr FlushRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {}
45
46 const VAddr addr;
47 const u64 size;
48};
49
50/// Command to signal to the GPU thread to invalidate a region
51struct InvalidateRegionCommand final {
52 explicit constexpr InvalidateRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {}
53
54 const VAddr addr;
55 const u64 size;
56};
57
58/// Command to signal to the GPU thread to flush and invalidate a region
59struct FlushAndInvalidateRegionCommand final {
60 explicit constexpr FlushAndInvalidateRegionCommand(VAddr addr, u64 size)
61 : addr{addr}, size{size} {}
62
63 const VAddr addr;
64 const u64 size;
65};
66
67using CommandData = std::variant<SubmitListCommand, SwapBuffersCommand, FlushRegionCommand,
68 InvalidateRegionCommand, FlushAndInvalidateRegionCommand>;
69
70/// Struct used to synchronize the GPU thread
71struct SynchState final {
72 std::atomic<bool> is_running{true};
73 std::condition_variable signal_condition;
74 std::mutex signal_mutex;
75 std::condition_variable idle_condition;
76 std::mutex idle_mutex;
77
78 // We use two queues for sending commands to the GPU thread, one for writing (push_queue) to and
79 // one for reading from (pop_queue). These are swapped whenever the current pop_queue becomes
80 // empty. This allows for efficient thread-safe access, as it does not require any copies.
81
82 using CommandQueue = std::queue<CommandData>;
83 std::array<CommandQueue, 2> command_queues;
84 CommandQueue* push_queue{&command_queues[0]};
85 CommandQueue* pop_queue{&command_queues[1]};
86
87 /// Returns true if the GPU thread should be idle, meaning there are no commands to process
88 bool IsIdle() const {
89 return command_queues[0].empty() && command_queues[1].empty();
90 }
91};
92
93/// Class used to manage the GPU thread
94class ThreadManager final {
95public:
96 explicit ThreadManager(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher);
97 ~ThreadManager();
98
99 /// Push GPU command entries to be processed
100 void SubmitList(Tegra::CommandList&& entries);
101
102 /// Swap buffers (render frame)
103 void SwapBuffers(
104 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer);
105
106 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
107 void FlushRegion(VAddr addr, u64 size);
108
109 /// Notify rasterizer that any caches of the specified region should be invalidated
110 void InvalidateRegion(VAddr addr, u64 size);
111
112 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
113 void FlushAndInvalidateRegion(VAddr addr, u64 size);
114
115 /// Waits the caller until the GPU thread is idle, used for synchronization
116 void WaitForIdle();
117
118private:
119 /// Pushes a command to be executed by the GPU thread
120 void PushCommand(CommandData&& command_data, bool wait_for_idle, bool allow_on_cpu);
121
122 /// Returns true if this is called by the GPU thread
123 bool IsGpuThread() const {
124 return std::this_thread::get_id() == thread_id;
125 }
126
127private:
128 SynchState state;
129 std::thread thread;
130 std::thread::id thread_id;
131 VideoCore::RendererBase& renderer;
132 Tegra::DmaPusher& dma_pusher;
133};
134
135} // namespace VideoCommon::GPUThread