From 450e4c7fea97ab033d70841efeb359f814cd1631 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 03:33:09 -0700 Subject: [PATCH] Factor out event queue logic to a template mixin. --- GPU/GLES/DisplayListInterpreter.cpp | 2 +- GPU/GPUCommon.cpp | 96 ++++--------------------- GPU/GPUCommon.h | 107 +++++++++++++++++++++++++--- GPU/GPUInterface.h | 4 ++ GPU/Null/NullGpu.h | 1 - 5 files changed, 116 insertions(+), 94 deletions(-) diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 39b0317a01..96b5919a2b 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -373,7 +373,7 @@ void GLES_GPU::ProcessEvent(GPUEvent ev) { break; default: - ERROR_LOG(G3D, "Unexpected GPU event type: %d", ev); + GPUCommon::ProcessEvent(ev); } } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 6f7ecfdc6a..e831bf380a 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -29,6 +29,7 @@ GPUCommon::GPUCommon() : dls[i].state = PSP_GE_DL_STATE_NONE; dls[i].waitTicks = 0; } + SetThreadEnabled(g_Config.bSeparateCPUThread); } void GPUCommon::PopDLQueue() { @@ -539,90 +540,19 @@ inline void GPUCommon::UpdateState(GPUState state) { downcount = 0; } -GPUEvent GPUCommon::GetNextEvent() { - easy_guard guard(eventsLock); - if (events.empty()) { - eventsDrain.notify_one(); - return GPU_EVENT_INVALID; +void GPUCommon::ProcessEvent(GPUEvent ev) { + switch (ev.type) { + case GPU_EVENT_PROCESS_QUEUE: + ProcessDLQueueInternal(); + break; + + case GPU_EVENT_REAPPLY_GFX_STATE: + ReapplyGfxStateInternal(); + break; + + default: + ERROR_LOG(G3D, "Unexpected GPU event type: %d", ev); } - - GPUEvent ev = events.front(); - events.pop_front(); - return ev; -} - -bool GPUCommon::HasEvents() { - easy_guard guard(eventsLock); - return !events.empty(); -} - -void GPUCommon::ScheduleEvent(GPUEvent ev) { - easy_guard guard(eventsLock); - events.push_back(ev); - eventsWait.notify_one(); - guard.unlock(); - - if (!g_Config.bSeparateCPUThread) { - RunEventsUntil(0); - } -} - -void GPUCommon::RunEventsUntil(u64 globalticks) { - do { - for (GPUEvent ev = GetNextEvent(); ev.type != GPU_EVENT_INVALID; ev = GetNextEvent()) { - switch (ev.type) { - case GPU_EVENT_PROCESS_QUEUE: - ProcessDLQueueInternal(); - break; - - case GPU_EVENT_REAPPLY_GFX_STATE: - ReapplyGfxStateInternal(); - break; - - case GPU_EVENT_FINISH_EVENT_LOOP: - // Stop waiting. - globalticks = 0; - break; - - case GPU_EVENT_SYNC_THREAD: - break; - - default: - ProcessEvent(ev); - } - } - - // Quit the loop if the queue is drained and coreState has tripped. - if (coreState != CORE_RUNNING) { - return; - } - - // coreState changes won't wake us, so recheck periodically. - if (!g_Config.bSeparateCPUThread) { - return; - } - eventsWait.wait_for(eventsWaitLock, 1); - } while (CoreTiming::GetTicks() < globalticks); -} - -void GPUCommon::FinishEventLoop() { - if (g_Config.bSeparateCPUThread) { - ScheduleEvent(GPU_EVENT_FINISH_EVENT_LOOP); - } -} - -void GPUCommon::SyncThread() { - if (!g_Config.bSeparateCPUThread) { - return; - } - - // It could be that we are *currently* processing the last event. - // The events queue will be empty (HasEvents() = false), but it's not done. - // So we schedule a nothing event and wait for that to finish. - ScheduleEvent(GPU_EVENT_SYNC_THREAD); - while (HasEvents() && coreState == CORE_RUNNING) { - eventsDrain.wait_for(eventsDrainLock, 1); - }; } int GPUCommon::GetNextListIndex() { diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 0641a9fdca..b274f7e820 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -2,17 +2,110 @@ #include "native/base/mutex.h" #include "GPU/GPUInterface.h" +#include "Core/CoreTiming.h" #include -class GPUCommon : public GPUInterface +template +struct ThreadEventQueue : public B { + void SetThreadEnabled(bool threadEnabled) { + threadEnabled_ = threadEnabled; + } + + void ScheduleEvent(Event ev) { + { + lock_guard guard(eventsLock_); + events_.push_back(ev); + eventsWait_.notify_one(); + } + + if (!threadEnabled_) { + RunEventsUntil(0); + } + } + + bool HasEvents() { + lock_guard guard(eventsLock_); + return !events_.empty(); + } + + Event GetNextEvent() { + lock_guard guard(eventsLock_); + if (events_.empty()) { + eventsDrain_.notify_one(); + return EVENT_INVALID; + } + + Event ev = events_.front(); + events_.pop_front(); + return ev; + } + + void RunEventsUntil(u64 globalticks) { + do { + for (Event ev = GetNextEvent(); EventType(ev) != EVENT_INVALID; ev = GetNextEvent()) { + switch (EventType(ev)) { + case EVENT_FINISH: + // Stop waiting. + globalticks = 0; + break; + + case EVENT_SYNC: + break; + + default: + ProcessEvent(ev); + } + } + + // Quit the loop if the queue is drained and coreState has tripped, or threading is disabled. + if (coreState != CORE_RUNNING || !threadEnabled_) { + return; + } + + // coreState changes won't wake us, so recheck periodically. + eventsWait_.wait_for(eventsWaitLock_, 1); + } while (CoreTiming::GetTicks() < globalticks); + } + + void SyncThread() { + if (!threadEnabled_) { + return; + } + + // While processing the last event, HasEvents() will be false even while not done. + // So we schedule a nothing event and wait for that to finish. + ScheduleEvent(EVENT_SYNC); + while (HasEvents() && coreState == CORE_RUNNING) { + eventsDrain_.wait_for(eventsDrainLock_, 1); + } + } + + void FinishEventLoop() { + if (threadEnabled_) { + ScheduleEvent(EVENT_FINISH); + } + } + +protected: + virtual void ProcessEvent(Event ev) = 0; + +private: + bool threadEnabled_; + std::deque events_; + recursive_mutex eventsLock_; + recursive_mutex eventsWaitLock_; + recursive_mutex eventsDrainLock_; + condition_variable eventsWait_; + condition_variable eventsDrain_; +}; +typedef ThreadEventQueue GPUThreadEventQueue; + +class GPUCommon : public GPUThreadEventQueue { public: GPUCommon(); virtual ~GPUCommon() {} - virtual void RunEventsUntil(u64 globalticks); - virtual void FinishEventLoop(); - virtual void InterruptStart(int listid); virtual void InterruptEnd(int listid); virtual void SyncEnd(WaitType waitType, int listid, bool wokeThreads); @@ -34,7 +127,6 @@ public: virtual u32 Continue(); virtual u32 Break(int mode); virtual void ReapplyGfxState(); - virtual void SyncThread(); protected: // To avoid virtual calls to PreExecuteOp(). @@ -45,12 +137,9 @@ protected: void PopDLQueue(); void CheckDrawSync(); int GetNextListIndex(); - GPUEvent GetNextEvent(); - bool HasEvents(); - void ScheduleEvent(GPUEvent ev); void ProcessDLQueueInternal(); void ReapplyGfxStateInternal(); - virtual void ProcessEvent(GPUEvent ev) = 0; + virtual void ProcessEvent(GPUEvent ev); // Allows early unlocking with a guard. Do not double unlock. class easy_guard { diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 856c943ef3..f98a16a923 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -163,6 +163,10 @@ struct GPUEvent { GPUInvalidationType type; } invalidate_cache; }; + + operator GPUEventType() const { + return type; + } }; class GPUInterface diff --git a/GPU/Null/NullGpu.h b/GPU/Null/NullGpu.h index f298dffc46..25a2bc6086 100644 --- a/GPU/Null/NullGpu.h +++ b/GPU/Null/NullGpu.h @@ -49,5 +49,4 @@ public: protected: virtual void FastRunLoop(DisplayList &list); - virtual void ProcessEvent(GPUEvent ev) {} };