diff options
| author | 2021-04-09 11:52:18 -0700 | |
|---|---|---|
| committer | 2021-04-09 11:52:18 -0700 | |
| commit | d6e5e053a6c4fe8538d4b97b8f5a1eba61e2fcac (patch) | |
| tree | 71dafa020afef119e3d3b57e22ca14f4ba42d9d8 /src/video_core/gpu_thread.cpp | |
| parent | Merge pull request #6164 from Morph1984/service-update-12.x (diff) | |
| parent | video_core: Use a CV for blocking commands. (diff) | |
| download | yuzu-d6e5e053a6c4fe8538d4b97b8f5a1eba61e2fcac.tar.gz yuzu-d6e5e053a6c4fe8538d4b97b8f5a1eba61e2fcac.tar.xz yuzu-d6e5e053a6c4fe8538d4b97b8f5a1eba61e2fcac.zip | |
Merge pull request #6162 from degasus/no_spin_loops
video_core: Avoid spin loops.
Diffstat (limited to 'src/video_core/gpu_thread.cpp')
| -rw-r--r-- | src/video_core/gpu_thread.cpp | 62 |
1 files changed, 41 insertions, 21 deletions
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 99353f15f..7addfbc7b 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp | |||
| @@ -29,8 +29,7 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer, | |||
| 29 | system.RegisterHostThread(); | 29 | system.RegisterHostThread(); |
| 30 | 30 | ||
| 31 | // Wait for first GPU command before acquiring the window context | 31 | // Wait for first GPU command before acquiring the window context |
| 32 | while (state.queue.Empty()) | 32 | state.queue.Wait(); |
| 33 | ; | ||
| 34 | 33 | ||
| 35 | // If emulation was stopped during disk shader loading, abort before trying to acquire context | 34 | // If emulation was stopped during disk shader loading, abort before trying to acquire context |
| 36 | if (!state.is_running) { | 35 | if (!state.is_running) { |
| @@ -57,11 +56,17 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer, | |||
| 57 | } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) { | 56 | } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) { |
| 58 | rasterizer->OnCPUWrite(invalidate->addr, invalidate->size); | 57 | rasterizer->OnCPUWrite(invalidate->addr, invalidate->size); |
| 59 | } else if (std::holds_alternative<EndProcessingCommand>(next.data)) { | 58 | } else if (std::holds_alternative<EndProcessingCommand>(next.data)) { |
| 60 | return; | 59 | ASSERT(state.is_running == false); |
| 61 | } else { | 60 | } else { |
| 62 | UNREACHABLE(); | 61 | UNREACHABLE(); |
| 63 | } | 62 | } |
| 64 | state.signaled_fence.store(next.fence); | 63 | state.signaled_fence.store(next.fence); |
| 64 | if (next.block) { | ||
| 65 | // We have to lock the write_lock to ensure that the condition_variable wait not get a | ||
| 66 | // race between the check and the lock itself. | ||
| 67 | std::lock_guard lk(state.write_lock); | ||
| 68 | state.cv.notify_all(); | ||
| 69 | } | ||
| 65 | } | 70 | } |
| 66 | } | 71 | } |
| 67 | 72 | ||
| @@ -69,13 +74,7 @@ ThreadManager::ThreadManager(Core::System& system_, bool is_async_) | |||
| 69 | : system{system_}, is_async{is_async_} {} | 74 | : system{system_}, is_async{is_async_} {} |
| 70 | 75 | ||
| 71 | ThreadManager::~ThreadManager() { | 76 | ThreadManager::~ThreadManager() { |
| 72 | if (!thread.joinable()) { | 77 | ShutDown(); |
| 73 | return; | ||
| 74 | } | ||
| 75 | |||
| 76 | // Notify GPU thread that a shutdown is pending | ||
| 77 | PushCommand(EndProcessingCommand()); | ||
| 78 | thread.join(); | ||
| 79 | } | 78 | } |
| 80 | 79 | ||
| 81 | void ThreadManager::StartThread(VideoCore::RendererBase& renderer, | 80 | void ThreadManager::StartThread(VideoCore::RendererBase& renderer, |
| @@ -112,9 +111,8 @@ void ThreadManager::FlushRegion(VAddr addr, u64 size) { | |||
| 112 | case Settings::GPUAccuracy::Extreme: { | 111 | case Settings::GPUAccuracy::Extreme: { |
| 113 | auto& gpu = system.GPU(); | 112 | auto& gpu = system.GPU(); |
| 114 | u64 fence = gpu.RequestFlush(addr, size); | 113 | u64 fence = gpu.RequestFlush(addr, size); |
| 115 | PushCommand(GPUTickCommand()); | 114 | PushCommand(GPUTickCommand(), true); |
| 116 | while (fence > gpu.CurrentFlushRequestFence()) { | 115 | ASSERT(fence <= gpu.CurrentFlushRequestFence()); |
| 117 | } | ||
| 118 | break; | 116 | break; |
| 119 | } | 117 | } |
| 120 | default: | 118 | default: |
| @@ -131,23 +129,45 @@ void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) { | |||
| 131 | rasterizer->OnCPUWrite(addr, size); | 129 | rasterizer->OnCPUWrite(addr, size); |
| 132 | } | 130 | } |
| 133 | 131 | ||
| 134 | void ThreadManager::WaitIdle() const { | 132 | void ThreadManager::ShutDown() { |
| 135 | while (state.last_fence > state.signaled_fence.load(std::memory_order_relaxed) && | 133 | if (!state.is_running) { |
| 136 | system.IsPoweredOn()) { | 134 | return; |
| 137 | } | 135 | } |
| 136 | |||
| 137 | { | ||
| 138 | std::lock_guard lk(state.write_lock); | ||
| 139 | state.is_running = false; | ||
| 140 | state.cv.notify_all(); | ||
| 141 | } | ||
| 142 | |||
| 143 | if (!thread.joinable()) { | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | |||
| 147 | // Notify GPU thread that a shutdown is pending | ||
| 148 | PushCommand(EndProcessingCommand()); | ||
| 149 | thread.join(); | ||
| 138 | } | 150 | } |
| 139 | 151 | ||
| 140 | void ThreadManager::OnCommandListEnd() { | 152 | void ThreadManager::OnCommandListEnd() { |
| 141 | PushCommand(OnCommandListEndCommand()); | 153 | PushCommand(OnCommandListEndCommand()); |
| 142 | } | 154 | } |
| 143 | 155 | ||
| 144 | u64 ThreadManager::PushCommand(CommandData&& command_data) { | 156 | u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) { |
| 145 | const u64 fence{++state.last_fence}; | ||
| 146 | state.queue.Push(CommandDataContainer(std::move(command_data), fence)); | ||
| 147 | |||
| 148 | if (!is_async) { | 157 | if (!is_async) { |
| 149 | // In synchronous GPU mode, block the caller until the command has executed | 158 | // In synchronous GPU mode, block the caller until the command has executed |
| 150 | WaitIdle(); | 159 | block = true; |
| 160 | } | ||
| 161 | |||
| 162 | std::unique_lock lk(state.write_lock); | ||
| 163 | const u64 fence{++state.last_fence}; | ||
| 164 | state.queue.Push(CommandDataContainer(std::move(command_data), fence, block)); | ||
| 165 | |||
| 166 | if (block) { | ||
| 167 | state.cv.wait(lk, [this, fence] { | ||
| 168 | return fence <= state.signaled_fence.load(std::memory_order_relaxed) || | ||
| 169 | !state.is_running; | ||
| 170 | }); | ||
| 151 | } | 171 | } |
| 152 | 172 | ||
| 153 | return fence; | 173 | return fence; |