mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-22 09:51:56 +00:00
Factor out event queue logic to a template mixin.
This commit is contained in:
parent
c6956c299a
commit
450e4c7fea
@ -373,7 +373,7 @@ void GLES_GPU::ProcessEvent(GPUEvent ev) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERROR_LOG(G3D, "Unexpected GPU event type: %d", ev);
|
GPUCommon::ProcessEvent(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ GPUCommon::GPUCommon() :
|
|||||||
dls[i].state = PSP_GE_DL_STATE_NONE;
|
dls[i].state = PSP_GE_DL_STATE_NONE;
|
||||||
dls[i].waitTicks = 0;
|
dls[i].waitTicks = 0;
|
||||||
}
|
}
|
||||||
|
SetThreadEnabled(g_Config.bSeparateCPUThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUCommon::PopDLQueue() {
|
void GPUCommon::PopDLQueue() {
|
||||||
@ -539,90 +540,19 @@ inline void GPUCommon::UpdateState(GPUState state) {
|
|||||||
downcount = 0;
|
downcount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUEvent GPUCommon::GetNextEvent() {
|
void GPUCommon::ProcessEvent(GPUEvent ev) {
|
||||||
easy_guard guard(eventsLock);
|
switch (ev.type) {
|
||||||
if (events.empty()) {
|
case GPU_EVENT_PROCESS_QUEUE:
|
||||||
eventsDrain.notify_one();
|
ProcessDLQueueInternal();
|
||||||
return GPU_EVENT_INVALID;
|
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() {
|
int GPUCommon::GetNextListIndex() {
|
||||||
|
107
GPU/GPUCommon.h
107
GPU/GPUCommon.h
@ -2,17 +2,110 @@
|
|||||||
|
|
||||||
#include "native/base/mutex.h"
|
#include "native/base/mutex.h"
|
||||||
#include "GPU/GPUInterface.h"
|
#include "GPU/GPUInterface.h"
|
||||||
|
#include "Core/CoreTiming.h"
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
class GPUCommon : public GPUInterface
|
template <typename B, typename Event, typename EventType, EventType EVENT_INVALID, EventType EVENT_SYNC, EventType EVENT_FINISH>
|
||||||
|
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<Event> events_;
|
||||||
|
recursive_mutex eventsLock_;
|
||||||
|
recursive_mutex eventsWaitLock_;
|
||||||
|
recursive_mutex eventsDrainLock_;
|
||||||
|
condition_variable eventsWait_;
|
||||||
|
condition_variable eventsDrain_;
|
||||||
|
};
|
||||||
|
typedef ThreadEventQueue<GPUInterface, GPUEvent, GPUEventType, GPU_EVENT_INVALID, GPU_EVENT_SYNC_THREAD, GPU_EVENT_FINISH_EVENT_LOOP> GPUThreadEventQueue;
|
||||||
|
|
||||||
|
class GPUCommon : public GPUThreadEventQueue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GPUCommon();
|
GPUCommon();
|
||||||
virtual ~GPUCommon() {}
|
virtual ~GPUCommon() {}
|
||||||
|
|
||||||
virtual void RunEventsUntil(u64 globalticks);
|
|
||||||
virtual void FinishEventLoop();
|
|
||||||
|
|
||||||
virtual void InterruptStart(int listid);
|
virtual void InterruptStart(int listid);
|
||||||
virtual void InterruptEnd(int listid);
|
virtual void InterruptEnd(int listid);
|
||||||
virtual void SyncEnd(WaitType waitType, int listid, bool wokeThreads);
|
virtual void SyncEnd(WaitType waitType, int listid, bool wokeThreads);
|
||||||
@ -34,7 +127,6 @@ public:
|
|||||||
virtual u32 Continue();
|
virtual u32 Continue();
|
||||||
virtual u32 Break(int mode);
|
virtual u32 Break(int mode);
|
||||||
virtual void ReapplyGfxState();
|
virtual void ReapplyGfxState();
|
||||||
virtual void SyncThread();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// To avoid virtual calls to PreExecuteOp().
|
// To avoid virtual calls to PreExecuteOp().
|
||||||
@ -45,12 +137,9 @@ protected:
|
|||||||
void PopDLQueue();
|
void PopDLQueue();
|
||||||
void CheckDrawSync();
|
void CheckDrawSync();
|
||||||
int GetNextListIndex();
|
int GetNextListIndex();
|
||||||
GPUEvent GetNextEvent();
|
|
||||||
bool HasEvents();
|
|
||||||
void ScheduleEvent(GPUEvent ev);
|
|
||||||
void ProcessDLQueueInternal();
|
void ProcessDLQueueInternal();
|
||||||
void ReapplyGfxStateInternal();
|
void ReapplyGfxStateInternal();
|
||||||
virtual void ProcessEvent(GPUEvent ev) = 0;
|
virtual void ProcessEvent(GPUEvent ev);
|
||||||
|
|
||||||
// Allows early unlocking with a guard. Do not double unlock.
|
// Allows early unlocking with a guard. Do not double unlock.
|
||||||
class easy_guard {
|
class easy_guard {
|
||||||
|
@ -163,6 +163,10 @@ struct GPUEvent {
|
|||||||
GPUInvalidationType type;
|
GPUInvalidationType type;
|
||||||
} invalidate_cache;
|
} invalidate_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
operator GPUEventType() const {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPUInterface
|
class GPUInterface
|
||||||
|
@ -49,5 +49,4 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void FastRunLoop(DisplayList &list);
|
virtual void FastRunLoop(DisplayList &list);
|
||||||
virtual void ProcessEvent(GPUEvent ev) {}
|
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user