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/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/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/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/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; 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/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 00ecb51ad7..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" @@ -162,6 +163,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)) @@ -171,9 +173,9 @@ 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); std::string realpath; // Special handling: host0:command.txt (as seen in Super Monkey Ball Adventures, for example) @@ -193,7 +195,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); } } @@ -225,14 +227,25 @@ 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; + 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); current = 6; // Ownership is a bit convoluted. Let's just delete everything once. @@ -252,8 +265,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)) @@ -268,6 +291,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 +307,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 +319,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 +335,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 +376,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 +391,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 +406,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 +438,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 +453,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 +461,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 +471,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 +481,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 +491,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..b7d99ebc51 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 { @@ -27,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; @@ -34,6 +40,8 @@ private: currentDir_t currentDir; std::string startingDirectory; + int lastOpenError; + recursive_mutex lock; public: MetaFileSystem() @@ -42,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); @@ -72,7 +80,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); @@ -94,6 +103,7 @@ public: // TODO: void IoCtl(...) void SetStartingDirectory(const std::string &dir) { + lock_guard guard(lock); startingDirectory = dir; } }; 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"}, 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/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 4766923377..f34ff7d9c6 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 @@ -294,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..."); @@ -305,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); @@ -328,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) @@ -782,7 +796,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 +810,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 +833,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 +1307,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 +1319,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); 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(); 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), 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 f50ae71eed..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; @@ -679,14 +680,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: DISABLE; @@ -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])); @@ -769,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; 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/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 diff --git a/Core/System.cpp b/Core/System.cpp index d091b82acd..13a6a2d459 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -112,10 +112,12 @@ bool CPU_HasPendingAction() { void CPU_WaitStatus(bool (*pred)()) { cpuThreadLock.lock(); while (!pred()) - cpuThreadCond.wait(cpuThreadLock); + cpuThreadCond.wait_for(cpuThreadLock, 16); cpuThreadLock.unlock(); } +void CPU_Shutdown(); + void CPU_Init() { currentCPU = &mipsr4k; numCPUs = 1; @@ -163,12 +165,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; @@ -182,20 +179,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; } 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/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 96b5919a2b..cea3838d5b 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, @@ -304,6 +304,11 @@ 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(); + VirtualFramebuffer *vfb = framebufferManager_.GetDisplayFBO(); if (vfb) return vfb->dirtyAfterDisplay; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index e831bf380a..6d610b5764 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() : @@ -48,6 +46,11 @@ 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(); + easy_guard guard(listLock); if (mode < 0 || mode > 1) return SCE_KERNEL_ERROR_INVALID_MODE; @@ -55,7 +58,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) { @@ -92,6 +95,11 @@ 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(); + easy_guard guard(listLock); if (listid < 0 || listid >= DisplayListMaxCount) return SCE_KERNEL_ERROR_INVALID_ID; @@ -124,8 +132,7 @@ int GPUCommon::ListSync(int listid, int mode) { } if (dl.waitTicks > CoreTiming::GetTicks()) { - guard.unlock(); - __KernelWaitCurThread(WAITTYPE_GELISTSYNC, listid, 0, 0, false, "GeListSync"); + __GeWaitCurrentThread(WAITTYPE_GELISTSYNC, listid, "GeListSync"); } return PSP_GE_LIST_COMPLETED; } @@ -238,8 +245,7 @@ u32 GPUCommon::DequeueList(int listid) { dlQueue.remove(listid); dls[listid].waitTicks = 0; - guard.unlock(); - __KernelTriggerWait(WAITTYPE_GELISTSYNC, listid, 0, "GeListSync"); + __GeTriggerWait(WAITTYPE_GELISTSYNC, listid, "GeListSync"); CheckDrawSync(); @@ -593,7 +599,6 @@ void GPUCommon::ProcessDLQueueInternal() { easy_guard guard(listLock); currentList = NULL; - guard.unlock(); drawCompleteTicks = startingTicks + cyclesExecuted; busyTicks = std::max(busyTicks, drawCompleteTicks); @@ -855,7 +860,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) diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index bd4e0259cf..411021ea1f 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 @@ -123,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(); @@ -160,13 +68,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; 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: 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