summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ameerj2021-09-15 20:32:54 -0400
committerGravatar ameerj2021-09-15 20:49:07 -0400
commit877cd60b00a3f827062fdaff93183b52174ec134 (patch)
treeddcd7153dade611b9200c1867cfa643719696e25
parentthreadsafe_queue: Add std::stop_token overload to PopWait (diff)
downloadyuzu-877cd60b00a3f827062fdaff93183b52174ec134.tar.gz
yuzu-877cd60b00a3f827062fdaff93183b52174ec134.tar.xz
yuzu-877cd60b00a3f827062fdaff93183b52174ec134.zip
gpu: Use std::jthread for async gpu thread
-rw-r--r--src/core/core.cpp6
-rw-r--r--src/video_core/gpu.cpp8
-rw-r--r--src/video_core/gpu.h3
-rw-r--r--src/video_core/gpu_thread.cpp57
-rw-r--r--src/video_core/gpu_thread.h13
5 files changed, 18 insertions, 69 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index b13350f6e..54ebed2c1 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -305,10 +305,7 @@ struct System::Impl {
305 is_powered_on = false; 305 is_powered_on = false;
306 exit_lock = false; 306 exit_lock = false;
307 307
308 if (gpu_core) { 308 gpu_core.reset();
309 gpu_core->ShutDown();
310 }
311
312 services.reset(); 309 services.reset();
313 service_manager.reset(); 310 service_manager.reset();
314 cheat_engine.reset(); 311 cheat_engine.reset();
@@ -317,7 +314,6 @@ struct System::Impl {
317 time_manager.Shutdown(); 314 time_manager.Shutdown();
318 core_timing.Shutdown(); 315 core_timing.Shutdown();
319 app_loader.reset(); 316 app_loader.reset();
320 gpu_core.reset();
321 perf_stats.reset(); 317 perf_stats.reset();
322 kernel.Shutdown(); 318 kernel.Shutdown();
323 memory.Reset(); 319 memory.Reset();
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index ff024f530..2ae3639b5 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -531,14 +531,6 @@ void GPU::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) const {
531 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value); 531 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value);
532} 532}
533 533
534void GPU::ShutDown() {
535 // Signal that threads should no longer block on syncpoint fences
536 shutting_down.store(true, std::memory_order_relaxed);
537 sync_cv.notify_all();
538
539 gpu_thread.ShutDown();
540}
541
542void GPU::OnCommandListEnd() { 534void GPU::OnCommandListEnd() {
543 if (is_async) { 535 if (is_async) {
544 // This command only applies to asynchronous GPU mode 536 // This command only applies to asynchronous GPU mode
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index a8e98e51b..e6a02a71b 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -219,9 +219,6 @@ public:
219 return *shader_notify; 219 return *shader_notify;
220 } 220 }
221 221
222 // Stops the GPU execution and waits for the GPU to finish working
223 void ShutDown();
224
225 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame. 222 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame.
226 void WaitFence(u32 syncpoint_id, u32 value); 223 void WaitFence(u32 syncpoint_id, u32 value);
227 224
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 46f642b19..9547f277a 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -17,9 +17,9 @@
17namespace VideoCommon::GPUThread { 17namespace VideoCommon::GPUThread {
18 18
19/// Runs the GPU thread 19/// Runs the GPU thread
20static void RunThread(Core::System& system, VideoCore::RendererBase& renderer, 20static void RunThread(std::stop_token stop_token, Core::System& system,
21 Core::Frontend::GraphicsContext& context, Tegra::DmaPusher& dma_pusher, 21 VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context,
22 SynchState& state) { 22 Tegra::DmaPusher& dma_pusher, SynchState& state) {
23 std::string name = "yuzu:GPU"; 23 std::string name = "yuzu:GPU";
24 MicroProfileOnThreadCreate(name.c_str()); 24 MicroProfileOnThreadCreate(name.c_str());
25 SCOPE_EXIT({ MicroProfileOnThreadExit(); }); 25 SCOPE_EXIT({ MicroProfileOnThreadExit(); });
@@ -28,20 +28,14 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
28 Common::SetCurrentThreadPriority(Common::ThreadPriority::High); 28 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
29 system.RegisterHostThread(); 29 system.RegisterHostThread();
30 30
31 // Wait for first GPU command before acquiring the window context
32 state.queue.Wait();
33
34 // If emulation was stopped during disk shader loading, abort before trying to acquire context
35 if (!state.is_running) {
36 return;
37 }
38
39 auto current_context = context.Acquire(); 31 auto current_context = context.Acquire();
40 VideoCore::RasterizerInterface* const rasterizer = renderer.ReadRasterizer(); 32 VideoCore::RasterizerInterface* const rasterizer = renderer.ReadRasterizer();
41 33
42 CommandDataContainer next; 34 while (!stop_token.stop_requested()) {
43 while (state.is_running) { 35 CommandDataContainer next = state.queue.PopWait(stop_token);
44 next = state.queue.PopWait(); 36 if (stop_token.stop_requested()) {
37 break;
38 }
45 if (auto* submit_list = std::get_if<SubmitListCommand>(&next.data)) { 39 if (auto* submit_list = std::get_if<SubmitListCommand>(&next.data)) {
46 dma_pusher.Push(std::move(submit_list->entries)); 40 dma_pusher.Push(std::move(submit_list->entries));
47 dma_pusher.DispatchCalls(); 41 dma_pusher.DispatchCalls();
@@ -55,8 +49,6 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
55 rasterizer->FlushRegion(flush->addr, flush->size); 49 rasterizer->FlushRegion(flush->addr, flush->size);
56 } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) { 50 } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) {
57 rasterizer->OnCPUWrite(invalidate->addr, invalidate->size); 51 rasterizer->OnCPUWrite(invalidate->addr, invalidate->size);
58 } else if (std::holds_alternative<EndProcessingCommand>(next.data)) {
59 ASSERT(state.is_running == false);
60 } else { 52 } else {
61 UNREACHABLE(); 53 UNREACHABLE();
62 } 54 }
@@ -73,16 +65,14 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
73ThreadManager::ThreadManager(Core::System& system_, bool is_async_) 65ThreadManager::ThreadManager(Core::System& system_, bool is_async_)
74 : system{system_}, is_async{is_async_} {} 66 : system{system_}, is_async{is_async_} {}
75 67
76ThreadManager::~ThreadManager() { 68ThreadManager::~ThreadManager() = default;
77 ShutDown();
78}
79 69
80void ThreadManager::StartThread(VideoCore::RendererBase& renderer, 70void ThreadManager::StartThread(VideoCore::RendererBase& renderer,
81 Core::Frontend::GraphicsContext& context, 71 Core::Frontend::GraphicsContext& context,
82 Tegra::DmaPusher& dma_pusher) { 72 Tegra::DmaPusher& dma_pusher) {
83 rasterizer = renderer.ReadRasterizer(); 73 rasterizer = renderer.ReadRasterizer();
84 thread = std::thread(RunThread, std::ref(system), std::ref(renderer), std::ref(context), 74 thread = std::jthread(RunThread, std::ref(system), std::ref(renderer), std::ref(context),
85 std::ref(dma_pusher), std::ref(state)); 75 std::ref(dma_pusher), std::ref(state));
86} 76}
87 77
88void ThreadManager::SubmitList(Tegra::CommandList&& entries) { 78void ThreadManager::SubmitList(Tegra::CommandList&& entries) {
@@ -117,26 +107,6 @@ void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) {
117 rasterizer->OnCPUWrite(addr, size); 107 rasterizer->OnCPUWrite(addr, size);
118} 108}
119 109
120void ThreadManager::ShutDown() {
121 if (!state.is_running) {
122 return;
123 }
124
125 {
126 std::lock_guard lk(state.write_lock);
127 state.is_running = false;
128 state.cv.notify_all();
129 }
130
131 if (!thread.joinable()) {
132 return;
133 }
134
135 // Notify GPU thread that a shutdown is pending
136 PushCommand(EndProcessingCommand());
137 thread.join();
138}
139
140void ThreadManager::OnCommandListEnd() { 110void ThreadManager::OnCommandListEnd() {
141 PushCommand(OnCommandListEndCommand()); 111 PushCommand(OnCommandListEndCommand());
142} 112}
@@ -152,9 +122,8 @@ u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
152 state.queue.Push(CommandDataContainer(std::move(command_data), fence, block)); 122 state.queue.Push(CommandDataContainer(std::move(command_data), fence, block));
153 123
154 if (block) { 124 if (block) {
155 state.cv.wait(lk, [this, fence] { 125 state.cv.wait(lk, thread.get_stop_token(), [this, fence] {
156 return fence <= state.signaled_fence.load(std::memory_order_relaxed) || 126 return fence <= state.signaled_fence.load(std::memory_order_relaxed);
157 !state.is_running;
158 }); 127 });
159 } 128 }
160 129
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 11a648f38..91bada925 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -33,9 +33,6 @@ class RendererBase;
33 33
34namespace VideoCommon::GPUThread { 34namespace VideoCommon::GPUThread {
35 35
36/// Command to signal to the GPU thread that processing has ended
37struct EndProcessingCommand final {};
38
39/// Command to signal to the GPU thread that a command list is ready for processing 36/// Command to signal to the GPU thread that a command list is ready for processing
40struct SubmitListCommand final { 37struct SubmitListCommand final {
41 explicit SubmitListCommand(Tegra::CommandList&& entries_) : entries{std::move(entries_)} {} 38 explicit SubmitListCommand(Tegra::CommandList&& entries_) : entries{std::move(entries_)} {}
@@ -83,7 +80,7 @@ struct OnCommandListEndCommand final {};
83struct GPUTickCommand final {}; 80struct GPUTickCommand final {};
84 81
85using CommandData = 82using CommandData =
86 std::variant<EndProcessingCommand, SubmitListCommand, SwapBuffersCommand, FlushRegionCommand, 83 std::variant<std::monostate, SubmitListCommand, SwapBuffersCommand, FlushRegionCommand,
87 InvalidateRegionCommand, FlushAndInvalidateRegionCommand, OnCommandListEndCommand, 84 InvalidateRegionCommand, FlushAndInvalidateRegionCommand, OnCommandListEndCommand,
88 GPUTickCommand>; 85 GPUTickCommand>;
89 86
@@ -100,14 +97,12 @@ struct CommandDataContainer {
100 97
101/// Struct used to synchronize the GPU thread 98/// Struct used to synchronize the GPU thread
102struct SynchState final { 99struct SynchState final {
103 std::atomic_bool is_running{true}; 100 using CommandQueue = Common::SPSCQueue<CommandDataContainer, true>;
104
105 using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
106 std::mutex write_lock; 101 std::mutex write_lock;
107 CommandQueue queue; 102 CommandQueue queue;
108 u64 last_fence{}; 103 u64 last_fence{};
109 std::atomic<u64> signaled_fence{}; 104 std::atomic<u64> signaled_fence{};
110 std::condition_variable cv; 105 std::condition_variable_any cv;
111}; 106};
112 107
113/// Class used to manage the GPU thread 108/// Class used to manage the GPU thread
@@ -149,7 +144,7 @@ private:
149 VideoCore::RasterizerInterface* rasterizer = nullptr; 144 VideoCore::RasterizerInterface* rasterizer = nullptr;
150 145
151 SynchState state; 146 SynchState state;
152 std::thread thread; 147 std::jthread thread;
153}; 148};
154 149
155} // namespace VideoCommon::GPUThread 150} // namespace VideoCommon::GPUThread