summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJordan Woyak <jordan.woyak@gmail.com>2025-10-25 16:40:56 -0500
committerJordan Woyak <jordan.woyak@gmail.com>2025-10-28 17:22:04 -0500
commit09a125fec4ba077006bc0add7a8bfcdc0a572bc9 (patch)
tree73c518a81dd485cefb91171e238e370ba930ce96 /Source/Core
parent3d764f7b42b860db834159bb2db12e88abdffbed (diff)
VideoCommon: Clean up and eliminate the mutex in AsyncRequests using WaitableSPSCQueue.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/VideoCommon/AsyncRequests.cpp30
-rw-r--r--Source/Core/VideoCommon/AsyncRequests.h39
2 files changed, 23 insertions, 46 deletions
diff --git a/Source/Core/VideoCommon/AsyncRequests.cpp b/Source/Core/VideoCommon/AsyncRequests.cpp
index 6671f93293..7348724e43 100644
--- a/Source/Core/VideoCommon/AsyncRequests.cpp
+++ b/Source/Core/VideoCommon/AsyncRequests.cpp
@@ -3,8 +3,6 @@
#include "VideoCommon/AsyncRequests.h"
-#include <mutex>
-
#include "Core/System.h"
#include "VideoCommon/Fifo.h"
@@ -16,33 +14,25 @@ AsyncRequests AsyncRequests::s_singleton;
AsyncRequests::AsyncRequests() = default;
-void AsyncRequests::PullEventsInternal()
+void AsyncRequests::PullEvents()
{
+ if (m_queue.Empty())
+ return;
+
// This is only called if the queue isn't empty.
// So just flush the pipeline to get accurate results.
g_vertex_manager->Flush();
- std::unique_lock<std::mutex> lock(m_mutex);
- m_empty.Set();
-
- while (!m_queue.empty())
+ while (!m_queue.Empty())
{
- Event e = std::move(m_queue.front());
- lock.unlock();
- std::invoke(e);
- lock.lock();
-
- m_queue.pop();
+ std::invoke(std::move(m_queue.Front()));
+ m_queue.Pop();
}
-
- m_cond.notify_one();
}
void AsyncRequests::QueueEvent(Event&& event)
{
- m_empty.Clear();
-
- m_queue.push(std::move(event));
+ m_queue.Push(std::move(event));
auto& system = Core::System::GetInstance();
system.GetFifo().RunGpu();
@@ -50,12 +40,10 @@ void AsyncRequests::QueueEvent(Event&& event)
void AsyncRequests::WaitForEmptyQueue()
{
- std::unique_lock<std::mutex> lock(m_mutex);
- m_cond.wait(lock, [this] { return m_queue.empty(); });
+ m_queue.WaitForEmpty();
}
void AsyncRequests::SetPassthrough(bool enable)
{
- std::unique_lock<std::mutex> lock(m_mutex);
m_passthrough = enable;
}
diff --git a/Source/Core/VideoCommon/AsyncRequests.h b/Source/Core/VideoCommon/AsyncRequests.h
index 7b8cdd036b..2c3e84fd47 100644
--- a/Source/Core/VideoCommon/AsyncRequests.h
+++ b/Source/Core/VideoCommon/AsyncRequests.h
@@ -3,14 +3,12 @@
#pragma once
-#include <condition_variable>
+#include <concepts>
#include <functional>
#include <future>
-#include <mutex>
-#include <queue>
-#include "Common/Flag.h"
#include "Common/Functional.h"
+#include "Common/SPSCQueue.h"
struct EfbPokeData;
class PointerWrap;
@@ -20,43 +18,39 @@ class AsyncRequests
public:
AsyncRequests();
- void PullEvents()
- {
- if (!m_empty.IsSet())
- PullEventsInternal();
- }
+ // Called from the Video thread.
+ void PullEvents();
+
+ // The following are called from the CPU thread.
void WaitForEmptyQueue();
- void SetPassthrough(bool enable);
- template <typename F>
+ template <std::invocable<> F>
void PushEvent(F&& callback)
{
- std::unique_lock<std::mutex> lock(m_mutex);
-
if (m_passthrough)
{
- std::invoke(callback);
+ std::invoke(std::forward<F>(callback));
return;
}
QueueEvent(Event{std::forward<F>(callback)});
}
- template <typename F>
+ template <std::invocable<> F>
auto PushBlockingEvent(F&& callback) -> std::invoke_result_t<F>
{
- std::unique_lock<std::mutex> lock(m_mutex);
-
if (m_passthrough)
- return std::invoke(callback);
+ return std::invoke(std::forward<F>(callback));
std::packaged_task task{std::forward<F>(callback)};
QueueEvent(Event{[&] { task(); }});
- lock.unlock();
return task.get_future().get();
}
+ // Not thread-safe. Only set during initialization.
+ void SetPassthrough(bool enable);
+
static AsyncRequests* GetInstance() { return &s_singleton; }
private:
@@ -64,14 +58,9 @@ private:
void QueueEvent(Event&& event);
- void PullEventsInternal();
-
static AsyncRequests s_singleton;
- Common::Flag m_empty;
- std::queue<Event> m_queue;
- std::mutex m_mutex;
- std::condition_variable m_cond;
+ Common::WaitableSPSCQueue<Event> m_queue;
bool m_passthrough = true;
};