diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index 77558817a2..a080adb17e 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -204,7 +204,7 @@ void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata { std::lock_guard 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 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; diff --git a/Core/CoreTiming.h b/Core/CoreTiming.h index 8d8281f6c8..77af7078c8 100644 --- a/Core/CoreTiming.h +++ b/Core/CoreTiming.h @@ -99,7 +99,6 @@ namespace CoreTiming void RemoveAllEvents(int event_type); bool IsScheduled(int event_type); void Advance(); - void AdvanceQuick(); void MoveEvents(); void ProcessFifoWaitEvents(); diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index ead492db14..f037b510d0 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -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); } diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 6e2147cb40..6ebc42ca29 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -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"; diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 28a5aea7f7..d015e44ca4 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -60,23 +60,15 @@ namespace SaveState void *cbUserData; }; - static int timer; static bool needsProcess = false; static std::vector 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 guard(mutex); - if (needsProcess) - { - CoreTiming::ScheduleEvent(0, timer); - needsProcess = false; - } } } diff --git a/Core/SaveState.h b/Core/SaveState.h index eb3e075a11..8327122100 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -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(); }; diff --git a/Core/System.cpp b/Core/System.cpp index ad90ca04e5..ea434b71bc 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -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); } diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index ead1c70679..5d7bf4c1d1 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -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); diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index 944c7798a7..1e86e06a76 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -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(); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 9bb123a596..6955339a91 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -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); diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 7dadd1a36b..2847e972e9 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -130,6 +130,7 @@ struct DisplayList int stackptr; bool interrupted; u64 waitTicks; + bool interruptsEnabled; }; enum GPUInvalidationType {