From 1b838c4403fbd2273237d7129c07c7bcbebedaf2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 09:08:31 -0700 Subject: [PATCH 01/21] Move ThreadEventQueue to its own file. --- CMakeLists.txt | 1 + Core/Core.vcxproj | 1 + Core/Core.vcxproj.filters | 3 + Core/ThreadEventQueue.h | 116 ++++++++++++++++++++++++++++++++++++++ GPU/GPUCommon.h | 97 +------------------------------ 5 files changed, 122 insertions(+), 96 deletions(-) create mode 100644 Core/ThreadEventQueue.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aba6a9d71a..36f71bfb8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -746,6 +746,7 @@ add_library(${CoreLibName} ${CoreLinkType} Core/CwCheat.h Core/HDRemaster.cpp Core/HDRemaster.h + Core/ThreadEventQueue.h Core/Debugger/Breakpoints.cpp Core/Debugger/Breakpoints.h Core/Debugger/DebugInterface.h diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 2ac6129b66..1416bbb4d0 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -486,6 +486,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index ae1395a957..d9861b0b99 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -837,6 +837,9 @@ FileSystems + + Core + diff --git a/Core/ThreadEventQueue.h b/Core/ThreadEventQueue.h new file mode 100644 index 0000000000..11231ea6ac --- /dev/null +++ b/Core/ThreadEventQueue.h @@ -0,0 +1,116 @@ +// Copyright (c) 2013- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "native/base/mutex.h" +#include "Core/CoreTiming.h" +#include + +template +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 events_; + recursive_mutex eventsLock_; + recursive_mutex eventsWaitLock_; + recursive_mutex eventsDrainLock_; + condition_variable eventsWait_; + condition_variable eventsDrain_; +}; \ No newline at end of file diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index b274f7e820..927a50e57a 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -1,103 +1,8 @@ #pragma once -#include "native/base/mutex.h" +#include "Core/ThreadEventQueue.h" #include "GPU/GPUInterface.h" -#include "Core/CoreTiming.h" -#include -template -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 events_; - recursive_mutex eventsLock_; - recursive_mutex eventsWaitLock_; - recursive_mutex eventsDrainLock_; - condition_variable eventsWait_; - condition_variable eventsDrain_; -}; typedef ThreadEventQueue GPUThreadEventQueue; class GPUCommon : public GPUThreadEventQueue From b5ac31bbeaf61f5f6a27cb5a5717fed2a50e430a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 09:27:06 -0700 Subject: [PATCH 02/21] Add locks to all the pspFileSystem methods. --- Core/FileSystems/MetaFileSystem.cpp | 19 +++++++++++++++++++ Core/FileSystems/MetaFileSystem.h | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 00ecb51ad7..9beb4c6a60 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -162,6 +162,7 @@ static bool RealPath(const std::string ¤tDirectory, const std::string &inP IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle) { + lock_guard guard(lock); for (size_t i = 0; i < fileSystems.size(); i++) { if (fileSystems[i].system->OwnsHandle(handle)) @@ -174,6 +175,7 @@ IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle) extern u32 ioErrorCode; bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath, MountPoint **system) { + lock_guard guard(lock); std::string realpath; // Special handling: host0:command.txt (as seen in Super Monkey Ball Adventures, for example) @@ -225,6 +227,7 @@ bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpat void MetaFileSystem::Mount(std::string prefix, IFileSystem *system) { + lock_guard guard(lock); MountPoint x; x.prefix=prefix; x.system=system; @@ -233,6 +236,7 @@ void MetaFileSystem::Mount(std::string prefix, IFileSystem *system) void MetaFileSystem::Shutdown() { + lock_guard guard(lock); current = 6; // Ownership is a bit convoluted. Let's just delete everything once. @@ -254,6 +258,7 @@ void MetaFileSystem::Shutdown() u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) { + lock_guard guard(lock); std::string of; MountPoint *mount; if (MapFilePath(filename, of, &mount)) @@ -268,6 +273,7 @@ u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access, const char PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename) { + lock_guard guard(lock); std::string of; IFileSystem *system; if (MapFilePath(filename, of, &system)) @@ -283,6 +289,7 @@ PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename) bool MetaFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) { + lock_guard guard(lock); std::string of; IFileSystem *system; if (MapFilePath(inpath, of, &system)) { @@ -294,6 +301,7 @@ bool MetaFileSystem::GetHostPath(const std::string &inpath, std::string &outpath std::vector MetaFileSystem::GetDirListing(std::string path) { + lock_guard guard(lock); std::string of; IFileSystem *system; if (MapFilePath(path, of, &system)) @@ -309,11 +317,13 @@ std::vector MetaFileSystem::GetDirListing(std::string path) void MetaFileSystem::ThreadEnded(int threadID) { + lock_guard guard(lock); currentDir.erase(threadID); } int MetaFileSystem::ChDir(const std::string &dir) { + lock_guard guard(lock); // Retain the old path and fail if the arg is 1023 bytes or longer. if (dir.size() >= 1023) return SCE_KERNEL_ERROR_NAMETOOLONG; @@ -348,6 +358,7 @@ int MetaFileSystem::ChDir(const std::string &dir) bool MetaFileSystem::MkDir(const std::string &dirname) { + lock_guard guard(lock); std::string of; IFileSystem *system; if (MapFilePath(dirname, of, &system)) @@ -362,6 +373,7 @@ bool MetaFileSystem::MkDir(const std::string &dirname) bool MetaFileSystem::RmDir(const std::string &dirname) { + lock_guard guard(lock); std::string of; IFileSystem *system; if (MapFilePath(dirname, of, &system)) @@ -376,6 +388,7 @@ bool MetaFileSystem::RmDir(const std::string &dirname) int MetaFileSystem::RenameFile(const std::string &from, const std::string &to) { + lock_guard guard(lock); std::string of; std::string rf; IFileSystem *osystem; @@ -407,6 +420,7 @@ int MetaFileSystem::RenameFile(const std::string &from, const std::string &to) bool MetaFileSystem::RemoveFile(const std::string &filename) { + lock_guard guard(lock); std::string of; IFileSystem *system; if (MapFilePath(filename, of, &system)) @@ -421,6 +435,7 @@ bool MetaFileSystem::RemoveFile(const std::string &filename) void MetaFileSystem::CloseFile(u32 handle) { + lock_guard guard(lock); IFileSystem *sys = GetHandleOwner(handle); if (sys) sys->CloseFile(handle); @@ -428,6 +443,7 @@ void MetaFileSystem::CloseFile(u32 handle) size_t MetaFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) { + lock_guard guard(lock); IFileSystem *sys = GetHandleOwner(handle); if (sys) return sys->ReadFile(handle,pointer,size); @@ -437,6 +453,7 @@ size_t MetaFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) size_t MetaFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) { + lock_guard guard(lock); IFileSystem *sys = GetHandleOwner(handle); if (sys) return sys->WriteFile(handle,pointer,size); @@ -446,6 +463,7 @@ size_t MetaFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) size_t MetaFileSystem::SeekFile(u32 handle, s32 position, FileMove type) { + lock_guard guard(lock); IFileSystem *sys = GetHandleOwner(handle); if (sys) return sys->SeekFile(handle,position,type); @@ -455,6 +473,7 @@ size_t MetaFileSystem::SeekFile(u32 handle, s32 position, FileMove type) void MetaFileSystem::DoState(PointerWrap &p) { + lock_guard guard(lock); p.Do(current); // Save/load per-thread current directory map diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index 7928851653..abf4b5a880 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -17,7 +17,8 @@ #pragma once -#include "FileSystem.h" +#include "native/base/mutex.h" +#include "Core/FileSystems/FileSystem.h" class MetaFileSystem : public IHandleAllocator, public IFileSystem { @@ -34,6 +35,7 @@ private: currentDir_t currentDir; std::string startingDirectory; + recursive_mutex lock; public: MetaFileSystem() @@ -94,6 +96,7 @@ public: // TODO: void IoCtl(...) void SetStartingDirectory(const std::string &dir) { + lock_guard guard(lock); startingDirectory = dir; } }; From 333cc33efbdd6312865bbea23cbea9a378fdcc71 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 09:54:14 -0700 Subject: [PATCH 03/21] Handle OpenFile() errors in a more threadsafe way. Probably needs better cleanup though. --- Core/FileSystems/MetaFileSystem.cpp | 12 ++++++++++-- Core/FileSystems/MetaFileSystem.h | 4 +++- Core/HLE/sceIo.cpp | 20 +++++++++----------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 9beb4c6a60..29c322b99d 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -172,7 +172,6 @@ IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle) return 0; } -extern u32 ioErrorCode; bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath, MountPoint **system) { lock_guard guard(lock); @@ -195,7 +194,7 @@ bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpat //Attempt to emulate SCE_KERNEL_ERROR_NOCWD / 8002032C: may break things requiring fixes elsewhere if (inpath.find(':') == std::string::npos /* means path is relative */) { - ioErrorCode = SCE_KERNEL_ERROR_NOCWD; + lastOpenError = SCE_KERNEL_ERROR_NOCWD; WARN_LOG_REPORT(HLE, "Path is relative, but current directory not set for thread %i. returning 8002032C(SCE_KERNEL_ERROR_NOCWD) instead.", currentThread); } } @@ -256,9 +255,18 @@ void MetaFileSystem::Shutdown() startingDirectory = ""; } +u32 MetaFileSystem::OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename) +{ + lock_guard guard(lock); + u32 h = OpenFile(filename, access, devicename); + error = lastOpenError; + return h; +} + u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) { lock_guard guard(lock); + lastOpenError = 0; std::string of; MountPoint *mount; if (MapFilePath(filename, of, &mount)) diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index abf4b5a880..8de7dd4e87 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -35,6 +35,7 @@ private: currentDir_t currentDir; std::string startingDirectory; + int lastOpenError; recursive_mutex lock; public: @@ -74,7 +75,8 @@ public: bool GetHostPath(const std::string &inpath, std::string &outpath); std::vector GetDirListing(std::string path); - u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL); + u32 OpenFile(std::string filename, FileAccess access, const char *devicename = NULL); + u32 OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename = NULL); void CloseFile(u32 handle); size_t ReadFile(u32 handle, u8 *pointer, s64 size); size_t WriteFile(u32 handle, const u8 *pointer, s64 size); diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 4766923377..5f6e4c466a 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -103,8 +103,6 @@ const int PSP_MIN_FD = 4; static int asyncNotifyEvent = -1; static SceUID fds[PSP_COUNT_FDS]; -u32 ioErrorCode = 0; - #define SCE_STM_FDIR 0x1000 #define SCE_STM_FREG 0x2000 #define SCE_STM_FLNK 0x4000 @@ -782,7 +780,7 @@ u32 sceIoLseek32Async(int id, int offset, int whence) { return 0; } -FileNode *__IoOpen(const char* filename, int flags, int mode) { +FileNode *__IoOpen(int &error, const char* filename, int flags, int mode) { //memory stick filename int access = FILEACCESS_NONE; if (flags & O_RDONLY) @@ -796,9 +794,7 @@ FileNode *__IoOpen(const char* filename, int flags, int mode) { PSPFileInfo info = pspFileSystem.GetFileInfo(filename); - ioErrorCode = 0; - - u32 h = pspFileSystem.OpenFile(filename, (FileAccess) access); + u32 h = pspFileSystem.OpenWithError(error, filename, (FileAccess) access); if (h == 0) { return NULL; } @@ -821,11 +817,12 @@ u32 sceIoOpen(const char* filename, int flags, int mode) { if (!__KernelIsDispatchEnabled()) return -1; - FileNode *f = __IoOpen(filename, flags, mode); + int error; + FileNode *f = __IoOpen(error, filename, flags, mode); if (f == NULL) { - //Timing is not accurate, aiming low for now. - if (ioErrorCode == SCE_KERNEL_ERROR_NOCWD) + // Timing is not accurate, aiming low for now. + if (error == SCE_KERNEL_ERROR_NOCWD) { ERROR_LOG(HLE, "SCE_KERNEL_ERROR_NOCWD=sceIoOpen(%s, %08x, %08x) - no current working directory", filename, flags, mode); return hleDelayResult(SCE_KERNEL_ERROR_NOCWD , "no cwd", 10000); @@ -1294,7 +1291,8 @@ u32 sceIoOpenAsync(const char *filename, int flags, int mode) if (!__KernelIsDispatchEnabled()) sceKernelResumeDispatchThread(1); - FileNode *f = __IoOpen(filename, flags, mode); + int error; + FileNode *f = __IoOpen(error, filename, flags, mode); int fd; // We have to return an fd here, which may have been destroyed when we reach Wait if it failed. @@ -1305,7 +1303,7 @@ u32 sceIoOpenAsync(const char *filename, int flags, int mode) f = new FileNode(); f->handle = kernelObjects.Create(f); f->fullpath = filename; - f->asyncResult = ERROR_ERRNO_FILE_NOT_FOUND; + f->asyncResult = error == 0 ? ERROR_ERRNO_FILE_NOT_FOUND : error; f->closePending = true; fd = __IoAllocFd(f); From 00ae8114467a13d6357d5934aa22a9187260d61d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 13:50:21 -0700 Subject: [PATCH 04/21] Shutdown the filesystem after HLE. --- Core/System.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Core/System.cpp b/Core/System.cpp index 6a005498d6..4af24e2ce3 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -116,6 +116,8 @@ void CPU_WaitStatus(bool (*pred)()) { cpuThreadLock.unlock(); } +void CPU_Shutdown(); + void CPU_Init() { currentCPU = &mipsr4k; numCPUs = 1; @@ -157,12 +159,7 @@ void CPU_Init() { // Why did we check for CORE_POWERDOWN here? if (!LoadFile(filename, &coreParameter.errorString)) { - pspFileSystem.Shutdown(); - CoreTiming::Shutdown(); - __KernelShutdown(); - HLEShutdown(); - host->ShutdownSound(); - Memory::Shutdown(); + CPU_Shutdown(); coreParameter.fileToStart = ""; CPU_SetState(CPU_THREAD_NOT_RUNNING); return; @@ -176,20 +173,18 @@ void CPU_Init() { } void CPU_Shutdown() { - pspFileSystem.Shutdown(); - - CoreTiming::Shutdown(); - if (g_Config.bAutoSaveSymbolMap) { host->SaveSymbolMap(); } + CoreTiming::Shutdown(); + __KernelShutdown(); + HLEShutdown(); if (coreParameter.enableSound) { host->ShutdownSound(); mixer = 0; // deleted in ShutdownSound } - __KernelShutdown(); - HLEShutdown(); + pspFileSystem.Shutdown(); Memory::Shutdown(); currentCPU = 0; } From 54ca1e212fec10e915098761d72d15e6f18bca50 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 14:02:18 -0700 Subject: [PATCH 05/21] Unmount filesystems during HLE shutdown. Fixes #3115. --- Core/FileSystems/MetaFileSystem.cpp | 14 ++++++++++++-- Core/FileSystems/MetaFileSystem.h | 7 ++++++- Core/HLE/sceIo.cpp | 30 ++++++++++++++++++++++------- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 29c322b99d..9b2076f4cd 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include "Common/StringUtils.h" #include "Core/FileSystems/MetaFileSystem.h" #include "Core/HLE/sceKernelThread.h" @@ -228,11 +229,20 @@ void MetaFileSystem::Mount(std::string prefix, IFileSystem *system) { lock_guard guard(lock); MountPoint x; - x.prefix=prefix; - x.system=system; + x.prefix = prefix; + x.system = system; fileSystems.push_back(x); } +void MetaFileSystem::Unmount(std::string prefix, IFileSystem *system) +{ + lock_guard guard(lock); + MountPoint x; + x.prefix = prefix; + x.system = system; + fileSystems.erase(std::remove(fileSystems.begin(), fileSystems.end(), x), fileSystems.end()); +} + void MetaFileSystem::Shutdown() { lock_guard guard(lock); diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index 8de7dd4e87..b7d99ebc51 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -28,6 +28,11 @@ private: { std::string prefix; IFileSystem *system; + + bool operator == (const MountPoint &other) const + { + return prefix == other.prefix && system == other.system; + } }; std::vector fileSystems; @@ -45,7 +50,7 @@ public: } void Mount(std::string prefix, IFileSystem *system); - void Unmount(IFileSystem *system); + void Unmount(std::string prefix, IFileSystem *system); void ThreadEnded(int threadID); diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 5f6e4c466a..f34ff7d9c6 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -292,6 +292,13 @@ void __IoAsyncNotify(u64 userdata, int cyclesLate) { } } +static DirectoryFileSystem *memstickSystem = NULL; +#ifdef ANDROID +static VFSFileSystem *flash0System = NULL; +#else +static DirectoryFileSystem *flash0System = NULL; +#endif + void __IoInit() { INFO_LOG(HLE, "Starting up I/O..."); @@ -303,16 +310,16 @@ void __IoInit() { std::string flash0path; GetSysDirectories(memstickpath, flash0path); - DirectoryFileSystem *memstick = new DirectoryFileSystem(&pspFileSystem, memstickpath); + memstickSystem = new DirectoryFileSystem(&pspFileSystem, memstickpath); #ifdef ANDROID - VFSFileSystem *flash0 = new VFSFileSystem(&pspFileSystem, "flash0"); + flash0System = new VFSFileSystem(&pspFileSystem, "flash0"); #else - DirectoryFileSystem *flash0 = new DirectoryFileSystem(&pspFileSystem, flash0path); + flash0System = new DirectoryFileSystem(&pspFileSystem, flash0path); #endif - pspFileSystem.Mount("ms0:", memstick); - pspFileSystem.Mount("fatms0:", memstick); - pspFileSystem.Mount("fatms:", memstick); - pspFileSystem.Mount("flash0:", flash0); + pspFileSystem.Mount("ms0:", memstickSystem); + pspFileSystem.Mount("fatms0:", memstickSystem); + pspFileSystem.Mount("fatms:", memstickSystem); + pspFileSystem.Mount("flash0:", flash0System); __KernelListenThreadEnd(&TellFsThreadEnded); @@ -326,6 +333,15 @@ void __IoDoState(PointerWrap &p) { } void __IoShutdown() { + pspFileSystem.Unmount("ms0:", memstickSystem); + pspFileSystem.Unmount("fatms0:", memstickSystem); + pspFileSystem.Unmount("fatms:", memstickSystem); + pspFileSystem.Unmount("flash0:", flash0System); + + delete memstickSystem; + memstickSystem = NULL; + delete flash0System; + flash0System = NULL; } u32 __IoGetFileHandleFromId(u32 id, u32 &outError) From f68ebfe230a6304d977ab8b5c32c865978ad7c8f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 14:04:23 -0700 Subject: [PATCH 06/21] Fix savestates while not running. Fixes #2791. --- Core/SaveState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index d015e44ca4..5e48f54417 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -88,6 +88,7 @@ namespace SaveState if (Core_IsInactive() && __KernelIsRunning()) { // Warning: this may run on a different thread. + needsProcess = true; Process(); } else From 0dac2b47833c8065605e1ad808b14dded9f335f7 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 10 Aug 2013 23:04:23 +0200 Subject: [PATCH 07/21] Update native, minor UI stuff and cleanups --- .gitignore | 1 + Core/ELF/PBPReader.cpp | 2 +- Core/MIPS/x86/Jit.cpp | 12 ++---------- UI/MainScreen.cpp | 2 ++ UI/MiscScreens.cpp | 5 ++++- native | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 7e50d2692b..ef982616ff 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ *.suo *.aps *.exp +*.qdact Debug Release Windows/x64 diff --git a/Core/ELF/PBPReader.cpp b/Core/ELF/PBPReader.cpp index 0e14d7bfc0..1b233a67ad 100644 --- a/Core/ELF/PBPReader.cpp +++ b/Core/ELF/PBPReader.cpp @@ -38,7 +38,7 @@ PBPReader::PBPReader(const char *filename) : header_() { return; } - INFO_LOG(LOADER, "Loading PBP, version = %08x", header_.version); + DEBUG_LOG(LOADER, "Loading PBP, version = %08x", header_.version); } u8 *PBPReader::GetSubFile(PBPSubFile file, size_t *outSize) { diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index a0aa56a8db..a57d84921f 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -278,11 +278,7 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b) fpr.Start(mips_, analysis); js.numInstructions = 0; - while (js.compiling) - { - if (js.prefixS & 0xF0000000) { - ERROR_LOG(CPU, "GARBAGE prefix S : %08x at %08x : %s", js.prefixS, js.compilerPC, currentMIPS->DisasmAt(js.compilerPC)); - } + while (js.compiling) { // Jit breakpoints are quite fast, so let's do them in release too. CheckJitBreakpoint(js.compilerPC, 0); @@ -291,8 +287,7 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b) MIPSCompileOp(inst); - if (js.afterOp & JitState::AFTER_CORE_STATE) - { + if (js.afterOp & JitState::AFTER_CORE_STATE) { // TODO: Save/restore? FlushAll(); @@ -314,9 +309,6 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b) js.compilerPC += 4; js.numInstructions++; } - if (js.prefixS & 0xF0000000) { - ERROR_LOG(CPU, "GARBAGE prefix S : %08x at %08x : %s", js.prefixS, js.compilerPC, currentMIPS->DisasmAt(js.compilerPC)); - } b->codeSize = (u32)(GetCodePtr() - b->normalEntry); NOP(); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 6c6970a8b2..261cc619a1 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -122,6 +122,8 @@ void GameButton::Draw(UIContext &dc) { dropsize = 3; y += txOffset * 2; } + dc.Draw()->Flush(); + dc.RebindTexture(); dc.Draw()->DrawImage4Grid(I_DROP_SHADOW, x - dropsize, y, x+w + dropsize, y+h+dropsize*1.5, alphaMul(shadowColor, 0.5f), 1.0f); dc.Draw()->Flush(); } diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 82886c5d33..877fc81b41 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -108,6 +108,7 @@ NewLanguageScreen::NewLanguageScreen() : ListPopupScreen("Language") { VFSGetFileListing("lang", &langs_, "ini"); #endif std::vector listing; + int selected = -1; for (size_t i = 0; i < langs_.size(); i++) { // Skip README if (langs_[i].name.find("README") != std::string::npos) { @@ -129,10 +130,12 @@ NewLanguageScreen::NewLanguageScreen() : ListPopupScreen("Language") { buttonTitle = langValuesMapping[code].first; } } + if (g_Config.languageIni == code) + selected = i; listing.push_back(buttonTitle); } - adaptor_ = UI::StringVectorListAdaptor(listing, 0); + adaptor_ = UI::StringVectorListAdaptor(listing, selected); } void NewLanguageScreen::OnCompleted() { diff --git a/native b/native index 44c239ef18..0c8692bc44 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 44c239ef182e2904aada4b1424165a1adf45b2cf +Subproject commit 0c8692bc44715aa64b0e592c0001413fe0b80b1c From 3bba464451daebf6fe1aaa4d347e011436ca5c11 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 14:04:42 -0700 Subject: [PATCH 08/21] Add one more missing sceCcc func. --- Core/HLE/sceCcc.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Core/HLE/sceCcc.cpp b/Core/HLE/sceCcc.cpp index a47a95fecf..ebd41a6b61 100644 --- a/Core/HLE/sceCcc.cpp +++ b/Core/HLE/sceCcc.cpp @@ -431,6 +431,12 @@ int sceCccIsValidJIS(u32 c) return c != 0; } +int sceCccIsValidUnicode(u32 c) +{ + WARN_LOG(HLE, "UNIMPL sceCccIsValidUnicode(%08x)", c); + return c != 0; +} + u32 sceCccSetErrorCharUTF8(u32 c) { DEBUG_LOG(HLE, "sceCccSetErrorCharUTF8(%08x)", c); @@ -507,6 +513,7 @@ const HLEFunction sceCcc[] = {0x76e33e9c, WrapI_U, "sceCccIsValidUCS2"}, {0xd2b18485, WrapI_U, "sceCccIsValidUCS4"}, {0xa2d5d209, WrapI_U, "sceCccIsValidJIS"}, + {0xbd11eef3, WrapI_U, "sceCccIsValidUnicode"}, {0x17e1d813, WrapU_U, "sceCccSetErrorCharUTF8"}, {0xb8476cf4, WrapU_U, "sceCccSetErrorCharUTF16"}, {0xc56949ad, WrapU_U, "sceCccSetErrorCharSJIS"}, From a517b8d53f59305fdcf3dbc5946d7cabb261a64b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 10 Aug 2013 23:25:55 +0200 Subject: [PATCH 09/21] Fix #3117 (by reverting part of a previous change), plus a minor change that might speed GT up. --- Core/MIPS/MIPSTables.cpp | 4 ++-- GPU/GLES/DisplayListInterpreter.cpp | 2 +- GPU/GeDisasm.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 3f2c9d4a66..f389a05f1f 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -506,8 +506,8 @@ const MIPSInstruction tableVFPU3[8] = //011011 xxx INSTR("vmax",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_Vminmax, IS_VFPU|OUT_EAT_PREFIX), {-2}, INSTR("vscmp",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vscmp, IS_VFPU|OUT_EAT_PREFIX), - INSTR("vsge",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_Vsge, IS_VFPU|OUT_EAT_PREFIX), - INSTR("vslt",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_Vslt, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsge",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vsge, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vslt",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vslt, IS_VFPU|OUT_EAT_PREFIX), }; const MIPSInstruction tableVFPU4Jump[32] = //110100 xxxxx diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 96b5919a2b..ac7b6d3a89 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -115,7 +115,7 @@ static const u8 flushOnChangedBeforeCommandList[] = { GE_CMD_CLUTFORMAT, GE_CMD_TEXFILTER, GE_CMD_TEXWRAP, - GE_CMD_TEXLEVEL, + // GE_CMD_TEXLEVEL, // we don't support this anyway, no need to flush. GE_CMD_TEXFUNC, GE_CMD_TEXENVCOLOR, //GE_CMD_TEXFLUSH, diff --git a/GPU/GeDisasm.cpp b/GPU/GeDisasm.cpp index 441244b9ee..7c00212676 100644 --- a/GPU/GeDisasm.cpp +++ b/GPU/GeDisasm.cpp @@ -896,9 +896,9 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) { case GE_CMD_TEXLEVEL: if (data & ~0xFF0003) - sprintf(buffer, "TexWrap mode: %i Offset: %i (extra %x)", data&3, data >> 16, data); + sprintf(buffer, "TexLevel mode: %i Offset: %i (extra %x)", data&3, data >> 16, data); else - sprintf(buffer, "TexWrap mode: %i Offset: %i", data&3, data >> 16); + sprintf(buffer, "TexLevel mode: %i Offset: %i", data&3, data >> 16); break; case GE_CMD_FOG1: From 4c6006190fcd5cd25e456b7347148a26f9924555 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 10 Aug 2013 23:32:12 +0200 Subject: [PATCH 10/21] Of course, found the real bug causing #3117 immediately after the revert. Fixed. --- Core/MIPS/MIPSTables.cpp | 4 ++-- Core/MIPS/x86/CompVFPU.cpp | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index f389a05f1f..3f2c9d4a66 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -506,8 +506,8 @@ const MIPSInstruction tableVFPU3[8] = //011011 xxx INSTR("vmax",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_Vminmax, IS_VFPU|OUT_EAT_PREFIX), {-2}, INSTR("vscmp",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vscmp, IS_VFPU|OUT_EAT_PREFIX), - INSTR("vsge",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vsge, IS_VFPU|OUT_EAT_PREFIX), - INSTR("vslt",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vslt, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsge",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_Vsge, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vslt",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_Vslt, IS_VFPU|OUT_EAT_PREFIX), }; const MIPSInstruction tableVFPU4Jump[32] = //110100 xxxxx diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index f50ae71eed..9ba153051e 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -679,13 +679,12 @@ void Jit::Comp_VecDo3(u32 op) { } break; case 27: //VFPU3 - switch ((op >> 23) & 3) { + switch ((op >> 23) & 7) { case 2: // vmin case 3: // vmax break; case 6: // vsge case 7: // vslt - DISABLE; // Something is wrong :/ MOVSS(XMM0, M((void *)&one)); break; default: @@ -759,7 +758,7 @@ void Jit::Comp_VecDo3(u32 op) { } break; case 27: //VFPU3 - switch ((op >> 23) & 3) + switch ((op >> 23) & 7) { case 2: // vmin MINSS(tempxregs[i], fpr.V(tregs[i])); From 89ddbb51bb79b0b31d80f1056140f04ef337f3b6 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 10 Aug 2013 23:37:48 +0200 Subject: [PATCH 11/21] Oops, XMM0 might be taken by temps. Also, s/GC_ALIGN16/MEMORY_ALIGN16 --- Common/Common.h | 4 ++-- Core/MIPS/x86/CompFPU.cpp | 8 ++++---- Core/MIPS/x86/CompVFPU.cpp | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Common/Common.h b/Common/Common.h index 5dafca92bc..7e5597aead 100644 --- a/Common/Common.h +++ b/Common/Common.h @@ -96,7 +96,7 @@ private: #define CHECK_HEAP_INTEGRITY() // Alignment - #define GC_ALIGNED16(x) __declspec(align(16)) x + #define MEMORY_ALIGNED16(x) __declspec(align(16)) x #define GC_ALIGNED32(x) __declspec(align(32)) x #define GC_ALIGNED64(x) __declspec(align(64)) x #define GC_ALIGNED128(x) __declspec(align(128)) x @@ -137,7 +137,7 @@ private: #endif #define __forceinline inline __attribute__((always_inline)) -#define GC_ALIGNED16(x) __attribute__((aligned(16))) x +#define MEMORY_ALIGNED16(x) __attribute__((aligned(16))) x #define GC_ALIGNED32(x) __attribute__((aligned(32))) x #define GC_ALIGNED64(x) __attribute__((aligned(64))) x #define GC_ALIGNED128(x) __attribute__((aligned(128))) x diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index 09598743dd..336c864565 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -87,7 +87,7 @@ void Jit::Comp_FPU3op(u32 op) } } -static u32 GC_ALIGNED16(ssLoadStoreTemp); +static u32 MEMORY_ALIGNED16(ssLoadStoreTemp); void Jit::Comp_FPULS(u32 op) { @@ -147,9 +147,9 @@ void Jit::Comp_FPULS(u32 op) } } -static const u64 GC_ALIGNED16(ssOneBits[2]) = {0x0000000100000001ULL, 0x0000000100000001ULL}; -static const u64 GC_ALIGNED16(ssSignBits2[2]) = {0x8000000080000000ULL, 0x8000000080000000ULL}; -static const u64 GC_ALIGNED16(ssNoSignMask[2]) = {0x7FFFFFFF7FFFFFFFULL, 0x7FFFFFFF7FFFFFFFULL}; +static const u64 MEMORY_ALIGNED16(ssOneBits[2]) = {0x0000000100000001ULL, 0x0000000100000001ULL}; +static const u64 MEMORY_ALIGNED16(ssSignBits2[2]) = {0x8000000080000000ULL, 0x8000000080000000ULL}; +static const u64 MEMORY_ALIGNED16(ssNoSignMask[2]) = {0x7FFFFFFF7FFFFFFFULL, 0x7FFFFFFF7FFFFFFFULL}; static u32 ssCompareTemp; diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 9ba153051e..93201d1fe6 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -57,8 +57,9 @@ static const float one = 1.0f; static const float minus_one = -1.0f; static const float zero = 0.0f; -const u32 GC_ALIGNED16( noSignMask[4] ) = {0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF}; -const u32 GC_ALIGNED16( signBitLower[4] ) = {0x80000000, 0, 0, 0}; +const u32 MEMORY_ALIGNED16( noSignMask[4] ) = {0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF}; +const u32 MEMORY_ALIGNED16( signBitLower[4] ) = {0x80000000, 0, 0, 0}; +const float MEMORY_ALIGNED16( oneOneOneOne[4] ) = {1.0f, 1.0f, 1.0f, 1.0f}; void Jit::Comp_VPFX(u32 op) { @@ -195,7 +196,7 @@ bool IsOverlapSafe(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] return IsOverlapSafeAllowS(dreg, di, sn, sregs, tn, tregs) && sregs[di] != dreg; } -static u32 GC_ALIGNED16(ssLoadStoreTemp); +static u32 MEMORY_ALIGNED16(ssLoadStoreTemp); void Jit::Comp_SV(u32 op) { CONDITIONAL_DISABLE; @@ -685,7 +686,6 @@ void Jit::Comp_VecDo3(u32 op) { break; case 6: // vsge case 7: // vslt - MOVSS(XMM0, M((void *)&one)); break; default: DISABLE; @@ -768,11 +768,11 @@ void Jit::Comp_VecDo3(u32 op) { break; case 6: // vsge CMPNLTSS(tempxregs[i], fpr.V(tregs[i])); - ANDPS(tempxregs[i], R(XMM0)); + ANDPS(tempxregs[i], M((void *)&oneOneOneOne)); break; case 7: // vslt CMPLTSS(tempxregs[i], fpr.V(tregs[i])); - ANDPS(tempxregs[i], R(XMM0)); + ANDPS(tempxregs[i], M((void *)&oneOneOneOne)); break; } break; From 408e570469fd81965b5a5ac22d96b9a4a5be2ef5 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 10 Aug 2013 23:41:29 +0200 Subject: [PATCH 12/21] Typo fix --- Core/MIPS/ARM/ArmCompVFPU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 4cb1f90a8c..afe85e8489 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -655,7 +655,7 @@ namespace MIPSComp break; // Unfortunately there is no VMIN/VMAX on ARM without NEON. case 27: //VFPU3 - switch ((op >> 23) & 3) { + switch ((op >> 23) & 7) { case 2: // vmin VCMP(fpr.V(sregs[i]), fpr.V(tregs[i])); VMRS_APSR(); From abc396cbe1e80fce48edad5633db7241ceb80455 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 15:16:49 -0700 Subject: [PATCH 13/21] Sync the GPU thread on list/draw sync. Otherwise, the CPU gets ahead (inside the frame) and games get confused. I don't think there's any good workaround to avoid this. --- GPU/GPUCommon.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index e831bf380a..1ab3899105 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -48,6 +48,9 @@ void GPUCommon::PopDLQueue() { } u32 GPUCommon::DrawSync(int mode) { + // Sync first, because the CPU is usually faster than the emulated GPU. + SyncThread(); + easy_guard guard(listLock); if (mode < 0 || mode > 1) return SCE_KERNEL_ERROR_INVALID_MODE; @@ -92,6 +95,9 @@ void GPUCommon::CheckDrawSync() { } int GPUCommon::ListSync(int listid, int mode) { + // Sync first, because the CPU is usually faster than the emulated GPU. + SyncThread(); + easy_guard guard(listLock); if (listid < 0 || listid >= DisplayListMaxCount) return SCE_KERNEL_ERROR_INVALID_ID; From 55c07bdc73c442f97abe901de1b46b107d23d138 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 16:16:54 -0700 Subject: [PATCH 14/21] 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 1ab3899105..c7dd65c592 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 15/21] Oops, left these here. --- GPU/GPUCommon.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index cfd7daa844..92d607ce85 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 16/21] 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 d0d9bee62d..6a6dd271e2 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 e11db00ed2..a9b456f009 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 c7dd65c592..d794b74b87 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 17/21] 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 ac7b6d3a89..b07082c2d8 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 92d607ce85..411021ea1f 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 18/21] 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 b07082c2d8..cea3838d5b 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 d794b74b87..6d610b5764 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 19/21] 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 c9a277e98b..ea23ca0fe2 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 20/21] 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 f135fa3487..13a6a2d459 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(); } From 82aca253e43274a9aac4bbe156af126dec5a39e8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Aug 2013 23:19:03 -0700 Subject: [PATCH 21/21] Add a few more OUT_EAT_PREFIX flags. Based on testing the instructions individually. Cuts a few cases in God Eater Burst where instructions bailed out of jit. --- Core/MIPS/MIPSTables.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 3f2c9d4a66..352c37286c 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -486,15 +486,15 @@ const MIPSInstruction tableVFPU0[8] = INSTR("vdiv",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU|OUT_EAT_PREFIX), }; -const MIPSInstruction tableVFPU1[8] = +const MIPSInstruction tableVFPU1[8] = // 011001 xxx { INSTR("vmul",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU|OUT_EAT_PREFIX), INSTR("vdot",&Jit::Comp_VDot, Dis_VectorDot, Int_VDot, IS_VFPU|OUT_EAT_PREFIX), INSTR("vscl",&Jit::Comp_VScl, Dis_VScl, Int_VScl, IS_VFPU|OUT_EAT_PREFIX), {-2}, INSTR("vhdp",&Jit::Comp_VHdp, Dis_Generic, Int_VHdp, IS_VFPU|OUT_EAT_PREFIX), - INSTR("vcrs",&Jit::Comp_VCrs, Dis_Vcrs, Int_Vcrs, IS_VFPU), - INSTR("vdet",&Jit::Comp_VDet, Dis_Generic, Int_Vdet, IS_VFPU), + INSTR("vcrs",&Jit::Comp_VCrs, Dis_Vcrs, Int_Vcrs, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vdet",&Jit::Comp_VDet, Dis_Generic, Int_Vdet, IS_VFPU|OUT_EAT_PREFIX), {-2}, }; @@ -566,10 +566,10 @@ const MIPSInstruction tableVFPU7[32] = {-2}, INSTR("vlgb", &Jit::Comp_Generic, Dis_Generic, Int_Vlgb, IS_VFPU), //24 - INSTR("vuc2i", &Jit::Comp_Vx2i, Dis_Vs2i, Int_Vx2i, IS_VFPU), // Seen in BraveStory, initialization 110100 00001110000 000 0001 0000 0000 - INSTR("vc2i", &Jit::Comp_Vx2i, Dis_Vs2i, Int_Vx2i, IS_VFPU), - INSTR("vus2i", &Jit::Comp_Vx2i, Dis_Vs2i, Int_Vx2i, IS_VFPU), - INSTR("vs2i", &Jit::Comp_Vx2i, Dis_Vs2i, Int_Vx2i, IS_VFPU), + INSTR("vuc2i", &Jit::Comp_Vx2i, Dis_Vs2i, Int_Vx2i, IS_VFPU|OUT_EAT_PREFIX), // Seen in BraveStory, initialization 110100 00001110000 000 0001 0000 0000 + INSTR("vc2i", &Jit::Comp_Vx2i, Dis_Vs2i, Int_Vx2i, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vus2i", &Jit::Comp_Vx2i, Dis_Vs2i, Int_Vx2i, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vs2i", &Jit::Comp_Vx2i, Dis_Vs2i, Int_Vx2i, IS_VFPU|OUT_EAT_PREFIX), INSTR("vi2uc", &Jit::Comp_Vi2x, Dis_Vi2x, Int_Vi2x, IS_VFPU|OUT_EAT_PREFIX), INSTR("vi2c", &Jit::Comp_Vi2x, Dis_Vi2x, Int_Vi2x, IS_VFPU|OUT_EAT_PREFIX),