mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-11-15 21:50:05 +00:00
gpu_thread: Fix deadlock with threading idle state check.
This commit is contained in:
parent
63aa08acbe
commit
84ad81ee67
@ -40,7 +40,7 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
|
|||||||
|
|
||||||
auto WaitForWakeup = [&]() {
|
auto WaitForWakeup = [&]() {
|
||||||
std::unique_lock<std::mutex> lock{state.signal_mutex};
|
std::unique_lock<std::mutex> lock{state.signal_mutex};
|
||||||
state.signal_condition.wait(lock, [&] { return !state.IsIdle() || !state.is_running; });
|
state.signal_condition.wait(lock, [&] { return !state.is_idle || !state.is_running; });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wait for first GPU command before acquiring the window context
|
// Wait for first GPU command before acquiring the window context
|
||||||
@ -70,8 +70,10 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
|
|||||||
state.pop_queue->pop();
|
state.pop_queue->pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.UpdateIdleState();
|
||||||
|
|
||||||
// Signal that the GPU thread has finished processing commands
|
// Signal that the GPU thread has finished processing commands
|
||||||
if (state.IsIdle()) {
|
if (state.is_idle) {
|
||||||
state.idle_condition.notify_one();
|
state.idle_condition.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,13 +128,14 @@ void ThreadManager::PushCommand(CommandData&& command_data, bool wait_for_idle,
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock{state.signal_mutex};
|
std::lock_guard<std::mutex> lock{state.signal_mutex};
|
||||||
|
|
||||||
if ((allow_on_cpu && state.IsIdle()) || IsGpuThread()) {
|
if ((allow_on_cpu && state.is_idle) || IsGpuThread()) {
|
||||||
// Execute the command synchronously on the current thread
|
// Execute the command synchronously on the current thread
|
||||||
ExecuteCommand(&command_data, renderer, dma_pusher);
|
ExecuteCommand(&command_data, renderer, dma_pusher);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push the command to the GPU thread
|
// Push the command to the GPU thread
|
||||||
|
state.UpdateIdleState();
|
||||||
state.push_queue->emplace(command_data);
|
state.push_queue->emplace(command_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +145,7 @@ void ThreadManager::PushCommand(CommandData&& command_data, bool wait_for_idle,
|
|||||||
if (wait_for_idle) {
|
if (wait_for_idle) {
|
||||||
// Wait for the GPU to be idle (all commands to be executed)
|
// Wait for the GPU to be idle (all commands to be executed)
|
||||||
std::unique_lock<std::mutex> lock{state.idle_mutex};
|
std::unique_lock<std::mutex> lock{state.idle_mutex};
|
||||||
state.idle_condition.wait(lock, [this] { return state.IsIdle(); });
|
state.idle_condition.wait(lock, [this] { return static_cast<bool>(state.is_idle); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ using CommandData = std::variant<SubmitListCommand, SwapBuffersCommand, FlushReg
|
|||||||
/// Struct used to synchronize the GPU thread
|
/// Struct used to synchronize the GPU thread
|
||||||
struct SynchState final {
|
struct SynchState final {
|
||||||
std::atomic<bool> is_running{true};
|
std::atomic<bool> is_running{true};
|
||||||
|
std::atomic<bool> is_idle{true};
|
||||||
std::condition_variable signal_condition;
|
std::condition_variable signal_condition;
|
||||||
std::mutex signal_mutex;
|
std::mutex signal_mutex;
|
||||||
std::condition_variable idle_condition;
|
std::condition_variable idle_condition;
|
||||||
@ -84,9 +85,9 @@ struct SynchState final {
|
|||||||
CommandQueue* push_queue{&command_queues[0]};
|
CommandQueue* push_queue{&command_queues[0]};
|
||||||
CommandQueue* pop_queue{&command_queues[1]};
|
CommandQueue* pop_queue{&command_queues[1]};
|
||||||
|
|
||||||
/// Returns true if the GPU thread should be idle, meaning there are no commands to process
|
void UpdateIdleState() {
|
||||||
bool IsIdle() const {
|
std::lock_guard<std::mutex> lock{idle_mutex};
|
||||||
return command_queues[0].empty() && command_queues[1].empty();
|
is_idle = command_queues[0].empty() && command_queues[1].empty();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user