From 55c07bdc73c442f97abe901de1b46b107d23d138 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 16:16:54 -0700 Subject: [PATCH 1/7] Avoid a possible thread sync issue. Could be that it's about to wake listsync, does, and then we wait. --- GPU/GPUCommon.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 1ab389910..c7dd65c59 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -130,7 +130,6 @@ int GPUCommon::ListSync(int listid, int mode) { } if (dl.waitTicks > CoreTiming::GetTicks()) { - guard.unlock(); __KernelWaitCurThread(WAITTYPE_GELISTSYNC, listid, 0, 0, false, "GeListSync"); } return PSP_GE_LIST_COMPLETED; @@ -244,7 +243,6 @@ u32 GPUCommon::DequeueList(int listid) { dlQueue.remove(listid); dls[listid].waitTicks = 0; - guard.unlock(); __KernelTriggerWait(WAITTYPE_GELISTSYNC, listid, 0, "GeListSync"); CheckDrawSync(); @@ -599,7 +597,6 @@ void GPUCommon::ProcessDLQueueInternal() { easy_guard guard(listLock); currentList = NULL; - guard.unlock(); drawCompleteTicks = startingTicks + cyclesExecuted; busyTicks = std::max(busyTicks, drawCompleteTicks); From cfb1d02182961777af6869832ce163fdd6986251 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 17:02:31 -0700 Subject: [PATCH 2/7] Oops, left these here. --- GPU/GPUCommon.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index cfd7daa84..92d607ce8 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -65,13 +65,6 @@ protected: DisplayListQueue dlQueue; recursive_mutex listLock; - std::deque events; - recursive_mutex eventsLock; - recursive_mutex eventsWaitLock; - recursive_mutex eventsDrainLock; - condition_variable eventsWait; - condition_variable eventsDrain; - bool interruptRunning; GPUState gpuState; bool isbreak; From 26c072df514b328ec68be2b765ff58560a01aaeb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 18:13:48 -0700 Subject: [PATCH 3/7] Don't wait directly from GPUCommon, do it in sceGe. Makes debugging a bit easier. --- Core/HLE/sceGe.cpp | 10 ++++++++++ Core/HLE/sceGe.h | 2 ++ GPU/GPUCommon.cpp | 10 ++++------ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index d0d9bee62..6a6dd271e 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -215,6 +215,16 @@ bool __GeTriggerInterrupt(int listid, u32 pc, u64 atTicks) return true; } +void __GeWaitCurrentThread(WaitType type, SceUID waitId, const char *reason) +{ + __KernelWaitCurThread(type, waitId, 0, 0, false, reason); +} + +void __GeTriggerWait(WaitType type, SceUID waitId, const char *reason, bool noSwitch) +{ + __KernelTriggerWait(type, waitId, 0, reason, noSwitch); +} + bool __GeHasPendingInterrupt() { return !ge_pending_cb.empty(); diff --git a/Core/HLE/sceGe.h b/Core/HLE/sceGe.h index e11db00ed..a9b456f00 100644 --- a/Core/HLE/sceGe.h +++ b/Core/HLE/sceGe.h @@ -43,6 +43,8 @@ void __GeDoState(PointerWrap &p); void __GeShutdown(); bool __GeTriggerSync(WaitType waitType, int id, u64 atTicks); bool __GeTriggerInterrupt(int listid, u32 pc, u64 atTicks); +void __GeWaitCurrentThread(WaitType type, SceUID waitId, const char *reason); +void __GeTriggerWait(WaitType type, SceUID waitId, const char *reason, bool noSwitch = false); bool __GeHasPendingInterrupt(); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index c7dd65c59..d794b74b8 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -10,9 +10,7 @@ #include "Core/MemMap.h" #include "Core/Host.h" #include "Core/Reporting.h" -#include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceKernelMemory.h" -#include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceGe.h" GPUCommon::GPUCommon() : @@ -58,7 +56,7 @@ u32 GPUCommon::DrawSync(int mode) { if (mode == 0) { // TODO: What if dispatch / interrupts disabled? if (drawCompleteTicks > CoreTiming::GetTicks()) { - __KernelWaitCurThread(WAITTYPE_GEDRAWSYNC, 1, 0, 0, false, "GeDrawSync"); + __GeWaitCurrentThread(WAITTYPE_GEDRAWSYNC, 1, "GeDrawSync"); } else { for (int i = 0; i < DisplayListMaxCount; ++i) { if (dls[i].state == PSP_GE_DL_STATE_COMPLETED) { @@ -130,7 +128,7 @@ int GPUCommon::ListSync(int listid, int mode) { } if (dl.waitTicks > CoreTiming::GetTicks()) { - __KernelWaitCurThread(WAITTYPE_GELISTSYNC, listid, 0, 0, false, "GeListSync"); + __GeWaitCurrentThread(WAITTYPE_GELISTSYNC, listid, "GeListSync"); } return PSP_GE_LIST_COMPLETED; } @@ -243,7 +241,7 @@ u32 GPUCommon::DequeueList(int listid) { dlQueue.remove(listid); dls[listid].waitTicks = 0; - __KernelTriggerWait(WAITTYPE_GELISTSYNC, listid, 0, "GeListSync"); + __GeTriggerWait(WAITTYPE_GELISTSYNC, listid, "GeListSync"); CheckDrawSync(); @@ -858,7 +856,7 @@ void GPUCommon::InterruptEnd(int listid) { // TODO: Unless the signal handler could change it? if (dl.state == PSP_GE_DL_STATE_COMPLETED || dl.state == PSP_GE_DL_STATE_NONE) { dl.waitTicks = 0; - __KernelTriggerWait(WAITTYPE_GELISTSYNC, listid, 0, "GeListSync", true); + __GeTriggerWait(WAITTYPE_GELISTSYNC, listid, "GeListSync", true); } if (dl.signal == PSP_GE_SIGNAL_HANDLER_PAUSE) From 639ab8306b7865acd084df0a51378f6c3cb1ac7e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 18:45:07 -0700 Subject: [PATCH 4/7] SyncThread before deciding if the fbo is dirty. Fixes fps drops in yet other games with multithreading enabled. --- GPU/GLES/DisplayListInterpreter.cpp | 3 +++ GPU/GPUCommon.h | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index ac7b6d3a8..b07082c2d 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -304,6 +304,9 @@ void GLES_GPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat fo } bool GLES_GPU::FramebufferDirty() { + // Allow it to process fully before deciding if it's dirty. + SyncThread(); + VirtualFramebuffer *vfb = framebufferManager_.GetDisplayFBO(); if (vfb) return vfb->dirtyAfterDisplay; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 92d607ce8..411021ea1 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -28,7 +28,10 @@ public: virtual int ListSync(int listid, int mode); virtual u32 DrawSync(int mode); virtual void DoState(PointerWrap &p); - virtual bool FramebufferDirty() { return true; } + virtual bool FramebufferDirty() { + SyncThread(); + return true; + } virtual u32 Continue(); virtual u32 Break(int mode); virtual void ReapplyGfxState(); From e0f699fd5f4498bd9a8746f0744d1ce295bb721d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 20:03:43 -0700 Subject: [PATCH 5/7] Use a possibly harmless hack to prevent hangs. Not sure where the problem is, but this fixes it pretty consistently for me... seems like lists are somehow not being processed after becoming processable? --- GPU/GLES/DisplayListInterpreter.cpp | 2 ++ GPU/GPUCommon.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index b07082c2d..cea3838d5 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -304,6 +304,8 @@ void GLES_GPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat fo } bool GLES_GPU::FramebufferDirty() { + // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. + ScheduleEvent(GPU_EVENT_PROCESS_QUEUE); // Allow it to process fully before deciding if it's dirty. SyncThread(); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d794b74b8..6d610b576 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -46,6 +46,8 @@ void GPUCommon::PopDLQueue() { } u32 GPUCommon::DrawSync(int mode) { + // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. + ScheduleEvent(GPU_EVENT_PROCESS_QUEUE); // Sync first, because the CPU is usually faster than the emulated GPU. SyncThread(); @@ -93,6 +95,8 @@ void GPUCommon::CheckDrawSync() { } int GPUCommon::ListSync(int listid, int mode) { + // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. + ScheduleEvent(GPU_EVENT_PROCESS_QUEUE); // Sync first, because the CPU is usually faster than the emulated GPU. SyncThread(); From 8786ec74ca426983338c874436ea17e6b4e11029 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 20:54:55 -0700 Subject: [PATCH 6/7] Fix some potential threading probs with SymbolMap. Got some strange crashes. --- Core/Debugger/SymbolMap.cpp | 18 +++++++++++++++--- Core/Debugger/SymbolMap.h | 4 +++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Core/Debugger/SymbolMap.cpp b/Core/Debugger/SymbolMap.cpp index c9a277e98..ea23ca0fe 100644 --- a/Core/Debugger/SymbolMap.cpp +++ b/Core/Debugger/SymbolMap.cpp @@ -52,7 +52,8 @@ static u32 ComputeHash(u32 start, u32 size) void SymbolMap::SortSymbols() { - std::sort(entries.begin(), entries.end()); + lock_guard guard(lock_); + std::sort(entries.begin(), entries.end()); } void SymbolMap::AnalyzeBackwards() @@ -104,6 +105,7 @@ void SymbolMap::AnalyzeBackwards() void SymbolMap::ResetSymbolMap() { + lock_guard guard(lock_); #ifdef BWLINKS for (int i=0; i #include #include @@ -106,6 +107,7 @@ private: std::set uniqueEntries; std::vector entries; std::map entryRanges; + mutable recursive_mutex lock_; }; extern SymbolMap symbolMap; From 169fbeaca6d7a7589683deba61c3cad2db21d02b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 21:27:51 -0700 Subject: [PATCH 7/7] As a safety, especially for win32, cap the wait. --- Core/System.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/System.cpp b/Core/System.cpp index f135fa348..13a6a2d45 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -112,7 +112,7 @@ bool CPU_HasPendingAction() { void CPU_WaitStatus(bool (*pred)()) { cpuThreadLock.lock(); while (!pred()) - cpuThreadCond.wait(cpuThreadLock); + cpuThreadCond.wait_for(cpuThreadLock, 16); cpuThreadLock.unlock(); }