diff --git a/Common/Thread.cpp b/Common/Thread.cpp index 38073a030d..2ca3ec08f8 100644 --- a/Common/Thread.cpp +++ b/Common/Thread.cpp @@ -20,6 +20,8 @@ #ifdef __APPLE__ #include +#elif defined(ANDROID) +#include #elif defined BSD4_4 #include #endif @@ -48,14 +50,14 @@ int CurrentThreadId() #ifdef _WIN32 -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) +bool SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { - SetThreadAffinityMask(thread, mask); + return SetThreadAffinityMask(thread, mask) != 0; } -void SetCurrentThreadAffinity(u32 mask) +bool SetCurrentThreadAffinity(u32 mask) { - SetThreadAffinityMask(GetCurrentThread(), mask); + return SetThreadAffinityMask(GetCurrentThread(), mask) != 0; } // Supporting functions @@ -127,29 +129,36 @@ void EnableCrashingOnCrashes() #else // !WIN32, so must be POSIX threads -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) +bool SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { #ifdef __APPLE__ - thread_policy_set(pthread_mach_thread_np(thread), - THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1); -#elif (defined __linux__ || defined BSD4_4) && !defined(ANDROID) + return thread_policy_set(pthread_mach_thread_np(thread), + THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1) == 0; +#elif defined(ANDROID) || defined(BLACKBERRY) + return false; +#elif (defined __linux__ || defined BSD4_4) cpu_set_t cpu_set; CPU_ZERO(&cpu_set); - for (int i = 0; i != sizeof(mask) * 8; ++i) + for (int i = 0; i != sizeof(mask) * 8; ++i) { if ((mask >> i) & 1) CPU_SET(i, &cpu_set); + } - pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); + return pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set) == 0; #endif + + return false; } -void SetCurrentThreadAffinity(u32 mask) +bool SetCurrentThreadAffinity(u32 mask) { #ifdef BLACKBERRY - ThreadCtl(_NTO_TCTL_RUNMASK, &mask); + return ThreadCtl(_NTO_TCTL_RUNMASK, &mask) != -1; +#elif defined(ANDROID) + return syscall(__NR_sched_setaffinity, gettid(), sizeof(mask), &mask) == 0; #else - SetThreadAffinity(pthread_self(), mask); + return SetThreadAffinity(pthread_self(), mask); #endif } diff --git a/Common/Thread.h b/Common/Thread.h index 0d1d02a0cb..0726bef34c 100644 --- a/Common/Thread.h +++ b/Common/Thread.h @@ -50,8 +50,8 @@ int CurrentThreadId(); // In Windows 7 SP1 or later, stops Windows from swallowing crashes in WndProcs and other callbacks. void EnableCrashingOnCrashes(); -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); -void SetCurrentThreadAffinity(u32 mask); +bool SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); +bool SetCurrentThreadAffinity(u32 mask); class Event { diff --git a/Core/Core.cpp b/Core/Core.cpp index 4bbc10b6a6..53db613311 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -267,6 +267,7 @@ reswitch: #endif break; + case CORE_POWERUP: case CORE_POWERDOWN: case CORE_ERROR: // Exit loop!! diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 963836a392..93bfe00f2d 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -429,7 +429,7 @@ static DirectoryFileSystem *flash0System = NULL; void __IoManagerThread() { setCurrentThreadName("IOThread"); - while (ioManagerThreadEnabled) { + while (ioManagerThreadEnabled && coreState != CORE_ERROR && coreState != CORE_POWERDOWN) { ioManager.RunEventsUntil(CoreTiming::GetTicks() + msToCycles(1000)); } } diff --git a/Core/HW/AsyncIOManager.cpp b/Core/HW/AsyncIOManager.cpp index 53b72308c9..9623a5f621 100644 --- a/Core/HW/AsyncIOManager.cpp +++ b/Core/HW/AsyncIOManager.cpp @@ -41,7 +41,7 @@ bool AsyncIOManager::PopResult(u32 handle, AsyncIOResult &result) { bool AsyncIOManager::WaitResult(u32 handle, AsyncIOResult &result) { lock_guard guard(resultsLock_); ScheduleEvent(IO_EVENT_SYNC); - while (HasEvents() && resultsPending_.find(handle) != resultsPending_.end()) { + while (HasEvents() && ThreadEnabled() && resultsPending_.find(handle) != resultsPending_.end()) { if (PopResult(handle, result)) { return true; } diff --git a/Core/System.cpp b/Core/System.cpp index 4cfae68b9a..6c044bf5ce 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -147,6 +147,7 @@ void CPU_WaitStatus(condition_variable &cond, bool (*pred)()) { void CPU_Shutdown(); void CPU_Init() { + coreState = CORE_POWERUP; currentCPU = &mipsr4k; numCPUs = 1; @@ -335,12 +336,18 @@ void PSP_RunLoopUntil(u64 globalticks) { } if (cpuThread != NULL) { + // Tell the gpu a new frame is about to begin, before we start the CPU. + gpu->SyncBeginFrame(); + cpuThreadUntil = globalticks; if (CPU_NextState(CPU_THREAD_RUNNING, CPU_THREAD_EXECUTE)) { // The CPU doesn't actually respect cpuThreadUntil well, especially when skipping frames. // TODO: Something smarter? Or force CPU to bail periodically? while (!CPU_IsReady()) { - gpu->RunEventsUntil(CoreTiming::GetTicks() + msToCycles(100)); + gpu->RunEventsUntil(CoreTiming::GetTicks() + msToCycles(1000)); + if (coreState != CORE_RUNNING) { + CPU_WaitStatus(cpuThreadReplyCond, &CPU_IsReady); + } } } else { ERROR_LOG(CPU, "Unable to execute CPU run loop, unexpected state: %d", cpuThreadState); diff --git a/Core/System.h b/Core/System.h index 300c8d03c7..4700e13870 100644 --- a/Core/System.h +++ b/Core/System.h @@ -78,6 +78,7 @@ enum CoreState CORE_RUNNING = 0, CORE_NEXTFRAME = 1, CORE_STEPPING, + CORE_POWERUP, CORE_POWERDOWN, CORE_ERROR, }; diff --git a/Core/ThreadEventQueue.h b/Core/ThreadEventQueue.h index b7c2f6ad2f..bbbf7276bd 100644 --- a/Core/ThreadEventQueue.h +++ b/Core/ThreadEventQueue.h @@ -24,13 +24,17 @@ template struct ThreadEventQueue : public B { - ThreadEventQueue() : threadEnabled_(false), eventsRunning_(false) { + ThreadEventQueue() : threadEnabled_(false), eventsRunning_(false), eventsHaveRun_(false) { } void SetThreadEnabled(bool threadEnabled) { threadEnabled_ = threadEnabled; } + bool ThreadEnabled() { + return threadEnabled_; + } + void ScheduleEvent(Event ev) { { lock_guard guard(eventsLock_); @@ -68,6 +72,7 @@ struct ThreadEventQueue : public B { void RunEventsUntil(u64 globalticks) { lock_guard guard(eventsLock_); eventsRunning_ = true; + eventsHaveRun_ = true; do { for (Event ev = GetNextEvent(); EventType(ev) != EVENT_INVALID; ev = GetNextEvent()) { @@ -103,6 +108,11 @@ struct ThreadEventQueue : public B { eventsRunning_ = false; } + void SyncBeginFrame() { + lock_guard guard(eventsLock_); + eventsHaveRun_ = false; + } + // Force ignores coreState. void SyncThread(bool force = false) { if (!threadEnabled_) { @@ -113,14 +123,18 @@ struct ThreadEventQueue : public B { // 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() && eventsRunning_ && (force || coreState == CORE_RUNNING)) { - eventsDrain_.wait_for(eventsLock_, 1); + while (HasEvents() && (eventsRunning_ || !eventsHaveRun_) && (force || coreState == CORE_RUNNING)) { + eventsDrain_.wait_for(eventsLock_, 1000); } } void FinishEventLoop() { if (threadEnabled_) { - ScheduleEvent(EVENT_FINISH); + lock_guard guard(eventsLock_); + // Don't schedule a finish if it's not even running. + if (eventsRunning_) { + ScheduleEvent(EVENT_FINISH); + } } } @@ -131,6 +145,7 @@ protected: private: bool threadEnabled_; bool eventsRunning_; + bool eventsHaveRun_; std::deque events_; recursive_mutex eventsLock_; condition_variable eventsWait_; diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index 4f09ec1fe6..6bdf122d65 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -539,10 +539,7 @@ 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. if (g_Config.bSeparateCPUThread) { - // 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(); } @@ -557,10 +554,7 @@ bool GLES_GPU::FramebufferDirty() { } bool GLES_GPU::FramebufferReallyDirty() { - // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. if (g_Config.bSeparateCPUThread) { - // 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 8fa6751ef1..7293d3bf8e 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -60,10 +60,7 @@ bool GPUCommon::BusyDrawing() { } u32 GPUCommon::DrawSync(int mode) { - // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. if (g_Config.bSeparateCPUThread) { - // 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(); } @@ -119,8 +116,6 @@ void GPUCommon::CheckDrawSync() { int GPUCommon::ListSync(int listid, int mode) { if (g_Config.bSeparateCPUThread) { - // 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(); } diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 82f812ec4d..1e3e2e6796 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -231,6 +231,7 @@ public: virtual void DeviceLost() = 0; virtual void ReapplyGfxState() = 0; virtual void SyncThread(bool force = false) = 0; + virtual void SyncBeginFrame() = 0; virtual u64 GetTickEstimate() = 0; virtual void DoState(PointerWrap &p) = 0;