mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-15 11:48:33 +00:00
Merge pull request #3075 from unknownbrackets/gpu-thread
Prep work for GE and CPU on separate threads
This commit is contained in:
commit
b8978e49d2
@ -204,7 +204,7 @@ void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
|
||||
Event *ne = GetNewTsEvent();
|
||||
ne->time = globalTimer + cyclesIntoFuture;
|
||||
ne->time = GetTicks() + cyclesIntoFuture;
|
||||
ne->type = event_type;
|
||||
ne->next = 0;
|
||||
ne->userdata = userdata;
|
||||
@ -337,7 +337,10 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
|
||||
}
|
||||
}
|
||||
if (!tsFirst)
|
||||
{
|
||||
tsLast = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
Event *prev = tsFirst;
|
||||
Event *ptr = prev->next;
|
||||
@ -348,6 +351,8 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
|
||||
result = ptr->time - globalTimer;
|
||||
|
||||
prev->next = ptr->next;
|
||||
if (ptr == tsLast)
|
||||
tsLast = prev;
|
||||
FreeTsEvent(ptr);
|
||||
ptr = prev->next;
|
||||
}
|
||||
@ -439,6 +444,7 @@ void RemoveThreadsafeEvent(int event_type)
|
||||
}
|
||||
if (!tsFirst)
|
||||
{
|
||||
tsLast = NULL;
|
||||
return;
|
||||
}
|
||||
Event *prev = tsFirst;
|
||||
@ -448,6 +454,8 @@ void RemoveThreadsafeEvent(int event_type)
|
||||
if (ptr->type == event_type)
|
||||
{
|
||||
prev->next = ptr->next;
|
||||
if (ptr == tsLast)
|
||||
tsLast = prev;
|
||||
FreeTsEvent(ptr);
|
||||
ptr = prev->next;
|
||||
}
|
||||
@ -460,7 +468,7 @@ void RemoveThreadsafeEvent(int event_type)
|
||||
}
|
||||
|
||||
void RemoveAllEvents(int event_type)
|
||||
{
|
||||
{
|
||||
RemoveThreadsafeEvent(event_type);
|
||||
RemoveEvent(event_type);
|
||||
}
|
||||
@ -491,7 +499,7 @@ void MoveEvents()
|
||||
Common::AtomicStoreRelease(hasTsEvents, 0);
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
|
||||
// Move events from async queue into main queue
|
||||
// Move events from async queue into main queue
|
||||
while (tsFirst)
|
||||
{
|
||||
Event *next = tsFirst->next;
|
||||
@ -511,12 +519,14 @@ void MoveEvents()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvanceQuick()
|
||||
void Advance()
|
||||
{
|
||||
int cyclesExecuted = slicelength - currentMIPS->downcount;
|
||||
globalTimer += cyclesExecuted;
|
||||
currentMIPS->downcount = slicelength;
|
||||
|
||||
if (Common::AtomicLoadAcquire(hasTsEvents))
|
||||
MoveEvents();
|
||||
ProcessFifoWaitEvents();
|
||||
|
||||
if (!first)
|
||||
@ -535,14 +545,6 @@ void AdvanceQuick()
|
||||
advanceCallback(cyclesExecuted);
|
||||
}
|
||||
|
||||
void Advance()
|
||||
{
|
||||
if (Common::AtomicLoadAcquire(hasTsEvents))
|
||||
MoveEvents();
|
||||
|
||||
AdvanceQuick();
|
||||
}
|
||||
|
||||
void LogPendingEvents()
|
||||
{
|
||||
Event *ptr = first;
|
||||
|
@ -99,7 +99,6 @@ namespace CoreTiming
|
||||
void RemoveAllEvents(int event_type);
|
||||
bool IsScheduled(int event_type);
|
||||
void Advance();
|
||||
void AdvanceQuick();
|
||||
void MoveEvents();
|
||||
void ProcessFifoWaitEvents();
|
||||
|
||||
|
@ -199,11 +199,11 @@ bool __GeTriggerSync(WaitType waitType, int id, u64 atTicks)
|
||||
s64 future = atTicks - CoreTiming::GetTicks();
|
||||
if (waitType == WAITTYPE_GEDRAWSYNC)
|
||||
{
|
||||
s64 left = CoreTiming::UnscheduleEvent(geSyncEvent, userdata);
|
||||
s64 left = CoreTiming::UnscheduleThreadsafeEvent(geSyncEvent, userdata);
|
||||
if (left > future)
|
||||
future = left;
|
||||
}
|
||||
CoreTiming::ScheduleEvent(future, geSyncEvent, userdata);
|
||||
CoreTiming::ScheduleEvent_Threadsafe(future, geSyncEvent, userdata);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ bool __GeTriggerSync(WaitType waitType, int id, u64 atTicks)
|
||||
bool __GeTriggerInterrupt(int listid, u32 pc, u64 atTicks)
|
||||
{
|
||||
u64 userdata = (u64)listid << 32 | (u64) pc;
|
||||
CoreTiming::ScheduleEvent(atTicks - CoreTiming::GetTicks(), geInterruptEvent, userdata);
|
||||
CoreTiming::ScheduleEvent_Threadsafe(atTicks - CoreTiming::GetTicks(), geInterruptEvent, userdata);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -279,7 +279,7 @@ int sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceGeListUpdateStallAddr(dlid=%i, stalladdr=%08x)", displayListID, stallAddress);
|
||||
hleEatCycles(190);
|
||||
CoreTiming::AdvanceQuick();
|
||||
CoreTiming::Advance();
|
||||
return gpu->UpdateStall(displayListID, stallAddress);
|
||||
}
|
||||
|
||||
|
@ -1169,7 +1169,7 @@ void __KernelIdle()
|
||||
CoreTiming::Idle();
|
||||
// Advance must happen between Idle and Reschedule, so that threads that were waiting for something
|
||||
// that was triggered at the end of the Idle period must get a chance to be scheduled.
|
||||
CoreTiming::AdvanceQuick();
|
||||
CoreTiming::Advance();
|
||||
|
||||
// We must've exited a callback?
|
||||
if (__KernelInCallback())
|
||||
@ -1724,7 +1724,7 @@ void __KernelReSchedule(const char *reason)
|
||||
}
|
||||
|
||||
// Execute any pending events while we're doing scheduling.
|
||||
CoreTiming::AdvanceQuick();
|
||||
CoreTiming::Advance();
|
||||
if (__IsInInterrupt() || __KernelInCallback() || !__KernelIsDispatchEnabled())
|
||||
{
|
||||
reason = "In Interrupt Or Callback";
|
||||
|
@ -60,23 +60,15 @@ namespace SaveState
|
||||
void *cbUserData;
|
||||
};
|
||||
|
||||
static int timer;
|
||||
static bool needsProcess = false;
|
||||
static std::vector<Operation> pending;
|
||||
static std::recursive_mutex mutex;
|
||||
|
||||
void Process(u64 userdata, int cyclesLate);
|
||||
|
||||
void SaveStart::DoState(PointerWrap &p)
|
||||
{
|
||||
// Gotta do CoreTiming first since we'll restore into it.
|
||||
CoreTiming::DoState(p);
|
||||
|
||||
// This save state even saves its own state.
|
||||
p.Do(timer);
|
||||
CoreTiming::RestoreRegisterEvent(timer, "SaveState", Process);
|
||||
p.DoMarker("SaveState");
|
||||
|
||||
Memory::DoState(p);
|
||||
MemoryStick_DoState(p);
|
||||
currentMIPS->DoState(p);
|
||||
@ -96,10 +88,8 @@ namespace SaveState
|
||||
if (Core_IsInactive() && __KernelIsRunning())
|
||||
{
|
||||
// Warning: this may run on a different thread.
|
||||
Process(0, 0);
|
||||
Process();
|
||||
}
|
||||
else if (__KernelIsRunning())
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, timer);
|
||||
else
|
||||
needsProcess = true;
|
||||
}
|
||||
@ -210,8 +200,12 @@ namespace SaveState
|
||||
return copy;
|
||||
}
|
||||
|
||||
void Process(u64 userdata, int cyclesLate)
|
||||
void Process()
|
||||
{
|
||||
if (!needsProcess)
|
||||
return;
|
||||
needsProcess = false;
|
||||
|
||||
if (!__KernelIsRunning())
|
||||
{
|
||||
ERROR_LOG(COMMON, "Savestate failure: Unable to load without kernel, this should never happen.");
|
||||
@ -272,15 +266,9 @@ namespace SaveState
|
||||
|
||||
void Init()
|
||||
{
|
||||
timer = CoreTiming::RegisterEvent("SaveState", Process);
|
||||
// Make sure there's a directory for save slots
|
||||
pspFileSystem.MkDir("ms0:/PSP/PPSSPP_STATE");
|
||||
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
if (needsProcess)
|
||||
{
|
||||
CoreTiming::ScheduleEvent(0, timer);
|
||||
needsProcess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,9 @@ namespace SaveState
|
||||
|
||||
void SaveSlot(int slot, Callback callback, void *cbUserData = 0);
|
||||
void LoadSlot(int slot, Callback callback, void *cbUserData = 0);
|
||||
// Checks whether there's an existing save in the specified slot.
|
||||
bool HasSaveInSlot(int slot);
|
||||
// Returns -1 if there's no newest slot.
|
||||
int GetNewestSlot();
|
||||
|
||||
// Load the specified file into the current state (async.)
|
||||
@ -45,4 +47,7 @@ namespace SaveState
|
||||
// For testing / automated tests. Runs a save state verification pass (async.)
|
||||
// Warning: callback will be called on a different thread.
|
||||
void Verify(Callback callback = 0, void *cbUserData = 0);
|
||||
|
||||
// Check if there's any save stating needing to be done. Normally called once per frame.
|
||||
void Process();
|
||||
};
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "Core/Loaders.h"
|
||||
#include "Core/PSPLoaders.h"
|
||||
#include "Core/ELF/ParamSFO.h"
|
||||
#include "Core/SaveState.h"
|
||||
#include "Common/LogManager.h"
|
||||
|
||||
MetaFileSystem pspFileSystem;
|
||||
@ -151,6 +152,7 @@ void PSP_Shutdown()
|
||||
}
|
||||
|
||||
void PSP_RunLoopUntil(u64 globalticks) {
|
||||
SaveState::Process();
|
||||
mipsr4k.RunLoopUntil(globalticks);
|
||||
}
|
||||
|
||||
|
@ -326,12 +326,6 @@ void GLES_GPU::CopyDisplayToOutput() {
|
||||
|
||||
// Render queue
|
||||
|
||||
u32 GLES_GPU::DrawSync(int mode)
|
||||
{
|
||||
transformDraw_.Flush();
|
||||
return GPUCommon::DrawSync(mode);
|
||||
}
|
||||
|
||||
void GLES_GPU::FastRunLoop(DisplayList &list) {
|
||||
for (; downcount > 0; --downcount) {
|
||||
u32 op = Memory::ReadUnchecked_U32(list.pc);
|
||||
|
@ -38,7 +38,6 @@ public:
|
||||
virtual void InitClear();
|
||||
virtual void PreExecuteOp(u32 op, u32 diff);
|
||||
virtual void ExecuteOp(u32 op, u32 diff);
|
||||
virtual u32 DrawSync(int mode);
|
||||
|
||||
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format);
|
||||
virtual void CopyDisplayToOutput();
|
||||
|
@ -186,6 +186,7 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head)
|
||||
dl.signal = PSP_GE_SIGNAL_NONE;
|
||||
dl.interrupted = false;
|
||||
dl.waitTicks = (u64)-1;
|
||||
dl.interruptsEnabled = interruptsEnabled_;
|
||||
|
||||
if (head) {
|
||||
if (currentList) {
|
||||
@ -720,7 +721,7 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
|
||||
break;
|
||||
}
|
||||
// TODO: Technically, jump/call/ret should generate an interrupt, but before the pc change maybe?
|
||||
if (interruptsEnabled_ && trigger) {
|
||||
if (currentList->interruptsEnabled && trigger) {
|
||||
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted))
|
||||
UpdateState(GPUSTATE_INTERRUPT);
|
||||
}
|
||||
@ -729,7 +730,7 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
|
||||
case GE_CMD_FINISH:
|
||||
switch (currentList->signal) {
|
||||
case PSP_GE_SIGNAL_HANDLER_PAUSE:
|
||||
if (interruptsEnabled_) {
|
||||
if (currentList->interruptsEnabled) {
|
||||
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted))
|
||||
UpdateState(GPUSTATE_INTERRUPT);
|
||||
}
|
||||
@ -744,7 +745,7 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
|
||||
currentList->subIntrToken = prev & 0xFFFF;
|
||||
currentList->state = PSP_GE_DL_STATE_COMPLETED;
|
||||
UpdateState(GPUSTATE_DONE);
|
||||
if (!interruptsEnabled_ || !__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
|
||||
if (!currentList->interruptsEnabled || !__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
|
||||
currentList->waitTicks = startingTicks + cyclesExecuted;
|
||||
busyTicks = std::max(busyTicks, currentList->waitTicks);
|
||||
__GeTriggerSync(WAITTYPE_GELISTSYNC, currentList->id, currentList->waitTicks);
|
||||
|
@ -130,6 +130,7 @@ struct DisplayList
|
||||
int stackptr;
|
||||
bool interrupted;
|
||||
u64 waitTicks;
|
||||
bool interruptsEnabled;
|
||||
};
|
||||
|
||||
enum GPUInvalidationType {
|
||||
|
Loading…
x
Reference in New Issue
Block a user