Explorar el Código

gpu_thread: Fix deadlock with threading idle state check.

bunnei hace 7 años
padre
commit
84ad81ee67
Se han modificado 2 ficheros con 11 adiciones y 7 borrados
  1. 7 4
      src/video_core/gpu_thread.cpp
  2. 4 3
      src/video_core/gpu_thread.h

+ 7 - 4
src/video_core/gpu_thread.cpp

@@ -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); });
     }
     }
 }
 }
 
 

+ 4 - 3
src/video_core/gpu_thread.h

@@ -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
-    bool IsIdle() const {
-        return command_queues[0].empty() && command_queues[1].empty();
+    void UpdateIdleState() {
+        std::lock_guard<std::mutex> lock{idle_mutex};
+        is_idle = command_queues[0].empty() && command_queues[1].empty();
     }
     }
 };
 };