diff --git a/.gitignore b/.gitignore index a99238ff41..86e02e32ae 100644 --- a/.gitignore +++ b/.gitignore @@ -42,8 +42,10 @@ build*/ __testoutput.txt __testerror.txt __testfinish.txt +__testfailure.bmp GameLogNotes.txt android/ui_atlas.zim +android/assets/flash0 ppge_atlas.zim.png local.properties diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a1402a5d0..cfabb3510d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,12 +63,12 @@ else() endif() #find_package(Qt5Widgets) -if(USING_GLES2) +if(USING_GLES2 AND NOT IOS) set(OPENGL_LIBRARIES GLESv2) -else() +elseif(NOT IOS) include(FindOpenGL REQUIRED) endif() -if (NOT BLACKBERRY AND NOT ANDROID) +if (NOT BLACKBERRY AND NOT ANDROID AND NOT IOS) include(FindSDL) endif() include(FindThreads) @@ -119,9 +119,8 @@ if(NOT MSVC) add_definitions(-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED -D__BSD_VISIBLE=1) add_definitions(-D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64) endif() - - if(APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + if(IOS) + add_definitions(-DGL_ETC1_RGB8_OES=0) endif() if(BLACKBERRY) @@ -133,6 +132,11 @@ if(NOT MSVC) add_definitions(-msse2) endif() + if(IOS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++") + elseif(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + endif() if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.0) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") else() @@ -415,9 +419,8 @@ elseif(IOS) ios/AppDelegate.h ios/ViewController.mm ios/ViewController.h) - set(CMAKE_EXE_LINKER_FLAGS "-framework Foundation -framework CoreGraphics -framework QuartzCore -framework OpenGLES -framework UIKit") - # No target - # set(TargetBin PPSSPP) + set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework OpenGLES -framework UIKit -framework GLKit") + set(TargetBin PPSSPP) elseif(USING_QT_UI) # Currently unused find_package(Qt4 COMPONENTS QtMultimedia QtOpenGL QtGui QtCore) @@ -589,6 +592,8 @@ endif() add_library(kirk STATIC ext/libkirk/AES.c ext/libkirk/AES.h + ext/libkirk/amctrl.c + ext/libkirk/amctrl.h ext/libkirk/SHA1.c ext/libkirk/SHA1.h ext/libkirk/bn.c @@ -679,6 +684,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/FileSystems/ISOFileSystem.h Core/FileSystems/MetaFileSystem.cpp Core/FileSystems/MetaFileSystem.h + Core/Font/PGF.cpp + Core/Font/PGF.h Core/HLE/FunctionWrappers.h Core/HLE/HLE.cpp Core/HLE/HLE.h @@ -764,6 +771,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/sceUtility.h Core/HLE/sceVaudio.cpp Core/HLE/sceVaudio.h + Core/HLE/scePspNpDrm_user.cpp + Core/HLE/scePspNpDrm_user.h Core/HW/MediaEngine.cpp Core/HW/MediaEngine.h Core/HW/MemoryStick.cpp @@ -811,7 +820,6 @@ add_library(${CoreLibName} ${CoreLinkType} Core/Util/BlockAllocator.h Core/Util/PPGeDraw.cpp Core/Util/PPGeDraw.h - Core/Util/Pool.h Core/Util/ppge_atlas.cpp Core/Util/ppge_atlas.h $ @@ -950,15 +958,26 @@ set(NativeAssets set(LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT} ${nativeExtraLibs}) if (TargetBin) - add_executable(${TargetBin} ${NativeAppSource}) + if (IOS) + add_executable(${TargetBin} MACOSX_BUNDLE ${NativeAppSource}) + else() + add_executable(${TargetBin} ${NativeAppSource}) + endif() target_link_libraries(${TargetBin} ${LinkCommon}) endif() +# installs file(INSTALL ${NativeAssets} DESTINATION assets) -# code signing +# packaging and code signing if (IOS) - set_target_properties(${NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST PPSSPP-Info.plist XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer: My Name") + set(RSRC_XIB_FILES assets/Icon@2x.png) + SET_SOURCE_FILES_PROPERTIES(${RSRC_XIB_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + set(APP_DIR_NAME \${TARGET_BUILD_DIR}/\${FULL_PRODUCT_NAME}) + add_custom_command(TARGET PPSSPP POST_BUILD + COMMAND tar -c -C . --exclude .DS_Store --exclude .git -H `find assets` | tar -x -C ${APP_DIR_NAME} + ) + set_target_properties(${TargetBin} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "../ios/PPSSPP-Info.plist" XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer: My Name") endif() #include(CPack) diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index 3b0c02cf26..3af790f333 100644 --- a/Common/ArmEmitter.cpp +++ b/Common/ArmEmitter.cpp @@ -151,6 +151,9 @@ void ARMXEmitter::SetCodePtr(u8 *ptr) { code = ptr; startcode = code; +#ifdef IOS + lastCacheFlushEnd = ptr; +#endif } const u8 *ARMXEmitter::GetCodePtr() const @@ -194,7 +197,8 @@ void ARMXEmitter::FlushIcacheSection(u8 *start, u8 *end) #elif defined(BLACKBERRY) msync(start, end - start, MS_SYNC | MS_INVALIDATE_ICACHE); #elif defined(IOS) - sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); + if (start != NULL) + sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); #elif !defined(_WIN32) __builtin___clear_cache(start, end); #endif @@ -494,6 +498,16 @@ void ARMXEmitter::SMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) Write4OpMultiply(0xC, destLo, destHi, rn, rm); } +void ARMXEmitter::UMLAL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0xA, destLo, destHi, rn, rm); +} + +void ARMXEmitter::SMLAL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0xE, destLo, destHi, rn, rm); +} + void ARMXEmitter::SXTB (ARMReg dest, ARMReg op2) { Write32(condition | (0x6AF << 16) | (dest << 12) | (7 << 4) | op2); @@ -537,12 +551,25 @@ void ARMXEmitter::WriteStoreOp(u32 op, ARMReg dest, ARMReg src, Operand2 op2) else Write32(condition | (op << 20) | (3 << 23) | (dest << 16) | (src << 12) | op2.Imm12()); } -void ARMXEmitter::STR (ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x40, dest, src, op);} -void ARMXEmitter::STRB(ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x44, dest, src, op);} -void ARMXEmitter::STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) +void ARMXEmitter::STR (ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x40, dest, src, op);} +void ARMXEmitter::STRH (ARMReg dest, ARMReg src, Operand2 op) +{ + u8 Imm = op.Imm8(); + Write32(condition | (0x04 << 20) | (src << 16) | (dest << 12) | ((Imm >> 4) << 8) | (0xB << 4) | (Imm & 0x0F)); +} +void ARMXEmitter::STRB (ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x44, dest, src, op);} +void ARMXEmitter::STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) { Write32(condition | (0x60 << 20) | (Index << 24) | (Add << 23) | (dest << 16) | (base << 12) | offset); } +void ARMXEmitter::STRH (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) +{ + Write32(condition | (0x00 << 20) | (Index << 24) | (Add << 23) | (dest << 16) | (base << 12) | (0xB << 4) | offset); +} +void ARMXEmitter::STRB (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) +{ + Write32(condition | (0x64 << 20) | (Index << 24) | (Add << 23) | (dest << 16) | (base << 12) | offset); +} void ARMXEmitter::LDREX(ARMReg dest, ARMReg base) { Write32(condition | (25 << 20) | (base << 16) | (dest << 12) | 0xF9F); @@ -567,12 +594,38 @@ void ARMXEmitter::LDRH(ARMReg dest, ARMReg src, Operand2 op) u8 Imm = op.Imm8(); Write32(condition | (0x05 << 20) | (src << 16) | (dest << 12) | ((Imm >> 4) << 8) | (0xB << 4) | (Imm & 0x0F)); } +void ARMXEmitter::LDRSH(ARMReg dest, ARMReg src, Operand2 op) +{ + u8 Imm = op.Imm8(); + Write32(condition | (0x05 << 20) | (src << 16) | (dest << 12) | ((Imm >> 4) << 8) | (0xF << 4) | (Imm & 0x0F)); +} void ARMXEmitter::LDRB(ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x45, src, dest, op);} +void ARMXEmitter::LDRSB(ARMReg dest, ARMReg src, Operand2 op) +{ + u8 Imm = op.Imm8(); + Write32(condition | (0x05 << 20) | (src << 16) | (dest << 12) | ((Imm >> 4) << 8) | (0xD << 4) | (Imm & 0x0F)); +} -void ARMXEmitter::LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) +void ARMXEmitter::LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) { Write32(condition | (0x61 << 20) | (Index << 24) | (Add << 23) | (base << 16) | (dest << 12) | offset); } +void ARMXEmitter::LDRH (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) +{ + Write32(condition | (0x01 << 20) | (Index << 24) | (Add << 23) | (base << 16) | (dest << 12) | (0xB << 4) | offset); +} +void ARMXEmitter::LDRSH(ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) +{ + Write32(condition | (0x01 << 20) | (Index << 24) | (Add << 23) | (base << 16) | (dest << 12) | (0xF << 4) | offset); +} +void ARMXEmitter::LDRB (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) +{ + Write32(condition | (0x65 << 20) | (Index << 24) | (Add << 23) | (base << 16) | (dest << 12) | offset); +} +void ARMXEmitter::LDRSB(ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add) +{ + Write32(condition | (0x01 << 20) | (Index << 24) | (Add << 23) | (base << 16) | (dest << 12) | (0xD << 4) | offset); +} void ARMXEmitter::WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegList) { Write32(condition | (op << 20) | (WriteBack << 21) | (dest << 16) | RegList); diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h index a9319c8dd6..58b77391a2 100644 --- a/Common/ArmEmitter.h +++ b/Common/ArmEmitter.h @@ -457,6 +457,9 @@ public: void UMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); void SMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); + void UMLAL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); + void SMLAL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); + void SXTB(ARMReg dest, ARMReg op2); void SXTH(ARMReg dest, ARMReg op2, u8 rotation = 0); void SXTAH(ARMReg dest, ARMReg src, ARMReg op2, u8 rotation = 0); @@ -467,16 +470,26 @@ public: void MRS (ARMReg dest); // Memory load/store operations - void LDR (ARMReg dest, ARMReg src, Operand2 op2 = 0); + void LDR (ARMReg dest, ARMReg src, Operand2 op2 = 0); + void LDRH (ARMReg dest, ARMReg src, Operand2 op2 = 0); + void LDRSH(ARMReg dest, ARMReg src, Operand2 op2 = 0); + void LDRB (ARMReg dest, ARMReg src, Operand2 op2 = 0); + void LDRSB(ARMReg dest, ARMReg src, Operand2 op2 = 0); // Offset adds to the base register in LDR - void LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); - void LDRH(ARMReg dest, ARMReg src, Operand2 op = 0); - void LDRB(ARMReg dest, ARMReg src, Operand2 op2 = 0); - void STR (ARMReg dest, ARMReg src, Operand2 op2 = 0); + void LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); + void LDRH (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); + void LDRSH(ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); + void LDRB (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); + void LDRSB(ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); + + void STR (ARMReg dest, ARMReg src, Operand2 op2 = 0); + void STRH (ARMReg dest, ARMReg src, Operand2 op2 = 0); + void STRB (ARMReg dest, ARMReg src, Operand2 op2 = 0); // Offset adds on to the destination register in STR - void STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); + void STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); + void STRH (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); + void STRB (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add); - void STRB(ARMReg dest, ARMReg src, Operand2 op2 = 0); void STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...); void LDMFD(ARMReg dest, bool WriteBack, const int Regnum, ...); @@ -556,7 +569,9 @@ public: // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. void FreeCodeSpace() { +#ifndef __SYMBIAN32__ FreeMemoryPages(region, region_size); +#endif region = NULL; region_size = 0; } diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h index 0344483514..8bf1c82232 100644 --- a/Common/ChunkFile.h +++ b/Common/ChunkFile.h @@ -34,8 +34,12 @@ #include #include #ifndef __SYMBIAN32__ +#ifdef IOS +#include +#else #include #endif +#endif #include "Common.h" #include "FileUtil.h" diff --git a/Common/ConsoleListener.cpp b/Common/ConsoleListener.cpp index 0fadc6ef2a..24ae9672b1 100644 --- a/Common/ConsoleListener.cpp +++ b/Common/ConsoleListener.cpp @@ -313,19 +313,19 @@ void ConsoleListener::SendToThread(LogTypes::LOG_LEVELS Level, const char *Text) if (logPendingWritePos == (u32) -1) return; - size_t Len = strlen(Text); + int Len = (int)strlen(Text); if (Len > LOG_PENDING_MAX) Len = LOG_PENDING_MAX - 16; char ColorAttr[16] = ""; - size_t ColorLen = 0; + int ColorLen = 0; if (bUseColor) { // Not ANSI, since the console doesn't support it, but ANSI-like. snprintf(ColorAttr, 16, "\033%d", Level); // For now, rather than properly support it. _dbg_assert_msg_(COMMON, strlen(ColorAttr) == 2, "Console logging doesn't support > 9 levels."); - ColorLen = strlen(ColorAttr); + ColorLen = (int)strlen(ColorAttr); } EnterCriticalSection(&criticalSection); @@ -333,7 +333,7 @@ void ConsoleListener::SendToThread(LogTypes::LOG_LEVELS Level, const char *Text) u32 prevLogWritePos = logWritePos; if (logWritePos + ColorLen + Len >= LOG_PENDING_MAX) { - for (size_t i = 0; i < ColorLen; ++i) + for (int i = 0; i < ColorLen; ++i) logPending[(logWritePos + i) % LOG_PENDING_MAX] = ColorAttr[i]; logWritePos += ColorLen; if (logWritePos >= LOG_PENDING_MAX) @@ -370,7 +370,7 @@ void ConsoleListener::SendToThread(LogTypes::LOG_LEVELS Level, const char *Text) // Okay, have it go right after the next newline. if (nextNewline != NULL) - logPendingReadPos = nextNewline - logPending + 1; + logPendingReadPos = (u32)(nextNewline - logPending + 1); } // Double check we didn't start quitting. diff --git a/Common/Crypto/aes.h b/Common/Crypto/aes.h index 8d5059e1be..c3006a775c 100644 --- a/Common/Crypto/aes.h +++ b/Common/Crypto/aes.h @@ -89,9 +89,9 @@ int AES_set_encrypt_key(const unsigned char* userKey, const int bits, int AES_set_decrypt_key(const unsigned char* userKey, const int bits, AES_KEY* key); -void AES_encrypt(const unsigned char* in, unsigned char* out, +void AES_encrypt1(const unsigned char* in, unsigned char* out, const AES_KEY* key); -void AES_decrypt(const unsigned char* in, unsigned char* out, +void AES_decrypt1(const unsigned char* in, unsigned char* out, const AES_KEY* key); void AES_ecb_encrypt(const unsigned char* in, unsigned char* out, diff --git a/Common/Crypto/aes_cbc.cpp b/Common/Crypto/aes_cbc.cpp index 780c35a88d..954878a5bb 100644 --- a/Common/Crypto/aes_cbc.cpp +++ b/Common/Crypto/aes_cbc.cpp @@ -75,7 +75,7 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, while (len >= AES_BLOCK_SIZE) { for(n=0; n < AES_BLOCK_SIZE; ++n) out[n] = in[n] ^ iv[n]; - AES_encrypt(out, out, key); + AES_encrypt1(out, out, key); iv = out; len -= AES_BLOCK_SIZE; in += AES_BLOCK_SIZE; @@ -86,13 +86,13 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, out[n] = in[n] ^ iv[n]; for(n=len; n < AES_BLOCK_SIZE; ++n) out[n] = iv[n]; - AES_encrypt(out, out, key); + AES_encrypt1(out, out, key); iv = out; } memcpy(ivec,iv,AES_BLOCK_SIZE); } else if (in != out) { while (len >= AES_BLOCK_SIZE) { - AES_decrypt(in, out, key); + AES_decrypt1(in, out, key); for(n=0; n < AES_BLOCK_SIZE; ++n) out[n] ^= iv[n]; iv = in; @@ -101,7 +101,7 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, out += AES_BLOCK_SIZE; } if (len) { - AES_decrypt(in,tmp,key); + AES_decrypt1(in,tmp,key); for(n=0; n < len; ++n) out[n] = tmp[n] ^ iv[n]; iv = in; @@ -110,7 +110,7 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, } else { while (len >= AES_BLOCK_SIZE) { memcpy(tmp, in, AES_BLOCK_SIZE); - AES_decrypt(in, out, key); + AES_decrypt1(in, out, key); for(n=0; n < AES_BLOCK_SIZE; ++n) out[n] ^= ivec[n]; memcpy(ivec, tmp, AES_BLOCK_SIZE); @@ -120,7 +120,7 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, } if (len) { memcpy(tmp, in, AES_BLOCK_SIZE); - AES_decrypt(tmp, out, key); + AES_decrypt1(tmp, out, key); for(n=0; n < len; ++n) out[n] ^= ivec[n]; for(n=len; n < AES_BLOCK_SIZE; ++n) diff --git a/Common/Crypto/aes_core.cpp b/Common/Crypto/aes_core.cpp index ad54bc6006..2bce4429a9 100644 --- a/Common/Crypto/aes_core.cpp +++ b/Common/Crypto/aes_core.cpp @@ -778,7 +778,7 @@ int AES_set_decrypt_key(const unsigned char *userKey, const int bits, * Encrypt a single block * in and out can overlap */ -void AES_encrypt(const unsigned char *in, unsigned char *out, +void AES_encrypt1(const unsigned char *in, unsigned char *out, const AES_KEY *key) { const u32 *rk; @@ -969,7 +969,7 @@ void AES_encrypt(const unsigned char *in, unsigned char *out, * Decrypt a single block * in and out can overlap */ -void AES_decrypt(const unsigned char *in, unsigned char *out, +void AES_decrypt1(const unsigned char *in, unsigned char *out, const AES_KEY *key) { const u32 *rk; diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index ebbff87265..956a1ae239 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -27,8 +27,8 @@ #endif // Unfortunately this is quite slow. -// #define LOG_MSC_OUTPUTDEBUG true #define LOG_MSC_OUTPUTDEBUG false +// #define LOG_MSC_OUTPUTDEBUG true void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char *file, int line, const char* fmt, ...) @@ -46,30 +46,30 @@ LogManager *LogManager::m_logManager = NULL; LogManager::LogManager() { // create log files - m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); - m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); - m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); - m_Log[LogTypes::CPU] = new LogContainer("CPU", "CPU"); - m_Log[LogTypes::LOADER] = new LogContainer("LOAD", "Loader"); - m_Log[LogTypes::IO] = new LogContainer("IO", "IO"); - m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "DiscIO"); - m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); - m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System"); - m_Log[LogTypes::G3D] = new LogContainer("G3D", "3D Graphics"); - m_Log[LogTypes::DMA] = new LogContainer("DMA", "DMA"); - m_Log[LogTypes::INTC] = new LogContainer("INTC", "Interrupts"); - m_Log[LogTypes::MEMMAP] = new LogContainer("MM", "Memory Map"); - m_Log[LogTypes::SOUND] = new LogContainer("SND", "Sound"); - m_Log[LogTypes::SAS] = new LogContainer("SAS", "Sound Mixer (Sas)"); - m_Log[LogTypes::HLE] = new LogContainer("HLE", "HLE"); - m_Log[LogTypes::TIMER] = new LogContainer("TMR", "Timer"); - m_Log[LogTypes::VIDEO] = new LogContainer("VID", "Video"); - m_Log[LogTypes::DYNA_REC] = new LogContainer("Jit", "JIT compiler"); - m_Log[LogTypes::NETPLAY] = new LogContainer("NET", "Net play"); - m_Log[LogTypes::ME] = new LogContainer("ME", "Media Engine"); + m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); + m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); + m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); + m_Log[LogTypes::CPU] = new LogContainer("CPU", "CPU"); + m_Log[LogTypes::LOADER] = new LogContainer("LOAD", "Loader"); + m_Log[LogTypes::IO] = new LogContainer("IO", "IO"); + m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "DiscIO"); + m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); + m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System"); + m_Log[LogTypes::G3D] = new LogContainer("G3D", "3D Graphics"); + m_Log[LogTypes::DMA] = new LogContainer("DMA", "DMA"); + m_Log[LogTypes::INTC] = new LogContainer("INTC", "Interrupts"); + m_Log[LogTypes::MEMMAP] = new LogContainer("MM", "Memory Map"); + m_Log[LogTypes::SOUND] = new LogContainer("SND", "Sound"); + m_Log[LogTypes::SAS] = new LogContainer("SAS", "Sound Mixer (Sas)"); + m_Log[LogTypes::HLE] = new LogContainer("HLE", "HLE"); + m_Log[LogTypes::TIMER] = new LogContainer("TMR", "Timer"); + m_Log[LogTypes::VIDEO] = new LogContainer("VID", "Video"); + m_Log[LogTypes::DYNA_REC] = new LogContainer("Jit", "JIT compiler"); + m_Log[LogTypes::NETPLAY] = new LogContainer("NET", "Net play"); + m_Log[LogTypes::ME] = new LogContainer("ME", "Media Engine"); // Remove file logging on small devices -#if !defined(ANDROID) && !defined(IOS) && !defined(BLACKBERRY) +#ifndef USING_GLES2 m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); m_consoleLog = new ConsoleListener(); m_debuggerLog = new DebuggerLogListener(); @@ -82,7 +82,7 @@ LogManager::LogManager() for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) { m_Log[i]->SetEnable(true); -#if !defined(ANDROID) && !defined(IOS) && !defined(BLACKBERRY) +#ifndef USING_GLES2 m_Log[i]->AddListener(m_fileLog); m_Log[i]->AddListener(m_consoleLog); #ifdef _MSC_VER @@ -97,11 +97,13 @@ LogManager::~LogManager() { for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) { +#ifndef USING_GLES2 if (m_fileLog != NULL) m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog); -#if !defined(ANDROID) && !defined(IOS) && !defined(BLACKBERRY) m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog); +#ifdef _MSC_VER m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog); +#endif #endif } @@ -109,7 +111,7 @@ LogManager::~LogManager() delete m_Log[i]; if (m_fileLog != NULL) delete m_fileLog; -#if !defined(ANDROID) && !defined(IOS) && !defined(BLACKBERRY) +#ifndef USING_GLES2 delete m_consoleLog; delete m_debuggerLog; #endif @@ -214,6 +216,9 @@ void LogContainer::RemoveListener(LogListener *listener) void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg) { +#ifdef __SYMBIAN32__ + RDebug::Printf("%s",msg); +#else std::lock_guard lk(m_listeners_lock); std::set::const_iterator i; @@ -221,6 +226,7 @@ void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg) { (*i)->Log(level, msg); } +#endif } FileLogListener::FileLogListener(const char *filename) @@ -235,11 +241,7 @@ void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) return; std::lock_guard lk(m_log_lock); -#ifdef __SYMBIAN32__ - RDebug::Printf("%s",msg); -#else m_logfile << msg << std::flush; -#endif } void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) diff --git a/Common/MemoryUtil.cpp b/Common/MemoryUtil.cpp index 6b0d089b7b..a7119b307c 100644 --- a/Common/MemoryUtil.cpp +++ b/Common/MemoryUtil.cpp @@ -62,6 +62,7 @@ void* AllocateExecutableMemory(size_t size, bool low) #elif defined(__SYMBIAN32__) //This function may be called more than once, and we want to create only one big //memory chunk for all the executable code for the JIT + void* ptr; if( g_code_chunk == NULL && g_code_heap == NULL) { TInt minsize = SYMBIAN_CODECHUNK_SIZE; @@ -69,8 +70,10 @@ void* AllocateExecutableMemory(size_t size, bool low) g_code_chunk = new RChunk(); g_code_chunk->CreateLocalCode(minsize, maxsize); g_code_heap = UserHeap::ChunkHeap(*g_code_chunk, minsize, 1, maxsize); + ptr = (void*) g_code_heap->Alloc( size ); } - void* ptr = (void*) g_code_heap->Alloc( size ); + else + ptr = g_code_heap->Base(); #else static char *map_hint = 0; #if defined(__x86_64__) && !defined(MAP_32BIT) @@ -116,11 +119,6 @@ void* AllocateExecutableMemory(size_t size, bool low) } #endif -#if defined(_M_X64) - if ((u64)ptr >= 0x80000000 && low == true) - PanicAlert("Executable memory ended up above 2GB!"); -#endif - return ptr; } diff --git a/Common/Thunk.cpp b/Common/Thunk.cpp index 70dc351b9d..0cc7fb966a 100644 --- a/Common/Thunk.cpp +++ b/Common/Thunk.cpp @@ -112,9 +112,9 @@ void *ThunkManager::ProtectFunction(void *function, int num_params) #else SUB(64, R(ESP), Imm8(0x8)); #endif - CALL((void*)save_regs); - CALL((void*)function); - CALL((void*)load_regs); + ABI_CallFunction((void*)save_regs); + ABI_CallFunction((void*)function); + ABI_CallFunction((void*)load_regs); #ifdef _WIN32 ADD(64, R(ESP), Imm8(0x28)); #else diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 3706931498..3bbd94a384 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -21,6 +21,7 @@ set(SRCS ELF/ElfReader.cpp ELF/ParamSFO.cpp ELF/PrxDecrypter.cpp + Font/PGF.cpp HLE/HLE.cpp HLE/HLETables.cpp HLE/sceAtrac.cpp diff --git a/Core/Config.cpp b/Core/Config.cpp index fd22d7b7df..e01790a52f 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -57,7 +57,8 @@ void CConfig::Load(const char *iniFileName) IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU"); cpu->Get("Jit", &bJit, true); - cpu->Get("FastMemory", &bFastMemory, true); + //FastMemory Default set back to True when solve UNIMPL _sceAtracGetContextAddress making game crash + cpu->Get("FastMemory", &bFastMemory, false); IniFile::Section *graphics = iniFile.GetOrCreateSection("Graphics"); graphics->Get("ShowFPSCounter", &bShowFPSCounter, false); @@ -74,10 +75,10 @@ void CConfig::Load(const char *iniFileName) #else graphics->Get("AnisotropyLevel", &iAnisotropyLevel, 8); #endif - graphics->Get("DisableG3DLog", &bDisableG3DLog, false); graphics->Get("VertexCache", &bVertexCache, true); graphics->Get("FullScreen", &bFullScreen, false); graphics->Get("StretchToDisplay", &bStretchToDisplay, false); + graphics->Get("TrueColor", &bTrueColor, true); IniFile::Section *sound = iniFile.GetOrCreateSection("Sound"); sound->Get("Enable", &bEnableSound, true); @@ -134,10 +135,10 @@ void CConfig::Save() graphics->Set("VBO", bUseVBO); graphics->Set("FrameSkip", iFrameSkip); graphics->Set("AnisotropyLevel", iAnisotropyLevel); - graphics->Set("DisableG3DLog", bDisableG3DLog); graphics->Set("VertexCache", bVertexCache); graphics->Set("FullScreen", bFullScreen); graphics->Set("StretchToDisplay", bStretchToDisplay); + graphics->Set("TrueColor", bTrueColor); IniFile::Section *sound = iniFile.GetOrCreateSection("Sound"); sound->Set("Enable", bEnableSound); diff --git a/Core/Config.h b/Core/Config.h index d39325cc4e..e3d4139a19 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -63,10 +63,10 @@ public: int iWindowZoom; // for Windows bool SSAntiAliasing; //for Windows, too - bool bDisableG3DLog; bool bVertexCache; bool bFullScreen; int iAnisotropyLevel; + bool bTrueColor; // Sound bool bEnableSound; diff --git a/Core/Core.cpp b/Core/Core.cpp index c2de39e787..481c1f4b2a 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -33,13 +33,24 @@ // HANDLE m_hStepEvent; event m_hStepEvent; recursive_mutex m_hStepMutex; +event m_hInactiveEvent; +recursive_mutex m_hInactiveMutex; // This can be read and written from ANYWHERE. volatile CoreState coreState = CORE_STEPPING; +// Note: intentionally not used for CORE_NEXTFRAME. +volatile bool coreStatePending = false; + +void Core_UpdateState(CoreState newState) +{ + if ((coreState == CORE_RUNNING || coreState == CORE_NEXTFRAME) && newState != CORE_RUNNING) + coreStatePending = true; + coreState = newState; +} void Core_ErrorPause() { - coreState = CORE_ERROR; + Core_UpdateState(CORE_ERROR); } void Core_Pause() @@ -56,7 +67,7 @@ void Core_Halt(const char *msg) void Core_Stop() { - coreState = CORE_POWERDOWN; + Core_UpdateState(CORE_POWERDOWN); m_hStepEvent.notify_one(); } @@ -65,6 +76,23 @@ bool Core_IsStepping() return coreState == CORE_STEPPING || coreState == CORE_POWERDOWN; } +bool Core_IsInactive() +{ + return coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME && !coreStatePending; +} + +void Core_WaitInactive() +{ + while (!Core_IsInactive()) + m_hInactiveEvent.wait(m_hInactiveMutex); +} + +void Core_WaitInactive(int milliseconds) +{ + while (!Core_IsInactive()) + m_hInactiveEvent.wait_for(m_hInactiveMutex, milliseconds); +} + void Core_RunLoop() { while (!coreState) { @@ -72,9 +100,9 @@ void Core_RunLoop() if (coreState == CORE_NEXTFRAME) { #ifdef _WIN32 + coreState = CORE_RUNNING; GL_SwapBuffers(); #endif - coreState = CORE_RUNNING; } } } @@ -110,6 +138,10 @@ reswitch: // We should never get here on Android. case CORE_STEPPING: + if (coreStatePending) + m_hInactiveEvent.notify_one(); + coreStatePending = false; + //1: wait for step command.. #if defined(USING_QT_UI) || defined(_DEBUG) host->UpdateDisassembly(); @@ -142,8 +174,13 @@ reswitch: case CORE_POWERDOWN: case CORE_ERROR: - case CORE_NEXTFRAME: //1: Exit loop!! + if (coreStatePending) + m_hInactiveEvent.notify_one(); + coreStatePending = false; + return; + + case CORE_NEXTFRAME: return; } } @@ -158,7 +195,7 @@ void Core_EnableStepping(bool step) #if defined(_DEBUG) host->SetDebugMode(true); #endif - coreState = CORE_STEPPING; + Core_UpdateState(CORE_STEPPING); } else { @@ -166,6 +203,7 @@ void Core_EnableStepping(bool step) host->SetDebugMode(false); #endif coreState = CORE_RUNNING; + coreStatePending = false; m_hStepEvent.notify_one(); } } diff --git a/Core/Core.h b/Core/Core.h index d9b07c7f6a..2b9d359fad 100644 --- a/Core/Core.h +++ b/Core/Core.h @@ -43,5 +43,10 @@ enum CoreState CORE_NEXTFRAME, }; +void Core_UpdateState(CoreState newState); +bool Core_IsInactive(); +void Core_WaitInactive(); +void Core_WaitInactive(int milliseconds); + extern volatile CoreState coreState; diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 50c55c3a01..c744df54b3 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -144,6 +144,7 @@ + @@ -312,6 +313,7 @@ + @@ -412,7 +414,6 @@ - diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index aeafbe3ada..04d25d780a 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -49,6 +49,9 @@ {0b77054f-7fc7-4c33-ada3-762aecde69e5} + + {1c79e88d-1c48-450b-8af6-f22ce7d40c66} + @@ -375,6 +378,10 @@ MIPS\ARM + + + Font + @@ -533,9 +540,6 @@ Util - - Util - Debugger @@ -695,6 +699,10 @@ MIPS\ARM + + + Font + diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index ce1180bd1b..77776468b5 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -422,12 +422,6 @@ void RemoveAllEvents(int event_type) //This raise only the events required while the fifo is processing data void ProcessFifoWaitEvents() { - if (Common::AtomicLoadAcquire(hasTsEvents)) - MoveEvents(); - - if (!first) - return; - while (first) { if (first->time <= globalTimer) @@ -471,7 +465,7 @@ void MoveEvents() } } -void Advance() +void AdvanceQuick() { int cyclesExecuted = slicelength - currentMIPS->downcount; globalTimer += cyclesExecuted; @@ -495,6 +489,14 @@ void Advance() advanceCallback(cyclesExecuted); } +void Advance() +{ + if (Common::AtomicLoadAcquire(hasTsEvents)) + MoveEvents(); + + AdvanceQuick(); +} + void LogPendingEvents() { Event *ptr = first; diff --git a/Core/CoreTiming.h b/Core/CoreTiming.h index 0a05d722c3..e619281450 100644 --- a/Core/CoreTiming.h +++ b/Core/CoreTiming.h @@ -100,6 +100,7 @@ namespace CoreTiming void RemoveAllEvents(int event_type); bool IsScheduled(int event_type); void Advance(); + void AdvanceQuick(); void MoveEvents(); void ProcessFifoWaitEvents(); diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index 3aed03de74..c3ae09d5d6 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -133,20 +133,20 @@ void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp) void CBreakPoints::InvalidateJit(u32 _iAddress) { // Don't want to clear cache while running, I think? - if (MIPSComp::jit && coreState == CORE_STEPPING) + if (MIPSComp::jit && Core_IsInactive()) MIPSComp::jit->ClearCacheAt(_iAddress); } void CBreakPoints::InvalidateJit() { // Don't want to clear cache while running, I think? - if (MIPSComp::jit && coreState == CORE_STEPPING) + if (MIPSComp::jit && Core_IsInactive()) MIPSComp::jit->ClearCache(); } int CBreakPoints::GetNumBreakpoints() { - return m_iBreakPoints.size(); + return (int)m_iBreakPoints.size(); } int CBreakPoints::GetBreakpointAddress(int i) diff --git a/Core/Dialog/PSPMsgDialog.cpp b/Core/Dialog/PSPMsgDialog.cpp index d6d58c8db8..23473a6fda 100644 --- a/Core/Dialog/PSPMsgDialog.cpp +++ b/Core/Dialog/PSPMsgDialog.cpp @@ -149,14 +149,9 @@ void PSPMsgDialog::DisplayYesNo() } void PSPMsgDialog::DisplayOk() -{ - PPGeDrawText("OK", 250, 150, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFF0000FF)); -} - -void PSPMsgDialog::DisplayEnter() { PPGeDrawImage(okButtonImg, 200, 220, 20, 20, 0, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText("Enter", 230, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("Ok", 230, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); } int PSPMsgDialog::Update() @@ -196,11 +191,9 @@ int PSPMsgDialog::Update() if(flag & DS_YESNO) DisplayYesNo(); - if(flag & DS_OK) + if (flag & (DS_OK | DS_VALIDBUTTON)) DisplayOk(); - if(flag & DS_VALIDBUTTON) - DisplayEnter(); if(flag & DS_CANCELBUTTON) DisplayBack(); diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index 5192911304..9e2c45d469 100644 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -20,15 +20,19 @@ #include "../HLE/sceCtrl.h" #include "ChunkFile.h" +#ifndef _WIN32 +#include +#endif + #define NUMKEYROWS 4 #define KEYSPERROW 12 #define NUMBEROFVALIDCHARS (KEYSPERROW * NUMKEYROWS) const char oskKeys[NUMKEYROWS][KEYSPERROW + 1] = { {'1','2','3','4','5','6','7','8','9','0','-','+','\0'}, - {'Q','W','E','R','T','Y','U','I','O','P','[',']','\0'}, - {'A','S','D','F','G','H','J','K','L',';','@','~','\0'}, - {'Z','X','C','V','B','N','M',',','.','/','?','\\','\0'}, + {'q','w','e','r','t','t','u','i','o','p','[',']','\0'}, + {'a','s','d','f','g','h','j','k','l',';','@','~','\0'}, + {'z','x','c','v','b','n','m',',','.','/','?','\\','\0'}, }; @@ -108,9 +112,9 @@ void PSPOskDialog::RenderKeyboard() if (limit <= 0) limit = 16; - const float keyboardLeftSide = (480.0f - (23.0f * KEYSPERROW)) / 2.0f; - float previewLeftSide = (480.0f - (15.0f * limit)) / 2.0f; - float title = (480.0f - (7.0f * limit)) / 2.0f; + const float keyboardLeftSide = (480.0f - (24.0f * KEYSPERROW)) / 2.0f; + float previewLeftSide = (480.0f - (16.0f * limit)) / 2.0f; + float title = (480.0f - limit) / 2.0f; PPGeDrawText(oskDesc.c_str(), title , 20, PPGE_ALIGN_CENTER, 0.5f, CalcFadedColor(0xFFFFFFFF)); for (u32 i = 0; i < limit; ++i) @@ -167,15 +171,19 @@ int PSPOskDialog::Update() StartDraw(); RenderKeyboard(); - PPGeDrawImage(I_CROSS, 100, 220, 20, 20, 0, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText("Select", 130, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawImage(I_CROSS, 30, 220, 20, 20, 0, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("Select", 60, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawImage(I_CIRCLE, 200, 220, 20, 20, 0, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText("Delete", 230, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawImage(I_CIRCLE, 130, 220, 20, 20, 0, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("Delete", 160, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawImage(I_BUTTON, 290, 220, 50, 20, 0, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText("Start", 305, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText("Finish", 350, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawImage(I_BUTTON, 230, 220, 50, 20, 0, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("Start", 245, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("Finish", 290, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + + PPGeDrawImage(I_BUTTON, 350, 220, 55, 20, 0, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("Select", 365, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("Caps", 410, 220, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); if (IsButtonPressed(CTRL_UP)) { @@ -203,7 +211,12 @@ int PSPOskDialog::Update() if (IsButtonPressed(CTRL_CROSS)) { if (inputChars.size() < limit) - inputChars += oskKeys[selectedRow][selectedExtra]; + inputChars += (oskKeys[selectedRow][selectedExtra]); + } + else if (IsButtonPressed(CTRL_SELECT)) + { + if (inputChars.size() < limit) + inputChars += toupper(oskKeys[selectedRow][selectedExtra]); } else if (IsButtonPressed(CTRL_CIRCLE)) { @@ -229,7 +242,7 @@ int PSPOskDialog::Update() Memory::Write_U16(value, oskData.outtextPtr + (2 * i)); } - oskData.outtextlength = inputChars.size(); + oskData.outtextlength = (u32)inputChars.size(); oskParams.base.result= 0; oskData.result = PSP_UTILITY_OSK_RESULT_CHANGED; Memory::WriteStruct(oskParams.SceUtilityOskDataPtr, &oskData); diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index 00a163fc5c..6938ed4fe0 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -18,7 +18,7 @@ #include "ChunkFile.h" #include "FileUtil.h" #include "DirectoryFileSystem.h" - +#include "file/zip_read.h" #ifdef _WIN32 #include @@ -595,3 +595,153 @@ void DirectoryFileSystem::DoState(PointerWrap &p) { ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly."); } } + + +VFSFileSystem::VFSFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath) { + INFO_LOG(HLE, "Creating VFS file system"); + hAlloc = _hAlloc; +} + +VFSFileSystem::~VFSFileSystem() { + for (auto iter = entries.begin(); iter != entries.end(); ++iter) { + delete [] iter->second.fileData; + } + entries.clear(); +} + +std::string VFSFileSystem::GetLocalPath(std::string localPath) { + return basePath + localPath; +} + +bool VFSFileSystem::MkDir(const std::string &dirname) { + // NOT SUPPORTED - READ ONLY + return false; +} + +bool VFSFileSystem::RmDir(const std::string &dirname) { + // NOT SUPPORTED - READ ONLY + return false; +} + +bool VFSFileSystem::RenameFile(const std::string &from, const std::string &to) { + // NOT SUPPORTED - READ ONLY + return false; +} + +bool VFSFileSystem::RemoveFile(const std::string &filename) { + // NOT SUPPORTED - READ ONLY + return false; +} + +u32 VFSFileSystem::OpenFile(std::string filename, FileAccess access) { + if (access != FILEACCESS_READ) { + ERROR_LOG(HLE, "VFSFileSystem only supports plain reading"); + return 0; + } + + std::string fullName = GetLocalPath(filename); + const char *fullNameC = fullName.c_str(); + INFO_LOG(HLE,"VFSFileSystem actually opening %s (%s)", fullNameC, filename.c_str()); + + size_t size; + u8 *data = VFSReadFile(fullNameC, &size); + if (!data) { + ERROR_LOG(HLE, "VFSFileSystem failed to open %s", filename.c_str()); + return 0; + } + + OpenFileEntry entry; + entry.fileData = data; + entry.size = size; + entry.seekPos = 0; + u32 newHandle = hAlloc->GetNewHandle(); + entries[newHandle] = entry; + return newHandle; +} + +PSPFileInfo VFSFileSystem::GetFileInfo(std::string filename) { + PSPFileInfo x; + x.name = filename; + + std::string fullName = GetLocalPath(filename); + INFO_LOG(HLE,"Getting VFS file info %s (%s)", fullName.c_str(), filename.c_str()); + FileInfo fo; + VFSGetFileInfo(fullName.c_str(), &fo); + x.exists = fo.exists; + if (x.exists) { + x.size = fo.size; + x.type = fo.isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; + } + INFO_LOG(HLE,"Got VFS file info: size = %i", (int)x.size); + return x; +} + +void VFSFileSystem::CloseFile(u32 handle) { + EntryMap::iterator iter = entries.find(handle); + if (iter != entries.end()) { + delete [] iter->second.fileData; + entries.erase(iter); + } else { + //This shouldn't happen... + ERROR_LOG(HLE,"Cannot close file that hasn't been opened: %08x", handle); + } +} + +bool VFSFileSystem::OwnsHandle(u32 handle) { + EntryMap::iterator iter = entries.find(handle); + return (iter != entries.end()); +} + +size_t VFSFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) { + INFO_LOG(HLE,"VFSFileSystem::ReadFile %08x %p %i", handle, pointer, (u32)size); + EntryMap::iterator iter = entries.find(handle); + if (iter != entries.end()) + { + size_t bytesRead = size; + memcpy(pointer, iter->second.fileData + iter->second.seekPos, size); + iter->second.seekPos += size; + return bytesRead; + } else { + ERROR_LOG(HLE,"Cannot read file that hasn't been opened: %08x", handle); + return 0; + } +} + +size_t VFSFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) { + // NOT SUPPORTED - READ ONLY + return 0; +} + +size_t VFSFileSystem::SeekFile(u32 handle, s32 position, FileMove type) { + EntryMap::iterator iter = entries.find(handle); + if (iter != entries.end()) { + switch (type) { + case FILEMOVE_BEGIN: iter->second.seekPos = position; break; + case FILEMOVE_CURRENT: iter->second.seekPos += position; break; + case FILEMOVE_END: iter->second.seekPos = iter->second.size + position; break; + } + return iter->second.seekPos; + } else { + //This shouldn't happen... + ERROR_LOG(HLE,"Cannot seek in file that hasn't been opened: %08x", handle); + return 0; + } +} + + +bool VFSFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) { + // NOT SUPPORTED + return false; +} + +std::vector VFSFileSystem::GetDirListing(std::string path) { + std::vector myVector; + // TODO + return myVector; +} + +void VFSFileSystem::DoState(PointerWrap &p) { + if (!entries.empty()) { + ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly."); + } +} diff --git a/Core/FileSystems/DirectoryFileSystem.h b/Core/FileSystems/DirectoryFileSystem.h index 61ee605406..1ee0ac474a 100644 --- a/Core/FileSystems/DirectoryFileSystem.h +++ b/Core/FileSystems/DirectoryFileSystem.h @@ -95,3 +95,41 @@ private: bool FixPathCase(std::string &path, FixPathCaseBehavior behavior); #endif }; + +// VFSFileSystem: Ability to map in Android APK paths as well! Does not support all features, only meant for fonts. +// Very inefficient - always load the whole file on open. +class VFSFileSystem : public IFileSystem { +public: + VFSFileSystem(IHandleAllocator *_hAlloc, std::string _basePath); + ~VFSFileSystem(); + + void DoState(PointerWrap &p); + std::vector GetDirListing(std::string path); + u32 OpenFile(std::string filename, FileAccess access); + void CloseFile(u32 handle); + size_t ReadFile(u32 handle, u8 *pointer, s64 size); + size_t WriteFile(u32 handle, const u8 *pointer, s64 size); + size_t SeekFile(u32 handle, s32 position, FileMove type); + PSPFileInfo GetFileInfo(std::string filename); + bool OwnsHandle(u32 handle); + + bool MkDir(const std::string &dirname); + bool RmDir(const std::string &dirname); + bool RenameFile(const std::string &from, const std::string &to); + bool RemoveFile(const std::string &filename); + bool GetHostPath(const std::string &inpath, std::string &outpath); + +private: + struct OpenFileEntry { + u8 *fileData; + size_t size; + size_t seekPos; + }; + + typedef std::map EntryMap; + EntryMap entries; + std::string basePath; + IHandleAllocator *hAlloc; + + std::string GetLocalPath(std::string localpath); +}; diff --git a/Core/FileSystems/ISOFileSystem.cpp b/Core/FileSystems/ISOFileSystem.cpp index 1c92fa9f03..0a91212a64 100644 --- a/Core/FileSystems/ISOFileSystem.cpp +++ b/Core/FileSystems/ISOFileSystem.cpp @@ -203,7 +203,6 @@ void ISOFileSystem::ReadDirectory(u32 startsector, u32 dirsize, TreeEntry *root) bool isFile = (dir.flags & 2) ? false : true; bool relative; - int fnLength = dir.identifierLength; TreeEntry *e = new TreeEntry(); if (dir.identifierLength == 1 && (dir.firstIdChar == '\x00' || dir.firstIdChar == '.')) diff --git a/Core/Font/PGF.cpp b/Core/Font/PGF.cpp new file mode 100644 index 0000000000..2fd2c4140b --- /dev/null +++ b/Core/Font/PGF.cpp @@ -0,0 +1,531 @@ +// Copyright (c) 2012- 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/. + +// ============== NOTE!!!! + +// Thanks to the JPCSP project! This sceFont implementation is basically a C++ take on JPCSP's font code. +// Some parts, especially in this file, were simply copied, so I guess this really makes this file GPL3. + +#include "Common/CommonTypes.h" +#include "Core/MemMap.h" +#include "Core/Font/PGF.h" + +// These fonts, created by ttf2pgf, don't have complete glyph info and need to be identified. +static bool isJPCSPFont(const char *fontName) { + return !strcmp(fontName, "Liberation") || !strcmp(fontName, "Sazanami") || !strcmp(fontName, "UnDotum"); +} + +// Gets a number of bits from an offset. +// TODO: Make more efficient. +static int getBits(int numBits, const u8 *buf, size_t pos) { + int v = 0; + for (int i = 0; i < numBits; i++) { + v = v | (((buf[pos >> 3] >> (pos & 7)) & 1) << i); + pos++; + } + return v; +} + +static std::vector getTable(const u8 *buf, int bpe, int length) { + std::vector vec; + vec.resize(length); + for (int i = 0; i < length; i++) { + vec[i] = getBits(bpe, buf, bpe * i); + } + return vec; +} + +PGF::PGF() + : fontData(0), charMap(0), shadowCharMap(0), charPointerTable(0) { + +} + +PGF::~PGF() { + delete [] fontData; + delete [] charMap; + delete [] shadowCharMap; + delete [] charPointerTable; +} + +void PGF::DoState(PointerWrap &p) { + // TODO! +} + +void PGF::ReadPtr(const u8 *ptr, size_t dataSize) { + const u8 *const startPtr = ptr; + + INFO_LOG(HLE, "Reading %i bytes of PGF header", sizeof(header)); + memcpy(&header, ptr, sizeof(header)); + ptr += sizeof(header); + + if (header.revision == 3) { + memcpy(&rev3extra, ptr, sizeof(rev3extra)); + rev3extra.compCharMapLength1 &= 0xFFFF; + rev3extra.compCharMapLength2 &= 0xFFFF; + ptr += sizeof(rev3extra); + } + + const u32 *wptr = (const u32 *)ptr; + dimensionTable[0].resize(header.dimTableLength); + dimensionTable[1].resize(header.dimTableLength); + for (int i = 0; i < header.dimTableLength; i++) { + dimensionTable[0][i] = *wptr++; + dimensionTable[1][i] = *wptr++; + } + + xAdjustTable[0].resize(header.xAdjustTableLength); + xAdjustTable[1].resize(header.xAdjustTableLength); + for (int i = 0; i < header.xAdjustTableLength; i++) { + xAdjustTable[0][i] = *wptr++; + xAdjustTable[1][i] = *wptr++; + } + + yAdjustTable[0].resize(header.yAdjustTableLength); + yAdjustTable[1].resize(header.yAdjustTableLength); + for (int i = 0; i < header.yAdjustTableLength; i++) { + yAdjustTable[0][i] = *wptr++; + yAdjustTable[1][i] = *wptr++; + } + + advanceTable[0].resize(header.advanceTableLength); + advanceTable[1].resize(header.advanceTableLength); + for (int i = 0; i < header.advanceTableLength; i++) { + advanceTable[0][i] = *wptr++; + advanceTable[1][i] = *wptr++; + } + + const u8 *uptr = (const u8 *)wptr; + + int shadowCharMapSize = ((header.shadowMapLength * header.shadowMapBpe + 31) & ~31) / 8; + shadowCharMap = new u8[shadowCharMapSize]; + for (int i = 0; i < shadowCharMapSize; i++) { + shadowCharMap[i] = *uptr++; + } + + const u16 *sptr = (const u16 *)uptr; + if (header.revision == 3) { + charmapCompressionTable1[0].resize(rev3extra.compCharMapLength1); + charmapCompressionTable1[1].resize(rev3extra.compCharMapLength1); + for (int i = 0; i < rev3extra.compCharMapLength1; i++) { + charmapCompressionTable1[0][i] = *sptr++; + charmapCompressionTable1[1][i] = *sptr++; + } + + charmapCompressionTable2[0].resize(rev3extra.compCharMapLength2); + charmapCompressionTable2[1].resize(rev3extra.compCharMapLength2); + for (int i = 0; i < rev3extra.compCharMapLength2; i++) { + charmapCompressionTable2[0][i] = *sptr++; + charmapCompressionTable2[1][i] = *sptr++; + } + } + + uptr = (const u8 *)sptr; + + int charMapSize = ((header.charMapLength * header.charMapBpe + 31) & ~31) / 8; + + charMap = new u8[charMapSize]; + for (int i = 0; i < charMapSize; i++) { + charMap[i] = *uptr++; + } + + int charPointerSize = (((header.charPointerLength * header.charPointerBpe + 31) & ~31) / 8); + charPointerTable = new u8[charPointerSize]; + for (int i = 0; i < charPointerSize; i++) { + charPointerTable[i] = *uptr++; + } + + // PGF Fontdata. + u32 fontDataOffset = uptr - startPtr; + + fontDataSize = dataSize - fontDataOffset; + fontData = new u8[fontDataSize]; + memcpy(fontData, uptr, fontDataSize); + + // charmap.resize(); + charmap.resize(header.charMapLength); + int charmap_compr_len = header.revision == 3 ? 7 : 1; + charmap_compr.resize(charmap_compr_len * 4); + glyphs.resize(header.charPointerLength); + shadowGlyphs.resize(header.shadowMapLength); + firstGlyph = header.firstGlyph; + + // Parse out the char map (array where each entry is an irregular number of bits) + // BPE = bits per entry, I think. + for (int i = 0; i < header.charMapLength; i++) { + charmap[i] = getBits(header.charMapBpe, charMap, i * header.charMapBpe); + // This check seems a little odd. + if ((size_t)charmap[i] >= glyphs.size()) + charmap[i] = 65535; + } + + std::vector charPointers = getTable(charPointerTable, header.charPointerBpe, glyphs.size()); + std::vector shadowMap = getTable(shadowCharMap, header.shadowMapBpe, shadowGlyphs.size()); + + // Pregenerate glyphs. + for (size_t i = 0; i < glyphs.size(); i++) { + GetGlyph(fontData, charPointers[i] * 4 * 8 /* ??? */, FONT_PGF_CHARGLYPH, glyphs[i]); + } + + // And shadow glyphs. + for (size_t i = 0; i < shadowGlyphs.size(); i++) { + size_t shadowId = glyphs[i].shadowID; + if (shadowId >= 0 && shadowId < shadowMap.size()) { + size_t charId = shadowMap[shadowId]; + if (charId >= 0 && charId < glyphs.size()) { + // TODO: check for pre existing shadow glyph + GetGlyph(fontData, charPointers[charId] * 4 * 8 /* ??? */, FONT_PGF_SHADOWGLYPH, shadowGlyphs[i]); + } + } + } +} + +int PGF::GetCharIndex(int charCode, const std::vector &charmapCompressed) { + int charIndex = 0; + for (size_t i = 0; i < charmapCompressed.size(); i += 2) { + if (charCode >= charmapCompressed[i] && charCode < charmapCompressed[i] + charmapCompressed[i + 1]) { + charIndex += charCode - charmapCompressed[i]; + return charIndex; + } + charIndex += charmapCompressed[i + 1]; + } + return -1; +} + +bool PGF::GetCharInfo(int charCode, PGFCharInfo *charInfo) { + Glyph glyph; + if (!GetCharGlyph(charCode, FONT_PGF_CHARGLYPH, glyph)) { + // Character not in font, return zeroed charInfo as on real PSP. + return false; + } + memset(charInfo, 0, sizeof(charInfo)); + + charInfo->bitmapWidth = glyph.w; + charInfo->bitmapHeight = glyph.h; + charInfo->bitmapLeft = glyph.left; + charInfo->bitmapTop = glyph.top; + charInfo->sfp26Width = glyph.dimensionWidth; + charInfo->sfp26Height = glyph.dimensionHeight; + charInfo->sfp26Ascender = glyph.top << 6; + charInfo->sfp26Descender = (glyph.h - glyph.top) << 6; + charInfo->sfp26BearingHX = glyph.xAdjustH; + charInfo->sfp26BearingHY = glyph.yAdjustH; + charInfo->sfp26BearingVX = glyph.xAdjustV; + charInfo->sfp26BearingVY = glyph.yAdjustV; + charInfo->sfp26AdvanceH = glyph.advanceH; + charInfo->sfp26AdvanceV = glyph.advanceV; + return true; +} + +void PGF::GetFontInfo(PGFFontInfo *fi) { + fi->maxGlyphWidthI = header.maxSize[0]; + fi->maxGlyphHeightI = header.maxSize[1]; + fi->maxGlyphAscenderI = header.maxAscender; + fi->maxGlyphDescenderI = header.maxDescender; + fi->maxGlyphLeftXI = header.maxLeftXAdjust; + fi->maxGlyphBaseYI = header.maxBaseYAdjust; + fi->minGlyphCenterXI = header.minCenterXAdjust; + fi->maxGlyphTopYI = header.maxTopYAdjust; + fi->maxGlyphAdvanceXI = header.maxAdvance[0]; + fi->maxGlyphAdvanceYI = header.maxAdvance[1]; + fi->maxGlyphWidthF = header.maxSize[0] / 64.0f; + fi->maxGlyphHeightF = header.maxSize[1] / 64.0f; + fi->maxGlyphAscenderF = header.maxAscender / 64.0f; + fi->maxGlyphDescenderF = header.maxDescender / 64.0f; + fi->maxGlyphLeftXF = header.maxLeftXAdjust / 64.0f; + fi->maxGlyphBaseYF = header.maxBaseYAdjust / 64.0f; + fi->minGlyphCenterXF = header.minCenterXAdjust / 64.0f; + fi->maxGlyphTopYF = header.maxTopYAdjust / 64.0f; + fi->maxGlyphAdvanceXF = header.maxAdvance[0] / 64.0f; + fi->maxGlyphAdvanceYF = header.maxAdvance[1] / 64.0f; + + fi->maxGlyphWidth = header.maxGlyphWidth; + fi->maxGlyphHeight = header.maxGlyphHeight; + fi->charMapLength = header.charMapLength; + fi->shadowMapLength = 0; // header.shadowMapLength; TODO + + fi->BPP = header.bpp; +} + +bool PGF::GetGlyph(const u8 *fontdata, size_t charPtr, int glyphType, Glyph &glyph) { + if (glyphType == FONT_PGF_SHADOWGLYPH) { + if (charPtr + 96 > fontDataSize * 8) + return false; + charPtr += getBits(14, fontdata, charPtr) * 8; + if (charPtr + 96 > fontDataSize * 8) + return false; + } + charPtr += 14; + + glyph.w = getBits(7, fontdata, charPtr); + charPtr += 7; + + glyph.h = getBits(7, fontdata, charPtr); + charPtr += 7; + + glyph.left = getBits(7, fontdata, charPtr); + charPtr += 7; + if (glyph.left >= 64) { + glyph.left -= 128; + } + + glyph.top = getBits(7, fontdata, charPtr); + charPtr += 7; + if (glyph.top >= 64) { + glyph.top -= 128; + } + + glyph.flags = getBits(6, fontdata, charPtr); + charPtr += 6; + + if (glyph.flags & FONT_PGF_CHARGLYPH) { + // Skip magic number + charPtr += 7; + + glyph.shadowID = getBits(9, fontdata, charPtr); + charPtr += 9; + + int dimensionIndex = getBits(8, fontdata, charPtr); + charPtr += 8; + + int xAdjustIndex = getBits(8, fontdata, charPtr); + charPtr += 8; + + int yAdjustIndex = getBits(8, fontdata, charPtr); + charPtr += 8; + + charPtr += + ((glyph.flags & FONT_PGF_METRIC_FLAG1) ? 0 : 56) + + ((glyph.flags & FONT_PGF_METRIC_FLAG2) ? 0 : 56) + + ((glyph.flags & FONT_PGF_METRIC_FLAG3) ? 0 : 56); + + int advanceIndex = getBits(8, fontdata, charPtr); + charPtr += 8; + + if (dimensionIndex < header.dimTableLength) { + glyph.dimensionWidth = dimensionTable[0][dimensionIndex]; + glyph.dimensionHeight = dimensionTable[1][dimensionIndex]; + } + + if (xAdjustIndex < header.xAdjustTableLength) { + glyph.xAdjustH = xAdjustTable[0][xAdjustIndex]; + glyph.xAdjustV = xAdjustTable[1][xAdjustIndex]; + } + + if (yAdjustIndex < header.xAdjustTableLength) { + glyph.yAdjustH = yAdjustTable[0][yAdjustIndex]; + glyph.yAdjustV = yAdjustTable[1][yAdjustIndex]; + } + + if (dimensionIndex == 0 && xAdjustIndex == 0 && yAdjustIndex == 0 && isJPCSPFont(fileName.c_str())) { + // Fonts created by ttf2pgf do not contain complete Glyph information. + // Provide default values. + glyph.dimensionWidth = glyph.w << 6; + glyph.dimensionHeight = glyph.h << 6; + // This stuff doesn't exactly look right. + glyph.xAdjustH = glyph.left << 6; + glyph.xAdjustV = glyph.left << 6; + glyph.yAdjustH = glyph.top << 6; + glyph.yAdjustV = glyph.top << 6; + } + + if (advanceIndex < header.advanceTableLength) { + glyph.advanceH = advanceTable[0][advanceIndex]; + glyph.advanceV = advanceTable[1][advanceIndex]; + } + } else { + glyph.shadowID = 65535; + glyph.advanceH = 0; + } + + glyph.ptr = (u32)(charPtr / 8); + return true; +} + +bool PGF::GetCharGlyph(int charCode, int glyphType, Glyph &glyph) { + if (charCode < firstGlyph) + return false; + charCode -= firstGlyph; + if (charCode < (int)charmap.size()) { + charCode = charmap[charCode]; + } + if (glyphType == FONT_PGF_CHARGLYPH) { + if (charCode >= (int)glyphs.size()) + return false; + glyph = glyphs[charCode]; + } else { + if (charCode >= (int)shadowGlyphs.size()) + return false; + glyph = shadowGlyphs[charCode]; + } + return true; +} + +void PGF::DrawCharacter(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int clipX, int clipY, int clipWidth, int clipHeight, int pixelformat, int charCode, int altCharCode, int glyphType) { + Glyph glyph; + if (!GetCharGlyph(charCode, glyphType, glyph)) { + // No Glyph available for this charCode, try to use the alternate char. + charCode = altCharCode; + if (!GetCharGlyph(charCode, glyphType, glyph)) { + return; + } + } + + if (glyph.w <= 0 || glyph.h <= 0) { + return; + } + + if (((glyph.flags & FONT_PGF_BMP_OVERLAY) != FONT_PGF_BMP_H_ROWS) && + ((glyph.flags & FONT_PGF_BMP_OVERLAY) != FONT_PGF_BMP_V_ROWS)) { + return; + } + + u32 bitPtr = glyph.ptr * 8; + int numberPixels = glyph.w * glyph.h; + int pixelIndex = 0; + + while (pixelIndex < numberPixels && bitPtr + 8 < fontDataSize * 8) { + // This is some kind of nibble based RLE compression. + int nibble = getBits(4, fontData, bitPtr); + bitPtr += 4; + + int count; + int value; + if (nibble < 8) { + value = getBits(4, fontData, bitPtr); + bitPtr += 4; + count = nibble + 1; + } else { + count = 16 - nibble; + } + + for (int i = 0; i < count && pixelIndex < numberPixels; i++) { + if (nibble >= 8) { + value = getBits(4, fontData, bitPtr); + bitPtr += 4; + } + + int xx, yy; + if ((glyph.flags & FONT_PGF_BMP_OVERLAY) == FONT_PGF_BMP_H_ROWS) { + xx = pixelIndex % glyph.w; + yy = pixelIndex / glyph.w; + } else { + xx = pixelIndex / glyph.h; + yy = pixelIndex % glyph.h; + } + + int pixelX = x + xx; + int pixelY = y + yy; + if (pixelX >= clipX && pixelX < clipX + clipWidth && pixelY >= clipY && pixelY < clipY + clipHeight) { + // 4-bit color value + int pixelColor = value; + switch (pixelformat) { + case PSP_FONT_PIXELFORMAT_8: + // 8-bit color value + pixelColor |= pixelColor << 4; + break; + case PSP_FONT_PIXELFORMAT_24: + // 24-bit color value + pixelColor |= pixelColor << 4; + pixelColor |= pixelColor << 8; + pixelColor |= pixelColor << 8; + break; + case PSP_FONT_PIXELFORMAT_32: + // 32-bit color value + pixelColor |= pixelColor << 4; + pixelColor |= pixelColor << 8; + pixelColor |= pixelColor << 16; + break; + } + + SetFontPixel(base, bpl, bufWidth, bufHeight, pixelX, pixelY, pixelColor, pixelformat); + } + + pixelIndex++; + } + } +} + +void PGF::SetFontPixel(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int pixelColor, int pixelformat) { + if (x < 0 || x >= bufWidth || y < 0 || y >= bufHeight) { + return; + } + + static const u8 fontPixelSizeInBytes[] = { 0, 0, 1, 3, 4 }; // 0 means 2 pixels per byte + int pixelBytes = fontPixelSizeInBytes[pixelformat]; + int bufMaxWidth = (pixelBytes == 0 ? bpl * 2 : bpl / pixelBytes); + if (x >= bufMaxWidth) { + return; + } + + int framebufferAddr = base + (y * bpl) + (pixelBytes == 0 ? x / 2 : x * pixelBytes); + + switch (pixelformat) { + case PSP_FONT_PIXELFORMAT_4: + case PSP_FONT_PIXELFORMAT_4_REV: + { + int oldColor = Memory::Read_U8(framebufferAddr); + int newColor; + if ((x & 1) != pixelformat) { + newColor = (pixelColor << 4) | (oldColor & 0xF); + } else { + newColor = (oldColor & 0xF0) | pixelColor; + } + Memory::Write_U8(newColor, framebufferAddr); + break; + } + case PSP_FONT_PIXELFORMAT_8: + { + Memory::Write_U8((u8)pixelColor, framebufferAddr); + break; + } + case PSP_FONT_PIXELFORMAT_24: + { + Memory::Write_U8(pixelColor & 0xFF, framebufferAddr + 0); + Memory::Write_U8(pixelColor >> 8, framebufferAddr + 1); + Memory::Write_U8(pixelColor >> 16, framebufferAddr + 2); + break; + } + case PSP_FONT_PIXELFORMAT_32: + { + Memory::Write_U32(pixelColor, framebufferAddr); + break; + } + } +} + +u32 GetFontPixelColor(int color, int pixelformat) { + switch (pixelformat) { + case PSP_FONT_PIXELFORMAT_4: + case PSP_FONT_PIXELFORMAT_4_REV: + // Use only 4-bit alpha + color = (color >> 28) & 0xF; + break; + case PSP_FONT_PIXELFORMAT_8: + // Use only 8-bit alpha + color = (color >> 24) & 0xFF; + break; + case PSP_FONT_PIXELFORMAT_24: + // Use RGB with 8-bit values + color = color & 0x00FFFFFF; + break; + case PSP_FONT_PIXELFORMAT_32: + // Use RGBA with 8-bit values + break; + } + + return color; +} \ No newline at end of file diff --git a/Core/Font/PGF.h b/Core/Font/PGF.h new file mode 100644 index 0000000000..bba9f29d3d --- /dev/null +++ b/Core/Font/PGF.h @@ -0,0 +1,289 @@ +// Copyright (c) 2012- 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/. + +// Thanks to the JPCSP project! This sceFont implementation is basically a C++ take on JPCSP's font code. + +#pragma once + +#include +#include + +#include "Common/Log.h" +#include "Common/ChunkFile.h" +#include "Common/CommonTypes.h" + +enum { + FONT_FILETYPE_PGF = 0x00, + FONT_FILETYPE_BWFON = 0x01, +}; + +enum { + FONT_PGF_BMP_H_ROWS = 0x01, + FONT_PGF_BMP_V_ROWS = 0x02, + FONT_PGF_BMP_OVERLAY = 0x03, + FONT_PGF_METRIC_FLAG1 = 0x04, + FONT_PGF_METRIC_FLAG2 = 0x08, + FONT_PGF_METRIC_FLAG3 = 0x10, + FONT_PGF_CHARGLYPH = 0x20, + FONT_PGF_SHADOWGLYPH = 0x40, +}; + +enum Family { + FONT_FAMILY_SANS_SERIF = 1, + FONT_FAMILY_SERIF = 2, +}; + +enum Style { + FONT_STYLE_REGULAR = 1, + FONT_STYLE_ITALIC = 2, + FONT_STYLE_BOLD = 5, + FONT_STYLE_BOLD_ITALIC = 6, + FONT_STYLE_DB = 103, // Demi-Bold / semi-bold +}; + +enum Language { + FONT_LANGUAGE_JAPANESE = 1, + FONT_LANGUAGE_LATIN = 2, + FONT_LANGUAGE_KOREAN = 3, + FONT_LANGUAGE_CHINESE = 4, +}; + +enum FontPixelFormat { + PSP_FONT_PIXELFORMAT_4 = 0, // 2 pixels packed in 1 byte (natural order) + PSP_FONT_PIXELFORMAT_4_REV = 1, // 2 pixels packed in 1 byte (reversed order) + PSP_FONT_PIXELFORMAT_8 = 2, // 1 pixel in 1 byte + PSP_FONT_PIXELFORMAT_24 = 3, // 1 pixel in 3 bytes (RGB) + PSP_FONT_PIXELFORMAT_32 = 4, // 1 pixel in 4 bytes (RGBA) +}; + + +struct PGFFontStyle { + float fontH; + float fontV; + float fontHRes; + float fontVRes; + float fontWeight; + u16 fontFamily; + u16 fontStyle; + // Check. + u16 fontStyleSub; + u16 fontLanguage; + u16 fontRegion; + u16 fontCountry; + char fontName[64]; + char fontFileName[64]; + u32 fontAttributes; + u32 fontExpire; +}; + + +class Glyph { +public: + int x; + int y; + int w; + int h; + int left; + int top; + int flags; + int shadowID; + int advanceH; + int advanceV; + int dimensionWidth, dimensionHeight; + int xAdjustH, xAdjustV; + int yAdjustH, yAdjustV; + u32 ptr; +}; + +#pragma pack(push,1) +struct PGFHeader +{ + u16 headerOffset; + u16 headerSize; + + char PGFMagic[4]; + int revision; + int version; + + int charMapLength; + int charPointerLength; + int charMapBpe; + int charPointerBpe; + + u8 pad1[2]; + u8 bpp; + u8 pad2[1]; + + int hSize; + int vSize; + int hResolution; + int vResolution; + + u8 pad3[1]; + char fontName[64]; + char fontType[64]; + u8 pad4[1]; + + u16 firstGlyph; + u16 lastGlyph; + + u8 pad5[26]; + + int maxAscender; + int maxDescender; + int maxLeftXAdjust; + int maxBaseYAdjust; + int minCenterXAdjust; + int maxTopYAdjust; + + int maxAdvance[2]; + int maxSize[2]; + u16 maxGlyphWidth; + u16 maxGlyphHeight; + u8 pad6[2]; + + u8 dimTableLength; + u8 xAdjustTableLength; + u8 yAdjustTableLength; + u8 advanceTableLength; + u8 pad7[102]; + + int shadowMapLength; + int shadowMapBpe; + float unknown1; + int shadowScale[2]; + u8 pad8[8]; +}; + +struct PGFHeaderRev3Extra { + int compCharMapBpe1; + int compCharMapLength1; + int compCharMapBpe2; + int compCharMapLength2; + u32 unknown; +}; + +struct PGFCharInfo { + u32 bitmapWidth; + u32 bitmapHeight; + u32 bitmapLeft; + u32 bitmapTop; + // Glyph metrics (in 26.6 signed fixed-point). + u32 sfp26Width; + u32 sfp26Height; + s32 sfp26Ascender; + s32 sfp26Descender; + s32 sfp26BearingHX; + s32 sfp26BearingHY; + s32 sfp26BearingVX; + s32 sfp26BearingVY; + s32 sfp26AdvanceH; + s32 sfp26AdvanceV; + u8 pad[4]; +}; + +struct PGFFontInfo { + // Glyph metrics (in 26.6 signed fixed-point). + int maxGlyphWidthI; + int maxGlyphHeightI; + int maxGlyphAscenderI; + int maxGlyphDescenderI; + int maxGlyphLeftXI; + int maxGlyphBaseYI; + int minGlyphCenterXI; + int maxGlyphTopYI; + int maxGlyphAdvanceXI; + int maxGlyphAdvanceYI; + + // Glyph metrics (replicated as float). + float maxGlyphWidthF; + float maxGlyphHeightF; + float maxGlyphAscenderF; + float maxGlyphDescenderF; + float maxGlyphLeftXF; + float maxGlyphBaseYF; + float minGlyphCenterXF; + float maxGlyphTopYF; + float maxGlyphAdvanceXF; + float maxGlyphAdvanceYF; + + // Bitmap dimensions. + short maxGlyphWidth; + short maxGlyphHeight; + int charMapLength; // Number of elements in the font's charmap. + int shadowMapLength; // Number of elements in the font's shadow charmap. + + // Font style (used by font comparison functions). + PGFFontStyle fontStyle; + + int BPP; // Font's BPP. +}; + +#pragma pack(pop) + +class PGF { +public: + PGF(); + ~PGF(); + + void ReadPtr(const u8 *ptr, size_t dataSize); + + bool GetCharInfo(int charCode, PGFCharInfo *ci); + void GetFontInfo(PGFFontInfo *fi); + void DrawCharacter(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int clipX, int clipY, int clipWidth, int clipHeight, int pixelformat, int charCode, int altCharCode, int glyphType); + + void DoState(PointerWrap &p); + + PGFHeader header; + +private: + bool GetGlyph(const u8 *fontdata, size_t charPtr, int glyphType, Glyph &glyph); + bool GetCharGlyph(int charCode, int glyphType, Glyph &glyph); + + // Unused + int GetCharIndex(int charCode, const std::vector &charmapCompressed); + + void SetFontPixel(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int pixelColor, int pixelformat); + + PGFHeaderRev3Extra rev3extra; + + // Font character image data + u8 *fontData; + size_t fontDataSize; + + std::string fileName; + + std::vector dimensionTable[2]; + std::vector xAdjustTable[2]; + std::vector yAdjustTable[2]; + std::vector advanceTable[2]; + + // Unused + std::vector charmapCompressionTable1[2]; + std::vector charmapCompressionTable2[2]; + + u8 *charMap; + u8 *shadowCharMap; + u8 *charPointerTable; + + std::vector charmap_compr; + std::vector charmap; + + std::vector glyphs; + std::vector shadowGlyphs; + int firstGlyph; +}; diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 85468754b8..95a13616f5 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -96,6 +96,11 @@ template void WrapF_V() { RETURNF(func()); } +// TODO: Not sure about the floating point parameter passing +template void WrapF_IFU() { + RETURNF(func(PARAM(0), PARAMF(0), PARAM(1))); +} + template void WrapU_U() { u32 retval = func(PARAM(0)); RETURN(retval); @@ -133,7 +138,7 @@ template void WrapI_UU() { template void WrapI_UFF() { // Not sure about the float arguments. - int retval = func(PARAM(0), currentMIPS->f[0], currentMIPS->f[1]); + int retval = func(PARAM(0), currentMIPS->f[12], currentMIPS->f[13]); RETURN(retval); } @@ -313,6 +318,11 @@ template void WrapI_IIII() { RETURN(retval); } +template void WrapI_ICIUU() { + int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); + RETURN(retval); +} + template void WrapI_IIU() { int retval = func(PARAM(0), PARAM(1), PARAM(2)); RETURN(retval); @@ -481,6 +491,11 @@ template void WrapU_UUUU() { RETURN(retval); } +template void WrapU_UCUU() { + u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); + RETURN(retval); +} + template void WrapU_UUUI() { u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); RETURN(retval); diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 48c0f87688..cc9e98ca6a 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -64,7 +64,7 @@ void HLEInit() void HLEDoState(PointerWrap &p) { - Syscall sc = {0}; + Syscall sc = {""}; p.Do(unresolvedSyscalls, sc); p.Do(exportedCalls, sc); p.DoMarker("HLE"); diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 8ff39c328c..40b4a17dbc 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -53,11 +53,12 @@ struct Syscall }; #define PARAM(n) currentMIPS->r[4+n] +#define PARAMF(n) currentMIPS->f[12+n] #define RETURN(n) currentMIPS->r[2]=n #define RETURNF(fl) currentMIPS->f[0]=fl #ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0]) +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #endif #include "FunctionWrappers.h" diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 3f9597b443..bd2302fa58 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -54,6 +54,7 @@ #include "sceVaudio.h" #include "sceUsb.h" #include "sceChnnlsv.h" +#include "scePspNpDrm_user.h" #define N(s) s diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 5ea398ca07..6e05803c5b 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -395,10 +395,11 @@ u32 sceAtracGetStreamDataInfo(int atracID, u32 writeAddr, u32 writableBytesAddr, Atrac *atrac = getAtrac(atracID); if (!atrac) { //return -1; + } else { + Memory::Write_U32(atrac->first.addr, writeAddr); + Memory::Write_U32(atrac->first.writableBytes, writableBytesAddr); + Memory::Write_U32(atrac->first.fileoffset, readOffsetAddr); } - Memory::Write_U32(atrac->first.addr, writeAddr); - Memory::Write_U32(atrac->first.writableBytes, writableBytesAddr); - Memory::Write_U32(atrac->first.fileoffset, readOffsetAddr); return 0; } diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 81d264e590..152b322fed 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -403,12 +403,15 @@ void hleEnterVblank(u64 userdata, int cyclesLate) { if (skipFrame) { gstate_c.skipDrawReason |= SKIPDRAW_SKIPFRAME; numSkippedFrames++; - } else { + } else { numSkippedFrames = 0; } if (!skipFlip) { - coreState = CORE_NEXTFRAME; + // Might've just quit / been paused. + if (coreState == CORE_RUNNING) { + coreState = CORE_NEXTFRAME; + } CoreTiming::ScheduleEvent(0 - cyclesLate, afterFlipEvent, 0); gpu->CopyDisplayToOutput(); diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 867d7ea664..7125478ba8 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -2,9 +2,38 @@ #include "base/timeutil.h" +#include + #include "HLE.h" #include "../MIPS/MIPS.h" #include "ChunkFile.h" +#include "Core/FileSystems/FileSystem.h" +#include "Core/System.h" +#include "Core/HLE/sceKernel.h" +#include "Core/Font/PGF.h" +#include "Core/HLE/sceKernelThread.h" + +enum { + ERROR_FONT_INVALID_LIBID = 0x80460002, + ERROR_FONT_INVALID_PARAMETER = 0x80460003, + ERROR_FONT_TOO_MANY_OPEN_FONTS = 0x80460009, +}; + +enum { + FONT_IS_CLOSED = 0, + FONT_IS_OPEN = 1, +}; + +// Actions +static int actionPostAllocCallback; +static int actionPostOpenCallback; + +// Monster Hunter sequence: +// 36:46:998 c:\dev\ppsspp\core\hle\scefont.cpp:469 E[HLE]: sceFontNewLib 89ad4a0, 9fff5cc +// 36:46:998 c:\dev\ppsspp\core\hle\scefont.cpp:699 E[HLE]: UNIMPL sceFontGetNumFontList 1, 9fff5cc +// 36:46:998 c:\dev\ppsspp\core\hle\scefont.cpp:526 E[HLE]: sceFontFindOptimumFont 1, 9fff524, 9fff5cc +// 36:46:999 c:\dev\ppsspp\core\hle\scefont.cpp:490 E[HLE]: sceFontOpenFont 1, 1, 0, 9fff5cc +// 36:46:999 c:\dev\ppsspp\core\hle\scefont.cpp:542 E[HLE]: sceFontGetFontInfo 1, 997140c typedef u32 FontLibraryHandle; typedef u32 FontHandle; @@ -25,109 +54,6 @@ struct FontNewLibParams { u32 ioFinishFuncAddr; }; -typedef enum Family { - FONT_FAMILY_SANS_SERIF = 1, - FONT_FAMILY_SERIF = 2, -}; - -typedef enum Style { - FONT_STYLE_REGULAR = 1, - FONT_STYLE_ITALIC = 2, - FONT_STYLE_BOLD = 5, - FONT_STYLE_BOLD_ITALIC = 6, - FONT_STYLE_DB = 103, // Demi-Bold / semi-bold -}; - -typedef enum Language { - FONT_LANGUAGE_JAPANESE = 1, - FONT_LANGUAGE_LATIN = 2, - FONT_LANGUAGE_KOREAN = 3, -}; - -struct FontStyle { - float fontH; - float fontV; - float fontHRes; - float fontVRes; - float fontWeight; - u16 fontFamily; - u16 fontStyle; - // Check. - u16 fontStyleSub; - u16 fontLanguage; - u16 fontRegion; - u16 fontCountry; - char fontName[64]; - char fontFileName[64]; - u32 fontAttributes; - u32 fontExpire; -}; - -struct FontInfo { - // Glyph metrics (in 26.6 signed fixed-point). - u32 maxGlyphWidthI; - u32 maxGlyphHeightI; - u32 maxGlyphAscenderI; - u32 maxGlyphDescenderI; - u32 maxGlyphLeftXI; - u32 maxGlyphBaseYI; - u32 minGlyphCenterXI; - u32 maxGlyphTopYI; - u32 maxGlyphAdvanceXI; - u32 maxGlyphAdvanceYI; - - // Glyph metrics (replicated as float). - float maxGlyphWidthF; - float maxGlyphHeightF; - float maxGlyphAscenderF; - float maxGlyphDescenderF; - float maxGlyphLeftXF; - float maxGlyphBaseYF; - float minGlyphCenterXF; - float maxGlyphTopYF; - float maxGlyphAdvanceXF; - float maxGlyphAdvanceYF; - - // Bitmap dimensions. - short maxGlyphWidth; - short maxGlyphHeight; - u32 charMapLength; // Number of elements in the font's charmap. - u32 shadowMapLength; // Number of elements in the font's shadow charmap. - - // Font style (used by font comparison functions). - FontStyle fontStyle; - - u8 BPP; // Font's BPP. - u8 pad[3]; -}; - -struct CharInfo { - u32 bitmapWidth; - u32 bitmapHeight; - u32 bitmapLeft; - u32 bitmapTop; - // Glyph metrics (in 26.6 signed fixed-point). - u32 spf26Width; - u32 spf26Height; - s32 spf26Ascender; - s32 spf26Descender; - s32 spf26BearingHX; - s32 spf26BearingHY; - s32 spf26BearingVX; - s32 spf26BearingVY; - s32 spf26AdvanceH; - s32 spf26AdvanceV; - u8 pad[4]; -}; - -enum FontPixelFormat { - PSP_FONT_PIXELFORMAT_4 = 0, - PSP_FONT_PIXELFORMAT_4_REV = 1, - PSP_FONT_PIXELFORMAT_8 = 2, - PSP_FONT_PIXELFORMAT_24 = 3, - PSP_FONT_PIXELFORMAT_32 = 4 -}; - struct GlyphImage { FontPixelFormat pixelFormat; s32 xPos64; @@ -139,184 +65,653 @@ struct GlyphImage { u32 bufferPtr; }; -FontNewLibParams fontLib; +struct FontRegistryEntry { + int hSize; + int vSize; + int hResolution; + int vResolution; + int extraAttributes; + int weight; + int familyCode; + int style; + int styleSub; + int languageCode; + int regionCode; + int countryCode; + const char *fileName; + const char *fontName; + int expireDate; + int shadow_option; +}; -void __FontInit() -{ - memset(&fontLib, 0, sizeof(fontLib)); +static const FontRegistryEntry fontRegistry[] = { + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_DB, 0, FONT_LANGUAGE_JAPANESE, 0, 1, "jpn0.pgf", "FTT-NewRodin Pro DB", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn0.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn1.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn2.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn3.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn4.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn5.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn6.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn7.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn8.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn9.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn10.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn11.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn12.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn13.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn14.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn15.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_KOREAN, 0, 3, "kr0.pgf", "AsiaNHH(512Johab)", 0, 0}, +}; + +static const float pointDPI = 72.f; + +class FontLib; + +// TODO: Merge this class with PGF? That'd make it harder to support .bwfon +// fonts though, unless that's added directly to PGF. +class Font { +public: + Font(const u8 *data, size_t dataSize) { + pgf_.ReadPtr(data, dataSize); + style_.fontH = pgf_.header.hSize / 64.0f; + style_.fontV = pgf_.header.vSize / 64.0f; + style_.fontHRes = pgf_.header.hResolution / 64.0f; + style_.fontVRes = pgf_.header.vResolution / 64.0f; + } + + Font(const u8 *data, size_t dataSize, const FontRegistryEntry &entry) { + pgf_.ReadPtr(data, dataSize); + style_.fontH = entry.hSize / 64.f; + style_.fontV = entry.vSize / 64.f; + style_.fontHRes = entry.hResolution / 64.f; + style_.fontVRes = entry.vResolution / 64.f; + style_.fontWeight = (float)entry.weight; + style_.fontFamily = (u16)entry.familyCode; + style_.fontStyle = (u16)entry.style; + style_.fontStyleSub = (u16)entry.styleSub; + style_.fontLanguage = (u16)entry.languageCode; + style_.fontRegion = (u16)entry.regionCode; + style_.fontCountry = (u16)entry.countryCode; + strncpy(style_.fontName, entry.fontName, sizeof(style_.fontName)); + strncpy(style_.fontFileName, entry.fileName, sizeof(style_.fontFileName)); + style_.fontAttributes = entry.extraAttributes; + style_.fontExpire = entry.expireDate; + } + + const PGFFontStyle &GetFontStyle() const { return style_; } + + bool MatchesStyle(const PGFFontStyle &style, bool optimum) const { + // TODO + return true; + } + + PGF *GetPGF() { return &pgf_; } + +private: + PGF pgf_; + PGFFontStyle style_; + DISALLOW_COPY_AND_ASSIGN(Font); +}; + +class LoadedFont { +public: + LoadedFont(Font *font, FontLib *fontLib, u32 handle) + : font_(font), fontLib_(fontLib), handle_(handle) {} + + Font *GetFont() { return font_; } + FontLib *GetFontLib() { return fontLib_; } + u32 Handle() const { return handle_; } + + bool IsOpen() const { return fontLib_ != 0; } + void Close() { + fontLib_ = 0; + // We keep the rest around until deleted, as some queries are allowed + // on closed fonts (which is rather strange). + } + +private: + FontLib *fontLib_; + Font *font_; + u32 handle_; + DISALLOW_COPY_AND_ASSIGN(LoadedFont); +}; + +class FontLib; + +// These should not need to be state saved. +static std::vector internalFonts; +// However, these we must save - but we could take a shortcut +// for LoadedFonts that point to internal fonts. +static std::map fontMap; +static std::map fontLibMap; + +class PostAllocCallback : public Action { +public: + PostAllocCallback() {} + static Action *Create() { return new PostAllocCallback(); } + void DoState(PointerWrap &p) { /*TODO*/ p.DoMarker("PostAllocCallback"); } + void run(MipsCall &call); + void SetFontLib(FontLib *fontLib) { fontLib_ = fontLib; } + +private: + FontLib *fontLib_; +}; + +class PostOpenCallback : public Action { +public: + PostOpenCallback() {} + static Action *Create() { return new PostOpenCallback(); } + void DoState(PointerWrap &p) { /*TODO*/ p.DoMarker("PostOpenCallback"); } + void run(MipsCall &call); + void SetFontLib(FontLib *fontLib) { fontLib_ = fontLib; } + +private: + FontLib *fontLib_; +}; + +// A "fontLib" is a container of loaded fonts. +// One can open either "internal" fonts or custom fonts into a fontlib. +class FontLib { +public: + FontLib(u32 paramPtr) : fontHRes_(128.0f), fontVRes_(128.0f) { + Memory::ReadStruct(paramPtr, ¶ms_); + + // We use the same strange scheme that JPCSP uses. + u32 allocSize = 4 + 4 * params_.numFonts; + PostAllocCallback *action = (PostAllocCallback*) __KernelCreateAction(actionPostAllocCallback); + action->SetFontLib(this); + u32 args[1] = { allocSize }; + __KernelDirectMipsCall(params_.allocFuncAddr, action, args, 1, false); + } + + void Close() { + __KernelDirectMipsCall(params_.closeFuncAddr, 0, 0, 0, false); + } + + void Done() { + for (size_t i = 0; i < fonts_.size(); i++) { + if (Memory::Read_U32(fonts_[i]) == FONT_IS_OPEN) { + fontMap[fonts_[i]]->Close(); + delete fontMap[fonts_[i]]; + fontMap.erase(fonts_[i]); + } + } + u32 args[1] = { (u32)handle_ }; + __KernelDirectMipsCall(params_.freeFuncAddr, 0, args, 1, false); + handle_ = 0; + fonts_.clear(); + } + + void AllocDone(u32 allocatedAddr) { + handle_ = allocatedAddr; + fonts_.resize(params_.numFonts); + for (size_t i = 0; i < fonts_.size(); i++) { + u32 addr = allocatedAddr + 4 + i * 4; + Memory::Write_U32(FONT_IS_CLOSED, addr); + fonts_[i] = addr; + } + } + + u32 handle() const { return handle_; } + int numFonts() const { return params_.numFonts; } + + void SetResolution(float hres, float vres) { + fontHRes_ = hres; + fontVRes_ = vres; + } + + float FontHRes() const { return fontHRes_; } + float FontVRes() const { return fontVRes_; } + + void SetAltCharCode(int charCode) { altCharCode_ = charCode; } + + int GetFontHandle(int index) { + return fonts_[index]; + } + + LoadedFont *OpenFont(Font *font) { + int freeFontIndex = -1; + for (size_t i = 0; i < fonts_.size(); i++) { + if (Memory::Read_U32(fonts_[i]) == FONT_IS_CLOSED) { + freeFontIndex = (int)i; + break; + } + } + if (freeFontIndex < 0) { + ERROR_LOG(HLE, "Too many fonts opened in FontLib"); + return 0; + } + LoadedFont *loadedFont = new LoadedFont(font, this, fonts_[freeFontIndex]); + Memory::Write_U32(FONT_IS_OPEN, fonts_[freeFontIndex]); + return loadedFont; + } + + void CloseFont(LoadedFont *font) { + for (size_t i = 0; i < fonts_.size(); i++) { + if (fonts_[i] == font->Handle()) { + Memory::Write_U32(FONT_IS_CLOSED, font->Handle()); + + } + } + font->Close(); + } + + void DoState(PointerWrap &p) { + p.Do(fonts_); + p.Do(params_); + p.Do(fontHRes_); + p.Do(fontVRes_); + p.Do(fileFontHandle_); + p.Do(handle_); + p.Do(altCharCode_); + } + + void SetFileFontHandle(u32 handle) { + fileFontHandle_ = handle; + } + + u32 GetAltCharCode() const { return altCharCode_; } + +private: + std::vector fonts_; + + FontNewLibParams params_; + float fontHRes_; + float fontVRes_; + int fileFontHandle_; + int handle_; + int altCharCode_; + DISALLOW_COPY_AND_ASSIGN(FontLib); +}; + + +void PostAllocCallback::run(MipsCall &call) { + INFO_LOG(HLE, "Entering PostAllocCallback::run"); + u32 v0 = currentMIPS->r[0]; + fontLib_->AllocDone(call.savedV0); + fontLibMap[fontLib_->handle()] = fontLib_; + call.setReturnValue(fontLib_->handle()); + INFO_LOG(HLE, "Leaving PostAllocCallback::run"); } -void __FontDoState(PointerWrap &p) -{ - p.Do(fontLib); +void PostOpenCallback::run(MipsCall &call) { + fontLib_->SetFileFontHandle(call.savedV0); +} + +FontLib *GetFontLib(u32 handle) { + if (fontLibMap.find(handle) != fontLibMap.end()) { + return fontLibMap[handle]; + } else { + ERROR_LOG(HLE, "No fontlib with handle %08x", handle); + return 0; + } +} + +LoadedFont *GetLoadedFont(u32 handle, bool allowClosed) { + auto iter = fontMap.find(handle); + if (iter != fontMap.end()) { + if (iter->second->IsOpen() || allowClosed) { + return fontMap[handle]; + } else { + ERROR_LOG(HLE, "Font exists but is closed, which was not allowed in this call."); + return 0; + } + } else { + ERROR_LOG(HLE, "No font with handle %08x", handle); + return 0; + } +} + +void __LoadInternalFonts() { + std::string fontPath = "flash0:/font/"; + if (!pspFileSystem.GetFileInfo(fontPath).exists) { + pspFileSystem.MkDir(fontPath); + } + for (size_t i = 0; i < ARRAY_SIZE(fontRegistry); i++) { + const FontRegistryEntry &entry = fontRegistry[i]; + std::string fontFilename = fontPath + entry.fileName; + PSPFileInfo info = pspFileSystem.GetFileInfo(fontFilename); + if (info.exists) { + INFO_LOG(HLE, "Loading font %s (%i bytes)", fontFilename.c_str(), (int)info.size); + u8 *buffer = new u8[(size_t)info.size]; + u32 handle = pspFileSystem.OpenFile(fontFilename, FILEACCESS_READ); + if (!handle) { + ERROR_LOG(HLE, "Failed opening font"); + delete [] buffer; + continue; + } + pspFileSystem.ReadFile(handle, buffer, info.size); + pspFileSystem.CloseFile(handle); + + internalFonts.push_back(new Font(buffer, (size_t)info.size, entry)); + + delete [] buffer; + INFO_LOG(HLE, "Loaded font %s", fontFilename.c_str()); + } else { + INFO_LOG(HLE, "Font file not found: %s", fontFilename.c_str()); + } + } +} + +Style FontStyleFromString(const std::string &str) { + if (str == "Regular") + return FONT_STYLE_REGULAR; + else if (str == "Italic") + return FONT_STYLE_ITALIC; + else if (str == "Bold") + return FONT_STYLE_BOLD; + else if (str == "Bold Italic") + return FONT_STYLE_BOLD_ITALIC; + return FONT_STYLE_REGULAR; +} + +Font *GetOptimumFont(const PGFFontStyle &requestedStyle, Font *optimumFont, Font *candidateFont) { + if (!optimumFont) + return candidateFont; + PGFFontStyle optimumStyle = optimumFont->GetFontStyle(); + PGFFontStyle candidateStyle = candidateFont->GetFontStyle(); + + bool testH = requestedStyle.fontH != 0.0f || requestedStyle.fontV == 0.0f; + if (testH && fabsf(requestedStyle.fontH - optimumStyle.fontH) > fabsf(requestedStyle.fontH - candidateStyle.fontH)) { + return candidateFont; + } + + // Check the fontV if it is specified or both fontH and fontV are unspecified + bool testV = requestedStyle.fontV != 0.f || requestedStyle.fontH == 0.f; + if (testV && fabsf(requestedStyle.fontV - optimumStyle.fontV) > fabsf(requestedStyle.fontV - candidateStyle.fontV)) { + return candidateFont; + } + + return optimumFont; +} + +int GetInternalFontIndex(Font *font) { + for (size_t i = 0; i < internalFonts.size(); i++) { + if (internalFonts[i] == font) + return i; + } + return 0; +} + +void __FontInit() { + __LoadInternalFonts(); + actionPostAllocCallback = __KernelRegisterActionType(PostAllocCallback::Create); + actionPostOpenCallback = __KernelRegisterActionType(PostOpenCallback::Create); +} + +void __FontShutdown() { + for (auto iter = fontMap.begin(); iter != fontMap.end(); iter++) { + FontLib *fontLib = iter->second->GetFontLib(); + if (fontLib) + fontLib->CloseFont(iter->second); + } + fontMap.clear(); + for (auto iter = fontLibMap.begin(); iter != fontLibMap.end(); iter++) { + delete iter->second; + } + fontLibMap.clear(); + for (auto iter = internalFonts.begin(); iter != internalFonts.end(); ++iter) { + delete *iter; + } + internalFonts.clear(); +} + +void __FontDoState(PointerWrap &p) { + // TODO: Needs much work. + + p.Do(actionPostAllocCallback); + __KernelRestoreActionType(actionPostAllocCallback, PostAllocCallback::Create); + p.Do(actionPostOpenCallback); + __KernelRestoreActionType(actionPostOpenCallback, PostOpenCallback::Create); p.DoMarker("sceFont"); } -u32 sceFontNewLib(u32 FontNewLibParamsPtr, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontNewLib %x, %x", FontNewLibParamsPtr, errorCodePtr); +u32 sceFontNewLib(u32 paramPtr, u32 errorCodePtr) { + INFO_LOG(HLE, "sceFontNewLib(%08x, %08x)", paramPtr, errorCodePtr); - if (Memory::IsValidAddress(FontNewLibParamsPtr)&&Memory::IsValidAddress(errorCodePtr)) - { + if (Memory::IsValidAddress(paramPtr) && Memory::IsValidAddress(errorCodePtr)) { Memory::Write_U32(0, errorCodePtr); - Memory::ReadStruct(FontNewLibParamsPtr, &fontLib); + + FontLib *newLib = new FontLib(paramPtr); + // The game should never see this value, the return value is replaced + // by the action. + return 0xDEADDEAD; } - return 1; -} - - -int sceFontDoneLib(u32 FontLibraryHandlePtr) -{ - ERROR_LOG(HLE, "sceFontDoneLib %x", FontLibraryHandlePtr); return 0; } - -u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontDoneLib %x, %x, %x, %x", libHandle, index, mode, errorCodePtr); - if (Memory::IsValidAddress(errorCodePtr)) - { - Memory::Write_U32(0, errorCodePtr); +int sceFontDoneLib(u32 fontLibHandle) { + INFO_LOG(HLE, "sceFontDoneLib(%08x)", fontLibHandle); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + fl->Done(); } - return 1; + return 0; } -u32 sceFontOpenUserMemory(u32 libHandle, u32 memoryFontAddrPtr, u32 memoryFontLength, u32 errorCodePtr) -{ +// Open internal font into a FontLib +u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) { + INFO_LOG(HLE, "sceFontOpen(%x, %x, %x, %x)", libHandle, index, mode, errorCodePtr); + if (!Memory::IsValidAddress(errorCodePtr)) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + FontLib *fontLib = GetFontLib(libHandle); + if (index < 0 || index >= internalFonts.size()) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + LoadedFont *font = fontLib->OpenFont(internalFonts[index]); + if (font) { + fontMap[font->Handle()] = font; + Memory::Write_U32(0, errorCodePtr); + return font->Handle(); + } else { + Memory::Write_U32(ERROR_FONT_TOO_MANY_OPEN_FONTS, errorCodePtr); + return 0; + } +} + +// Open a user font in RAM into a FontLib +u32 sceFontOpenUserMemory(u32 libHandle, u32 memoryFontAddrPtr, u32 memoryFontLength, u32 errorCodePtr) { ERROR_LOG(HLE, "sceFontOpenUserMemory %x, %x, %x, %x", libHandle, memoryFontAddrPtr, memoryFontLength, errorCodePtr); - if (Memory::IsValidAddress(errorCodePtr)) - { + if (!Memory::IsValidAddress(errorCodePtr) || !Memory::IsValidAddress(memoryFontAddrPtr)) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + FontLib *fontLib = GetFontLib(libHandle); + if (!fontLib) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + const u8 *fontData = Memory::GetPointer(memoryFontAddrPtr); + LoadedFont *font = fontLib->OpenFont(new Font(fontData, memoryFontLength)); + if (font) { + fontMap[font->Handle()] = font; Memory::Write_U32(0, errorCodePtr); + return font->Handle(); + } else { + Memory::Write_U32(ERROR_FONT_TOO_MANY_OPEN_FONTS, errorCodePtr); + return 0; } - return 1; } -u32 sceFontOpenUserFile(u32 libHandle, u32 fileNamePtr, u32 mode, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontOpenUserFile %x, %x, %x, %x", libHandle, fileNamePtr, mode, errorCodePtr); - if (Memory::IsValidAddress(errorCodePtr)) - { +// Open a user font in a file into a FontLib +u32 sceFontOpenUserFile(u32 libHandle, const char *fileName, u32 mode, u32 errorCodePtr) { + ERROR_LOG(HLE, "sceFontOpenUserFile(%08x, %s, %08x, %08x)", libHandle, fileName, mode, errorCodePtr); + if (!Memory::IsValidAddress(errorCodePtr)) + return ERROR_FONT_INVALID_PARAMETER; + + PSPFileInfo info = pspFileSystem.GetFileInfo(fileName); + if (!info.exists) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + FontLib *fontLib = GetFontLib(libHandle); + if (!fontLib) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + u8 *buffer = new u8[(size_t)info.size]; + + u32 fileHandle = pspFileSystem.OpenFile(fileName, FILEACCESS_READ); + pspFileSystem.ReadFile(fileHandle, buffer, info.size); + pspFileSystem.CloseFile(fileHandle); + + LoadedFont *font = fontLib->OpenFont(new Font(buffer, (size_t)info.size)); + if (font) { + fontMap[font->Handle()] = font; Memory::Write_U32(0, errorCodePtr); + return font->Handle(); + } else { + Memory::Write_U32(ERROR_FONT_TOO_MANY_OPEN_FONTS, errorCodePtr); + return 0; } - return 1; } -int sceFontClose(u32 fontHandle) -{ - ERROR_LOG(HLE, "sceFontClose %x", fontHandle); +int sceFontClose(u32 fontHandle) { + LoadedFont *font = GetLoadedFont(fontHandle, false); + if (font) + { + INFO_LOG(HLE, "sceFontClose(%x)", fontHandle); + FontLib *fontLib = font->GetFontLib(); + if (fontLib) + fontLib->CloseFont(font); + } + else + ERROR_LOG(HLE, "sceFontClose(%x) - font not open?", fontHandle); return 0; } -int sceFontFindOptimumFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontFindOptimumFont %x, %x, %x", libHandlePtr, fontStylePtr, errorCodePtr); - if (Memory::IsValidAddress(errorCodePtr)) - { +int sceFontFindOptimumFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr) { + ERROR_LOG(HLE, "sceFontFindOptimumFont(%08x, %08x, %08x)", libHandlePtr, fontStylePtr, errorCodePtr); + if (!fontStylePtr) + return 0; + + if (!Memory::IsValidAddress(errorCodePtr)) + return SCE_KERNEL_ERROR_INVALID_ARGUMENT; + + PGFFontStyle requestedStyle; + Memory::ReadStruct(fontStylePtr, &requestedStyle); + + Font *optimumFont = 0; + for (size_t i = 0; i < internalFonts.size(); i++) { + if (internalFonts[i]->MatchesStyle(requestedStyle, true)) { + optimumFont = GetOptimumFont(requestedStyle, optimumFont, internalFonts[i]); + } + } + if (optimumFont) { Memory::Write_U32(0, errorCodePtr); + return GetInternalFontIndex(optimumFont); + } else { + Memory::Write_U32(0, errorCodePtr); + return 0; } - return 1; } -int sceFontFindFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontFindFont %x, %x, %x", libHandlePtr, fontStylePtr, errorCodePtr); - return 1; +// Returns the font index, not handle +int sceFontFindFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr) { + ERROR_LOG(HLE, "sceFontFindFont(%x, %x, %x)", libHandlePtr, fontStylePtr, errorCodePtr); + if (!Memory::IsValidAddress(errorCodePtr)) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + PGFFontStyle style; + Memory::ReadStruct(fontStylePtr, &style); + + for (size_t i = 0; i < internalFonts.size(); i++) { + if (internalFonts[i]->MatchesStyle(style, false)) { + Memory::Write_U32(0, errorCodePtr); + return i; + } + } + return -1; } -int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr) -{ - ERROR_LOG(HLE, "sceFontGetFontInfo %x, %x", fontHandle, fontInfoPtr); +int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr) { + ERROR_LOG(HLE, "sceFontGetFontInfo(%x, %x)", fontHandle, fontInfoPtr); - FontInfo fi; + PGFFontInfo fi; memset (&fi, 0, sizeof(fi)); - if (Memory::IsValidAddress(fontInfoPtr)) - { - fi.BPP = 4; - fi.charMapLength = 255; - fi.maxGlyphAdvanceXF = 2.0; - fi.maxGlyphAdvanceXI = 2; - fi.maxGlyphAdvanceYF = 2.0; - fi.maxGlyphAdvanceYI = 32 << 6; - fi.maxGlyphAscenderF = 32 << 6; - fi.maxGlyphAscenderI = 32 << 6; - fi.maxGlyphBaseYF = 0.0; - fi.maxGlyphBaseYI = 0; - fi.maxGlyphDescenderF = 0; - fi.maxGlyphDescenderI = 0; - fi.maxGlyphHeight = 32; - fi.maxGlyphHeightF = 32; - fi.maxGlyphHeightI = 32; - fi.maxGlyphLeftXF = 0; - fi.maxGlyphLeftXI = 0; - fi.maxGlyphTopYF = 0; - fi.maxGlyphTopYI = 0; - fi.maxGlyphWidth = 32; - fi.maxGlyphWidthF = 32; - fi.maxGlyphWidthI = 32; - fi.minGlyphCenterXF = 16; - fi.minGlyphCenterXI = 16; - fi.shadowMapLength = 0; - fi.fontStyle.fontAttributes=1; - fi.fontStyle.fontCountry= 1; - fi.fontStyle.fontExpire= 1; - fi.fontStyle.fontFamily= 1; - strcpy(fi.fontStyle.fontFileName, "asd"); - fi.fontStyle.fontH=32; - fi.fontStyle.fontHRes=32; - fi.fontStyle.fontLanguage=1; - strcpy(fi.fontStyle.fontName, "ppsspp"); - fi.fontStyle.fontRegion=9; - fi.fontStyle.fontV=32; - fi.fontStyle.fontVRes=32; - fi.fontStyle.fontWeight= 32; - Memory::WriteStruct(fontInfoPtr, &fi); - } + if (!Memory::IsValidAddress(fontInfoPtr)) + return 0; + LoadedFont *font = GetLoadedFont(fontHandle, true); + if (!font) + return 0; + PGF *pgf = font->GetFont()->GetPGF(); + pgf->GetFontInfo(&fi); + fi.fontStyle = font->GetFont()->GetFontStyle(); + + Memory::WriteStruct(fontInfoPtr, &fi); return 0; } -int sceFontGetFontInfoByIndexNumber(u32 libHandle, u32 fontInfoPtr, u32 unknown, u32 fontIndex) -{ - ERROR_LOG(HLE, "HACK sceFontGetFontInfoByIndexNumber %x, %x, %x, %x", libHandle, fontInfoPtr, unknown, fontIndex); - // clearly wrong.. - return sceFontGetFontInfo(libHandle, fontInfoPtr); - +int sceFontGetFontInfoByIndexNumber(u32 libHandle, u32 fontInfoPtr, u32 unknown, u32 fontIndex) { + ERROR_LOG(HLE, "HACK sceFontGetFontInfoByIndexNumber(%x, %x, %i, %i)", libHandle, fontInfoPtr, unknown, fontIndex); + FontLib *fl = GetFontLib(libHandle); + u32 fontHandle = fl->GetFontHandle(fontIndex); + return sceFontGetFontInfo(fontHandle, fontInfoPtr); } -int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) -{ - ERROR_LOG(HLE, "HACK sceFontGetCharInfo %x, %x, %x", fontHandle, charCode, charInfoPtr); - if (Memory::IsValidAddress(charInfoPtr)) - { - CharInfo pspCharInfo; - memset(&pspCharInfo, 0, sizeof(pspCharInfo)); - pspCharInfo.bitmapWidth = 16; - pspCharInfo.bitmapHeight = 16; +int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) { + INFO_LOG(HLE, "sceFontGetCharInfo(%08x, %i, %08x)", fontHandle, charCode, charInfoPtr); + if (!Memory::IsValidAddress(charInfoPtr)) + return -1; - pspCharInfo.spf26Width = pspCharInfo.bitmapWidth << 6; - pspCharInfo.spf26Height = pspCharInfo.bitmapHeight << 6; - pspCharInfo.spf26AdvanceH = pspCharInfo.bitmapWidth << 6; - pspCharInfo.spf26AdvanceV = pspCharInfo.bitmapHeight << 6; - Memory::WriteStruct(charInfoPtr, &pspCharInfo); + PGFCharInfo charInfo; + memset(&charInfo, 0, sizeof(charInfo)); + LoadedFont *font = GetLoadedFont(fontHandle, false); + if (font) { + font->GetFont()->GetPGF()->GetCharInfo(charCode, &charInfo); + } else { + ERROR_LOG(HLE, "sceFontGetCharInfo - invalid font"); + } + Memory::WriteStruct(charInfoPtr, &charInfo); + return 0; +} + +// Not sure about the arguments. +int sceFontGetShadowInfo(u32 fontHandle, u32 charCode, u32 shadowCharInfoPtr) { + ERROR_LOG(HLE, "UNIMPL sceFontGetShadowInfo(%08x, %i, %08x)", fontHandle, charCode, shadowCharInfoPtr); + // TODO + return 0; +} + +int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) { + ERROR_LOG(HLE, "HACK sceFontGetCharImageRect(%08x, %i, %08x) (char: %c)", fontHandle, charCode, charRectPtr, (char)charCode); + if (!Memory::IsValidAddress(charRectPtr)) + return -1; + + PGFCharInfo charInfo; + LoadedFont *font = GetLoadedFont(fontHandle, false); + if (font) { + font->GetFont()->GetPGF()->GetCharInfo(charCode, &charInfo); + Memory::Write_U16(charInfo.bitmapWidth, charRectPtr); // character bitmap width in pixels + Memory::Write_U16(charInfo.bitmapHeight, charRectPtr + 2); // character bitmap height in pixels + } else { + ERROR_LOG(HLE, "sceFontGetCharImageRect - invalid font"); } return 0; } -int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) -{ - ERROR_LOG(HLE, "HACK sceFontGetCharImageRect %x, %x (%c)", fontHandle, charRectPtr, charCode); - if (Memory::IsValidAddress(charRectPtr)) { - Memory::Write_U16(16, charRectPtr); // character bitmap width in pixels - Memory::Write_U16(16, charRectPtr + 2); // character bitmap height in pixels - } +int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) { + ERROR_LOG(HLE, "UNIMPL sceFontGetShadowImageRect()"); return 0; } -int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) -{ - ERROR_LOG(HLE, "HACK sceFontGetCharGlyphImage %x, %x, %x (%c)", fontHandle, charCode, glyphImagePtr, charCode); +int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) { + ERROR_LOG(HLE, "HACK sceFontGetCharGlyphImage(%x, %x, %x) (char: %c)", fontHandle, charCode, glyphImagePtr, (char)charCode); int pixelFormat = Memory::Read_U32(glyphImagePtr); int xPos64 = Memory::Read_U32(glyphImagePtr+4); @@ -326,74 +721,123 @@ int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) int bytesPerLine = Memory::Read_U16(glyphImagePtr+16); int buffer = Memory::Read_U32(glyphImagePtr+20); - // Small chessboard. Does not respect pixelformat currently... - - // Actually should be really easy to substitute in a proper font here... - // could even grab pixel data from the PPGe one. - for (int y = 0; y < bufHeight; y++) - { - for (int x = 0; x < bytesPerLine; x++) - { - Memory::Write_U8((((x >> 1) ^ (y >> 1)) & 1) ? 0xff : 0x00, buffer + (y * bytesPerLine + x)); - } + LoadedFont *font = GetLoadedFont(fontHandle, false); + if (!font) { + ERROR_LOG(HLE, "%08x is not a valid font handle!", fontHandle); + return 0; } - + int altCharCode = font->GetFontLib()->GetAltCharCode(); + font->GetFont()->GetPGF()->DrawCharacter(buffer, bytesPerLine, bufWidth, bufHeight, xPos64 >> 6, yPos64 >> 6, 0, 0, 8192, 8192, pixelFormat, charCode, altCharCode, FONT_PGF_CHARGLYPH); return 0; } -int sceFontGetCharGlyphImage_Clip(u32 libHandler, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) -{ - ERROR_LOG(HLE, "sceFontGetCharGlyphImage_Clip %x, %x, %x (%c)", libHandler, charCode, glyphImagePtr, charCode); - //sceFontGetCharGlyphImage(libHandler, charCode, glyphImagePtr); +int sceFontGetCharGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) { + ERROR_LOG(HLE, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i) (%c)", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight, charCode); + + int pixelFormat = Memory::Read_U32(glyphImagePtr); + int xPos64 = Memory::Read_U32(glyphImagePtr+4); + int yPos64 = Memory::Read_U32(glyphImagePtr+8); + int bufWidth = Memory::Read_U16(glyphImagePtr+12); + int bufHeight = Memory::Read_U16(glyphImagePtr+14); + int bytesPerLine = Memory::Read_U16(glyphImagePtr+16); + int buffer = Memory::Read_U32(glyphImagePtr+20); + + LoadedFont *font = GetLoadedFont(fontHandle, false); + if (!font) { + ERROR_LOG(HLE, "%08x is not a valid font handle!", fontHandle); + return 0; + } + int altCharCode = font->GetFontLib()->GetAltCharCode(); + font->GetFont()->GetPGF()->DrawCharacter(buffer, bytesPerLine, bufWidth, bufHeight, xPos64 >> 6, yPos64 >> 6, clipXPos, clipYPos, clipXPos + clipWidth, clipYPos + clipHeight, pixelFormat, charCode, altCharCode, FONT_PGF_CHARGLYPH); return 0; } -int sceFontSetAltCharacterCode(u32 libHandle, u32 charCode) -{ - ERROR_LOG(HLE, "sceFontSetAltCharacterCode %x (%c)", libHandle, charCode); +int sceFontSetAltCharacterCode(u32 fontLibHandle, u32 charCode) { + INFO_LOG(HLE, "sceFontSetAltCharacterCode(%08x) (%c)", fontLibHandle, charCode); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + fl->SetAltCharCode(charCode); + } return 0; } -int sceFontFlush(u32 fontHandle) -{ - DEBUG_LOG(HLE, "sceFontFlush(%i)", fontHandle); +int sceFontFlush(u32 fontHandle) { + INFO_LOG(HLE, "sceFontFlush(%i)", fontHandle); + // Probably don't need to do anything here. return 0; } -int sceFontGetFontList(u32 fontLibHandle, u32 fontStylePtr, u32 numFonts) -{ - ERROR_LOG(HLE, "sceFontGetFontList %x, %x, %x", fontLibHandle, fontStylePtr, numFonts); - - FontStyle style; - memset(&style, 0, sizeof (style)); - - style.fontH = 20 / 64.f; - style.fontV = 20 / 64.f; - style.fontHRes = 20 / 64.f; - style.fontVRes = 20 / 64.f; - style.fontStyle = 1; - //style.fontFamily - +// One would think that this should loop through the fonts loaded in the fontLibHandle, +// but it seems not. +int sceFontGetFontList(u32 fontLibHandle, u32 fontStylePtr, u32 numFonts) { + ERROR_LOG(HLE, "sceFontGetFontList(%08x, %08x, %i)", fontLibHandle, fontStylePtr, numFonts); + numFonts = std::min(numFonts, (u32)internalFonts.size()); for (u32 i = 0; i < numFonts; i++) { - Memory::WriteStruct(fontStylePtr + (sizeof(style)) * i, &style); + PGFFontStyle style = internalFonts[i]->GetFontStyle(); + Memory::WriteStruct(fontStylePtr, &style); + fontStylePtr += sizeof(style); } return 0; } -int sceFontGetNumFontList(u32 libHandle, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "UNIMPL sceFontGetNumFontList %x, %x", libHandle, errorCodePtr); +int sceFontGetNumFontList(u32 fontLibHandle, u32 errorCodePtr) { + INFO_LOG(HLE, "sceFontGetNumFontList(%08x, %08x)", fontLibHandle, errorCodePtr); if (Memory::IsValidAddress(errorCodePtr)) - { Memory::Write_U32(0, errorCodePtr); - } - return 1; + return internalFonts.size(); } -int sceFontSetResolution(u32 fontLibHandle, float hRes, float vRes) -{ - ERROR_LOG(HLE, "UNIMPL sceFontSetResolution(%i, %f, %f)", fontLibHandle, hRes, vRes); +int sceFontSetResolution(u32 fontLibHandle, float hRes, float vRes) { + INFO_LOG(HLE, "sceFontSetResolution(%08x, %f, %f)", fontLibHandle, hRes, vRes); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + fl->SetResolution(hRes, vRes); + } + return 0; +} + +float sceFontPixelToPointH(int fontLibHandle, float fontPixelsH, u32 errorCodePtr) { + INFO_LOG(HLE, "sceFontPixelToPointH(%08x, %f, %08x)", fontLibHandle, fontPixelsH, errorCodePtr); + if (Memory::IsValidAddress(errorCodePtr)) + Memory::Write_U32(0, errorCodePtr); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + return fontPixelsH * pointDPI / fl->FontHRes(); + } + return 0; +} + +float sceFontPixelToPointV(int fontLibHandle, float fontPixelsV, u32 errorCodePtr) { + INFO_LOG(HLE, "UNIMPL sceFontPixelToPointV(%08x, %f, %08x)", fontLibHandle, fontPixelsV, errorCodePtr); + if (Memory::IsValidAddress(errorCodePtr)) + Memory::Write_U32(0, errorCodePtr); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + return fontPixelsV * pointDPI / fl->FontVRes(); + } + return 0; +} + +float sceFontPointToPixelH(int fontLibHandle, float fontPointsH, u32 errorCodePtr) { + INFO_LOG(HLE, "UNIMPL sceFontPointToPixelH(%08x, %f, %08x)", fontLibHandle, fontPointsH, errorCodePtr); + if (Memory::IsValidAddress(errorCodePtr)) + Memory::Write_U32(0, errorCodePtr); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + return fontPointsH * fl->FontHRes() / pointDPI; + } + return 0; +} + +float sceFontPointToPixelV(int fontLibHandle, float fontPointsV, u32 errorCodePtr) { + INFO_LOG(HLE, "UNIMPL sceFontPointToPixelV(%08x, %f, %08x)", fontLibHandle, fontPointsV, errorCodePtr); + if (Memory::IsValidAddress(errorCodePtr)) + Memory::Write_U32(0, errorCodePtr); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + return fontPointsV * fl->FontVRes() / pointDPI; + } return 0; } @@ -402,10 +846,17 @@ int sceFontCalcMemorySize() { return 0; } +int sceFontGetShadowGlyphImage() { + ERROR_LOG(HLE, "UNIMPL sceFontGetShadowGlyphImage()"); + return 0; +} +int sceFontGetShadowGlyphImage_Clip() { + ERROR_LOG(HLE, "UNIMPL sceFontGetShadowGlyphImage_Clip()"); + return 0; +} -const HLEFunction sceLibFont[] = -{ +const HLEFunction sceLibFont[] = { {0x67f17ed7, WrapU_UU, "sceFontNewLib"}, {0x574b6fbc, WrapI_U, "sceFontDoneLib"}, {0x48293280, WrapI_UFF, "sceFontSetResolution"}, @@ -416,28 +867,27 @@ const HLEFunction sceLibFont[] = {0x2f67356a, WrapI_V, "sceFontCalcMemorySize"}, {0x5333322d, WrapI_UUUU, "sceFontGetFontInfoByIndexNumber"}, {0xa834319d, WrapU_UUUU, "sceFontOpen"}, - {0x57fcb733, WrapU_UUUU, "sceFontOpenUserFile"}, + {0x57fcb733, WrapU_UCUU, "sceFontOpenUserFile"}, {0xbb8e7fe6, WrapU_UUUU, "sceFontOpenUserMemory"}, {0x3aea8cb6, WrapI_U, "sceFontClose"}, {0x0da7535e, WrapI_UU, "sceFontGetFontInfo"}, {0xdcc80c2f, WrapI_UUU, "sceFontGetCharInfo"}, + {0xaa3de7b5, WrapI_UUU, "sceFontGetShadowInfo"}, {0x5c3e4a9e, WrapI_UUU, "sceFontGetCharImageRect"}, + {0x48b06520, WrapI_UUU, "sceFontGetShadowImageRect"}, {0x980f4895, WrapI_UUU, "sceFontGetCharGlyphImage"}, {0xca1e6945, WrapI_UUUIIII, "sceFontGetCharGlyphImage_Clip"}, - {0x74b21701, 0, "sceFontPixelToPointH"}, - {0xf8f0752e, 0, "sceFontPixelToPointV"}, - {0x472694cd, 0, "sceFontPointToPixelH"}, - {0x3c4b7e82, 0, "sceFontPointToPixelV"}, + {0x74b21701, WrapF_IFU, "sceFontPixelToPointH"}, + {0xf8f0752e, WrapF_IFU, "sceFontPixelToPointV"}, + {0x472694cd, WrapF_IFU, "sceFontPointToPixelH"}, + {0x3c4b7e82, WrapF_IFU, "sceFontPointToPixelV"}, {0xee232411, WrapI_UU, "sceFontSetAltCharacterCode"}, - {0xaa3de7b5, 0, "sceFontGetShadowInfo"}, - {0x48b06520, 0, "sceFontGetShadowImageRect"}, - {0x568be516, 0, "sceFontGetShadowGlyphImage"}, - {0x5dcf6858, 0, "sceFontGetShadowGlyphImage_Clip"}, + {0x568be516, WrapI_V, "sceFontGetShadowGlyphImage"}, + {0x5dcf6858, WrapI_V, "sceFontGetShadowGlyphImage_Clip"}, {0x02d7f94b, WrapI_U, "sceFontFlush"}, - }; -void Register_sceFont() -{ + +void Register_sceFont() { RegisterModule("sceLibFont", ARRAY_SIZE(sceLibFont), sceLibFont); } diff --git a/Core/HLE/sceFont.h b/Core/HLE/sceFont.h index 81d095c5bb..c8b8cf9b07 100644 --- a/Core/HLE/sceFont.h +++ b/Core/HLE/sceFont.h @@ -5,4 +5,5 @@ class PointerWrap; void Register_sceFont(); void __FontInit(); +void __FontShutdown(); void __FontDoState(PointerWrap &p); diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 7ea643ab06..d1003f5db1 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -31,6 +31,10 @@ #include "../FileSystems/ISOFileSystem.h" #include "../FileSystems/DirectoryFileSystem.h" +extern "C" { +#include "ext/libkirk/amctrl.h" +}; + #include "sceIo.h" #include "sceRtc.h" #include "sceKernel.h" @@ -76,6 +80,7 @@ umd01: block access - umd #define O_CREAT 0x0200 #define O_TRUNC 0x0400 #define O_NOWAIT 0x8000 +#define O_NPDRM 0x40000000 typedef s32 SceMode; @@ -168,8 +173,17 @@ public: PSPFileInfo info; u32 openMode; + + u32 npdrm; + PGD_DESC *pgdInfo; }; +/******************************************************************************/ + + + +/******************************************************************************/ + static void TellFsThreadEnded (SceUID threadID) { pspFileSystem.ThreadEnded(threadID); } @@ -183,7 +197,7 @@ void __IoInit() { char path_buffer[_MAX_PATH], drive[_MAX_DRIVE] ,dir[_MAX_DIR], file[_MAX_FNAME], ext[_MAX_EXT]; char memstickpath[_MAX_PATH]; - char flashpath[_MAX_PATH]; + char flash0path[_MAX_PATH]; GetModuleFileName(NULL,path_buffer,sizeof(path_buffer)); @@ -196,24 +210,25 @@ void __IoInit() { // Mount a couple of filesystems sprintf(memstickpath, "%s%sMemStick\\", drive, dir); - sprintf(flashpath, "%s%sFlash\\", drive, dir); + sprintf(flash0path, "%s%sflash0\\", drive, dir); #else // TODO std::string memstickpath = g_Config.memCardDirectory; - std::string flashpath = g_Config.flashDirectory; + std::string flash0path = g_Config.flashDirectory; #endif - DirectoryFileSystem *memstick; - DirectoryFileSystem *flash; - memstick = new DirectoryFileSystem(&pspFileSystem, memstickpath); - flash = new DirectoryFileSystem(&pspFileSystem, flashpath); + DirectoryFileSystem *memstick = new DirectoryFileSystem(&pspFileSystem, memstickpath); +#ifdef ANDROID + VFSFileSystem *flash0 = new VFSFileSystem(&pspFileSystem, "flash0"); +#else + DirectoryFileSystem *flash0 = new DirectoryFileSystem(&pspFileSystem, flash0path); +#endif pspFileSystem.Mount("ms0:", memstick); pspFileSystem.Mount("fatms0:", memstick); pspFileSystem.Mount("fatms:", memstick); - pspFileSystem.Mount("flash0:", flash); - pspFileSystem.Mount("flash1:", flash); + pspFileSystem.Mount("flash0:", flash0); __KernelListenThreadEnd(&TellFsThreadEnded); } @@ -342,6 +357,42 @@ u32 sceIoGetstat(const char *filename, u32 addr) { } } +u32 npdrmRead(FileNode *f, u8 *data, int size) { + PGD_DESC *pgd = f->pgdInfo; + u32 block, offset; + u32 remain_size, copy_size; + + block = pgd->file_offset/pgd->block_size; + offset = pgd->file_offset%pgd->block_size; + + remain_size = size; + + while(remain_size){ + + if(pgd->current_block!=block){ + pspFileSystem.ReadFile(f->handle, pgd->block_buf, pgd->block_size); + pgd_decrypt_block(pgd, block); + pgd->current_block = block; + } + + if(offset+remain_size>pgd->block_size){ + copy_size = pgd->block_size-offset; + block += 1; + offset = 0; + }else{ + copy_size = remain_size; + } + + memcpy(data, pgd->block_buf+offset, copy_size); + + data += copy_size; + remain_size -= copy_size; + pgd->file_offset += copy_size; + } + + return size; +} + //Not sure about wrapping it or not, since the log seems to take the address of the data var u32 sceIoRead(int id, u32 data_addr, int size) { if (id == 3) { @@ -358,7 +409,11 @@ u32 sceIoRead(int id, u32 data_addr, int size) { } else if (Memory::IsValidAddress(data_addr)) { u8 *data = (u8*) Memory::GetPointer(data_addr); - f->asyncResult = (u32) pspFileSystem.ReadFile(f->handle, data, size); + if(f->npdrm){ + f->asyncResult = (u32) npdrmRead(f, data, size); + }else{ + f->asyncResult = (u32) pspFileSystem.ReadFile(f->handle, data, size); + } DEBUG_LOG(HLE, "%i=sceIoRead(%d, %08x , %i)", f->asyncResult, id, data_addr, size); return f->asyncResult; } else { @@ -445,6 +500,26 @@ u32 sceIoCancel(int id) return error; } +u32 npdrmLseek(FileNode *f, s32 where, FileMove whence) +{ + u32 newPos; + + if(whence==FILEMOVE_BEGIN){ + newPos = where; + }else if(whence==FILEMOVE_CURRENT){ + newPos = f->pgdInfo->file_offset+where; + }else{ + newPos = f->pgdInfo->data_size+where; + } + + if(newPos<0 || newPos>f->pgdInfo->data_size){ + return -EINVAL; + } + + f->pgdInfo->file_offset = newPos; + return newPos; +} + s64 sceIoLseek(int id, s64 offset, int whence) { u32 error; FileNode *f = kernelObjects.Get < FileNode > (id, error); @@ -468,7 +543,11 @@ s64 sceIoLseek(int id, s64 offset, int whence) { if(newPos < 0) return -1; - f->asyncResult = (u32) pspFileSystem.SeekFile(f->handle, (s32) offset, seek); + if(f->npdrm){ + f->asyncResult = npdrmLseek(f, (s32)offset, seek); + }else{ + f->asyncResult = (u32) pspFileSystem.SeekFile(f->handle, (s32) offset, seek); + } DEBUG_LOG(HLE, "%i = sceIoLseek(%d,%i,%i)", f->asyncResult, id, (int) offset, whence); return f->asyncResult; } else { @@ -500,7 +579,11 @@ u32 sceIoLseek32(int id, int offset, int whence) { if(newPos < 0) return -1; - f->asyncResult = (u32) pspFileSystem.SeekFile(f->handle, (s32) offset, seek); + if(f->npdrm){ + f->asyncResult = npdrmLseek(f, (s32)offset, seek); + }else{ + f->asyncResult = (u32) pspFileSystem.SeekFile(f->handle, (s32) offset, seek); + } DEBUG_LOG(HLE, "%i = sceIoLseek32(%d,%i,%i)", f->asyncResult, id, (int) offset, whence); return f->asyncResult; } else { @@ -520,6 +603,8 @@ u32 sceIoOpen(const char* filename, int flags, int mode) { access |= FILEACCESS_APPEND; if (flags & O_CREAT) access |= FILEACCESS_CREATE; + if (flags & O_NPDRM) + PSPFileInfo info = pspFileSystem.GetFileInfo(filename); u32 h = pspFileSystem.OpenFile(filename, (FileAccess) access); @@ -535,14 +620,22 @@ u32 sceIoOpen(const char* filename, int flags, int mode) { f->handle = h; f->fullpath = filename; f->asyncResult = id; - f->info = info; + f->info = pspFileSystem.GetFileInfo(filename); f->openMode = access; + + f->npdrm = (flags & O_NPDRM)? true: false; + DEBUG_LOG(HLE, "%i=sceIoOpen(%s, %08x, %08x)", id, filename, flags, mode); return id; } u32 sceIoClose(int id) { + u32 error; DEBUG_LOG(HLE, "sceIoClose(%d)", id); + FileNode *f = kernelObjects.Get < FileNode > (id, error); + if(f && f->npdrm){ + pgd_close(f->pgdInfo); + } return kernelObjects.Destroy < FileNode > (id); } @@ -1091,8 +1184,17 @@ u32 sceIoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 ou case 0x04100001: if (Memory::IsValidAddress(indataPtr) && inlen == 16) { u8 keybuf[16]; + u8 pgd_header[0x90]; + INFO_LOG(HLE, "Decrypting PGD DRM files"); memcpy(keybuf, Memory::GetPointer(indataPtr), 16); - ERROR_LOG(HLE, "PGD DRM not yet supported, sorry."); + pspFileSystem.ReadFile(f->handle, pgd_header, 0x90); + f->pgdInfo = pgd_open(pgd_header, 2, keybuf); + if(f->pgdInfo==NULL){ + DEBUG_LOG(HLE, "Not a valid PGD file. Open as normal file."); + f->npdrm = false; + pspFileSystem.SeekFile(f->handle, (s32)0, FILEMOVE_BEGIN); + } + f->asyncResult = 0; } break; diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 04e5a8368e..3b31b7fbe3 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -60,6 +60,7 @@ #include "scePsmf.h" #include "sceImpose.h" #include "sceUsb.h" +#include "scePspNpDrm_user.h" #include "../Util/PPGeDraw.h" @@ -127,6 +128,8 @@ void __KernelShutdown() INFO_LOG(HLE, "Shutting down kernel - %i kernel objects alive", kernelObjects.GetCount()); kernelObjects.Clear(); + __FontShutdown(); + __MpegShutdown(); __PsmfShutdown(); __PPGeShutdown(); @@ -539,35 +542,37 @@ u32 sceKernelReferGlobalProfiler(u32 statusPtr) { const HLEFunction ThreadManForUser[] = { - {0x55C20A00,&WrapI_CUUU, "sceKernelCreateEventFlag"}, - {0x812346E4,&WrapU_IU, "sceKernelClearEventFlag"}, - {0xEF9E4C70,&WrapU_I, "sceKernelDeleteEventFlag"}, - {0x1fb15a32,&WrapU_IU, "sceKernelSetEventFlag"}, - {0x402FCF22,&WrapI_IUUUU, "sceKernelWaitEventFlag"}, - {0x328C546A,&WrapI_IUUUU, "sceKernelWaitEventFlagCB"}, - {0x30FD48F0,&WrapI_IUUUU, "sceKernelPollEventFlag"}, - {0xCD203292,&WrapU_IUU, "sceKernelCancelEventFlag"}, - {0xA66B0120,&WrapU_IU, "sceKernelReferEventFlagStatus"}, + {0x55C20A00,&WrapI_CUUU, "sceKernelCreateEventFlag"}, + {0x812346E4,&WrapU_IU, "sceKernelClearEventFlag"}, + {0xEF9E4C70,&WrapU_I, "sceKernelDeleteEventFlag"}, + {0x1fb15a32,&WrapU_IU, "sceKernelSetEventFlag"}, + {0x402FCF22,&WrapI_IUUUU, "sceKernelWaitEventFlag"}, + {0x328C546A,&WrapI_IUUUU, "sceKernelWaitEventFlagCB"}, + {0x30FD48F0,&WrapI_IUUUU, "sceKernelPollEventFlag"}, + {0xCD203292,&WrapU_IUU, "sceKernelCancelEventFlag"}, + {0xA66B0120,&WrapU_IU, "sceKernelReferEventFlagStatus"}, - {0x8FFDF9A2,&WrapI_IIU, "sceKernelCancelSema"}, - {0xD6DA4BA1,&WrapI_CUIIU, "sceKernelCreateSema"}, - {0x28b6489c,&WrapI_I, "sceKernelDeleteSema"}, - {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, - {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, - {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, - {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema"}, - {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB"}, + {0x8FFDF9A2,&WrapI_IIU, "sceKernelCancelSema"}, + {0xD6DA4BA1,&WrapI_CUIIU, "sceKernelCreateSema"}, + {0x28b6489c,&WrapI_I, "sceKernelDeleteSema"}, + {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, + {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, + {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, + {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema"}, + {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB"}, - {0x60107536,&WrapI_U, "sceKernelDeleteLwMutex"}, - {0x19CFF145,&WrapI_UCUIU, "sceKernelCreateLwMutex"}, - {0xf8170fbe,&WrapI_I, "sceKernelDeleteMutex"}, - {0xB011B11F,&WrapI_IIU, "sceKernelLockMutex"}, - {0x5bf4dd27,&WrapI_IIU, "sceKernelLockMutexCB"}, - {0x6b30100f,&WrapI_II, "sceKernelUnlockMutex"}, - {0xb7d098c6,&WrapI_CUIU, "sceKernelCreateMutex"}, - {0x0DDCD2C9,&WrapI_II, "sceKernelTryLockMutex"}, - {0xA9C2CB9A,&WrapI_IU, "sceKernelReferMutexStatus"}, - // NOTE: LockLwMutex and UnlockLwMutex are in Kernel_Library, see sceKernelInterrupt.cpp. + {0x60107536,&WrapI_U, "sceKernelDeleteLwMutex"}, + {0x19CFF145,&WrapI_UCUIU, "sceKernelCreateLwMutex"}, + {0x4C145944,&WrapI_IU, "sceKernelReferLwMutexStatusByID"}, + // NOTE: LockLwMutex, UnlockLwMutex, and ReferLwMutexStatus are in Kernel_Library, see sceKernelInterrupt.cpp. + + {0xf8170fbe,&WrapI_I, "sceKernelDeleteMutex"}, + {0xB011B11F,&WrapI_IIU, "sceKernelLockMutex"}, + {0x5bf4dd27,&WrapI_IIU, "sceKernelLockMutexCB"}, + {0x6b30100f,&WrapI_II, "sceKernelUnlockMutex"}, + {0xb7d098c6,&WrapI_CUIU, "sceKernelCreateMutex"}, + {0x0DDCD2C9,&WrapI_II, "sceKernelTryLockMutex"}, + {0xA9C2CB9A,&WrapI_IU, "sceKernelReferMutexStatus"}, {0xFCCFAD26,sceKernelCancelWakeupThread,"sceKernelCancelWakeupThread"}, {0xea748e31,sceKernelChangeCurrentThreadAttr,"sceKernelChangeCurrentThreadAttr"}, diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index 17911153d9..65df209f35 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -87,6 +87,7 @@ enum SCE_KERNEL_ERROR_ILLEGAL_CHUNK_ID = 0x800200de, SCE_KERNEL_ERROR_NOCHUNK = 0x800200df, SCE_KERNEL_ERROR_NO_FREECHUNK = 0x800200e0, + SCE_ERROR_KERNEL_ILLEGAL_ALIGNMENT_SIZE = 0x800200e4, SCE_KERNEL_ERROR_LINKERR = 0x8002012c, SCE_KERNEL_ERROR_ILLEGAL_OBJECT = 0x8002012d, SCE_KERNEL_ERROR_UNKNOWN_MODULE = 0x8002012e, diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index a4791308e8..299a67b40a 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -213,7 +213,7 @@ void __InterruptsInit() { interruptsEnabled = 1; inInterrupt = false; - for (size_t i = 0; i < ARRAY_SIZE(intrHandlers); ++i) + for (int i = 0; i < (int)ARRAY_SIZE(intrHandlers); ++i) intrHandlers[i] = new IntrHandler(i); intState.clear(); } @@ -553,6 +553,7 @@ const HLEFunction Kernel_Library[] = {0xbea46419,WrapI_UIU, "sceKernelLockLwMutex"}, {0x1FC64E09,WrapI_UIU, "sceKernelLockLwMutexCB"}, {0x15b6446b,WrapI_UI, "sceKernelUnlockLwMutex"}, + {0xc1734599,WrapI_UU, "sceKernelReferLwMutexStatus"}, {0x293b45b8,sceKernelGetThreadId, "sceKernelGetThreadId"}, {0x1839852A,WrapU_UUU,"sce_paf_private_memcpy"}, }; diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index b4d8f9d9d9..4614842f61 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -390,6 +390,14 @@ void sceKernelReferFplStatus() ////////////////////////////////////////////////////////////////////////// //00:49:12 ector, well the partitions are 1 = kernel, 2 = user, 3 = me, 4 = kernel mirror :) +enum MemblockType +{ + PSP_SMEM_Low = 0, + PSP_SMEM_High = 1, + PSP_SMEM_Addr = 2, + PSP_SMEM_LowAligned = 3, + PSP_SMEM_HighAligned = 4, +}; class PartitionMemoryBlock : public KernelObject { @@ -401,23 +409,34 @@ public: int sz = alloc->GetBlockSizeFromAddress(address); sprintf(ptr, "MemPart: %08x - %08x size: %08x", address, address + sz, sz); } - static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_MPPID; } /// ???? + static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_UID; } int GetIDType() const { return PPSSPP_KERNEL_TMID_PMB; } - PartitionMemoryBlock(BlockAllocator *_alloc, u32 size, bool fromEnd) + PartitionMemoryBlock(BlockAllocator *_alloc, const char *_name, u32 size, MemblockType type, u32 alignment) { alloc = _alloc; + strncpy(name, _name, 32); + name[31] = '\0'; // 0 is used for save states to wake up. if (size != 0) { - address = alloc->Alloc(size, fromEnd, "PMB"); + if (type == PSP_SMEM_Addr) + { + alignment &= ~0xFF; + address = alloc->AllocAt(alignment, size, name); + } + else if (type == PSP_SMEM_LowAligned || type == PSP_SMEM_HighAligned) + address = alloc->AllocAligned(size, alignment, type == PSP_SMEM_HighAligned, name); + else + address = alloc->Alloc(size, type == PSP_SMEM_High, name); alloc->ListBlocks(); } } ~PartitionMemoryBlock() { - alloc->Free(address); + if (address != (u32)-1) + alloc->Free(address); } bool IsValid() {return address != (u32)-1;} BlockAllocator *alloc; @@ -449,54 +468,78 @@ void sceKernelTotalFreeMemSize() RETURN(retVal); } -void sceKernelAllocPartitionMemory() +int sceKernelAllocPartitionMemory(int partition, const char *name, int type, u32 size, u32 addr) { - int partid = PARAM(0); - const char *name = Memory::GetCharPointer(PARAM(1)); - int type = PARAM(2); - u32 size = PARAM(3); - int addr = PARAM(4); //only if type includes ADDR + if (name == NULL) + { + WARN_LOG(HLE, "%08x=sceKernelAllocPartitionMemory(): invalid name", SCE_KERNEL_ERROR_ERROR); + return SCE_KERNEL_ERROR_ERROR; + } + if (size == 0) + { + WARN_LOG(HLE, "%08x=sceKernelAllocPartitionMemory(): invalid size %x", SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED, size); + return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; + } + if (partition < 1 || partition > 9 || partition == 7) + { + WARN_LOG(HLE, "%08x=sceKernelAllocPartitionMemory(): invalid partition %x", SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, partition); + return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; + } + // We only support user right now. + if (partition != 2 && partition != 5 && partition != 6) + { + WARN_LOG(HLE, "%08x=sceKernelAllocPartitionMemory(): invalid partition %x", SCE_KERNEL_ERROR_ILLEGAL_PARTITION, partition); + return SCE_KERNEL_ERROR_ILLEGAL_PARTITION; + } + if (type < PSP_SMEM_Low || type > PSP_SMEM_HighAligned) + { + WARN_LOG(HLE, "%08x=sceKernelAllocPartitionMemory(): invalid type %x", SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE, type); + return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE; + } + // Alignment is only allowed for powers of 2. + if ((type == PSP_SMEM_LowAligned || type == PSP_SMEM_HighAligned) && ((addr & (addr - 1)) != 0 || addr == 0)) + { + WARN_LOG(HLE, "%08x=sceKernelAllocPartitionMemory(): invalid alignment %x", SCE_ERROR_KERNEL_ILLEGAL_ALIGNMENT_SIZE, addr); + return SCE_ERROR_KERNEL_ILLEGAL_ALIGNMENT_SIZE; + } - PartitionMemoryBlock *block = new PartitionMemoryBlock(&userMemory, size, type==1); + PartitionMemoryBlock *block = new PartitionMemoryBlock(&userMemory, name, size, (MemblockType)type, addr); if (!block->IsValid()) { + delete block; ERROR_LOG(HLE, "ARGH! sceKernelAllocPartitionMemory failed"); - RETURN(-1); + return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; } SceUID uid = kernelObjects.Create(block); - strncpy(block->name, name, 32); DEBUG_LOG(HLE,"%i = sceKernelAllocPartitionMemory(partition = %i, %s, type= %i, size= %i, addr= %08x)", - uid, partid,name,type,size,addr); + uid, partition, name, type, size, addr); if (type == 2) ERROR_LOG(HLE, "ARGH! sceKernelAllocPartitionMemory wants a specific address"); - RETURN(uid); //for now + return uid; } -void sceKernelFreePartitionMemory() +int sceKernelFreePartitionMemory(SceUID id) { - SceUID id = PARAM(0); DEBUG_LOG(HLE,"sceKernelFreePartitionMemory(%d)",id); - RETURN(kernelObjects.Destroy(id)); + return kernelObjects.Destroy(id); } -void sceKernelGetBlockHeadAddr() +u32 sceKernelGetBlockHeadAddr(SceUID id) { - SceUID id = PARAM(0); - u32 error; PartitionMemoryBlock *block = kernelObjects.Get(id, error); if (block) { DEBUG_LOG(HLE,"%08x = sceKernelGetBlockHeadAddr(%i)", block->address, id); - RETURN(block->address); + return block->address; } else { ERROR_LOG(HLE,"sceKernelGetBlockHeadAddr failed(%i)", id); - RETURN(error); + return 0; } } @@ -719,7 +762,7 @@ KernelObject *__KernelMemoryVPLObject() KernelObject *__KernelMemoryPMBObject() { // TODO: We could theoretically handle kernelMemory too, but we don't support that now anyway. - return new PartitionMemoryBlock(&userMemory, 0, true); + return new PartitionMemoryBlock(&userMemory, "", 0, PSP_SMEM_Low, 0); } // VPL = variable length memory pool @@ -1135,9 +1178,9 @@ const HLEFunction SysMemUserForUser[] = { {0xA291F107,sceKernelMaxFreeMemSize,"sceKernelMaxFreeMemSize"}, {0xF919F628,sceKernelTotalFreeMemSize,"sceKernelTotalFreeMemSize"}, {0x3FC9AE6A,WrapU_V,"sceKernelDevkitVersion"}, - {0x237DBD4F,sceKernelAllocPartitionMemory,"sceKernelAllocPartitionMemory"}, //(int size) ? - {0xB6D61D02,sceKernelFreePartitionMemory,"sceKernelFreePartitionMemory"}, //(void *ptr) ? - {0x9D9A5BA1,sceKernelGetBlockHeadAddr,"sceKernelGetBlockHeadAddr"}, //(void *ptr) ? + {0x237DBD4F,WrapI_ICIUU,"sceKernelAllocPartitionMemory"}, //(int size) ? + {0xB6D61D02,WrapI_I,"sceKernelFreePartitionMemory"}, //(void *ptr) ? + {0x9D9A5BA1,WrapU_I,"sceKernelGetBlockHeadAddr"}, //(void *ptr) ? {0x13a5abef,sceKernelPrintf,"sceKernelPrintf 0x13a5abef"}, {0x7591c7db,&WrapV_I,"sceKernelSetCompiledSdkVersion"}, {0x342061E5,&WrapV_I,"sceKernelSetCompiledSdkVersion370"}, diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index a1828cb2e3..cd87a8f190 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -46,7 +46,6 @@ #define PSP_LWMUTEX_ERROR_UNLOCK_UNDERFLOW 0x800201CE #define PSP_LWMUTEX_ERROR_ALREADY_LOCKED 0x800201CF -// Guesswork - not exposed anyway struct NativeMutex { SceSize size; @@ -54,6 +53,8 @@ struct NativeMutex SceUInt attr; int initialCount; int lockLevel; + SceUID lockThread; + // Not kept up to date. int numWaitThreads; }; @@ -69,22 +70,28 @@ struct Mutex : public KernelObject p.Do(nm); SceUID dv = 0; p.Do(waitingThreads, dv); - p.Do(lockThread); p.DoMarker("Mutex"); } NativeMutex nm; std::vector waitingThreads; - int lockThread; // The thread holding the lock }; -// Guesswork - not exposed anyway + struct NativeLwMutex { SceSize size; char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; SceUInt attr; - SceUInt workareaPtr; + SceUID uid; + u32 workareaPtr; + int initialCount; + // Not kept up to date. + int currentCount; + // Not kept up to date. + SceUID lockThread; + // Not kept up to date. + int numWaitThreads; }; struct NativeLwMutexWorkarea @@ -178,7 +185,7 @@ void __KernelMutexAcquireLock(Mutex *mutex, int count, SceUID thread) mutexHeldLocks.insert(std::make_pair(thread, mutex->GetUID())); mutex->nm.lockLevel = count; - mutex->lockThread = thread; + mutex->nm.lockThread = thread; } void __KernelMutexAcquireLock(Mutex *mutex, int count) @@ -188,10 +195,10 @@ void __KernelMutexAcquireLock(Mutex *mutex, int count) void __KernelMutexEraseLock(Mutex *mutex) { - if (mutex->lockThread != -1) + if (mutex->nm.lockThread != -1) { SceUID id = mutex->GetUID(); - std::pair locked = mutexHeldLocks.equal_range(mutex->lockThread); + std::pair locked = mutexHeldLocks.equal_range(mutex->nm.lockThread); for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { if ((*iter).second == id) @@ -201,7 +208,7 @@ void __KernelMutexEraseLock(Mutex *mutex) } } } - mutex->lockThread = -1; + mutex->nm.lockThread = -1; } std::vector::iterator __KernelMutexFindPriority(std::vector &waiting) @@ -245,7 +252,7 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio Mutex *mutex = new Mutex(); SceUID id = kernelObjects.Create(mutex); - mutex->nm.size = sizeof(mutex); + mutex->nm.size = sizeof(mutex->nm); strncpy(mutex->nm.name, name, KERNELOBJECT_MAX_NAME_LENGTH); mutex->nm.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; mutex->nm.attr = attr; @@ -253,7 +260,7 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio if (initialCount == 0) { mutex->nm.lockLevel = 0; - mutex->lockThread = -1; + mutex->nm.lockThread = -1; } else __KernelMutexAcquireLock(mutex, initialCount); @@ -307,7 +314,7 @@ int sceKernelDeleteMutex(SceUID id) for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE); - if (mutex->lockThread != -1) + if (mutex->nm.lockThread != -1) __KernelMutexEraseLock(mutex); mutex->waitingThreads.clear(); @@ -343,7 +350,7 @@ bool __KernelLockMutex(Mutex *mutex, int count, u32 &error) return true; } - if (mutex->lockThread == __KernelGetCurThread()) + if (mutex->nm.lockThread == __KernelGetCurThread()) { // Recursive mutex, let's just increase the lock count and keep going if (mutex->nm.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) @@ -379,7 +386,7 @@ bool __KernelUnlockMutex(Mutex *mutex, u32 &error) } if (!wokeThreads) - mutex->lockThread = -1; + mutex->nm.lockThread = -1; return wokeThreads; } @@ -528,7 +535,7 @@ int sceKernelUnlockMutex(SceUID id, int count) return SCE_KERNEL_ERROR_ILLEGAL_COUNT; if ((mutex->nm.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && count > 1) return SCE_KERNEL_ERROR_ILLEGAL_COUNT; - if (mutex->nm.lockLevel == 0 || mutex->lockThread != __KernelGetCurThread()) + if (mutex->nm.lockLevel == 0 || mutex->nm.lockThread != __KernelGetCurThread()) return PSP_MUTEX_ERROR_NOT_LOCKED; if (mutex->nm.lockLevel < count) return PSP_MUTEX_ERROR_UNLOCK_UNDERFLOW; @@ -544,6 +551,32 @@ int sceKernelUnlockMutex(SceUID id, int count) return 0; } +int sceKernelReferMutexStatus(SceUID id, u32 infoAddr) +{ + u32 error; + Mutex *m = kernelObjects.Get(id, error); + if (!m) + { + ERROR_LOG(HLE, "sceKernelReferMutexStatus(%i, %08x): invalid mutex id", id, infoAddr); + return error; + } + + DEBUG_LOG(HLE, "sceKernelReferMutexStatus(%08x, %08x)", id, infoAddr); + + // Should we crash the thread somehow? + if (!Memory::IsValidAddress(infoAddr)) + return -1; + + // Don't write if the size is 0. Anything else is A-OK, though, apparently. + if (Memory::Read_U32(infoAddr) != 0) + { + // Refresh and write + m->nm.numWaitThreads = m->waitingThreads.size(); + Memory::WriteStruct(infoAddr, &m->nm); + } + return 0; +} + int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!name) @@ -564,11 +597,13 @@ int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int init LwMutex *mutex = new LwMutex(); SceUID id = kernelObjects.Create(mutex); - mutex->nm.size = sizeof(mutex); + mutex->nm.size = sizeof(mutex->nm); strncpy(mutex->nm.name, name, KERNELOBJECT_MAX_NAME_LENGTH); mutex->nm.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; mutex->nm.attr = attr; + mutex->nm.uid = id; mutex->nm.workareaPtr = workareaPtr; + mutex->nm.initialCount = initialCount; NativeLwMutexWorkarea workarea; workarea.init(); workarea.lockLevel = initialCount; @@ -591,26 +626,6 @@ int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int init return 0; } -int sceKernelReferMutexStatus(SceUID id, u32 infoAddr) -{ - u32 error; - Mutex *m = kernelObjects.Get(id, error); - if (!m) - { - ERROR_LOG(HLE, "sceKernelReferMutexStatus(%i, %08x): invalid mbx id", id, infoAddr); - return error; - } - - // Should we crash the thread somehow? - if (!Memory::IsValidAddress(infoAddr)) - return -1; - - // Refresh and write - m->nm.numWaitThreads = m->waitingThreads.size(); - Memory::WriteStruct(infoAddr, &m->nm); - return 0; -} - bool __KernelUnlockLwMutexForThread(LwMutex *mutex, NativeLwMutexWorkarea &workarea, SceUID threadID, u32 &error, int result) { SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); @@ -925,3 +940,64 @@ int sceKernelUnlockLwMutex(u32 workareaPtr, int count) return 0; } + +int __KernelReferLwMutexStatus(SceUID uid, u32 infoPtr) +{ + u32 error; + LwMutex *m = kernelObjects.Get(uid, error); + if (!m) + return error; + + // Should we crash the thread somehow? + if (!Memory::IsValidAddress(infoPtr)) + return -1; + + if (Memory::Read_U32(infoPtr) != 0) + { + NativeLwMutexWorkarea workarea; + Memory::ReadStruct(m->nm.workareaPtr, &workarea); + + // Refresh and write + m->nm.currentCount = workarea.lockLevel; + m->nm.lockThread = workarea.lockThread == 0 ? -1 : workarea.lockThread; + m->nm.numWaitThreads = m->waitingThreads.size(); + Memory::WriteStruct(infoPtr, &m->nm); + } + return 0; +} + +int sceKernelReferLwMutexStatusByID(SceUID uid, u32 infoPtr) +{ + int error = __KernelReferLwMutexStatus(uid, infoPtr); + if (error >= 0) + { + DEBUG_LOG(HLE, "sceKernelReferLwMutexStatusByID(%08x, %08x)", uid, infoPtr); + return error; + } + else + { + ERROR_LOG(HLE, "%08x=sceKernelReferLwMutexStatusByID(%08x, %08x)", error, uid, infoPtr); + return error; + } +} + +int sceKernelReferLwMutexStatus(u32 workareaPtr, u32 infoPtr) +{ + if (!Memory::IsValidAddress(workareaPtr)) + return -1; + + NativeLwMutexWorkarea workarea; + Memory::ReadStruct(workareaPtr, &workarea); + + int error = __KernelReferLwMutexStatus(workarea.uid, infoPtr); + if (error >= 0) + { + DEBUG_LOG(HLE, "sceKernelReferLwMutexStatus(%08x, %08x)", workareaPtr, infoPtr); + return error; + } + else + { + ERROR_LOG(HLE, "%08x=sceKernelReferLwMutexStatus(%08x, %08x)", error, workareaPtr, infoPtr); + return error; + } +} \ No newline at end of file diff --git a/Core/HLE/sceKernelMutex.h b/Core/HLE/sceKernelMutex.h index 259f9f886c..9e7bf57973 100644 --- a/Core/HLE/sceKernelMutex.h +++ b/Core/HLE/sceKernelMutex.h @@ -32,6 +32,8 @@ int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count); int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr); int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr); int sceKernelUnlockLwMutex(u32 workareaPtr, int count); +int sceKernelReferLwMutexStatusByID(SceUID uid, u32 infoPtr); +int sceKernelReferLwMutexStatus(u32 workareaPtr, u32 infoPtr); void __KernelMutexTimeout(u64 userdata, int cyclesLate); void __KernelLwMutexTimeout(u64 userdata, int cyclesLate); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 89d5e38326..aa093cc09c 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -795,7 +795,7 @@ void __KernelIdle() CoreTiming::Idle(); // Advance must happen between Idle and Reschedule, so that threads that were waiting for something // that was triggered at the end of the Idle period must get a chance to be scheduled. - CoreTiming::Advance(); + CoreTiming::AdvanceQuick(); // We must've exited a callback? if (__KernelInCallback()) @@ -1034,6 +1034,9 @@ void __KernelLoadContext(ThreadContext *ctx) currentMIPS->fcr0 = ctx->fcr0; currentMIPS->fcr31 = ctx->fcr31; currentMIPS->fpcond = ctx->fpcond; + + // Reset the llBit, the other thread may have touched memory. + currentMIPS->llBit = 0; } u32 __KernelResumeThreadFromWait(SceUID threadID) @@ -1213,7 +1216,7 @@ u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason, bo { // TODO: Unless they should be run before deletion? for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) - readyCallbacksCount -= t->readyCallbacks[i].size(); + readyCallbacksCount -= (int)t->readyCallbacks[i].size(); } return kernelObjects.Destroy(threadID); @@ -1260,7 +1263,7 @@ void __KernelReSchedule(const char *reason) } // Execute any pending events while we're doing scheduling. - CoreTiming::Advance(); + CoreTiming::AdvanceQuick(); if (__IsInInterrupt() || __KernelInCallback()) { reason = "In Interrupt Or Callback"; diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index e5a870a010..c1afe5c0fe 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -833,7 +833,7 @@ int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initAddr) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(HLE, "sceMpegAvcDecodeYCbCr(%08x, %08x, %d, %08x, %08x): bad mpeg handle", mpeg, auAddr, bufferAddr, initAddr); + WARN_LOG(HLE, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, auAddr, bufferAddr, initAddr); return 0; } diff --git a/Core/HLE/scePspNpDrm_user.cpp b/Core/HLE/scePspNpDrm_user.cpp new file mode 100644 index 0000000000..f47f4e56a0 --- /dev/null +++ b/Core/HLE/scePspNpDrm_user.cpp @@ -0,0 +1,68 @@ +#include "scePspNpDrm_user.h" + +#include "HLE.h" + +int sceNpDrmSetLicenseeKey() +{ + ERROR_LOG(HLE, "UNIMPL sceNpDrmSetLicenseeKey"); + return 0; +} + +int sceNpDrmClearLicenseeKey() +{ + ERROR_LOG(HLE, "UNIMPL sceNpDrmClearLicenseeKey"); + return 0; +} + +int sceNpDrmRenameCheck() +{ + ERROR_LOG(HLE, "UNIMPL sceNpDrmRenameCheck"); + return 0; +} + +int sceNpDrmEdataSetupKey(u32 edataFd) +{ + ERROR_LOG(HLE, "UNIMPL sceNpDrmEdataSetupKey %x", edataFd); + return 0; +} + +int sceNpDrmEdataGetDataSize(u32 edataFd) +{ + ERROR_LOG(HLE, "UNIMPL sceNpDrmEdataGetDataSize %x", edataFd); + return 0; +} + +int sceNpDrmOpen() +{ + ERROR_LOG(HLE, "UNIMPL sceNpDrmOpen"); + return 0; +} + +int sceKernelLoadModuleNpDrm() +{ + ERROR_LOG(HLE, "UNIMPL sceKernelLoadModuleNpDrm"); + return 0; +} + +int sceKernelLoadExecNpDrm() +{ + ERROR_LOG(HLE, "UNIMPL sceKernelLoadExecNpDrm"); + return 0; +} + +const HLEFunction sceNpDrm[] = +{ + {0xA1336091, 0, "sceNpDrmSetLicenseeKey"}, + {0x9B745542, 0, "sceNpDrmClearLicenseeKey"}, + {0x275987D1, 0, "sceNpDrmRenameCheck"}, + {0x08d98894, WrapI_U, "sceNpDrmEdataSetupKey"}, + {0x219EF5CC, WrapI_U, "sceNpDrmEdataGetDataSize"}, + {0x2BAA4294, 0, "sceNpDrmOpen"}, + {0xC618D0B1, 0, "sceKernelLoadModuleNpDrm"}, + {0xAA5FC85B, 0, "sceKernelLoadExecNpDrm"}, +}; + +void Register_sceNpDrm() +{ + RegisterModule("sceNpDrm", ARRAY_SIZE(sceNpDrm), sceNpDrm); +} diff --git a/Core/HLE/scePspNpDrm_user.h b/Core/HLE/scePspNpDrm_user.h new file mode 100644 index 0000000000..3e59c6aa39 --- /dev/null +++ b/Core/HLE/scePspNpDrm_user.h @@ -0,0 +1,5 @@ +#pragma once + +class PointerWrap; + +void Register_sceNpDrm(); diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 77996f6793..222fc8bb66 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -24,6 +24,8 @@ const int PSP_ERROR_UMD_INVALID_PARAM = 0x80010016; +const u64 MICRO_DELAY_ACTIVATE = 4000; + #define UMD_NOT_PRESENT 0x01 #define UMD_PRESENT 0x02 #define UMD_CHANGED 0x04 @@ -31,12 +33,27 @@ const int PSP_ERROR_UMD_INVALID_PARAM = 0x80010016; #define UMD_READY 0x10 #define UMD_READABLE 0x20 +struct UmdWaitingThread +{ + SceUID threadID; + u32 stat; + + inline static UmdWaitingThread Make(SceUID threadID, u32 stat) + { + UmdWaitingThread th; + th.threadID = threadID; + th.stat = stat; + return th; + } +}; static u8 umdActivated = 1; static u32 umdStatus = 0; static u32 umdErrorStat = 0; static int driveCBId = -1; -static int umdStatTimer = -1; +static int umdStatTimeoutEvent = -1; +static int umdStatChangeEvent = -1; +static std::vector umdWaitingThreads; #define PSP_UMD_TYPE_GAME 0x10 @@ -49,10 +66,12 @@ struct PspUmdInfo { }; void __UmdStatTimeout(u64 userdata, int cyclesLate); +void __UmdStatChange(u64 userdata, int cyclesLate); void __UmdInit() { - umdStatTimer = CoreTiming::RegisterEvent("UmdTimeout", __UmdStatTimeout); + umdStatTimeoutEvent = CoreTiming::RegisterEvent("UmdTimeout", __UmdStatTimeout); + umdStatChangeEvent = CoreTiming::RegisterEvent("UmdChange", __UmdStatChange); umdActivated = 1; umdStatus = 0; umdErrorStat = 0; @@ -65,8 +84,11 @@ void __UmdDoState(PointerWrap &p) p.Do(umdStatus); p.Do(umdErrorStat); p.Do(driveCBId); - p.Do(umdStatTimer); - CoreTiming::RestoreRegisterEvent(umdStatTimer, "UmdTimeout", __UmdStatTimeout); + p.Do(umdStatTimeoutEvent); + CoreTiming::RestoreRegisterEvent(umdStatTimeoutEvent, "UmdTimeout", __UmdStatTimeout); + p.Do(umdStatChangeEvent); + CoreTiming::RestoreRegisterEvent(umdStatChangeEvent, "UmdChange", __UmdStatChange); + p.Do(umdWaitingThreads); p.DoMarker("sceUmd"); } @@ -83,24 +105,55 @@ u8 __KernelUmdGetState() return state; } +void __UmdStatChange(u64 userdata, int cyclesLate) +{ + // TODO: Why not a bool anyway? + umdActivated = userdata & 0xFF; + + // Wake anyone waiting on this. + for (size_t i = 0; i < umdWaitingThreads.size(); ++i) + { + UmdWaitingThread &info = umdWaitingThreads[i]; + + u32 error; + SceUID waitID = __KernelGetWaitID(info.threadID, WAITTYPE_UMD, error); + bool keep = false; + if (waitID == 1) + { + if ((info.stat & __KernelUmdGetState()) != 0) + __KernelResumeThreadFromWait(info.threadID, 0); + // Only if they are still waiting do we keep them in the list. + else + keep = true; + } + + if (!keep) + umdWaitingThreads.erase(umdWaitingThreads.begin() + i--); + } +} + void __KernelUmdActivate() { - umdActivated = 1; + u32 notifyArg = UMD_PRESENT | UMD_READABLE; + __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); + + // Don't activate immediately, take time to "spin up." + CoreTiming::RemoveAllEvents(umdStatChangeEvent); + CoreTiming::ScheduleEvent(usToCycles(MICRO_DELAY_ACTIVATE), umdStatChangeEvent, 1); } void __KernelUmdDeactivate() { - umdActivated = 0; + u32 notifyArg = UMD_PRESENT | UMD_READY; + __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); + + CoreTiming::RemoveAllEvents(umdStatChangeEvent); + __UmdStatChange(0, 0); } -// typedef int (*UmdCallback)(int unknown, int event); - - -//int sceUmdCheckMedium(int a); int sceUmdCheckMedium() { - DEBUG_LOG(HLE,"1=sceUmdCheckMedium(?)"); - //ignore PARAM(0) + DEBUG_LOG(HLE, "1=sceUmdCheckMedium()"); return 1; //non-zero: disc in drive } @@ -128,7 +181,6 @@ int sceUmdActivate(u32 unknown, const char *name) if (unknown < 1 || unknown > 2) return PSP_ERROR_UMD_INVALID_PARAM; - bool changed = umdActivated == 0; __KernelUmdActivate(); if (unknown == 1) @@ -140,9 +192,6 @@ int sceUmdActivate(u32 unknown, const char *name) ERROR_LOG(HLE, "UNTESTED 0=sceUmdActivate(%d, %s)", unknown, name); } - u32 notifyArg = UMD_PRESENT | UMD_READABLE; - __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); - return 0; } @@ -152,7 +201,6 @@ int sceUmdDeactivate(u32 unknown, const char *name) if (unknown > 18) return PSP_ERROR_UMD_INVALID_PARAM; - bool changed = umdActivated != 0; __KernelUmdDeactivate(); if (unknown == 1) @@ -164,9 +212,6 @@ int sceUmdDeactivate(u32 unknown, const char *name) ERROR_LOG(HLE, "UNTESTED 0=sceUmdDeactivate(%d, %s)", unknown, name); } - u32 notifyArg = UMD_PRESENT | UMD_READY; - __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); - return 0; } @@ -225,6 +270,12 @@ void __UmdStatTimeout(u64 userdata, int cyclesLate) // Assuming it's still waiting. if (waitID == 1) __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); + + for (size_t i = 0; i < umdWaitingThreads.size(); ++i) + { + if (umdWaitingThreads[i].threadID == threadID) + umdWaitingThreads.erase(umdWaitingThreads.begin() + i--); + } } void __UmdWaitStat(u32 timeout) @@ -235,7 +286,7 @@ void __UmdWaitStat(u32 timeout) else if (timeout <= 215) timeout = 250; - CoreTiming::ScheduleEvent(usToCycles((int) timeout), umdStatTimer, __KernelGetCurThread()); + CoreTiming::ScheduleEvent(usToCycles((int) timeout), umdStatTimeoutEvent, __KernelGetCurThread()); } /** @@ -250,7 +301,10 @@ int sceUmdWaitDriveStat(u32 stat) DEBUG_LOG(HLE,"0=sceUmdWaitDriveStat(stat = %08x)", stat); if ((stat & __KernelUmdGetState()) == 0) + { + umdWaitingThreads.push_back(UmdWaitingThread::Make(__KernelGetCurThread(), stat)); __KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, 0, "umd stat waited"); + } return 0; } @@ -262,7 +316,8 @@ int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) if ((stat & __KernelUmdGetState()) == 0) { __UmdWaitStat(timeout); - __KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, 0, "umd stat waited"); + umdWaitingThreads.push_back(UmdWaitingThread::Make(__KernelGetCurThread(), stat)); + __KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, 0, "umd stat waited with timer"); } else hleReSchedule("umd stat waited with timer"); @@ -272,14 +327,7 @@ int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) { - if (driveCBId != -1) - { - DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout); - } - else - { - WARN_LOG(HLE, "0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d) without callback", stat, timeout); - } + DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout); hleCheckCurrentCallbacks(); if ((stat & __KernelUmdGetState()) == 0) @@ -288,6 +336,7 @@ int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) timeout = 8000; __UmdWaitStat(timeout); + umdWaitingThreads.push_back(UmdWaitingThread::Make(__KernelGetCurThread(), stat)); __KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, true, "umd stat waited"); } else @@ -324,8 +373,6 @@ u32 sceUmdReplacePermit() return 0; } - - const HLEFunction sceUmdUser[] = { {0xC6183D47,WrapI_UC,"sceUmdActivate"}, diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index aa22d3b875..ce79551865 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -88,6 +88,11 @@ void VagDecoder::GetSamples(s16 *outSamples, int numSamples) { return; } u8 *readp = Memory::GetPointer(read_); + if (!readp) + { + WARN_LOG(HLE, "Bad VAG samples address?"); + return; + } u8 *origp = readp; for (int i = 0; i < numSamples; i++) { if (curSample == 28) { diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index 47bb07aeee..f9b8c599f0 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -145,7 +145,12 @@ namespace MIPSComp break; } } - + + void Jit::Comp_RType2(u32 op) + { + DISABLE; + } + void Jit::Comp_RType3(u32 op) { int rt = _RT; @@ -154,11 +159,11 @@ namespace MIPSComp switch (op & 63) { - //case 10: if (!R(rt)) R(rd) = R(rs); break; //movz - //case 11: if (R(rt)) R(rd) = R(rs); break; //movn + //case 10: if (!R(rt)) R(rd) = R(rs); break; //movz + //case 11: if (R(rt)) R(rd) = R(rs); break; //movn - // case 32: //R(rd) = R(rs) + R(rt); break; //add - case 33: //R(rd) = R(rs) + R(rt); break; //addu + // case 32: //R(rd) = R(rs) + R(rt); break; //add + case 33: //R(rd) = R(rs) + R(rt); break; //addu // Some optimized special cases if (rs == 0) { gpr.MapDirtyIn(rd, rt); @@ -171,25 +176,25 @@ namespace MIPSComp ADD(gpr.R(rd), gpr.R(rs), gpr.R(rt)); } break; - case 34: //R(rd) = R(rs) - R(rt); break; //sub + case 34: //R(rd) = R(rs) - R(rt); break; //sub case 35: gpr.MapDirtyInIn(rd, rs, rt); SUB(gpr.R(rd), gpr.R(rs), gpr.R(rt)); break; - case 36: //R(rd) = R(rs) & R(rt); break; //and + case 36: //R(rd) = R(rs) & R(rt); break; //and gpr.MapDirtyInIn(rd, rs, rt); AND(gpr.R(rd), gpr.R(rs), gpr.R(rt)); break; - case 37: //R(rd) = R(rs) | R(rt); break; //or + case 37: //R(rd) = R(rs) | R(rt); break; //or gpr.MapDirtyInIn(rd, rs, rt); ORR(gpr.R(rd), gpr.R(rs), gpr.R(rt)); break; - case 38: //R(rd) = R(rs) ^ R(rt); break; //xor/eor + case 38: //R(rd) = R(rs) ^ R(rt); break; //xor/eor gpr.MapDirtyInIn(rd, rs, rt); EOR(gpr.R(rd), gpr.R(rs), gpr.R(rt)); break; - case 39: // R(rd) = ~(R(rs) | R(rt)); //nor + case 39: // R(rd) = ~(R(rs) | R(rt)); break; //nor gpr.MapDirtyInIn(rd, rs, rt); if (rt == 0) { MVN(gpr.R(rd), gpr.R(rs)); @@ -209,7 +214,7 @@ namespace MIPSComp SetCC(CC_AL); break; - case 43: //R(rd) = R(rs) < R(rt); break; //sltu + case 43: //R(rd) = R(rs) < R(rt); break; //sltu gpr.MapDirtyInIn(rd, rs, rt); CMP(gpr.R(rs), gpr.R(rt)); SetCC(CC_LO); @@ -219,11 +224,25 @@ namespace MIPSComp SetCC(CC_AL); break; - // case 44: R(rd) = (R(rs) > R(rt)) ? R(rs) : R(rt); break; //max - // CMP(a,b); CMOVLT(a,b) + case 44: //R(rd) = max(R(rs), R(rt); break; //max + gpr.MapDirtyInIn(rd, rs, rt); + CMP(gpr.R(rs), gpr.R(rt)); + SetCC(CC_GT); + MOV(gpr.R(rd), gpr.R(rs)); + SetCC(CC_LE); + MOV(gpr.R(rd), gpr.R(rt)); + SetCC(CC_AL); + break; - // case 45: R(rd) = (R(rs) < R(rt)) ? R(rs) : R(rt); break; //min - // CMP(a,b); CMOVGT(a,b) + case 45: //R(rd) = min(R(rs), R(rt)); break; //min + gpr.MapDirtyInIn(rd, rs, rt); + CMP(gpr.R(rs), gpr.R(rt)); + SetCC(CC_LT); + MOV(gpr.R(rd), gpr.R(rs)); + SetCC(CC_GE); + MOV(gpr.R(rd), gpr.R(rt)); + SetCC(CC_AL); + break; default: // gpr.UnlockAll(); @@ -263,15 +282,17 @@ namespace MIPSComp */ void Jit::Comp_ShiftType(u32 op) { + int rs = _RS; + int fd = _FD; // WARNIGN : ROTR switch (op & 0x3f) { case 0: CompShiftImm(op, ST_LSL); break; - case 2: CompShiftImm(op, ST_LSR); break; // srl + case 2: CompShiftImm(op, rs == 1 ? ST_ROR : ST_LSR); break; // srl case 3: CompShiftImm(op, ST_ASR); break; // sra // case 4: CompShiftVar(op, &XEmitter::SHL); break; // R(rd) = R(rt) << R(rs); break; //sllv - // case 6: CompShiftVar(op, &XEmitter::SHR); break; // R(rd) = R(rt) >> R(rs); break; //srlv + // case 6: CompShiftVar(op, fd == 1 ? &XEmitter::ROR : &XEmitter::SHR); break; // R(rd) = R(rt) >> R(rs); break; //srlv // case 7: CompShiftVar(op, &XEmitter::SAR); break; // R(rd) = ((s32)R(rt)) >> R(rs); break; //srav default: @@ -289,29 +310,44 @@ namespace MIPSComp void Jit::Comp_Allegrex(u32 op) { - DISABLE int rt = _RT; int rd = _RD; switch ((op >> 6) & 31) { + /* case 16: // seb // R(rd) = (u32)(s32)(s8)(u8)R(rt); - /* gpr.Lock(rd, rt); gpr.BindToRegister(rd, true, true); MOV(32, R(EAX), gpr.R(rt)); // work around the byte-register addressing problem MOVSX(32, 8, gpr.RX(rd), R(EAX)); - gpr.UnlockAll();*/ + gpr.UnlockAll(); break; case 24: // seh - /* gpr.Lock(rd, rt); gpr.BindToRegister(rd, true, true); MOVSX(32, 16, gpr.RX(rd), gpr.R(rt)); - gpr.UnlockAll();*/ + gpr.UnlockAll(); break; - + */ case 20: //bitrev + if (gpr.IsImm(rt)) + { + // http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel + u32 v = gpr.GetImm(rt); + // swap odd and even bits + v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); + // swap consecutive pairs + v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); + // swap nibbles ... + v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); + // swap bytes + v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); + // swap 2-byte long pairs + v = ( v >> 16 ) | ( v << 16); + gpr.SetImm(rd,v); + break; + } default: Comp_Generic(op); return; @@ -355,6 +391,17 @@ namespace MIPSComp case 25: //multu (2nd) lo,hi = unsigned mul (rs * rt) gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt); UMULL(gpr.R(MIPSREG_LO), gpr.R(MIPSREG_HI), gpr.R(rs), gpr.R(rt)); + break; + + case 28: //madd + gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt, false); + SMLAL(gpr.R(MIPSREG_LO), gpr.R(MIPSREG_HI), gpr.R(rs), gpr.R(rt)); + break; + + case 29: //maddu + gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt, false); + UMLAL(gpr.R(MIPSREG_LO), gpr.R(MIPSREG_HI), gpr.R(rs), gpr.R(rt)); + break; default: DISABLE; diff --git a/Core/MIPS/ARM/ArmCompLoadStore.cpp b/Core/MIPS/ARM/ArmCompLoadStore.cpp index 854e5f2075..94d75f7f54 100644 --- a/Core/MIPS/ARM/ArmCompLoadStore.cpp +++ b/Core/MIPS/ARM/ArmCompLoadStore.cpp @@ -84,6 +84,7 @@ namespace MIPSComp void Jit::Comp_ITypeMem(u32 op) { int offset = (signed short)(op&0xFFFF); + bool load = false; int rt = _RT; int rs = _RS; int o = op>>26; @@ -93,62 +94,44 @@ namespace MIPSComp } switch (o) { - case 37: //R(rt) = ReadMem16(addr); break; //lhu - Comp_Generic(op); - return; - - case 35: //R(rt) = ReadMem32(addr); //lw - case 36: //R(rt) = ReadMem8 (addr); break; //lbu - if (g_Config.bFastMemory) { - if (gpr.IsImm(rs)) { - // We can compute the full address at compile time. Kickass. - u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF; - gpr.MapReg(rt, MAP_NOINIT | MAP_DIRTY); // must be OK even if rs == rt since we have the value from imm already. - MOVI2R(R0, addr); - } else { - gpr.MapDirtyIn(rt, rs); - SetR0ToEffectiveAddress(rs, offset); - } - if (o == 35) { - LDR(gpr.R(rt), R11, R0, true, true); - } else if (o == 36) { - ADD(R0, R0, R11); // TODO: Merge with next instruction - LDRB(gpr.R(rt), R0); - } - } else { - Comp_Generic(op); - return; - } - break; - - case 41: //WriteMem16(addr, R(rt)); break; //sh - Comp_Generic(op); - return; - + case 32: //lb + case 33: //lh + case 35: //lw + case 36: //lbu + case 37: //lhu + load = true; case 40: //sb - case 43: //WriteMem32(addr, R(rt)); break; //sw + case 41: //sh + case 43: //sw if (g_Config.bFastMemory) { if (gpr.IsImm(rs)) { // We can compute the full address at compile time. Kickass. u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF; - gpr.MapReg(rt); + // Must be OK even if rs == rt since we have the value from imm already. + gpr.MapReg(rt, load ? MAP_NOINIT | MAP_DIRTY : 0); MOVI2R(R0, addr); } else { - gpr.MapInIn(rt, rs); + load ? gpr.MapDirtyIn(rt, rs) : gpr.MapInIn(rt, rs); SetR0ToEffectiveAddress(rs, offset); } - if (o == 43) { - STR(R0, gpr.R(rt), R11, true, true); - } else if (o == 40) { - ADD(R0, R0, R11); - STRB(R0, gpr.R(rt)); + switch (o) + { + // Load + case 35: LDR (gpr.R(rt), R11, R0, true, true); break; + case 37: LDRH (gpr.R(rt), R11, R0, true, true); break; + case 33: LDRSH(gpr.R(rt), R11, R0, true, true); break; + case 36: LDRB (gpr.R(rt), R11, R0, true, true); break; + case 32: LDRSB(gpr.R(rt), R11, R0, true, true); break; + // Store + case 43: STR (R0, gpr.R(rt), R11, true, true); break; + case 41: STRH (R0, gpr.R(rt), R11, true, true); break; + case 40: STRB (R0, gpr.R(rt), R11, true, true); break; } } else { Comp_Generic(op); return; } break; - // break; /* case 34: //lwl { diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 73e12d3231..19cb4b6bbc 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -483,7 +483,7 @@ namespace MIPSComp fpr.ReleaseSpillLocks(); } - + void Jit::Comp_Mftv(u32 op) { // DISABLE; diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h index 48be4fa9bb..358e6a83d1 100644 --- a/Core/MIPS/ARM/ArmJit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -163,6 +163,7 @@ public: void Comp_Break(u32 op); void Comp_IType(u32 op); + void Comp_RType2(u32 op); void Comp_RType3(u32 op); void Comp_ShiftType(u32 op); void Comp_Allegrex(u32 op); @@ -187,7 +188,6 @@ public: void Comp_Vmtvc(u32 op); void Comp_Vmmov(u32 op); - ArmJitBlockCache *GetBlockCache() { return &blocks; } void ClearCache(); diff --git a/Core/MIPS/ARM/ArmRegCache.cpp b/Core/MIPS/ARM/ArmRegCache.cpp index cba6b85743..5a7f5cac50 100644 --- a/Core/MIPS/ARM/ArmRegCache.cpp +++ b/Core/MIPS/ARM/ArmRegCache.cpp @@ -135,16 +135,16 @@ void ArmRegCache::MapInIn(MIPSReg rd, MIPSReg rs) { void ArmRegCache::MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad) { SpillLock(rd, rs); - bool overlap = avoidLoad && rd == rs; - MapReg(rd, MAP_DIRTY | (overlap ? 0 : MAP_NOINIT)); + bool load = !avoidLoad || rd == rs; + MapReg(rd, MAP_DIRTY | (load ? 0 : MAP_NOINIT)); MapReg(rs); ReleaseSpillLocks(); } void ArmRegCache::MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad) { SpillLock(rd, rs, rt); - bool overlap = avoidLoad && (rd == rs || rd == rt); - MapReg(rd, MAP_DIRTY | (overlap ? 0 : MAP_NOINIT)); + bool load = !avoidLoad || (rd == rs || rd == rt); + MapReg(rd, MAP_DIRTY | (load ? 0 : MAP_NOINIT)); MapReg(rt); MapReg(rs); ReleaseSpillLocks(); @@ -152,10 +152,10 @@ void ArmRegCache::MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoa void ArmRegCache::MapDirtyDirtyInIn(MIPSReg rd1, MIPSReg rd2, MIPSReg rs, MIPSReg rt, bool avoidLoad) { SpillLock(rd1, rd2, rs, rt); - bool overlap1 = avoidLoad && (rd1 == rs || rd1 == rt); - bool overlap2 = avoidLoad && (rd2 == rs || rd2 == rt); - MapReg(rd1, MAP_DIRTY | (overlap1 ? 0 : MAP_NOINIT)); - MapReg(rd2, MAP_DIRTY | (overlap2 ? 0 : MAP_NOINIT)); + bool load1 = !avoidLoad || (rd1 == rs || rd1 == rt); + bool load2 = !avoidLoad || (rd2 == rs || rd2 == rt); + MapReg(rd1, MAP_DIRTY | (load1 ? 0 : MAP_NOINIT)); + MapReg(rd2, MAP_DIRTY | (load2 ? 0 : MAP_NOINIT)); MapReg(rt); MapReg(rs); ReleaseSpillLocks(); diff --git a/Core/MIPS/MIPSDebugInterface.h b/Core/MIPS/MIPSDebugInterface.h index 46ae3ae439..70e70a900f 100644 --- a/Core/MIPS/MIPSDebugInterface.h +++ b/Core/MIPS/MIPSDebugInterface.h @@ -74,7 +74,40 @@ public: u32 GetRegValue(int cat, int index) { - return cpu->r[index]; + switch (cat) + { + case 0: + return cpu->r[index]; + + case 1: + return *(u32 *)&cpu->f[index]; + + case 2: + return *(u32 *)&cpu->v[index]; + + default: + return 0; + } } + void SetRegValue(int cat, int index, u32 value) + { + switch (cat) + { + case 0: + cpu->r[index] = value; + break; + + case 1: + cpu->f[index] = *(float *)&value; + break; + + case 2: + cpu->v[index] = *(float *)&value; + break; + + default: + break; + } + } }; diff --git a/Core/MIPS/MIPSDis.cpp b/Core/MIPS/MIPSDis.cpp index 3a72a79418..638f84ecdf 100644 --- a/Core/MIPS/MIPSDis.cpp +++ b/Core/MIPS/MIPSDis.cpp @@ -76,7 +76,7 @@ namespace MIPSDis int ft = _FT; int rs = _RS; const char *name = MIPSGetName(op); - sprintf(out, "%s\t%s, %d(%s)",name,FN(ft),offset,RN(rs)); + sprintf(out, "%s\t%s, 0x%X(%s)",name,FN(ft),offset,RN(rs)); } void Dis_FPUComp(u32 op, char *out) { @@ -151,7 +151,7 @@ namespace MIPSDis int rt = _RT; int rs = _RS; const char *name = MIPSGetName(op); - sprintf(out, "%s\t%s, %s, %i",name,RN(rt),RN(rs),imm); + sprintf(out, "%s\t%s, %s, 0x%X",name,RN(rt),RN(rs),imm); } void Dis_ori(u32 op, char *out) { @@ -160,9 +160,9 @@ namespace MIPSDis int rs = _RS; const char *name = MIPSGetName(op); if (rs == 0) - sprintf(out, "li\t%s, %i",RN(rt),imm); + sprintf(out, "li\t%s, 0x%X",RN(rt),imm); else - sprintf(out, "%s\t%s, %s, %i",name,RN(rt),RN(rs),imm); + sprintf(out, "%s\t%s, %s, 0x%X",name,RN(rt),RN(rs),imm); } void Dis_IType1(u32 op, char *out) @@ -170,7 +170,7 @@ namespace MIPSDis int imm = (signed short)(op&0xFFFF); int rt = _RT; const char *name = MIPSGetName(op); - sprintf(out, "%s\t%s, %i",name,RN(rt),imm); + sprintf(out, "%s\t%s, 0x%X",name,RN(rt),imm); } void Dis_addi(u32 op, char *out) @@ -179,7 +179,7 @@ namespace MIPSDis int rt = _RT; int rs = _RS; if (rs == 0) - sprintf(out, "li\t%s, %i",RN(rt),imm); + sprintf(out, "li\t%s, 0x%X",RN(rt),imm); else Dis_IType(op,out); } @@ -190,7 +190,7 @@ namespace MIPSDis int rt = _RT; int rs = _RS; const char *name = MIPSGetName(op); - sprintf(out, "%s\t%s, %i(%s)",name,RN(rt),imm,RN(rs)); + sprintf(out, "%s\t%s, 0x%X(%s)",name,RN(rt),imm,RN(rs)); } void Dis_RType2(u32 op, char *out) @@ -237,7 +237,7 @@ namespace MIPSDis name = "rotr"; if (((op & 0x3f) == 6) && sa == 1) name = "rotrv"; - sprintf(out, "%s\t%s, %s, %d",name,RN(rd),RN(rt),sa); + sprintf(out, "%s\t%s, %s, 0x%X",name,RN(rd),RN(rt),sa); } void Dis_VarShiftType(u32 op, char *out) @@ -271,13 +271,13 @@ namespace MIPSDis case 0x0: //ext { int size = _SIZE + 1; - sprintf(out,"%s\t%s, %s, %i, %i",name,RN(Rt),RN(rs),pos,size); + sprintf(out,"%s\t%s, %s, 0x%X, 0x%X",name,RN(Rt),RN(rs),pos,size); } break; case 0x4: // ins { int size = (_SIZE + 1) - pos; - sprintf(out,"%s\t%s, %s, %i, %i",name,RN(Rt),RN(rs),pos,size); + sprintf(out,"%s\t%s, %s, 0x%X, 0x%X",name,RN(Rt),RN(rs),pos,size); } break; } diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index 057c1edf9a..098908ddcf 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -187,7 +187,7 @@ namespace MIPSInt void Int_Break(u32 op) { ERROR_LOG(CPU, "BREAK!"); - coreState = CORE_STEPPING; + Core_UpdateState(CORE_STEPPING); PC += 4; } @@ -304,7 +304,6 @@ namespace MIPSInt _dbg_assert_msg_(CPU,0,"Jump in delay slot :("); } - int rs = (op>>21)&0x1f; u32 addr = R(rs); switch (op & 0x3f) @@ -362,14 +361,18 @@ namespace MIPSInt switch (op >> 26) { case 48: // ll - R(rt) = Memory::Read_U32(addr); + if (rt != 0) { + R(rt) = Memory::Read_U32(addr); + } currentMIPS->llBit = 1; break; case 56: // sc if (currentMIPS->llBit) { Memory::Write_U32(R(rt), addr); - R(rt) = 1; - } else { + if (rt != 0) { + R(rt) = 1; + } + } else if (rt != 0) { R(rt) = 0; } break; @@ -388,6 +391,13 @@ namespace MIPSInt int rd = _RD; static bool has_warned = false; + // Don't change $zr. + if (rd == 0) + { + PC += 4; + return; + } + switch (op & 63) { case 10: if (R(rt) == 0) R(rd) = R(rs); break; //movz @@ -533,6 +543,14 @@ namespace MIPSInt { int rs = _RS; int rd = _RD; + + // Don't change $zr. + if (rd == 0) + { + PC += 4; + return; + } + switch (op & 63) { case 22: //clz @@ -675,6 +693,13 @@ namespace MIPSInt int rs = _RS; int rd = _RD; int sa = _FD; + + // Don't change $zr. + if (rd == 0) + { + PC += 4; + return; + } switch (op & 0x3f) { @@ -720,6 +745,14 @@ namespace MIPSInt { int rt = _RT; int rd = _RD; + + // Don't change $zr. + if (rd == 0) + { + PC += 4; + return; + } + switch((op>>6)&31) { case 16: // seb @@ -756,6 +789,13 @@ namespace MIPSInt int rt = _RT; int rd = _RD; + // Don't change $zr. + if (rd == 0) + { + PC += 4; + return; + } + switch (op & 0x3ff) { case 0xA0: //wsbh @@ -777,6 +817,13 @@ namespace MIPSInt int rt = _RT; int pos = _POS; + // Don't change $zr. + if (rt == 0) + { + PC += 4; + return; + } + switch (op & 0x3f) { case 0x0: //ext @@ -785,7 +832,7 @@ namespace MIPSInt R(rt) = (R(rs) >> pos) & ((1<= cst ? cst : f; +} + +// Preserves NaN in first param, takes sign of equal value in others. +inline float nanclamp(float f, float lower, float upper) +{ + return nanmin(nanmax(f, lower), upper); +} void ApplyPrefixST(float *v, u32 data, VectorSize size) { @@ -486,15 +513,16 @@ namespace MIPSInt case 0: d[i] = s[i]; break; //vmov case 1: d[i] = fabsf(s[i]); break; //vabs case 2: d[i] = -s[i]; break; //vneg - case 4: if (s[i] < 0) d[i] = 0; else {if(s[i] > 1.0f) d[i] = 1.0f; else d[i] = s[i];} break; // vsat0 + // vsat0 changes -0.0 to +0.0. + case 4: if (s[i] <= 0) d[i] = 0; else {if(s[i] > 1.0f) d[i] = 1.0f; else d[i] = s[i];} break; // vsat0 case 5: if (s[i] < -1.0f) d[i] = -1.0f; else {if(s[i] > 1.0f) d[i] = 1.0f; else d[i] = s[i];} break; // vsat1 case 16: d[i] = 1.0f / s[i]; break; //vrcp case 17: d[i] = 1.0f / sqrtf(s[i]); break; //vrsq case 18: d[i] = sinf((float)M_PI_2 * s[i]); break; //vsin case 19: d[i] = cosf((float)M_PI_2 * s[i]); break; //vcos - case 20: d[i] = powf(2.0f, s[i]); break; - case 21: d[i] = logf(s[i])/log(2.0f); break; - case 22: d[i] = sqrtf(s[i]); break; //vsqrt + case 20: d[i] = powf(2.0f, s[i]); break; //vexp2 + case 21: d[i] = logf(s[i])/log(2.0f); break; //vlog2 + case 22: d[i] = fabsf(sqrtf(s[i])); break; //vsqrt case 23: d[i] = asinf(s[i] * (float)M_2_PI); break; //vasin case 24: d[i] = -1.0f / s[i]; break; // vnrcp case 26: d[i] = -sinf((float)M_PI_2 * s[i]); break; // vnsin @@ -519,7 +547,8 @@ namespace MIPSInt ReadVector(s, sz, vs); for (int i = 0; i < GetNumVectorElements(sz); i++) { - d[i] = 1.0f - s[i]; + // Always positive NaN. + d[i] = isnan(s[i]) ? fabsf(s[i]) : 1.0f - s[i]; } ApplyPrefixD(d, sz); WriteVector(d, sz, vd); @@ -536,13 +565,13 @@ namespace MIPSInt ReadVector(s, sz, vs); int n = GetNumVectorElements(sz); float x = s[0]; - d[0] = std::min(std::max(0.0f, 1.0f - x), 1.0f); - d[1] = std::min(std::max(0.0f, x), 1.0f); + d[0] = nanclamp(1.0f - x, 0.0f, 1.0f); + d[1] = nanclamp(x, 0.0f, 1.0f); VectorSize outSize = V_Pair; if (n > 1) { float y = s[1]; - d[2] = std::min(std::max(0.0f, 1.0f - y), 1.0f); - d[3] = std::min(std::max(0.0f, y), 1.0f); + d[2] = nanclamp(1.0f - y, 0.0f, 1.0f); + d[3] = nanclamp(y, 0.0f, 1.0f); outSize = V_Quad; } WriteVector(d, outSize, vd); @@ -616,8 +645,8 @@ namespace MIPSInt int imm = (op >> 16) & 0x1f; float mult = 1.0f/(float)(1 << imm); VectorSize sz = GetVecSize(op); - ReadVector((float*)&s, sz, vs); - ApplySwizzleS((float*)&s, sz); //TODO: and the mask to kill everything but swizzle + ReadVector((float*)&s[0], sz, vs); + ApplySwizzleS((float*)&s[0], sz); //TODO: and the mask to kill everything but swizzle for (int i = 0; i < GetNumVectorElements(sz); i++) { d[i] = (float)s[i] * mult; @@ -638,6 +667,7 @@ namespace MIPSInt }; // magic code from ryg: http://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/ + // See also SSE2 version: https://gist.github.com/rygorous/2144712 static FP32 half_to_float_fast5(FP16 h) { static const FP32 magic = { (127 + (127 - 15)) << 23 }; @@ -658,6 +688,42 @@ namespace MIPSInt return fp.f; } + // More magic code: https://gist.github.com/rygorous/2156668 + static FP16 float_to_half_fast3(FP32 f) + { + static const FP32 f32infty = { 255 << 23 }; + static const FP32 f16infty = { 31 << 23 }; + static const FP32 magic = { 15 << 23 }; + static const u32 sign_mask = 0x80000000u; + static const u32 round_mask = ~0xfffu; + FP16 o = { 0 }; + + u32 sign = f.u & sign_mask; + f.u ^= sign; + + if (f.u >= f32infty.u) // Inf or NaN (all exponent bits set) + o.u = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf + else // (De)normalized number or zero + { + f.u &= round_mask; + f.f *= magic.f; + f.u -= round_mask; + if (f.u > f16infty.u) f.u = f16infty.u; // Clamp to signed infinity if overflowed + + o.u = f.u >> 13; // Take the bits! + } + + o.u |= sign >> 16; + return o; + } + + static u16 ShrinkToHalf(float full) { + FP32 fp32; + fp32.f = full; + FP16 fp = float_to_half_fast3(fp32); + return fp.u; + } + void Int_Vh2f(u32 op) { u32 s[4]; @@ -665,7 +731,8 @@ namespace MIPSInt int vd = _VD; int vs = _VS; VectorSize sz = GetVecSize(op); - ReadVector((float*)&s, sz, vs); + ReadVector((float*)&s[0], sz, vs); + ApplySwizzleS((float*)&s[0], sz); VectorSize outsize = V_Pair; switch (sz) { @@ -686,35 +753,40 @@ namespace MIPSInt _dbg_assert_msg_(CPU, 0, "Trying to interpret Int_Vh2f instruction that can't be interpreted"); break; } - ApplyPrefixD(d, sz); //TODO: and the mask to kill everything but mask - WriteVector(d, sz, vd); + ApplyPrefixD(d, outsize); + WriteVector(d, outsize, vd); PC += 4; EatPrefixes(); } void Int_Vf2h(u32 op) { - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); - // See http://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion - - /* - int s[4]; - float d[4]; + float s[4]; + u32 d[4]; int vd = _VD; int vs = _VS; - int imm = (op >> 16) & 0x1f; - float mult = 1.0f/(float)(1 << imm); VectorSize sz = GetVecSize(op); - ReadVector((float*)&s, sz, vs); - ApplySwizzleS((float*)&s, sz); //TODO: and the mask to kill everything but swizzle + ReadVector(s, sz, vs); + ApplySwizzleS(s, sz); - for (int i = 0; i < GetNumVectorElements(sz); i++) - { - d[i] = (float)s[i] * mult; + VectorSize outsize = V_Single; + switch (sz) { + case V_Pair: + outsize = V_Single; + d[0] = ShrinkToHalf(s[0]) | ((u32)ShrinkToHalf(s[1]) << 16); + break; + case V_Quad: + outsize = V_Pair; + d[0] = ShrinkToHalf(s[0]) | ((u32)ShrinkToHalf(s[1]) << 16); + d[1] = ShrinkToHalf(s[2]) | ((u32)ShrinkToHalf(s[3]) << 16); + break; + case V_Single: + case V_Triple: + _dbg_assert_msg_(CPU, 0, "Trying to interpret Int_Vf2h instruction that can't be interpreted"); + break; } - ApplyPrefixD(d, sz); //TODO: and the mask to kill everything but mask - WriteVector(d, sz, vd); - */ + ApplyPrefixD((float*)&d[0], outsize); + WriteVector((float*)&d[0], outsize, vd); PC += 4; EatPrefixes(); } @@ -954,7 +1026,7 @@ namespace MIPSInt { sum += (i == n - 1) ? t[i] : s[i]*t[i]; } - d = sum; + d = isnan(sum) ? fabsf(sum) : sum; ApplyPrefixD(&d,V_Single); V(vd) = d; PC += 4; @@ -1452,10 +1524,6 @@ namespace MIPSInt VC_NS }; -#ifdef _MSC_VER -#define isnan _isnan -#endif - void Int_Vcmp(u32 op) { int vs = _VS; @@ -1491,16 +1559,18 @@ namespace MIPSInt case VC_EZ: c = s[i] == 0.0f || s[i] == -0.0f; break; case VC_EN: c = isnan(s[i]); break; - case VC_EI: c = 0; break; - case VC_ES: c = (s[i] != s[i]) || (s[i] == std::numeric_limits::infinity()); break; // Tekken Dark Resurrection + case VC_EI: c = isinf(s[i]); break; + case VC_ES: c = isnan(s[i]) || isinf(s[i]); break; // Tekken Dark Resurrection case VC_NZ: c = s[i] != 0; break; - case VC_NN: c = s[i] != 0; break; - case VC_NI: c = s[i] != 0; break; - case VC_NS: c = s[i] != 0; break; + case VC_NN: c = !isnan(s[i]); break; + case VC_NI: c = !isinf(s[i]); break; + case VC_NS: c = !isnan(s[i]) && !isinf(s[i]); break; + default: _dbg_assert_msg_(CPU,0,"Unsupported vcmp condition code %d", cond); PC += 4; + EatPrefixes(); return; } cc |= (c<(&Jit)); - ABI_RestoreStack(0); -#elif _M_X64 - CALL((void *)&Jit); -#endif + ABI_CallFunction((void *)&Jit); JMP(dispatcherNoCheck); // Let's just dispatch again, we'll enter the block since we know it's there. SetJumpTarget(bail); diff --git a/Core/MIPS/x86/CompALU.cpp b/Core/MIPS/x86/CompALU.cpp index e7da034134..7b447674f2 100644 --- a/Core/MIPS/x86/CompALU.cpp +++ b/Core/MIPS/x86/CompALU.cpp @@ -17,6 +17,7 @@ #include "Jit.h" #include "RegCache.h" +#include using namespace MIPSAnalyst; #define _RS ((op>>21) & 0x1F) @@ -77,16 +78,26 @@ namespace MIPSComp gpr.Lock(rt, rs); gpr.BindToRegister(rt, rt == rs, true); - if (rt != rs) + if (rt == rs || gpr.R(rs).IsSimpleReg()) + LEA(32, gpr.RX(rt), MDisp(gpr.RX(rs), simm)); + else + { MOV(32, gpr.R(rt), gpr.R(rs)); - if (simm != 0) - ADD(32, gpr.R(rt), Imm32((u32)(s32)simm)); - // TODO: Can also do LEA if both operands happen to be in registers. + if (simm != 0) + ADD(32, gpr.R(rt), Imm32((u32)(s32)simm)); + } gpr.UnlockAll(); } break; case 10: // R(rt) = (s32)R(rs) < simm; break; //slti + // There's a mips compiler out there asking it already knows the answer to... + if (gpr.IsImmediate(rs)) + { + gpr.SetImmediate32(rt, (s32)gpr.GetImmediate32(rs) < simm); + break; + } + gpr.Lock(rt, rs); gpr.BindToRegister(rs, true, false); gpr.BindToRegister(rt, rt == rs, true); @@ -98,6 +109,12 @@ namespace MIPSComp break; case 11: // R(rt) = R(rs) < uimm; break; //sltiu + if (gpr.IsImmediate(rs)) + { + gpr.SetImmediate32(rt, gpr.GetImmediate32(rs) < uimm); + break; + } + gpr.Lock(rt, rs); gpr.BindToRegister(rs, true, false); gpr.BindToRegister(rt, rt == rs, true); @@ -141,6 +158,29 @@ namespace MIPSComp } } + void Jit::Comp_RType2(u32 op) + { + CONDITIONAL_DISABLE; + int rs = _RS; + int rd = _RD; + + // Don't change $zr. + if (rd == 0) + return; + + switch (op & 63) + { + case 22: //clz + DISABLE; + break; + case 23: //clo + DISABLE; + break; + default: + DISABLE; + } + } + static u32 RType3_ImmAdd(const u32 a, const u32 b) { return a + b; @@ -180,17 +220,37 @@ namespace MIPSComp return; } + // Act like zero was used if the operand is equivalent. This happens. + if (gpr.IsImmediate(rs) && gpr.GetImmediate32(rs) == 0) + rs = 0; + if (gpr.IsImmediate(rt) && gpr.GetImmediate32(rt) == 0) + rt = 0; + gpr.Lock(rt, rs, rd); - // Optimize out + 0 and | 0. - if ((doImm == &RType3_ImmAdd || doImm == &RType3_ImmOr) && (rs == 0 || rt == 0)) + // Optimize out operations against 0... and is the only one that isn't a MOV. + if (rt == 0 || (rs == 0 && doImm != &RType3_ImmSub)) { - int rsource = rt == 0 ? rs : rt; - if (rsource != rd) + if (doImm == &RType3_ImmAnd) + gpr.SetImmediate32(rd, 0); + else { - gpr.BindToRegister(rd, false, true); - MOV(32, gpr.R(rd), gpr.R(rsource)); + int rsource = rt == 0 ? rs : rt; + if (rsource != rd) + { + gpr.BindToRegister(rd, false, true); + MOV(32, gpr.R(rd), gpr.R(rsource)); + } } } + else if (gpr.IsImmediate(rt)) + { + // No temporary needed. + u32 rtval = gpr.GetImmediate32(rt); + gpr.BindToRegister(rd, rs == rd, true); + if (rs != rd) + MOV(32, gpr.R(rd), gpr.R(rs)); + (this->*arith)(32, gpr.R(rd), Imm32(rtval)); + } else { // Use EAX as a temporary if we'd overwrite it. @@ -218,15 +278,63 @@ namespace MIPSComp switch (op & 63) { - //case 10: if (!R(rt)) R(rd) = R(rs); break; //movz - //case 11: if (R(rt)) R(rd) = R(rs); break; //movn + case 10: //if (R(rt) == 0) R(rd) = R(rs); break; //movz + if (rd == rs) + break; + gpr.Lock(rt, rs, rd); + if (!gpr.IsImmediate(rt)) + { + gpr.KillImmediate(rs, true, false); + // Need to load rd in case the condition fails. + gpr.BindToRegister(rd, true, true); + CMP(32, gpr.R(rt), Imm32(0)); + CMOVcc(32, gpr.RX(rd), gpr.R(rs), CC_E); + } + else if (gpr.GetImmediate32(rt) == 0) + { + // Yes, this actually happens. + if (gpr.IsImmediate(rs)) + gpr.SetImmediate32(rd, gpr.GetImmediate32(rs)); + else if (rd != rs) + { + gpr.BindToRegister(rd, false, true); + MOV(32, gpr.R(rd), gpr.R(rs)); + } + } + gpr.UnlockAll(); + break; - // case 32: //R(rd) = R(rs) + R(rt); break; //add + case 11: //if (R(rt) != 0) R(rd) = R(rs); break; //movn + if (rd == rs) + break; + gpr.Lock(rt, rs, rd); + if (!gpr.IsImmediate(rt)) + { + gpr.KillImmediate(rs, true, false); + // Need to load rd in case the condition fails. + gpr.BindToRegister(rd, true, true); + CMP(32, gpr.R(rt), Imm32(0)); + CMOVcc(32, gpr.RX(rd), gpr.R(rs), CC_NE); + } + else if (gpr.GetImmediate32(rt) != 0) + { + if (gpr.IsImmediate(rs)) + gpr.SetImmediate32(rd, gpr.GetImmediate32(rs)); + else if (rd != rs) + { + gpr.BindToRegister(rd, false, true); + MOV(32, gpr.R(rd), gpr.R(rs)); + } + } + gpr.UnlockAll(); + break; + + case 32: //R(rd) = R(rs) + R(rt); break; //add case 33: //R(rd) = R(rs) + R(rt); break; //addu CompTriArith(op, &XEmitter::ADD, &RType3_ImmAdd); break; case 34: //R(rd) = R(rs) - R(rt); break; //sub - case 35: + case 35: //R(rd) = R(rs) - R(rt); break; //subu CompTriArith(op, &XEmitter::SUB, &RType3_ImmSub); break; case 36: //R(rd) = R(rs) & R(rt); break; //and @@ -248,45 +356,111 @@ namespace MIPSComp break; case 42: //R(rd) = (int)R(rs) < (int)R(rt); break; //slt - gpr.Lock(rt, rs, rd); - gpr.BindToRegister(rs, true, true); - gpr.BindToRegister(rd, true, true); - XOR(32, R(EAX), R(EAX)); - CMP(32, gpr.R(rs), gpr.R(rt)); - SETcc(CC_L, R(EAX)); - MOV(32, gpr.R(rd), R(EAX)); - gpr.UnlockAll(); + if (gpr.IsImmediate(rs) && gpr.IsImmediate(rt)) + gpr.SetImmediate32(rd, (s32)gpr.GetImmediate32(rs) < (s32)gpr.GetImmediate32(rt)); + else + { + gpr.Lock(rt, rs, rd); + gpr.BindToRegister(rs, true, false); + gpr.BindToRegister(rd, rd == rt, true); + XOR(32, R(EAX), R(EAX)); + CMP(32, gpr.R(rs), gpr.R(rt)); + SETcc(CC_L, R(EAX)); + MOV(32, gpr.R(rd), R(EAX)); + gpr.UnlockAll(); + } break; case 43: //R(rd) = R(rs) < R(rt); break; //sltu - gpr.Lock(rd, rs, rt); - gpr.BindToRegister(rs, true, true); - gpr.BindToRegister(rd, true, true); - XOR(32, R(EAX), R(EAX)); - CMP(32, gpr.R(rs), gpr.R(rt)); - SETcc(CC_B, R(EAX)); - MOV(32, gpr.R(rd), R(EAX)); - gpr.UnlockAll(); + if (gpr.IsImmediate(rs) && gpr.IsImmediate(rt)) + gpr.SetImmediate32(rd, gpr.GetImmediate32(rs) < gpr.GetImmediate32(rt)); + else + { + gpr.Lock(rd, rs, rt); + gpr.BindToRegister(rs, true, false); + gpr.BindToRegister(rd, rd == rt, true); + XOR(32, R(EAX), R(EAX)); + CMP(32, gpr.R(rs), gpr.R(rt)); + SETcc(CC_B, R(EAX)); + MOV(32, gpr.R(rd), R(EAX)); + gpr.UnlockAll(); + } break; - // case 44: R(rd) = (R(rs) > R(rt)) ? R(rs) : R(rt); break; //max - // CMP(a,b); CMOVLT(a,b) + case 44: //R(rd) = (R(rs) > R(rt)) ? R(rs) : R(rt); break; //max + if (gpr.IsImmediate(rs) && gpr.IsImmediate(rt)) + gpr.SetImmediate32(rd, std::max((s32)gpr.GetImmediate32(rs), (s32)gpr.GetImmediate32(rt))); + else + { + int rsrc = rd == rt ? rs : rt; + gpr.Lock(rd, rs, rt); + gpr.KillImmediate(rsrc, true, false); + gpr.BindToRegister(rd, rd == rs || rd == rt, true); + if (rd != rt && rd != rs) + MOV(32, gpr.R(rd), gpr.R(rs)); + CMP(32, gpr.R(rd), gpr.R(rsrc)); + CMOVcc(32, gpr.RX(rd), gpr.R(rsrc), CC_L); + gpr.UnlockAll(); + } + break; + + case 45: //R(rd) = (R(rs) < R(rt)) ? R(rs) : R(rt); break; //min + if (gpr.IsImmediate(rs) && gpr.IsImmediate(rt)) + gpr.SetImmediate32(rd, std::min((s32)gpr.GetImmediate32(rs), (s32)gpr.GetImmediate32(rt))); + else + { + int rsrc = rd == rt ? rs : rt; + gpr.Lock(rd, rs, rt); + gpr.KillImmediate(rsrc, true, false); + gpr.BindToRegister(rd, rd == rs || rd == rt, true); + if (rd != rt && rd != rs) + MOV(32, gpr.R(rd), gpr.R(rs)); + CMP(32, gpr.R(rd), gpr.R(rsrc)); + CMOVcc(32, gpr.RX(rd), gpr.R(rsrc), CC_G); + gpr.UnlockAll(); + } + break; - // case 45: R(rd) = (R(rs) < R(rt)) ? R(rs) : R(rt); break; //min - // CMP(a,b); CMOVGT(a,b) default: Comp_Generic(op); break; } } + static u32 ShiftType_ImmLogicalLeft(const u32 a, const u32 b) + { + return a << (b & 0x1f); + } - void Jit::CompShiftImm(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg)) + static u32 ShiftType_ImmLogicalRight(const u32 a, const u32 b) + { + return a >> (b & 0x1f); + } + + static u32 ShiftType_ImmArithRight(const u32 a, const u32 b) + { + return ((s32) a) >> (b & 0x1f); + } + + static u32 ShiftType_ImmRotateRight(const u32 a, const u32 b) + { + const s8 sa = b & 0x1f; + return (a >> sa) | (a << (32 - sa)); + } + + void Jit::CompShiftImm(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32)) { int rd = _RD; int rt = _RT; - gpr.Lock(rd, rt); int sa = _SA; + + if (doImm && gpr.IsImmediate(rt)) + { + gpr.SetImmediate32(rd, doImm(gpr.GetImmediate32(rt), sa)); + return; + } + + gpr.Lock(rd, rt); gpr.BindToRegister(rd, rd == rt, true); if (rd != rt) MOV(32, gpr.R(rd), gpr.R(rt)); @@ -295,38 +469,56 @@ namespace MIPSComp } // "over-shifts" work the same as on x86 - only bottom 5 bits are used to get the shift value - void Jit::CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg)) + void Jit::CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32)) { int rd = _RD; int rt = _RT; int rs = _RS; - gpr.FlushLockX(ECX); + + if (doImm && gpr.IsImmediate(rs) && gpr.IsImmediate(rt)) + { + gpr.SetImmediate32(rd, doImm(gpr.GetImmediate32(rt), gpr.GetImmediate32(rs))); + return; + } + gpr.Lock(rd, rt, rs); - gpr.BindToRegister(rd, rd == rt || rd == rs, true); - MOV(32, R(ECX), gpr.R(rs)); // Only ECX can be used for variable shifts. - AND(32, R(ECX), Imm32(0x1f)); - if (rd != rt) - MOV(32, gpr.R(rd), gpr.R(rt)); - (this->*shift)(32, gpr.R(rd), R(ECX)); + if (gpr.IsImmediate(rs)) + { + int sa = gpr.GetImmediate32(rs); + gpr.BindToRegister(rd, rd == rt, true); + if (rd != rt) + MOV(32, gpr.R(rd), gpr.R(rt)); + (this->*shift)(32, gpr.R(rd), Imm8(sa)); + } + else + { + gpr.FlushLockX(ECX); + gpr.BindToRegister(rd, rd == rt || rd == rs, true); + MOV(32, R(ECX), gpr.R(rs)); // Only ECX can be used for variable shifts. + AND(32, R(ECX), Imm32(0x1f)); + if (rd != rt) + MOV(32, gpr.R(rd), gpr.R(rt)); + (this->*shift)(32, gpr.R(rd), R(ECX)); + gpr.UnlockAllX(); + } gpr.UnlockAll(); - gpr.UnlockAllX(); } void Jit::Comp_ShiftType(u32 op) { - CONDITIONAL_DISABLE + CONDITIONAL_DISABLE; int rs = _RS; int fd = _FD; // WARNIGN : ROTR switch (op & 0x3f) { - case 0: CompShiftImm(op, &XEmitter::SHL); break; - case 2: CompShiftImm(op, rs == 1 ? &XEmitter::ROR : &XEmitter::SHR); break; // srl, rotr - case 3: CompShiftImm(op, &XEmitter::SAR); break; // sra + case 0: CompShiftImm(op, &XEmitter::SHL, &ShiftType_ImmLogicalLeft); break; + case 2: CompShiftImm(op, rs == 1 ? &XEmitter::ROR : &XEmitter::SHR, rs == 1 ? &ShiftType_ImmRotateRight : &ShiftType_ImmLogicalRight); break; // srl, rotr + case 3: CompShiftImm(op, &XEmitter::SAR, &ShiftType_ImmArithRight); break; // sra - case 4: CompShiftVar(op, &XEmitter::SHL); break; //sllv - case 6: CompShiftVar(op, fd == 1 ? &XEmitter::ROR : &XEmitter::SHR); break; //srlv - case 7: CompShiftVar(op, &XEmitter::SAR); break; //srav + case 4: CompShiftVar(op, &XEmitter::SHL, &ShiftType_ImmLogicalLeft); break; //sllv + case 6: CompShiftVar(op, fd == 1 ? &XEmitter::ROR : &XEmitter::SHR, fd == 1 ? &ShiftType_ImmRotateRight : &ShiftType_ImmLogicalRight); break; //srlv + case 7: CompShiftVar(op, &XEmitter::SAR, &ShiftType_ImmArithRight); break; //srav default: Comp_Generic(op); @@ -337,8 +529,69 @@ namespace MIPSComp void Jit::Comp_Special3(u32 op) { - // ext, ins - DISABLE; + CONDITIONAL_DISABLE; + int rs = _RS; + int rt = _RT; + int pos = _POS; + + int size = _SIZE + 1; + u32 mask = 0xFFFFFFFFUL >> (32 - size); + + // Don't change $zr. + if (rt == 0) + return; + + switch (op & 0x3f) + { + case 0x0: //ext + if (gpr.IsImmediate(rs)) + { + gpr.SetImmediate32(rt, (gpr.GetImmediate32(rs) >> pos) & mask); + return; + } + + gpr.Lock(rs, rt); + gpr.BindToRegister(rt, rs == rt, true); + if (rs != rt) + MOV(32, gpr.R(rt), gpr.R(rs)); + SHR(32, gpr.R(rt), Imm8(pos)); + AND(32, gpr.R(rt), Imm32(mask)); + gpr.UnlockAll(); + break; + + case 0x4: //ins + { + u32 sourcemask = mask >> pos; + u32 destmask = ~(sourcemask << pos); + if (gpr.IsImmediate(rs)) + { + u32 inserted = (gpr.GetImmediate32(rs) & sourcemask) << pos; + if (gpr.IsImmediate(rt)) + { + gpr.SetImmediate32(rt, (gpr.GetImmediate32(rt) & destmask) | inserted); + return; + } + + gpr.Lock(rs, rt); + gpr.BindToRegister(rt, true, true); + AND(32, gpr.R(rt), Imm32(destmask)); + OR(32, gpr.R(rt), Imm32(inserted)); + gpr.UnlockAll(); + } + else + { + gpr.Lock(rs, rt); + gpr.BindToRegister(rt, true, true); + MOV(32, R(EAX), gpr.R(rs)); + AND(32, R(EAX), Imm32(sourcemask)); + SHL(32, R(EAX), Imm8(pos)); + AND(32, gpr.R(rt), Imm32(destmask)); + OR(32, gpr.R(rt), R(EAX)); + gpr.UnlockAll(); + } + } + break; + } } @@ -350,23 +603,98 @@ namespace MIPSComp switch ((op >> 6) & 31) { case 16: // seb // R(rd) = (u32)(s32)(s8)(u8)R(rt); - gpr.Lock(rd, rt); - gpr.BindToRegister(rd, true, true); - MOV(32, R(EAX), gpr.R(rt)); // work around the byte-register addressing problem - MOVSX(32, 8, gpr.RX(rd), R(EAX)); - gpr.UnlockAll(); - break; + if (gpr.IsImmediate(rt)) + { + gpr.SetImmediate32(rd, (u32)(s32)(s8)(u8)gpr.GetImmediate32(rt)); + break; + } - case 24: // seh gpr.Lock(rd, rt); - // MOVSX doesn't like immediate arguments, for example, so let's force it to a register. - gpr.BindToRegister(rt, true, false); - gpr.BindToRegister(rd, true, true); - MOVSX(32, 16, gpr.RX(rd), gpr.R(rt)); + gpr.BindToRegister(rd, rd == rt, true); +#ifdef _M_IX86 + // work around the byte-register addressing problem + if (!gpr.R(rt).IsSimpleReg(EDX) && !gpr.R(rt).IsSimpleReg(ECX)) + { + MOV(32, R(EAX), gpr.R(rt)); + MOVSX(32, 8, gpr.RX(rd), R(EAX)); + } + else +#endif + { + gpr.KillImmediate(rt, true, false); + MOVSX(32, 8, gpr.RX(rd), gpr.R(rt)); + } gpr.UnlockAll(); break; case 20: //bitrev + if (gpr.IsImmediate(rt)) + { + // http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel + u32 v = gpr.GetImmediate32(rt); + // swap odd and even bits + v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); + // swap consecutive pairs + v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); + // swap nibbles ... + v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); + // swap bytes + v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); + // swap 2-byte long pairs + v = ( v >> 16 ) | ( v << 16); + gpr.SetImmediate32(rd, v); + break; + } + + gpr.Lock(rd, rt); + gpr.BindToRegister(rd, rd == rt, true); + if (rd != rt) + MOV(32, gpr.R(rd), gpr.R(rt)); + + LEA(32, EAX, MScaled(gpr.RX(rd), 2, 0)); + SHR(32, gpr.R(rd), Imm8(1)); + XOR(32, gpr.R(rd), R(EAX)); + AND(32, gpr.R(rd), Imm32(0x55555555)); + XOR(32, gpr.R(rd), R(EAX)); + + LEA(32, EAX, MScaled(gpr.RX(rd), 4, 0)); + SHR(32, gpr.R(rd), Imm8(2)); + XOR(32, gpr.R(rd), R(EAX)); + AND(32, gpr.R(rd), Imm32(0x33333333)); + XOR(32, gpr.R(rd), R(EAX)); + + MOV(32, R(EAX), gpr.R(rd)); + SHL(32, R(EAX), Imm8(4)); + SHR(32, gpr.R(rd), Imm8(4)); + XOR(32, gpr.R(rd), R(EAX)); + AND(32, gpr.R(rd), Imm32(0x0F0F0F0F)); + XOR(32, gpr.R(rd), R(EAX)); + + MOV(32, R(EAX), gpr.R(rd)); + SHL(32, R(EAX), Imm8(8)); + SHR(32, gpr.R(rd), Imm8(8)); + XOR(32, gpr.R(rd), R(EAX)); + AND(32, gpr.R(rd), Imm32(0x00FF00FF)); + XOR(32, gpr.R(rd), R(EAX)); + + ROL(32, gpr.R(rd), Imm8(16)); + + gpr.UnlockAll(); + break; + + case 24: // seh // R(rd) = (u32)(s32)(s16)(u16)R(rt); + if (gpr.IsImmediate(rt)) + { + gpr.SetImmediate32(rd, (u32)(s32)(s16)(u16)gpr.GetImmediate32(rt)); + break; + } + + gpr.Lock(rd, rt); + gpr.BindToRegister(rd, rd == rt, true); + MOVSX(32, 16, gpr.RX(rd), gpr.R(rt)); + gpr.UnlockAll(); + break; + default: Comp_Generic(op); return; @@ -376,6 +704,7 @@ namespace MIPSComp void Jit::Comp_MulDivType(u32 op) { + CONDITIONAL_DISABLE; int rt = _RT; int rs = _RS; int rd = _RD; diff --git a/Core/MIPS/x86/CompBranch.cpp b/Core/MIPS/x86/CompBranch.cpp index 1ac36e0799..d5c76463aa 100644 --- a/Core/MIPS/x86/CompBranch.cpp +++ b/Core/MIPS/x86/CompBranch.cpp @@ -144,7 +144,7 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely) if (rt == 0) { - gpr.KillImmediate(rs, true, true); + gpr.KillImmediate(rs, true, false); CMP(32, gpr.R(rs), Imm32(0)); } else diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 5b56caad72..6a5bb0ac54 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -348,6 +348,8 @@ void Jit::WriteExitDestInEAX() CMP(32, R(EAX), Imm32(PSP_GetUserMemoryEnd())); FixupBranch tooHigh = J_CC(CC_GE); + // Need to set neg flag again if necessary. + SUB(32, M(¤tMIPS->downcount), Imm32(0)); JMP(asm_.dispatcher, true); SetJumpTarget(tooLow); @@ -355,12 +357,18 @@ void Jit::WriteExitDestInEAX() ABI_CallFunctionA(thunks.ProtectFunction((void *) Memory::GetPointer, 1), R(EAX)); CMP(32, R(EAX), Imm32(0)); - J_CC(CC_NE, asm_.dispatcher, true); + FixupBranch skip = J_CC(CC_NE); // TODO: "Ignore" this so other threads can continue? if (g_Config.bIgnoreBadMemAccess) - MOV(32, M((void*)&coreState), Imm32(CORE_ERROR)); + ABI_CallFunctionA(thunks.ProtectFunction((void *) Core_UpdateState, 1), Imm32(CORE_ERROR)); + + SUB(32, M(¤tMIPS->downcount), Imm32(0)); JMP(asm_.dispatcherCheckCoreState, true); + SetJumpTarget(skip); + + SUB(32, M(¤tMIPS->downcount), Imm32(0)); + J_CC(CC_NE, asm_.dispatcher, true); } else JMP(asm_.dispatcher, true); @@ -378,7 +386,7 @@ bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset) { FlushAll(); MOV(32, M(&mips_->pc), Imm32(js.compilerPC)); - CALL((void *)&JitBreakpoint); + ABI_CallFunction((void *)&JitBreakpoint); WriteDowncount(downcountOffset); JMP(asm_.dispatcherCheckCoreState, true); diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index cf86376393..f5bf0bdf53 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -171,6 +171,7 @@ public: void Comp_Break(u32 op); void Comp_IType(u32 op); + void Comp_RType2(u32 op); void Comp_RType3(u32 op); void Comp_ShiftType(u32 op); void Comp_Allegrex(u32 op); @@ -185,10 +186,13 @@ public: void Comp_SV(u32 op); void Comp_SVQ(u32 op); void Comp_VPFX(u32 op); + void Comp_VVectorInit(u32 op); void Comp_VDot(u32 op); void Comp_VecDo3(u32 op); + void Comp_VV2Op(u32 op); void Comp_Mftv(u32 op); void Comp_Vmtvc(u32 op); + void Comp_Vmmov(u32 op); void Comp_DoNothing(u32 op); @@ -238,8 +242,8 @@ private: // Utilities to reduce duplicated code void CompImmLogic(u32 op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &)); void CompTriArith(u32 op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &), u32 (*doImm)(const u32, const u32)); - void CompShiftImm(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg)); - void CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg)); + void CompShiftImm(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32)); + void CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32)); void CompITypeMemRead(u32 op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), void *safeFunc); void CompITypeMemWrite(u32 op, u32 bits, void *safeFunc); diff --git a/Core/MIPS/x86/RegCache.cpp b/Core/MIPS/x86/RegCache.cpp index cb863533ef..7c36b0f37e 100644 --- a/Core/MIPS/x86/RegCache.cpp +++ b/Core/MIPS/x86/RegCache.cpp @@ -38,7 +38,7 @@ static const int allocationOrder[] = #endif }; -GPRRegCache::GPRRegCache() : emit(0), mips(0) { +GPRRegCache::GPRRegCache() : mips(0), emit(0) { memset(regs, 0, sizeof(regs)); memset(xregs, 0, sizeof(xregs)); } diff --git a/Core/MIPS/x86/RegCacheFPU.cpp b/Core/MIPS/x86/RegCacheFPU.cpp index 9256a6d8fa..0973863d63 100644 --- a/Core/MIPS/x86/RegCacheFPU.cpp +++ b/Core/MIPS/x86/RegCacheFPU.cpp @@ -23,7 +23,7 @@ u32 FPURegCache::tempValues[NUM_TEMPS]; -FPURegCache::FPURegCache() : emit(0), mips(0) { +FPURegCache::FPURegCache() : mips(0), emit(0) { memset(regs, 0, sizeof(regs)); memset(xregs, 0, sizeof(xregs)); vregs = regs + 32; diff --git a/Core/MemMapFunctions.cpp b/Core/MemMapFunctions.cpp index d174cdb7e1..dcc895d212 100644 --- a/Core/MemMapFunctions.cpp +++ b/Core/MemMapFunctions.cpp @@ -56,6 +56,10 @@ u8 *GetPointer(const u32 address) else { ERROR_LOG(MEMMAP, "Unknown GetPointer %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); + if (!g_Config.bIgnoreBadMemAccess) { + Core_EnableStepping(true); + host->SetDebugMode(true); + } return 0; } } diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index e73ec60564..e1beb4cade 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -89,6 +89,10 @@ bool Load_PSP_ISO(const char *filename, std::string *error_string) if (pspFileSystem.GetFileInfo("disc0:/PSP_GAME/SYSDIR/EBOOT.OLD").exists) { bootpath = "disc0:/PSP_GAME/SYSDIR/EBOOT.OLD"; } + // bypass another patchers + if (pspFileSystem.GetFileInfo("disc0:/PSP_GAME/SYSDIR/EBOOT.DAT").exists) { + bootpath = "disc0:/PSP_GAME/SYSDIR/EBOOT.DAT"; + } bool hasEncrypted = false; u32 fd; if ((fd = pspFileSystem.OpenFile(bootpath, FILEACCESS_READ)) != 0) diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 8a450081c3..a320c4e70b 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -90,7 +90,7 @@ namespace SaveState // Don't actually run it until next CoreTiming::Advance(). // It's possible there might be a duplicate but it won't hurt us. - if (Core_IsStepping() && __KernelIsRunning()) + if (Core_IsInactive() && __KernelIsRunning()) { // Warning: this may run on a different thread. Process(0, 0); diff --git a/Core/Util/BlockAllocator.cpp b/Core/Util/BlockAllocator.cpp index 227d28f1ab..abd5bf9cf1 100644 --- a/Core/Util/BlockAllocator.cpp +++ b/Core/Util/BlockAllocator.cpp @@ -1,3 +1,20 @@ +// Copyright (c) 2012- 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/. + #include "Log.h" #include "BlockAllocator.h" #include "ChunkFile.h" diff --git a/Core/Util/BlockAllocator.h b/Core/Util/BlockAllocator.h index 98cb3e1cd2..b385fedcb9 100644 --- a/Core/Util/BlockAllocator.h +++ b/Core/Util/BlockAllocator.h @@ -1,3 +1,19 @@ +// Copyright (c) 2012- 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 @@ -9,8 +25,7 @@ class PointerWrap; -// Generic allocator thingy -// Allocates blocks from a range +// Generic allocator thingy. Allocates blocks from a range. class BlockAllocator { diff --git a/Core/Util/Pool.h b/Core/Util/Pool.h deleted file mode 100644 index dee8633c10..0000000000 --- a/Core/Util/Pool.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "../../Globals.h" - -// pool allocator -template -class Pool -{ - T pool[size]; - int count; -public: - Pool() - { - Reset(); - } - void Reset() - { - count=0; - } - T* Alloc() - { - _dbg_assert_msg_(CPU,count> 8) & 1; - bool alphaMask = (data >> 9) & 1; - bool updateZ = (data >> 10) & 1; - glstate.colorMask.set(colMask, colMask, colMask, alphaMask); - glstate.depthWrite.set(updateZ ? GL_TRUE : GL_FALSE); -} - -static void LeaveClearMode() { - // We have to reset the following state as per the state of the command registers: - // Back face culling - // Texture map enable (meh) - // Fogging - // Antialiasing - // Alpha test - glstate.colorMask.set(1,1,1,1); - glstate.depthWrite.set(!(gstate.zmsk & 1) ? GL_TRUE : GL_FALSE); - // dirtyshader? -} - void GLES_GPU::PreExecuteOp(u32 op, u32 diff) { u32 cmd = op >> 24; if (flushBeforeCommand_[cmd] == 1 || (diff && flushBeforeCommand_[cmd] == 2)) @@ -542,6 +524,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { break; case GE_CMD_CULLFACEENABLE: + case GE_CMD_CULL: break; case GE_CMD_TEXTUREMAPENABLE: @@ -642,6 +625,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_CLUTADDR: case GE_CMD_CLUTADDRUPPER: case GE_CMD_LOADCLUT: + case GE_CMD_CLUTFORMAT: gstate_c.textureChanged = true; // This could be used to "dirty" textures with clut. break; @@ -650,10 +634,6 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_TEXSHADELS: break; - case GE_CMD_CLUTFORMAT: - gstate_c.textureChanged = true; - break; - case GE_CMD_TRANSFERSRC: case GE_CMD_TRANSFERSRCW: case GE_CMD_TRANSFERDST: @@ -807,9 +787,6 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_LIGHTENABLE3: break; - case GE_CMD_CULL: - break; - case GE_CMD_SHADEMODE: break; @@ -826,14 +803,8 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { // CLEARING ////////////////////////////////////////////////////////////////// case GE_CMD_CLEARMODE: - // If it becomes a performance problem, check diff&1 - if (data & 1) - EnterClearMode(data); - else - LeaveClearMode(); break; - ////////////////////////////////////////////////////////////////// // ALPHA BLENDING ////////////////////////////////////////////////////////////////// @@ -845,7 +816,12 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_ALPHATESTENABLE: case GE_CMD_COLORTESTENABLE: - // This is done in the shader. + // They are done in the fragment shader. + break; + + case GE_CMD_COLORTEST: + case GE_CMD_COLORTESTMASK: + shaderManager_->DirtyUniform(DIRTY_COLORMASK); break; case GE_CMD_COLORREF: @@ -992,8 +968,8 @@ void GLES_GPU::UpdateStats() { gpuStats.numVertexShaders = shaderManager_->NumVertexShaders(); gpuStats.numFragmentShaders = shaderManager_->NumFragmentShaders(); gpuStats.numShaders = shaderManager_->NumPrograms(); - gpuStats.numTextures = textureCache_.NumLoadedTextures(); - gpuStats.numFBOs = framebufferManager_.NumVFBs(); + gpuStats.numTextures = (int)textureCache_.NumLoadedTextures(); + gpuStats.numFBOs = (int)framebufferManager_.NumVFBs(); } void GLES_GPU::DoBlockTransfer() { diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index b0e8fc6a7c..3394acc5e2 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -94,6 +94,7 @@ void GenerateFragmentShader(char *buffer) WRITE(p, "uniform sampler2D tex;\n"); if (enableAlphaTest || enableColorTest) { WRITE(p, "uniform vec4 u_alphacolorref;\n"); + WRITE(p, "uniform vec4 u_colormask;\n"); } if (gstate.textureMapEnable & 1) { WRITE(p, "uniform vec3 u_texenv;\n"); @@ -189,9 +190,8 @@ void GenerateFragmentShader(char *buffer) const char *colorTestFuncs[] = { "#", "#", " == ", " != " }; // never/always don't make sense} int colorTestMask = gstate.colormask; if (colorTestFuncs[colorTestFunc][0] != '#') - WRITE(p, "if (!(v.rgb %s u_alphacolorref.rgb)) discard;\n", colorTestFuncs[colorTestFunc]); - }*/ - + WRITE(p, "if (!(v.rgb %s (u_alphacolorref.rgb & u_colormask.rgb)) discard;\n", colorTestFuncs[colorTestFunc]); + }*/ if (enableFog) { WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n"); WRITE(p, " gl_FragColor = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n"); diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 1a994f8c01..8b4f9d5a09 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -125,7 +125,9 @@ FramebufferManager::FramebufferManager() : // And an initial clear. We don't clear per frame as the games are supposed to handle that // by themselves. - glClearColor(0, 0, 0, 0); + glstate.depthWrite.set(GL_TRUE); + glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); convBuf = new u8[480 * 272 * 4]; @@ -235,7 +237,7 @@ void FramebufferManager::DrawActiveTexture(float x, float y, float w, float h, b glsl_unbind(); } -FramebufferManager::VirtualFramebuffer *FramebufferManager::GetDisplayFBO() { +VirtualFramebuffer *FramebufferManager::GetDisplayFBO() { for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) { VirtualFramebuffer *v = *iter; if (MaskedEqual(v->fb_address, displayFramebufPtr_) && v->format == displayFormat_) { @@ -325,6 +327,7 @@ void FramebufferManager::SetRenderFrameBuffer() { vfb->renderWidth = (u16)(drawing_width * renderWidthFactor); vfb->renderHeight = (u16)(drawing_height * renderHeightFactor); vfb->format = fmt; + vfb->usageFlags = FB_USAGE_RENDERTARGET; switch (fmt) { case GE_FORMAT_4444: vfb->colorDepth = FBO_4444; break; @@ -333,12 +336,16 @@ void FramebufferManager::SetRenderFrameBuffer() { case GE_FORMAT_8888: vfb->colorDepth = FBO_8888; break; default: vfb->colorDepth = FBO_8888; break; } + + if (g_Config.bTrueColor) + vfb->colorDepth = FBO_8888; + //#ifdef ANDROID // vfb->colorDepth = FBO_8888; //#endif vfb->fbo = fbo_create(vfb->renderWidth, vfb->renderHeight, 1, true, vfb->colorDepth); - textureCache_->NotifyFramebuffer(vfb->fb_address, vfb->fbo); + textureCache_->NotifyFramebuffer(vfb->fb_address, vfb); vfb->last_frame_used = gpuStats.numFrames; vfbs_.push_back(vfb); @@ -347,6 +354,9 @@ void FramebufferManager::SetRenderFrameBuffer() { glEnable(GL_DITHER); glstate.viewport.set(0, 0, vfb->renderWidth, vfb->renderHeight); currentRenderVfb_ = vfb; + glstate.depthWrite.set(GL_TRUE); + glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); INFO_LOG(HLE, "Creating FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format); return; @@ -363,15 +373,22 @@ void FramebufferManager::SetRenderFrameBuffer() { vfb->last_frame_used = gpuStats.numFrames; fbo_bind_as_render_target(vfb->fbo); + + textureCache_->NotifyFramebuffer(vfb->fb_address, vfb); + #ifdef USING_GLES2 // Some tiled mobile GPUs benefit IMMENSELY from clearing an FBO before rendering // to it. This broke stuff before, so now it only clears on the first use of an // FBO in a frame. This means that some games won't be able to avoid the on-some-GPUs // performance-crushing framebuffer reloads from RAM, but we'll have to live with that. if (vfb->last_frame_used != gpuStats.numFrames) + { + glstate.depthWrite.set(GL_TRUE); + glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } #endif - textureCache_->NotifyFramebuffer(vfb->fb_address, vfb->fbo); glstate.viewport.set(0, 0, vfb->renderWidth, vfb->renderHeight); currentRenderVfb_ = vfb; } @@ -385,6 +402,8 @@ void FramebufferManager::CopyDisplayToOutput() { if (!vfb) { DEBUG_LOG(HLE, "Found no FBO! displayFBPtr = %08x", displayFramebufPtr_); // No framebuffer to display! Clear to black. + glstate.depthWrite.set(GL_TRUE); + glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); return; @@ -403,10 +422,13 @@ void FramebufferManager::CopyDisplayToOutput() { glstate.cullFace.disable(); glstate.depthTest.disable(); glstate.scissorTest.disable(); - + glstate.stencilTest.disable(); + fbo_bind_color_as_texture(vfb->fbo, 0); if (resized_) { + glstate.depthWrite.set(GL_TRUE); + glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } @@ -431,6 +453,8 @@ void FramebufferManager::BeginFrame() { glstate.cullFace.disable(); glstate.depthTest.disable(); glstate.blend.disable(); + glstate.scissorTest.disable(); + glstate.stencilTest.disable(); DrawPixels(pspframebuf, displayFormat_, displayStride_); // TODO: restore state? } @@ -477,7 +501,7 @@ void FramebufferManager::DecimateFBOs() { } if ((*iter)->last_frame_used + FBO_OLD_AGE < gpuStats.numFrames) { INFO_LOG(HLE, "Destroying FBO for %08x (%i x %i x %i)", vfb->fb_address, vfb->width, vfb->height, vfb->format) - textureCache_->NotifyFramebufferDestroyed(vfb->fb_address, vfb->fbo); + textureCache_->NotifyFramebufferDestroyed(vfb->fb_address, vfb); fbo_destroy(vfb->fbo); delete vfb; vfbs_.erase(iter++); @@ -490,7 +514,7 @@ void FramebufferManager::DecimateFBOs() { void FramebufferManager::DestroyAllFBOs() { for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) { VirtualFramebuffer *vfb = *iter; - textureCache_->NotifyFramebufferDestroyed(vfb->fb_address, vfb->fbo); + textureCache_->NotifyFramebufferDestroyed(vfb->fb_address, vfb); fbo_destroy(vfb->fbo); delete vfb; } diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index c5a86426c9..c40fcc7c24 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -38,6 +38,34 @@ enum PspDisplayPixelFormat { PSP_DISPLAY_PIXEL_FORMAT_8888 = 3, }; +enum { + FB_USAGE_RENDERTARGET = 1, + FB_USAGE_TEXTURE = 2, +}; + + +struct VirtualFramebuffer { + int last_frame_used; + + u32 fb_address; + u32 z_address; + int fb_stride; + int z_stride; + + // There's also a top left of the drawing region, but meh... + u16 width; + u16 height; + u16 renderWidth; + u16 renderHeight; + + u16 usageFlags; + + int format; // virtual, right now they are all RGBA8888 + FBOColorDepth colorDepth; + FBO *fbo; +}; + + class FramebufferManager { public: FramebufferManager(); @@ -47,25 +75,6 @@ public: textureCache_ = tc; } - struct VirtualFramebuffer { - int last_frame_used; - - u32 fb_address; - u32 z_address; - int fb_stride; - int z_stride; - - // There's also a top left of the drawing region, but meh... - u16 width; - u16 height; - u16 renderWidth; - u16 renderHeight; - - int format; // virtual, right now they are all RGBA8888 - FBOColorDepth colorDepth; - FBO *fbo; - }; - void DrawPixels(const u8 *framebuf, int pixelFormat, int linesize); void DrawActiveTexture(float x, float y, float w, float h, bool flip = false); diff --git a/GPU/GLES/ShaderManager.cpp b/GPU/GLES/ShaderManager.cpp index 6a985c8446..ac789f5726 100644 --- a/GPU/GLES/ShaderManager.cpp +++ b/GPU/GLES/ShaderManager.cpp @@ -89,6 +89,7 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs) u_fogcolor = glGetUniformLocation(program, "u_fogcolor"); u_fogcoef = glGetUniformLocation(program, "u_fogcoef"); u_alphacolorref = glGetUniformLocation(program, "u_alphacolorref"); + u_colormask = glGetUniformLocation(program, "u_colormask"); // Transform u_view = glGetUniformLocation(program, "u_view"); @@ -243,7 +244,7 @@ void LinkedShader::updateUniforms() { if (u_proj_through != -1 && (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX)) { Matrix4x4 proj_through; - proj_through.setOrtho(0.0f, 480, 272, 0, -1, 0); // TODO: Store this somewhere instead of regenerating! And not in each LinkedShader object! + proj_through.setOrtho(0.0f, 480, 272, 0, 0, 1); glUniformMatrix4fv(u_proj_through, 1, GL_FALSE, proj_through.getReadPtr()); } if (u_texenv != -1 && (dirtyUniforms & DIRTY_TEXENV)) { @@ -252,6 +253,9 @@ void LinkedShader::updateUniforms() { if (u_alphacolorref != -1 && (dirtyUniforms & DIRTY_ALPHACOLORREF)) { SetColorUniform3Alpha(u_alphacolorref, gstate.colorref, (gstate.alphatest >> 8) & 0xFF); } + if (u_colormask != -1 && (dirtyUniforms & DIRTY_COLORMASK)) { + SetColorUniform3(u_colormask, gstate.colormask); + } if (u_fogcolor != -1 && (dirtyUniforms & DIRTY_FOGCOLOR)) { SetColorUniform3(u_fogcolor, gstate.fogcolor); } diff --git a/GPU/GLES/ShaderManager.h b/GPU/GLES/ShaderManager.h index c83ad3a66a..38bb73e805 100644 --- a/GPU/GLES/ShaderManager.h +++ b/GPU/GLES/ShaderManager.h @@ -58,6 +58,7 @@ public: // Fragment processing inputs int u_alphacolorref; + int u_colormask; int u_fogcolor; int u_fogcoef; @@ -88,7 +89,7 @@ enum DIRTY_TEXENV = (1 << 4), DIRTY_ALPHACOLORREF = (1 << 5), DIRTY_COLORREF = (1 << 6), - + DIRTY_COLORMASK = (1 << 7), DIRTY_LIGHT0 = (1 << 8), DIRTY_LIGHT1 = (1 << 9), DIRTY_LIGHT2 = (1 << 10), diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 9d9deca257..1b377de734 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -84,22 +84,19 @@ void TransformDrawEngine::ApplyDrawState(int prim) { gstate_c.textureChanged = false; } - // TODO: The top bit of the alpha channel should be written to the stencil bit somehow. This appears to require very expensive multipass rendering :( Alternatively, one could do a - // single fullscreen pass that converts alpha to stencil (or 2 passes, to set both the 0 and 1 values) very easily. - // Set cull bool wantCull = !gstate.isModeClear() && !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); glstate.cullFace.set(wantCull); + if (wantCull) + glstate.cullFaceMode.set(cullingMode[gstate.getCullMode()]); - if (wantCull) { - u8 cullMode = gstate.getCullMode(); - glstate.cullFaceMode.set(cullingMode[cullMode]); - } + // TODO: The top bit of the alpha channel should be written to the stencil bit somehow. This appears to require very expensive multipass rendering :( Alternatively, one could do a + // single fullscreen pass that converts alpha to stencil (or 2 passes, to set both the 0 and 1 values) very easily. // Set blend - bool wantBlend = !gstate.isModeClear() && (gstate.alphaBlendEnable & 1); + bool wantBlend = !gstate.isModeClear() && gstate.isAlphaBlendEnabled(); glstate.blend.set(wantBlend); - if(wantBlend) { + if (wantBlend) { // This can't be done exactly as there are several PSP blend modes that are impossible to do on OpenGL ES 2.0, and some even on regular OpenGL for desktop. // HOWEVER - we should be able to approximate the 2x modes in the shader, although they will clip wrongly. @@ -168,46 +165,54 @@ void TransformDrawEngine::ApplyDrawState(int prim) { } } - bool wantDepthTest = gstate.isModeClear() || gstate.isDepthTestEnabled(); - glstate.depthTest.set(wantDepthTest); - if(wantDepthTest) { - // Force GL_ALWAYS if mode clear - without depth test, no depth write. - int depthTestFunc = gstate.isModeClear() ? 1 : gstate.getDepthTestFunc(); - glstate.depthFunc.set(ztests[depthTestFunc]); - } + // Set Dither + glstate.dither.set(gstate.isDitherEnabled()); - // PSP color/alpha mask is per bit but we can only support per byte. - // But let's do that, at least. And let's try a threshold. - if (!gstate.isModeClear()) { + // Set ColorMask/Stencil/Depth + if (gstate.isModeClear()) { + bool colorMask = (gstate.clearmode >> 8) & 1; + bool alphaMask = (gstate.clearmode >> 9) & 1; + bool depthMask = ((gstate.clearmode >> 10) & 1) || !(gstate.zmsk & 1); + + glstate.colorMask.set(colorMask, colorMask, colorMask, alphaMask); + + glstate.stencilTest.enable(); + glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glstate.stencilFunc.set(GL_ALWAYS, 0, 0xFF); + + glstate.depthTest.enable(); + glstate.depthFunc.set(GL_ALWAYS); + glstate.depthWrite.set(depthMask ? GL_TRUE : GL_FALSE); + + } else { + if (gstate.isDepthTestEnabled()) { + glstate.depthTest.enable(); + glstate.depthFunc.set(ztests[gstate.getDepthTestFunc()]); + glstate.depthWrite.set(gstate.isDepthWriteEnabled() ? GL_TRUE : GL_FALSE); + } else { + glstate.depthTest.disable(); + } + + // PSP color/alpha mask is per bit but we can only support per byte. + // But let's do that, at least. And let's try a threshold. bool rmask = (gstate.pmskc & 0xFF) < 128; bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128; bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128; bool amask = (gstate.pmska & 0xFF) < 128; glstate.colorMask.set(rmask, gmask, bmask, amask); + + if (gstate.isStencilTestEnabled()) { + glstate.stencilTest.enable(); + glstate.stencilFunc.set(ztests[gstate.stenciltest & 0x7], // func + (gstate.stenciltest >> 8) & 0xFF, // ref + (gstate.stenciltest >> 16) & 0xFF); // mask + glstate.stencilOp.set(stencilOps[gstate.stencilop & 0x7], // stencil fail + stencilOps[(gstate.stencilop >> 8) & 0x7], // depth fail + stencilOps[(gstate.stencilop >> 16) & 0x7]); // depth pass + } else { + glstate.stencilTest.disable(); + } } - - // Stencil test - if (!gstate.isModeClear() && gstate.isStencilTestEnabled()) { - glstate.stencilTest.enable(); - glstate.stencilFunc.set(ztests[gstate.stenciltest & 0x7], // func - (gstate.stenciltest >> 8) & 0xFF, // ref - (gstate.stenciltest >> 16) & 0xFF); // mask - glstate.stencilOp.set(stencilOps[gstate.stencilop & 0x7], // stencil fail - stencilOps[(gstate.stencilop >> 8) & 0x7], // depth fail - stencilOps[(gstate.stencilop >> 16) & 0x7]); - } else if (gstate.isModeClear()) { - glstate.stencilTest.enable(); - glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE); - glstate.stencilFunc.set(GL_ALWAYS, 0, 0xFF); - } else { - glstate.stencilTest.disable(); - } - - // Dither - glstate.dither.set(gstate.ditherEnable & 1); - - bool wantDepthWrite = gstate.isModeClear() || gstate.isDepthWriteEnabled(); - glstate.depthWrite.set(wantDepthWrite ? GL_TRUE : GL_FALSE); } void TransformDrawEngine::UpdateViewportAndProjection() { @@ -236,7 +241,7 @@ void TransformDrawEngine::UpdateViewportAndProjection() { if (throughmode) { // No viewport transform here. Let's experiment with using region. glstate.viewport.set((0 + regionX1) * renderWidthFactor, (0 - regionY1) * renderHeightFactor, (regionX2 - regionX1) * renderWidthFactor, (regionY2 - regionY1) * renderHeightFactor); - glstate.depthRange.set(1.0, 0.0); + glstate.depthRange.set(0.0f, 1.0f); } else { // These we can turn into a glViewport call, offset by offsetX and offsetY. Math after. float vpXa = getFloat24(gstate.viewportx1); @@ -269,8 +274,8 @@ void TransformDrawEngine::UpdateViewportAndProjection() { // Sadly, as glViewport takes integers, we will not be able to support sub pixel offsets this way. But meh. // shaderManager_->DirtyUniform(DIRTY_PROJMATRIX); - float zScale = getFloat24(gstate.viewportz1) / 65535.f; - float zOff = getFloat24(gstate.viewportz2) / 65535.f; + float zScale = getFloat24(gstate.viewportz1) / 65535.0f; + float zOff = getFloat24(gstate.viewportz2) / 65535.0f; float depthRangeMin = zOff - zScale; float depthRangeMax = zOff + zScale; glstate.depthRange.set(depthRangeMin, depthRangeMax); diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 96ccc7768b..cd1a4b6b52 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -18,11 +18,12 @@ #include #include -#include "../../Core/MemMap.h" -#include "../ge_constants.h" -#include "../GPUState.h" -#include "TextureCache.h" -#include "../Core/Config.h" +#include "Core/MemMap.h" +#include "GPU/ge_constants.h" +#include "GPU/GPUState.h" +#include "GPU/GLES/TextureCache.h" +#include "GPU/GLES/Framebuffer.h" +#include "Core/Config.h" // If a texture hasn't been seen for this many frames, get rid of it. #define TEXTURE_KILL_AGE 200 @@ -79,7 +80,7 @@ void TextureCache::Clear(bool delete_them) { // Removes old textures. void TextureCache::Decimate() { glBindTexture(GL_TEXTURE_2D, 0); - for (TexCache::iterator iter = cache.begin(), end = cache.end(); iter != end; ) { + for (TexCache::iterator iter = cache.begin(); iter != cache.end(); ) { if (iter->second.lastFrame + TEXTURE_KILL_AGE < gpuStats.numFrames) { glDeleteTextures(1, &iter->second.texture); cache.erase(iter++); @@ -131,21 +132,21 @@ TextureCache::TexCacheEntry *TextureCache::GetEntryAt(u32 texaddr) { return 0; } -void TextureCache::NotifyFramebuffer(u32 address, FBO *fbo) { +void TextureCache::NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer) { // Must be in VRAM so | 0x04000000 it is. TexCacheEntry *entry = GetEntryAt(address | 0x04000000); if (entry) { DEBUG_LOG(HLE, "Render to texture detected at %08x!", address); - if (!entry->fbo) - entry->fbo = fbo; + if (!entry->framebuffer) + entry->framebuffer= framebuffer; // TODO: Delete the original non-fbo texture too. } } -void TextureCache::NotifyFramebufferDestroyed(u32 address, FBO *fbo) { +void TextureCache::NotifyFramebufferDestroyed(u32 address, VirtualFramebuffer *fbo) { TexCacheEntry *entry = GetEntryAt(address | 0x04000000); - if (entry && entry->fbo) { - entry->fbo = 0; + if (entry && entry->framebuffer) { + entry->framebuffer = 0; } } @@ -676,7 +677,6 @@ void TextureCache::SetTexture() { } bool hasClut = formatUsesClut[format]; - const u8 *texptr = Memory::GetPointer(texaddr); u64 cachekey = texaddr; u32 clutformat, clutaddr; @@ -699,19 +699,15 @@ void TextureCache::SetTexture() { if (iter != cache.end()) { entry = &iter->second; // Check for FBO - slow! - if (entry->fbo) { - int w = 1 << (gstate.texsize[0] & 0xf); - int h = 1 << ((gstate.texsize[0] >> 8) & 0xf); - - fbo_bind_color_as_texture(entry->fbo, 0); + if (entry->framebuffer) { + fbo_bind_color_as_texture(entry->framebuffer->fbo, 0); UpdateSamplingParams(*entry, false); - int fbow, fboh; - fbo_get_dimensions(entry->fbo, &fbow, &fboh); - // This isn't right. - gstate_c.curTextureWidth = w; //w; //RoundUpToPowerOf2(fbow); - gstate_c.curTextureHeight = h; // RoundUpToPowerOf2(fboh); + gstate_c.curTextureWidth = entry->framebuffer->width; + gstate_c.curTextureHeight = entry->framebuffer->height; + int h = 1 << ((gstate.texsize[0] >> 8) & 0xf); + gstate_c.actualTextureHeight = h; gstate_c.flipTexture = true; entry->lastFrame = gpuStats.numFrames; return; @@ -807,7 +803,7 @@ void TextureCache::SetTexture() { entry->hash = texhash; entry->format = format; entry->lastFrame = gpuStats.numFrames; - entry->fbo = 0; + entry->framebuffer = 0; entry->maxLevel = maxLevel; entry->lodBias = 0.0f; @@ -1153,14 +1149,8 @@ bool TextureCache::DecodeTexture(u8* output, GPUgstate state) } u32 clutformat = gstate.clutformat & 3; - u32 clutaddr = GetClutAddr(clutformat == GE_CMODE_32BIT_ABGR8888 ? 4 : 2); const u8 *texptr = Memory::GetPointer(texaddr); - u32 texhash = texptr ? MiniHash((const u32*)texptr) : 0; - - u64 cachekey = texaddr ^ texhash; - if (formatUsesClut[format]) - cachekey |= (u64) clutaddr << 32; int bufw = gstate.texbufwidth[0] & 0x3ff; diff --git a/GPU/GLES/TextureCache.h b/GPU/GLES/TextureCache.h index 65c64b4eb3..62008ec0dd 100644 --- a/GPU/GLES/TextureCache.h +++ b/GPU/GLES/TextureCache.h @@ -21,6 +21,8 @@ #include "gfx_es2/fbo.h" #include "GPU/GPUState.h" +struct VirtualFramebuffer; + class TextureCache { public: @@ -36,16 +38,16 @@ public: // FramebufferManager keeps TextureCache updated about what regions of memory // are being rendered to. This is barebones so far. - void NotifyFramebuffer(u32 address, FBO *fbo); - void NotifyFramebufferDestroyed(u32 address, FBO *fbo); + void NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer); + void NotifyFramebufferDestroyed(u32 address, VirtualFramebuffer *framebuffer); size_t NumLoadedTextures() const { return cache.size(); } bool DecodeTexture(u8 *output, GPUgstate state); + private: - struct TexCacheEntry { // After marking STATUS_UNRELIABLE, if it stays the same this many frames we'll trust it again. const static int FRAMES_REGAIN_TRUST = 1000; @@ -60,7 +62,7 @@ private: int status; u32 addr; u32 hash; - FBO *fbo; // if null, not sourced from an FBO. + VirtualFramebuffer *framebuffer; // if null, not sourced from an FBO. u32 sizeInRAM; int lastFrame; int numFrames; diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index 72b2066c57..ee9687fd05 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -640,7 +640,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw( transformed[index].fog = fogCoef; memcpy(&transformed[index].u, uv, 2 * sizeof(float)); if (gstate_c.flipTexture) - transformed[index].v = 1.0f - transformed[index].v * 2.0f; + transformed[index].v = 1.0f - transformed[index].v; //(float)gstate_c.actualTextureHeight / gstate_c.curTextureHeight - transformed[index].v; for (int i = 0; i < 4; i++) { transformed[index].color0[i] = c0[i] * 255.0f; } @@ -660,10 +660,6 @@ void TransformDrawEngine::SoftwareTransformAndDraw( numTrans = vertexCount; drawIndexed = true; } else { - // Temporary storage for RECTANGLES emulation - float v2[3] = {0}; - float uv2[2] = {0}; - numTrans = 0; drawBuffer = transformedExpanded; TransformedVertex *trans = &transformedExpanded[0]; @@ -930,7 +926,7 @@ void TransformDrawEngine::Flush() { gpuStats.numFlushes++; - gpuStats.numTrackedVertexArrays = vai_.size(); + gpuStats.numTrackedVertexArrays = (int)vai_.size(); // TODO: This should not be done on every drawcall, we should collect vertex data // until critical state changes. That's when we draw (flush). diff --git a/GPU/GLES/VertexDecoder.h b/GPU/GLES/VertexDecoder.h index 243983c5ac..496e29b24c 100644 --- a/GPU/GLES/VertexDecoder.h +++ b/GPU/GLES/VertexDecoder.h @@ -191,20 +191,43 @@ public: void ReadPos(float pos[3]) { switch (decFmt_.posfmt) { case DEC_FLOAT_3: - memcpy(pos, data_ + decFmt_.posoff, 12); + { + const float *f = (const float *)(data_ + decFmt_.posoff); + memcpy(pos, f, 12); + if (isThrough()) { + // Integer value passed in a float. Wraps and all, required for Monster Hunter. + pos[2] = (float)((u16)(s32)pos[2]) * (1.0f / 65535.0f); + } + } break; case DEC_S16_3: { - const s16 *p = (s16 *)(data_ + decFmt_.posoff); - for (int i = 0; i < 3; i++) - pos[i] = p[i] * (1.f / 32768.f); + // X and Y are signed 16 bit, Z is unsigned 16 bit + const s16 *s = (const s16 *)(data_ + decFmt_.posoff); + const u16 *u = (const u16 *)(data_ + decFmt_.posoff); + if (isThrough()) { + for (int i = 0; i < 2; i++) + pos[i] = s[i]; + pos[2] = u[2] * (1.0f / 65535.0f); + } else { + for (int i = 0; i < 3; i++) + pos[i] = s[i] * (1.f / 32767.f); + } } break; case DEC_S8_3: { - const s8 *p = (s8 *)(data_ + decFmt_.posoff); - for (int i = 0; i < 3; i++) - pos[i] = p[i] * (1.f / 128.f); + // X and Y are signed 8 bit, Z is unsigned 8 bit + const s8 *b = (const s8 *)(data_ + decFmt_.posoff); + const u8 *u = (const u8 *)(data_ + decFmt_.posoff); + if (isThrough()) { + for (int i = 0; i < 2; i++) + pos[i] = b[i]; + pos[2] = u[2] / 255.0f; + } else { + for (int i = 0; i < 3; i++) + pos[i] = b[i] * (1.f / 127.f); + } } break; default: @@ -216,20 +239,25 @@ public: void ReadNrm(float nrm[3]) { switch (decFmt_.nrmfmt) { case DEC_FLOAT_3: - memcpy(nrm, data_ + decFmt_.nrmoff, 12); + //memcpy(nrm, data_ + decFmt_.nrmoff, 12); + { + const float *f = (const float *)(data_ + decFmt_.nrmoff); + for (int i = 0; i < 3; i++) + nrm[i] = f[i] ; + } break; case DEC_S16_3: { - const s16 *p = (s16 *)(data_ + decFmt_.nrmoff); + const s16 *s = (const s16 *)(data_ + decFmt_.nrmoff); for (int i = 0; i < 3; i++) - nrm[i] = p[i] * (1.f / 32768.f); + nrm[i] = s[i] * (1.f / 32767.f); } break; case DEC_S8_3: { - const s8 *p = (s8 *)(data_ + decFmt_.nrmoff); + const s8 *b = (const s8 *)(data_ + decFmt_.nrmoff); for (int i = 0; i < 3; i++) - nrm[i] = p[i] * (1.f / 128.0f); + nrm[i] = b[i] * (1.f / 127.f); } break; default: @@ -259,8 +287,8 @@ public: case DEC_FLOAT_2: { const float *f = (const float *)(data_ + decFmt_.uvoff); - uv[0] = f[0] * 2.0f; - uv[1] = f[1] * 2.0f; + uv[0] = f[0] * 2.f; + uv[1] = f[1] * 2.f; } break; @@ -281,13 +309,14 @@ public: switch (decFmt_.c0fmt) { case DEC_U8_4: { - const u8 *p = (const u8 *)(data_ + decFmt_.c0off); + const u8 *b = (const u8 *)(data_ + decFmt_.c0off); for (int i = 0; i < 4; i++) - color[i] = p[i] * (1.f / 255.f); + color[i] = b[i] * (1.f / 255.f); } break; case DEC_FLOAT_4: - memcpy(color, data_ + decFmt_.c0off, 16); break; + memcpy(color, data_ + decFmt_.c0off, 16); + break; default: ERROR_LOG(G3D, "Reader: Unsupported C0 Format"); break; @@ -298,13 +327,14 @@ public: switch (decFmt_.c1fmt) { case DEC_U8_4: { - const u8 *p = (const u8 *)(data_ + decFmt_.c1off); + const u8 *b = (const u8 *)(data_ + decFmt_.c1off); for (int i = 0; i < 3; i++) - color[i] = p[i] * (1.f / 255.f); + color[i] = b[i] * (1.f / 255.f); } break; case DEC_FLOAT_4: - memcpy(color, data_ + decFmt_.c1off, 12); break; + memcpy(color, data_ + decFmt_.c1off, 12); + break; default: ERROR_LOG(G3D, "Reader: Unsupported C1 Format"); break; @@ -313,7 +343,7 @@ public: void ReadWeights(float weights[8]) { const float *f = (const float *)(data_ + decFmt_.w0off); - const u8 *p = (const u8 *)(data_ + decFmt_.w0off); + const u8 *b = (const u8 *)(data_ + decFmt_.w0off); const u16 *s = (const u16 *)(data_ + decFmt_.w0off); switch (decFmt_.w0fmt) { case DEC_FLOAT_1: @@ -321,12 +351,12 @@ public: case DEC_FLOAT_3: case DEC_FLOAT_4: for (int i = 0; i <= decFmt_.w0fmt - DEC_FLOAT_1; i++) - weights[i] = f[i] * 2.0; + weights[i] = f[i] * 2.f; break; - case DEC_U8_1: weights[0] = p[0] * (1.f / 128.f); break; - case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i] = p[i] * (1.f / 128.f); break; - case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i] = p[i] * (1.f / 128.f); break; - case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i] = p[i] * (1.f / 128.f); break; + case DEC_U8_1: weights[0] = b[0] * (1.f / 128.f); break; + case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i] = b[i] * (1.f / 128.f); break; + case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i] = b[i] * (1.f / 128.f); break; + case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i] = b[i] * (1.f / 128.f); break; case DEC_U16_1: weights[0] = s[0] * (1.f / 32768.f); break; case DEC_U16_2: for (int i = 0; i < 2; i++) weights[i] = s[i] * (1.f / 32768.f); break; case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i] = s[i] * (1.f / 32768.f); break; @@ -336,8 +366,8 @@ public: break; } - f = (const float*)(data_ + decFmt_.w1off); - p = (const u8 *)(data_ + decFmt_.w1off); + f = (const float *)(data_ + decFmt_.w1off); + b = (const u8 *)(data_ + decFmt_.w1off); s = (const u16 *)(data_ + decFmt_.w1off); switch (decFmt_.w1fmt) { case 0: @@ -348,8 +378,12 @@ public: case DEC_FLOAT_3: case DEC_FLOAT_4: for (int i = 0; i <= decFmt_.w1fmt - DEC_FLOAT_1; i++) - weights[i+4] = f[i] * 2.0; + weights[i+4] = f[i] * 2.f; break; + case DEC_U8_1: weights[4] = b[0] * (1.f / 128.f); break; + case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i+4] = b[i] * (1.f / 128.f); break; + case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i+4] = b[i] * (1.f / 128.f); break; + case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i+4] = b[i] * (1.f / 128.f); break; case DEC_U16_1: weights[4] = s[0] * (1.f / 32768.f); break; case DEC_U16_2: for (int i = 0; i < 2; i++) weights[i+4] = s[i] * (1.f / 32768.f); break; case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i+4] = s[i] * (1.f / 32768.f); break; diff --git a/GPU/GLES/VertexShaderGenerator.cpp b/GPU/GLES/VertexShaderGenerator.cpp index d5cb6c1e2c..bddcd1ab19 100644 --- a/GPU/GLES/VertexShaderGenerator.cpp +++ b/GPU/GLES/VertexShaderGenerator.cpp @@ -401,7 +401,7 @@ void GenerateVertexShader(int prim, char *buffer) { break; } if (flipV) - WRITE(p, " v_texcoord.y = 1.0 - v_texcoord.y;\n"); + WRITE(p, " v_texcoord.y = 1.0 - v_texcoord.y * 2.0;\n"); } // Compute fogdepth diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index 75474fcb6f..35a5be2b7d 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -64,6 +64,9 @@ void InitGfxState() case GPU_GLES: gpu = new GLES_GPU(); break; + case GPU_SOFTWARE: + gpu = new NullGPU(); + break; } } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 8f12c7d045..7ddb5853c0 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -209,6 +209,8 @@ struct GPUgstate int getDepthTestFunc() const { return ztestfunc & 0x7; } bool isFogEnabled() const { return fogEnable & 1; } bool isStencilTestEnabled() const { return stencilTestEnable & 1; } + bool isAlphaBlendEnabled() const { return alphaBlendEnable & 1; } + bool isDitherEnabled() const { return ditherEnable & 1; } // UV gen int getUVGenMode() const { return texmapmode & 3;} // 2 bits @@ -255,6 +257,7 @@ struct GPUStateCache u32 curTextureWidth; u32 curTextureHeight; + u32 actualTextureHeight; float vpWidth; float vpHeight; diff --git a/Qt/Core.pro b/Qt/Core.pro index d9f6260185..69f6bb9fc8 100755 --- a/Qt/Core.pro +++ b/Qt/Core.pro @@ -18,6 +18,11 @@ x86 { HEADERS += ../Core/MIPS/x86/*.h } +win32 { + SOURCES += ../Windows/OpenGLBase.cpp + HEADERS += ../Windows/OpenGLBase.h +} + SOURCES += ../Core/CPU.cpp \ # Core ../Core/Config.cpp \ ../Core/Core.cpp \ @@ -34,6 +39,7 @@ SOURCES += ../Core/CPU.cpp \ # Core ../Core/Dialog/*.cpp \ ../Core/ELF/*.cpp \ ../Core/FileSystems/*.cpp \ + ../Core/Font/*.cpp \ ../Core/HLE/*.cpp \ ../Core/HW/*.cpp \ ../Core/MIPS/*.cpp \ @@ -63,6 +69,7 @@ HEADERS += ../Core/CPU.h \ ../Core/Dialog/*.h \ ../Core/ELF/*.h \ ../Core/FileSystems/*.h \ + ../Core/Font/*.h \ ../Core/HLE/*.h \ ../Core/HW/*.h \ ../Core/MIPS/*.h \ diff --git a/Qt/PPSSPP.pro b/Qt/PPSSPP.pro index 77b2c18df8..64c09839d2 100755 --- a/Qt/PPSSPP.pro +++ b/Qt/PPSSPP.pro @@ -10,7 +10,14 @@ include(Settings.pri) # Libs symbian: LIBS += -lCore.lib -lCommon.lib -lNative.lib -lcone -leikcore -lavkon -lezlib blackberry: LIBS += -L. -lCore -lCommon -lNative -lscreen -lsocket -lstdc++ -win32: LIBS += -L$$OUT_PWD/release -lCore -lCommon -lNative -lwinmm -lws2_32 -lkernel32 -luser32 -lgdi32 -lshell32 -lcomctl32 -ldsound -lxinput +win32 { + CONFIG(release, debug|release) { + LIBS += -L$$OUT_PWD/release + } else { + LIBS += -L$$OUT_PWD/debug + } + LIBS += -lCore -lCommon -lNative -lwinmm -lws2_32 -lkernel32 -luser32 -lgdi32 -lshell32 -lcomctl32 -ldsound -lxinput +} linux: LIBS += -L. -lCore -lCommon -lNative linux:!mobile_platform { diff --git a/Qt/Settings.pri b/Qt/Settings.pri index 953e138ec3..7b9a238008 100644 --- a/Qt/Settings.pri +++ b/Qt/Settings.pri @@ -1,5 +1,4 @@ DEFINES += USING_QT_UI -blackberry|symbian|contains(MEEGO_EDITION,harmattan): CONFIG += mobile_platform unix:!blackberry:!symbian:!macx: CONFIG += linux # Global specific @@ -8,7 +7,7 @@ INCLUDEPATH += ../ext/zlib ../native/ext/glew ../Common win32-msvc* { QMAKE_CXXFLAGS_RELEASE += /O2 /arch:SSE2 /fp:fast - DEFINES += _MBCS GLEW_STATIC NOMINMAX + DEFINES += _MBCS GLEW_STATIC NOMINMAX NODRAWTEXT _CRT_SECURE_NO_WARNINGS PRECOMPILED_HEADER = ../Windows/stdafx.h PRECOMPILED_SOURCE = ../Windows/stdafx.cpp } else { @@ -17,7 +16,8 @@ win32-msvc* { } # Arch specific -contains(QT_ARCH, i686)|contains(QT_ARCH, x86)|contains(QT_ARCH, x86_64)|contains(QT_ARCH, windows): { +xarch = $$find(QT_ARCH, "86") +contains(QT_ARCH, windows)|count(xarch, 1) { !win32-msvc*: QMAKE_CXXFLAGS += -msse2 CONFIG += x86 } @@ -25,8 +25,13 @@ else { # Assume ARM DEFINES += ARM CONFIG += arm } -mobile_platform: DEFINES += USING_GLES2 +gleslib = $$lower($$QMAKE_LIBS_OPENGL) +gleslib = $$find(gleslib, "gles") +!count(gleslib,0) { + DEFINES += USING_GLES2 + CONFIG += mobile_platform +} # Platform specific contains(MEEGO_EDITION,harmattan): DEFINES += MEEGO_EDITION_HARMATTAN "_SYS_UCONTEXT_H=1" diff --git a/Qt/ctrldisasmview.cpp b/Qt/ctrldisasmview.cpp index 92d43f8e51..3bf021f23e 100644 --- a/Qt/ctrldisasmview.cpp +++ b/Qt/ctrldisasmview.cpp @@ -33,26 +33,15 @@ void CtrlDisAsmView::keyPressEvent(QKeyEvent *e) { int page=(rect().bottom()/rowHeight)/2-1; - if(e->key() == Qt::Key_Down) + switch (e->key()) { - curAddress += align; - e->accept(); - } - else if(e->key() == Qt::Key_Up) - { - curAddress -= align; - e->accept(); - } - else if(e->key() == Qt::Key_PageDown) - { - curAddress += page*align; - e->accept(); - } - else if(e->key() == Qt::Key_PageUp) - { - curAddress -= page*align; - e->accept(); + case Qt::Key_Down: curAddress += align; break; + case Qt::Key_Up: curAddress -= align; break; + case Qt::Key_PageDown: curAddress += page*align; break; + case Qt::Key_PageUp: curAddress -= page*align; break; + default: QWidget::keyPressEvent(e); break; } + update(); } @@ -68,7 +57,6 @@ void CtrlDisAsmView::mousePressEvent(QMouseEvent *e) selecting=true; if (!oldselecting || (selection!=oldSelection)) redraw(); - e->accept(); } else { @@ -77,7 +65,6 @@ void CtrlDisAsmView::mousePressEvent(QMouseEvent *e) EmuThread_LockDraw(false); parentWindow->Update(); redraw(); - e->accept(); } } @@ -85,12 +72,11 @@ void CtrlDisAsmView::wheelEvent(QWheelEvent* e) { int numDegrees = e->delta() / 8; int numSteps = numDegrees / 15; - if (e->orientation() == Qt::Horizontal) { - } else { + if (e->orientation() == Qt::Vertical) + { curAddress -= numSteps*align; - e->accept(); update(); - } + } } void CtrlDisAsmView::redraw() @@ -243,7 +229,7 @@ void CtrlDisAsmView::RenameFunction() } else { - QMessageBox::information(this,"Warning","No symbol selected",QMessageBox::Ok); + QMessageBox::information(this,tr("Warning"),tr("No symbol selected"),QMessageBox::Ok); } } @@ -265,20 +251,20 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) int width = rect().width(); int numRows=(rect().height()/rowHeight)/2+1; - QColor bgColor = QColor(0xFFFFFFFF); - QPen nullPen= QPen(bgColor); - QPen currentPen=QPen(QColor(0,0,0)); - QPen selPen=QPen(QColor(0xFF808080)); - QPen condPen=QPen(QColor(0xFFFF3020)); + QColor bgColor(0xFFFFFFFF); + QPen nullPen(bgColor); + QPen currentPen(QColor(0,0,0)); + QPen selPen(QColor(0xFF808080)); + QPen condPen(QColor(0xFFFF3020)); QBrush lbr; lbr.setColor(bgColor); - QBrush currentBrush=QBrush(QColor(0xFFFFEfE8)); - QBrush pcBrush=QBrush(QColor(0xFF70FF70)); + QBrush currentBrush(QColor(0xFFFFEfE8)); + QBrush pcBrush(QColor(0xFF70FF70)); - QFont normalFont = QFont("Arial", 10); - QFont boldFont = QFont("Arial", 10); - QFont alignedFont = QFont("Monospace", 10); + QFont normalFont("Arial", 10); + QFont boldFont("Arial", 10); + QFont alignedFont("Monospace", 10); boldFont.setBold(true); painter.setFont(normalFont); @@ -295,17 +281,17 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) int rowY1 = rect().bottom()/2 + rowHeight*i - rowHeight/2; int rowY2 = rect().bottom()/2 + rowHeight*i + rowHeight/2 - 1; - lbr.setColor(marker==address?QColor(0xFFFFEEE0):QColor(debugger->getColor(address))); + lbr.setColor((unsigned int)marker == address ? QColor(0xFFFFEEE0) : QColor(debugger->getColor(address))); QColor bg = lbr.color(); painter.setPen(nullPen); painter.drawRect(0,rowY1,16-1,rowY2-rowY1); - if (selecting && address == selection) + if (selecting && address == (unsigned int)selection) painter.setPen(selPen); else painter.setPen(i==0 ? currentPen : nullPen); - QBrush mojsBrush=QBrush(lbr.color()); + QBrush mojsBrush(lbr.color()); painter.setBrush(mojsBrush); if (address == debugger->getPC()) @@ -315,7 +301,7 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) painter.drawRect(16,rowY1,width-16-1,rowY2-rowY1); painter.setBrush(currentBrush); - QPen textPen = QPen(QColor(halfAndHalf(bg.rgba(),0))); + QPen textPen(QColor(halfAndHalf(bg.rgba(),0))); painter.setPen(textPen); painter.setFont(alignedFont); painter.drawText(17,rowY1-3+rowHeight,QString("%1").arg(address,8,16,QChar('0'))); @@ -412,7 +398,7 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) { painter.setPen(branches[i].conditional ? condPen : currentPen); int x=280+(branches[i].srcAddr%9)*8; - QPoint curPos = QPoint(x-2,branches[i].src); + QPoint curPos(x-2,branches[i].src); if (branches[i].dst-200) { diff --git a/Qt/ctrldisasmview.h b/Qt/ctrldisasmview.h index dd1bce826b..d60be7ac77 100644 --- a/Qt/ctrldisasmview.h +++ b/Qt/ctrldisasmview.h @@ -12,7 +12,6 @@ class CtrlDisAsmView : public QWidget Q_OBJECT public: explicit CtrlDisAsmView(QWidget *parent = 0); - void redraw(); void setAlign(int l) @@ -73,7 +72,6 @@ protected: void mousePressEvent(QMouseEvent *e); void keyPressEvent(QKeyEvent *); void wheelEvent(QWheelEvent *e); -signals: public slots: void CopyAddress(); diff --git a/Qt/ctrlmemview.cpp b/Qt/ctrlmemview.cpp index 0ebaa97775..5023d4f5f4 100644 --- a/Qt/ctrlmemview.cpp +++ b/Qt/ctrlmemview.cpp @@ -15,7 +15,6 @@ CtrlMemView::CtrlMemView(QWidget *parent) : QWidget(parent) { - curAddress=0; rowHeight=14; align=4; @@ -32,44 +31,30 @@ void CtrlMemView::redraw() update(); } - void CtrlMemView::wheelEvent(QWheelEvent* e) { int numDegrees = e->delta() / 8; int numSteps = numDegrees / 15; - if (e->orientation() == Qt::Horizontal) { - } else { + if (e->orientation() == Qt::Vertical) + { curAddress -= numSteps*align*alignMul; - e->accept(); redraw(); - } + } } - void CtrlMemView::keyPressEvent(QKeyEvent *e) { int page=(rect().bottom()/rowHeight)/2-1; - if(e->key() == Qt::Key_Up) + switch (e->key()) { - curAddress-=align*alignMul; - e->accept(); - } - else if(e->key() == Qt::Key_Down) - { - curAddress+=align*alignMul; - e->accept(); - } - else if(e->key() == Qt::Key_PageUp) - { - curAddress-=page*align*alignMul; - e->accept(); - } - else if(e->key() == Qt::Key_PageDown) - { - curAddress+=page*align*alignMul; - e->accept(); + case Qt::Key_Up: curAddress -= align*alignMul; break; + case Qt::Key_Down: curAddress += align*alignMul; break; + case Qt::Key_PageUp: curAddress -= page*align*alignMul; break; + case Qt::Key_PageDown: curAddress += page*align*alignMul; break; + default: QWidget::keyPressEvent(e); break; } + redraw(); } @@ -86,17 +71,17 @@ void CtrlMemView::paintEvent(QPaintEvent *) int width = rect().width(); int numRows=(rect().bottom()/rowHeight)/2+1; - QPen nullPen=QPen(0xFFFFFF); - QPen currentPen=QPen(0xFF000000); - QPen selPen=QPen(0x808080); - QBrush lbr = QBrush(0xFFFFFF); - QBrush nullBrush=QBrush(0xFFFFFF); - QBrush currentBrush=QBrush(0xFFEfE8); - QBrush pcBrush=QBrush(0x70FF70); + QPen nullPen(0xFFFFFF); + QPen currentPen(0xFF000000); + QPen selPen(0x808080); + QBrush lbr(0xFFFFFF); + QBrush nullBrush(0xFFFFFF); + QBrush currentBrush(0xFFEFE8); + QBrush pcBrush(0x70FF70); QPen textPen; - QFont normalFont = QFont("Arial", 10); - QFont alignedFont = QFont("Monospace", 10); + QFont normalFont("Arial", 10); + QFont alignedFont("Monospace", 10); painter.setFont(normalFont); int i; @@ -112,7 +97,7 @@ void CtrlMemView::paintEvent(QPaintEvent *) painter.setBrush(currentBrush); - if (selecting && address == selection) + if (selecting && address == (unsigned int)selection) painter.setPen(selPen); else painter.setPen(i==0 ? currentPen : nullPen); @@ -188,6 +173,7 @@ void CtrlMemView::paintEvent(QPaintEvent *) painter.drawText(85,rowY1 - 2 + rowHeight, temp); break; } + case MV_MAX: break; } } } @@ -259,7 +245,7 @@ void CtrlMemView::Change() if (ok && !text.isEmpty()) { EmuThread_LockDraw(true); - Memory::WriteUnchecked_U32(text.toInt(0,16),selection); + Memory::WriteUnchecked_U32(text.toUInt(0,16),selection); EmuThread_LockDraw(false); redraw(); } diff --git a/Qt/ctrlmemview.h b/Qt/ctrlmemview.h index cc7f31c506..e4b52cfe63 100644 --- a/Qt/ctrlmemview.h +++ b/Qt/ctrlmemview.h @@ -67,7 +67,6 @@ protected: void keyPressEvent(QKeyEvent *e); void wheelEvent(QWheelEvent *e); void mousePressEvent(QMouseEvent *e); -signals: public slots: void CopyValue(); diff --git a/Qt/ctrlregisterlist.cpp b/Qt/ctrlregisterlist.cpp index a52c5c88ab..64c19644a0 100644 --- a/Qt/ctrlregisterlist.cpp +++ b/Qt/ctrlregisterlist.cpp @@ -68,26 +68,15 @@ void CtrlRegisterList::scrollChanged(int action) void CtrlRegisterList::keyPressEvent(QKeyEvent *e) { - if(e->key() == Qt::Key_Down) + switch (e->key()) { - selection += 1; - e->accept(); - } - else if(e->key() == Qt::Key_Up) - { - selection -= 1; - e->accept(); - } - else if(e->key() == Qt::Key_PageDown) - { - selection += 4; - e->accept(); - } - else if(e->key() == Qt::Key_PageUp) - { - selection -= 4; - e->accept(); + case Qt::Key_Down: selection += 1; break; + case Qt::Key_Up: selection -= 1; break; + case Qt::Key_PageDown: selection += 4; break; + case Qt::Key_PageUp: selection -= 4; break; + default: QWidget::keyPressEvent(e); break; } + int maxRowsDisplay =rect().bottom()/rowHeight - 1; curVertOffset = std::min(std::max(curVertOffset, selection-maxRowsDisplay),selection); update(); @@ -127,19 +116,17 @@ void CtrlRegisterList::mousePressEvent(QMouseEvent *e) { redraw(); } - e->accept(); } void CtrlRegisterList::wheelEvent(QWheelEvent* e) { int numDegrees = e->delta() / 8; int numSteps = numDegrees / 15; - if (e->orientation() == Qt::Horizontal) { - } else { + if (e->orientation() == Qt::Vertical) + { curVertOffset -= numSteps; - e->accept(); update(); - } + } } @@ -175,17 +162,17 @@ void CtrlRegisterList::paintEvent(QPaintEvent *) int width = rect().width(); - QColor bgColor = QColor(0xffffff); - QPen nullPen=QPen(bgColor); - QPen currentPen=QPen(QColor(0xFF000000)); - QPen selPen=QPen(0x808080); + QColor bgColor(0xffffff); + QPen nullPen(bgColor); + QPen currentPen(QColor(0xFF000000)); + QPen selPen(0x808080); QPen textPen; QBrush lbr; lbr.setColor(bgColor); - QBrush nullBrush=QBrush(bgColor); - QBrush currentBrush=QBrush(0xFFEfE8); - QBrush pcBrush=QBrush(0x70FF70); + QBrush nullBrush(bgColor); + QBrush currentBrush(0xFFEfE8); + QBrush pcBrush(0x70FF70); int nc = cpu->GetNumCategories(); for (int i=0; iDisasmView->setAlign(cpu->getInstructionSize(0)); ui->DisasmView->redraw(); ui->RegList->redraw(); @@ -344,7 +346,7 @@ void Debugger_Disasm::FillFunctions() if(symbolMap.GetSymbolType(i) & ST_FUNCTION) { QListWidgetItem* item = new QListWidgetItem(); - item->setText(QString(symbolMap.GetSymbolName(i)) + " ("+ QString::number(symbolMap.GetSymbolSize(i)) +")"); + item->setText(QString("%1 (%2)").arg(symbolMap.GetSymbolName(i)).arg(symbolMap.GetSymbolSize(i))); item->setData(Qt::UserRole, symbolMap.GetAddress(i)); ui->FuncList->addItem(item); } @@ -429,7 +431,7 @@ void Debugger_Disasm::UpdateThreadGUI() std::vector threads = GetThreadsInfo(); EmuThread_LockDraw(false); - for(int i = 0; i < threads.size(); i++) + for(size_t i = 0; i < threads.size(); i++) { QTreeWidgetItem* item = new QTreeWidgetItem(); item->setText(0,QString::number(threads[i].id)); @@ -478,7 +480,7 @@ void Debugger_Disasm::on_threadList_customContextMenuRequested(const QPoint &pos connect(gotoEntryPoint, SIGNAL(triggered()), this, SLOT(GotoThreadEntryPoint())); menu.addAction(gotoEntryPoint); - QMenu* changeStatus = menu.addMenu("Change status"); + QMenu* changeStatus = menu.addMenu(tr("Change status")); QAction *statusRunning = new QAction(tr("Running"), this); connect(statusRunning, SIGNAL(triggered()), this, SLOT(SetThreadStatusRun())); @@ -564,7 +566,7 @@ void Debugger_Disasm::UpdateDisplayListGUI() item->setText(3,QString("%1").arg(dl->pc,8,16,QChar('0'))); item->setData(3, Qt::UserRole, dl->pc); ui->displayList->addTopLevelItem(item); - if(curDlId == dl->id) + if(curDlId == (u32)dl->id) { ui->displayList->setCurrentItem(item); displayListRowSelected = item; @@ -593,7 +595,7 @@ void Debugger_Disasm::UpdateDisplayListGUI() item->setText(3,QString("%1").arg(it->pc,8,16,QChar('0'))); item->setData(3, Qt::UserRole, it->pc); ui->displayList->addTopLevelItem(item); - if(curDlId == it->id) + if(curDlId == (u32)it->id) { ui->displayList->setCurrentItem(item); displayListRowSelected = item; diff --git a/Qt/debugger_disasm.h b/Qt/debugger_disasm.h index 5ca646e4be..4788b42fbf 100644 --- a/Qt/debugger_disasm.h +++ b/Qt/debugger_disasm.h @@ -58,49 +58,31 @@ private slots: void UpdateThreadGUI(); void on_GotoPc_clicked(); - void on_Go_clicked(); - void on_Stop_clicked(); - void on_StepInto_clicked(); - void on_StepOver_clicked(); - void on_Skip_clicked(); - void on_NextHLE_clicked(); - void on_GotoLr_clicked(); - void on_GotoInt_currentIndexChanged(int index); - void on_Address_textChanged(const QString &arg1); - void on_DisasmView_customContextMenuRequested(const QPoint &pos); - void releaseLock(); void on_RegList_customContextMenuRequested(const QPoint &pos); - void on_vfpu_clicked(); - void on_FuncList_itemClicked(QListWidgetItem *item); - void on_breakpointsList_itemClicked(QTreeWidgetItem *item, int column); - void on_breakpointsList_customContextMenuRequested(const QPoint &pos); - void on_clearAllBP_clicked(); - void on_threadList_itemClicked(QTreeWidgetItem *item, int column); - void on_threadList_customContextMenuRequested(const QPoint &pos); void SetThreadStatusRun(); void SetThreadStatusWait(); void SetThreadStatusSuspend(); void on_displayList_customContextMenuRequested(const QPoint &pos); - + void releaseLock(); private: void SetThreadStatus(ThreadStatus status); diff --git a/Qt/debugger_displaylist.cpp b/Qt/debugger_displaylist.cpp index 5b688d7337..ffbf6b0047 100644 --- a/Qt/debugger_displaylist.cpp +++ b/Qt/debugger_displaylist.cpp @@ -13,7 +13,6 @@ #include "base/display.h" #include "mainwindow.h" #include "GPU/GLES/VertexDecoder.h" -#include Debugger_DisplayList::Debugger_DisplayList(DebugInterface *_cpu, MainWindow* mainWindow_, QWidget *parent) : @@ -78,39 +77,8 @@ void Debugger_DisplayList::UpdateDisplayListGUI() EmuThread_LockDraw(true); const std::deque& dlQueue = gpu->GetDisplayLists(); - DisplayList* dl = gpu->GetCurrentDisplayList(); - if(dl) - { - QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setText(0,QString::number(dl->id)); - item->setData(0, Qt::UserRole, dl->id); - switch(dl->status) - { - case PSP_GE_LIST_DONE: item->setText(1,"Done"); break; - case PSP_GE_LIST_QUEUED: item->setText(1,"Queued"); break; - case PSP_GE_LIST_DRAWING: item->setText(1,"Drawing"); break; - case PSP_GE_LIST_STALL_REACHED: item->setText(1,"Stall Reached"); break; - case PSP_GE_LIST_END_REACHED: item->setText(1,"End Reached"); break; - case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break; - default: break; - } - item->setText(2,QString("%1").arg(dl->startpc,8,16,QChar('0'))); - item->setData(2, Qt::UserRole, dl->startpc); - item->setText(3,QString("%1").arg(dl->pc,8,16,QChar('0'))); - item->setData(3, Qt::UserRole, dl->pc); - ui->displayList->addTopLevelItem(item); - if(curDlId == dl->id) - { - ui->displayList->setCurrentItem(item); - displayListRowSelected = item; - ShowDLCode(); - } - } - for(auto it = dlQueue.begin(); it != dlQueue.end(); ++it) { - if(dl && it->id == dl->id) - continue; QTreeWidgetItem* item = new QTreeWidgetItem(); item->setText(0,QString::number(it->id)); item->setData(0, Qt::UserRole, it->id); @@ -129,7 +97,7 @@ void Debugger_DisplayList::UpdateDisplayListGUI() item->setText(3,QString("%1").arg(it->pc,8,16,QChar('0'))); item->setData(3, Qt::UserRole, it->pc); ui->displayList->addTopLevelItem(item); - if(curDlId == it->id) + if(curDlId == (u32)it->id) { ui->displayList->setCurrentItem(item); displayListRowSelected = item; @@ -138,6 +106,14 @@ void Debugger_DisplayList::UpdateDisplayListGUI() } for(int i = 0; i < ui->displayList->columnCount(); i++) ui->displayList->resizeColumnToContents(i); + + if (ui->displayList->selectedItems().size() == 0 && ui->displayList->topLevelItemCount() != 0) + { + ui->displayList->setCurrentItem(ui->displayList->topLevelItem(0)); + displayListRowSelected = ui->displayList->topLevelItem(0); + ShowDLCode(); + } + EmuThread_LockDraw(false); } @@ -171,7 +147,7 @@ void Debugger_DisplayList::ShowDLCode() item->setText(1,QString("%1").arg(it->second.cmd,2,16,QChar('0'))); item->setText(2,QString("%1").arg(it->second.data,6,16,QChar('0'))); item->setText(3,it->second.comment); - if(curPc == it->first) + if(curPc == (u32)it->first) { curTexAddr = it->second.texAddr; curVtxAddr = it->second.vtxAddr; @@ -187,7 +163,7 @@ void Debugger_DisplayList::ShowDLCode() } ui->displayListData->addTopLevelItem(item); - if(curPc == it->first) + if(curPc == (u32)it->first) { ui->displayListData->setCurrentItem(item); } @@ -209,7 +185,7 @@ void Debugger_DisplayList::ShowDLCode() // Textures QTreeWidgetItem* item = new QTreeWidgetItem(); u32 texaddr = (drawGPUState[i].texaddr[0] & 0xFFFFF0) | ((drawGPUState[i].texbufwidth[0]<<8) & 0x0F000000); - if(!(usedTexAddr.find(texaddr) != usedTexAddr.end() || !Memory::IsValidAddress(texaddr))) + if(usedTexAddr.find(texaddr) == usedTexAddr.end() && Memory::IsValidAddress(texaddr)) { u32 format = drawGPUState[i].texformat & 0xF; int w = 1 << (drawGPUState[i].texsize[0] & 0xf); @@ -234,7 +210,7 @@ void Debugger_DisplayList::ShowDLCode() QTreeWidgetItem* vertexItem = new QTreeWidgetItem(); u32 baseExtended = ((drawGPUState[i].base & 0x0F0000) << 8) | (drawGPUState[i].vaddr & 0xFFFFFF); u32 vaddr = ((drawGPUState[i].offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; - if(!((drawGPUState[i].vaddr) == 0 || !Memory::IsValidAddress(vaddr) || usedVtxAddr.find(vaddr) != usedVtxAddr.end())) + if(drawGPUState[i].vaddr != 0 && Memory::IsValidAddress(vaddr) && usedVtxAddr.find(vaddr) == usedVtxAddr.end()) { vertexItem->setText(0, QString("%1").arg(vaddr,8,16,QChar('0'))); vertexItem->setData(0,Qt::UserRole, i); @@ -296,7 +272,7 @@ void Debugger_DisplayList::ShowDLCode() QTreeWidgetItem* indexItem = new QTreeWidgetItem(); baseExtended = ((drawGPUState[i].base & 0x0F0000) << 8) | (drawGPUState[i].iaddr & 0xFFFFFF); u32 iaddr = ((drawGPUState[i].offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; - if(!((drawGPUState[i].iaddr & 0xFFFFFF) == 0 || !Memory::IsValidAddress(iaddr) || usedIdxAddr.find(iaddr) != usedIdxAddr.end())) + if((drawGPUState[i].iaddr & 0xFFFFFF) != 0 && Memory::IsValidAddress(iaddr) && usedIdxAddr.find(iaddr) == usedIdxAddr.end()) { indexItem->setText(0, QString("%1").arg(iaddr,8,16,QChar('0'))); indexItem->setData(0,Qt::UserRole, i); @@ -1467,6 +1443,8 @@ void Debugger_DisplayList::FillDisplayListCmd(std::map& data, u32 void Debugger_DisplayList::Update() { + if(!isVisible()) + return; UpdateRenderBuffer(); UpdateRenderBufferList(); UpdateDisplayList(); @@ -1571,7 +1549,7 @@ void Debugger_DisplayList::on_gotoPCBtn_clicked() for(int i = 0; i < ui->displayListData->topLevelItemCount(); i++) { - if(ui->displayListData->topLevelItem(i)->data(0, Qt::UserRole).toInt() == currentPC) + if((u32)ui->displayListData->topLevelItem(i)->data(0, Qt::UserRole).toInt() == currentPC) { ui->displayListData->setCurrentItem(ui->displayListData->topLevelItem(i)); } @@ -1608,7 +1586,7 @@ void Debugger_DisplayList::UpdateRenderBufferListGUI() std::vector fboList = gpu->GetFramebufferList(); - for(int i = 0; i < fboList.size(); i++) + for(size_t i = 0; i < fboList.size(); i++) { QTreeWidgetItem* item = new QTreeWidgetItem(); item->setText(0,QString("%1").arg(fboList[i].fb_address,8,16,QChar('0'))); @@ -1641,7 +1619,7 @@ void Debugger_DisplayList::setCurrentFBO(u32 addr) { for(int i = 0; i < ui->fboList->topLevelItemCount(); i++) { - if(ui->fboList->topLevelItem(i)->data(0,Qt::UserRole+1).toInt() == addr) + if((u32)ui->fboList->topLevelItem(i)->data(0,Qt::UserRole+1).toInt() == addr) { for(int j = 0; j < ui->fboList->colorCount(); j++) ui->fboList->topLevelItem(i)->setTextColor(j,Qt::green); @@ -1686,7 +1664,7 @@ void Debugger_DisplayList::UpdateVertexInfo() VertexDecoder vtcDec; vtcDec.SetVertexType(state.vertType); - u8 tmp[20*vtcDec.GetDecVtxFmt().stride]; + u8* tmp = new u8[20*vtcDec.GetDecVtxFmt().stride]; vtcDec.DecodeVerts(tmp,Memory::GetPointer(vaddr),0,0,0,0,19); VertexReader vtxRead(tmp,vtcDec.GetDecVtxFmt(),state.vertType); @@ -1738,6 +1716,7 @@ void Debugger_DisplayList::UpdateVertexInfo() item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(pos[0]).arg(pos[1]).arg(pos[2])); itemTop->addChild(item); } + delete [] tmp; for(int i = 0; i < ui->vertexData->columnCount(); i++) { ui->vertexData->resizeColumnToContents(i); @@ -1821,7 +1800,7 @@ void Debugger_DisplayList::on_displayListData_customContextMenuRequested(const Q void Debugger_DisplayList::RunToDLPC() { - u32 addr = displayListDataSelected->text(0).toInt(0,16); + u32 addr = displayListDataSelected->text(0).toUInt(0,16); host->SetGPUStep(true, 2, addr); host->NextGPUStep(); } @@ -1844,7 +1823,7 @@ void Debugger_DisplayList::on_texturesList_customContextMenuRequested(const QPoi void Debugger_DisplayList::RunToDrawTex() { - u32 addr = textureDataSelected->text(0).toInt(0,16); + u32 addr = textureDataSelected->text(0).toUInt(0,16); host->SetGPUStep(true, 3, addr); host->NextGPUStep(); } diff --git a/Qt/debugger_displaylist.h b/Qt/debugger_displaylist.h index 7ecec82302..78b19d86b4 100644 --- a/Qt/debugger_displaylist.h +++ b/Qt/debugger_displaylist.h @@ -63,40 +63,23 @@ private slots: void releaseLock(); void on_displayList_itemClicked(QTreeWidgetItem *item, int column); - void on_stepBtn_clicked(); - void on_runBtn_clicked(); - void on_stopBtn_clicked(); - void on_nextDrawBtn_clicked(); - void on_gotoPCBtn_clicked(); - void on_texturesList_itemDoubleClicked(QTreeWidgetItem *item, int column); - void on_comboBox_currentIndexChanged(int index); - void on_fboList_itemClicked(QTreeWidgetItem *item, int column); - void on_nextDLBtn_clicked(); void setCurrentFBO(u32 addr); - void on_zoommBtn_clicked(); - void on_zoompBtn_clicked(); - void on_vertexList_itemClicked(QTreeWidgetItem *item, int column); - void on_pushButton_clicked(); - void on_nextIdx_clicked(); - void on_indexList_itemClicked(QTreeWidgetItem *item, int column); - void on_displayListData_customContextMenuRequested(const QPoint &pos); - void on_texturesList_customContextMenuRequested(const QPoint &pos); void RunToDLPC(); void RunToDrawTex(); diff --git a/Qt/debugger_memory.cpp b/Qt/debugger_memory.cpp index 3b5cdedf08..d044145f5d 100644 --- a/Qt/debugger_memory.cpp +++ b/Qt/debugger_memory.cpp @@ -51,7 +51,7 @@ void Debugger_Memory::Goto(u32 addr) void Debugger_Memory::on_editAddress_textChanged(const QString &arg1) { - ui->memView->gotoAddr(arg1.toInt(0,16) & ~3); + ui->memView->gotoAddr(arg1.toUInt(0,16) & ~3); } void Debugger_Memory::on_normalBtn_clicked() diff --git a/Qt/debugger_memorytex.cpp b/Qt/debugger_memorytex.cpp index cdbf4ae640..e3fbc38285 100644 --- a/Qt/debugger_memorytex.cpp +++ b/Qt/debugger_memorytex.cpp @@ -61,15 +61,15 @@ void Debugger_MemoryTex::on_readBtn_clicked() EmuThread_LockDraw(true); GPUgstate state; - state.texaddr[0] = ui->texaddr->text().toInt(0,16); - state.texbufwidth[0] = ui->texbufwidth0->text().toInt(0,16); - state.texformat = ui->texformat->text().toInt(0,16); - state.texsize[0] = ui->texsize->text().toInt(0,16); - state.texmode = ui->texmode->text().toInt(0,16); - state.clutformat = ui->clutformat->text().toInt(0,16); - state.clutaddr = ui->clutaddr->text().toInt(0,16); - state.clutaddrupper = ui->clutaddrupper->text().toInt(0,16); - state.loadclut = ui->loadclut->text().toInt(0,16); + state.texaddr[0] = ui->texaddr->text().toUInt(0,16); + state.texbufwidth[0] = ui->texbufwidth0->text().toUInt(0,16); + state.texformat = ui->texformat->text().toUInt(0,16); + state.texsize[0] = ui->texsize->text().toUInt(0,16); + state.texmode = ui->texmode->text().toUInt(0,16); + state.clutformat = ui->clutformat->text().toUInt(0,16); + state.clutaddr = ui->clutaddr->text().toUInt(0,16); + state.clutaddrupper = ui->clutaddrupper->text().toUInt(0,16); + state.loadclut = ui->loadclut->text().toUInt(0,16); int bufW = state.texbufwidth[0] & 0x3ff; int w = 1 << (state.texsize[0] & 0xf); int h = 1 << ((state.texsize[0]>>8) & 0xf); diff --git a/Qt/debugger_vfpu.cpp b/Qt/debugger_vfpu.cpp index 5c30f3e12f..290dd26f08 100644 --- a/Qt/debugger_vfpu.cpp +++ b/Qt/debugger_vfpu.cpp @@ -12,7 +12,7 @@ Debugger_VFPU::Debugger_VFPU(DebugInterface *_cpu, MainWindow* mainWindow_, QWid { ui->setupUi(this); - setWindowTitle(QString("VFPU - ")+cpu->GetName()); + setWindowTitle(QString("VFPU - %1").arg(cpu->GetName())); ui->vfpu->setCPU(_cpu); } diff --git a/Qt/gamepaddialog.cpp b/Qt/gamepaddialog.cpp index 5094fc032c..2b1fb03e03 100644 --- a/Qt/gamepaddialog.cpp +++ b/Qt/gamepaddialog.cpp @@ -44,10 +44,10 @@ const int configOffset = 200; GamePadDialog::GamePadDialog(InputState* state, QWidget *parent) : QDialog(parent), ui(new Ui::GamePadDialog), - m_inputState(state), #if QT_HAS_SDL m_joystick(0), #endif + m_inputState(state), m_isInit(false) { ui->setupUi(this); @@ -108,15 +108,10 @@ void GamePadDialog::showEvent(QShowEvent *) void GamePadDialog::changeEvent(QEvent *event) { - QDialog::changeEvent(event); - - if (0 != event) + if (event->type() == QEvent::LanguageChange) { - if (event->type() == QEvent::LanguageChange) - { - ui->retranslateUi(this); - on_refreshListBtn_clicked(); - } + ui->retranslateUi(this); + on_refreshListBtn_clicked(); } } diff --git a/Qt/gamepaddialog.h b/Qt/gamepaddialog.h index 24163731cc..4157fa2aa5 100644 --- a/Qt/gamepaddialog.h +++ b/Qt/gamepaddialog.h @@ -21,23 +21,16 @@ public: ~GamePadDialog(); void SetViewMode(); - void SetCalibMode(); - void CalibNextButton(); protected: void showEvent(QShowEvent *); void changeEvent(QEvent *); private slots: void releaseLock(); void on_refreshListBtn_clicked(); - void on_SelectPadBtn_clicked(); - void pollJoystick(); - void on_AssignBtn_clicked(); - void on_buttonBox_accepted(); - private: int GetIntFromMapping(int inputId, int type, int sign); void GetMappingFromInt(int value, int &inputId, int &type, int &sign); diff --git a/Qt/languages/ppsspp_cn.ts b/Qt/languages/ppsspp_cn.ts index 7e628dd6f7..0185206b1a 100644 --- a/Qt/languages/ppsspp_cn.ts +++ b/Qt/languages/ppsspp_cn.ts @@ -1,13 +1,13 @@ - + Controls Controls Controls window title - 控制器 + 控制器 @@ -65,7 +65,7 @@ New function name: - + 新函数名称: @@ -116,7 +116,7 @@ Set new value: - + 设置新值: @@ -125,7 +125,7 @@ Disassembler Window title - + 反汇编器 @@ -330,7 +330,7 @@ Memory Viewer - %1 - + 内存查看器 - %1 @@ -338,7 +338,7 @@ VFPU - + VFPU @@ -527,37 +527,37 @@ Lo&g Levels - + (&G)日志级别 &Language - + (&L)语言选择 &Video - + (&V)视频 &Anisotropic filtering - + (&A)各向异性过滤 &Zoom - + (&Z)缩放 Co&ntrols - + (&N)控制 &Core - + (&C)核心 @@ -702,47 +702,47 @@ &Keyboard - + (&K)键盘 &Toggle fullscreen - + (&T)全屏 Show &debug statistics - + (&D)显示调试信息 I&gnore illegal reads/writes - + (&G)忽略非法读写 &Gamepad - + (&G)手柄 Run on loa&d - + (&D)载入时运行 Show &FPS counter - + (&F)显示帧率计数器 S&tretch to display - + (&T)拉伸显示 &Sound emulation - + (&S)模拟声音 @@ -895,27 +895,27 @@ Off - + 关闭 2x - + 2x 4x - + 4x 8x - + 8x 16x - + 16x diff --git a/Qt/languages/ppsspp_tc.ts b/Qt/languages/ppsspp_tc.ts index a42937ece9..8b4520c1a0 100644 --- a/Qt/languages/ppsspp_tc.ts +++ b/Qt/languages/ppsspp_tc.ts @@ -1,1014 +1,1014 @@ - - - - - Controls - - - Controls - Controls window title - 控制器 - - - - CtrlDisAsmView - - - Copy &address - (&A)複製地址 - - - - Copy instruction (&hex) - (&H)複製指令(十六進制型) - - - - Copy instruction (&disasm) - (&D)複製指令(反彙編型) - - - - &Run to here - (&R)執行到此處 - - - - &Set Next Statement - (&S)設置下一語句 - - - - &Toggle breakpoint - (&T)鎖定斷點 - - - - &Follow branch - (&F)跟隨分支 - - - - Go to in &Memory View - (&M)轉到內存視圖 - - - - &Rename function... - (&R)重命名函數... - - - - New function name - 新函數名稱 - - - - New function name: - - - - - CtrlMemView - - - Go to in &disasm - (&D)轉到反彙編器 - - - - &Copy value - (&C)複製值 - - - - Dump... - 轉儲... - - - - CtrlRegisterList - - - Go to in &memory view - (&M)轉到內存視圖 - - - - Go to in &disasm - (&D)轉到反彙編器 - - - - &Copy value - (&C)複製值 - - - - C&hange... - (&H)更改... - - - - Set new value - 設置新值 - - - - Set new value: - - - - - Debugger_Disasm - - - Disassembler - Window title - - - - - Ctr: - 計數器: - - - - &Go to - (&G)轉到 - - - - &PC - (&P)PC寄存器 - - - - &LR - (&L)連接寄存器 - - - - Show VFPU - 顯示VFPU - - - - Regs - 寄存器 - - - - Funcs - 函數 - - - - &Go - (&G)轉到 - - - - Stop - 停止 - - - - Step &Into - (&I)單步跟進 - - - - Step &Over - (&O)單步步過 - - - - S&kip - (&K)跳過 - - - - Next &HLE - (&H)下一HLE - - - - Breakpoints - 斷點 - - - - Address - 地址 - - - - Clear All - 清空所有 - - - - Callstack - 調用棧 - - - - Display Lists - 顯示列表 - - - - - Id - Id - - - - - Status - 狀態 - - - - Start Address - 起始地址 - - - - Current Address - 當前地址 - - - - Run - 執行 - - - - Step - 單步執行 - - - - Threads - 線程 - - - - Name - 名稱 - - - - Current PC - 當前PC寄存器 - - - - Entry point - 入口點 - - - - Remove breakpoint - 移除斷點 - - - - Go to entry point - 轉到入口點 - - - - Running - 執行中 - - - - Wait - 等待 - - - - Suspend - 掛起 - - - - Show code - 顯示代碼 - - - - Debugger_Memory - - - Dialog - 對話框 - - - - Goto: - 轉到: - - - - Mode - 模式 - - - - Normal - 普通模式 - - - - Symbols - 特徵符模式 - - - - Memory Viewer - %1 - - - - - Debugger_VFPU - - - VFPU - - - - - Float - 浮點型 - - - - HalfFloat - 半浮點型 - - - - Hex - 十六進制型 - - - - Bytes - 字節型 - - - - Shorts - 短整型 - - - - Ints - 整型 - - - - GamePadDialog - - - Gamepad Configuration - 手柄設置 - - - - GamePad List - 手柄列表 - - - - Refresh - 刷新 - - - - Select - 選中 - - - - Gamepad Values : - 手柄值: - - - - TextLabel - TextLabel - TextLabel - - - - Assign Gamepad input - 指定該手柄 - - - - to PSP button/axis - 作為PSP按鍵/搖桿輸入 - - - - Assign - 指定 - - - - Press buttons on your gamePad to verify mapping : - 按下手柄按鍵來確認鍵位映射: - - - - - <b>No gamepad</b> - <b>未發現手柄</b> - - - - <b>Unknown gamepad</b> - <b>未識別的手柄</b> - - - - Buttons - 按鈕 - - - - - Button %1 - 按鈕 %1 - - - - Axes - 搖桿 - - - - %1 Neg - %1 Neg - - - - Axes %1 Neg - Axes %1 Neg - - - - %1 Pos - %1 Pos - - - - Axes %1 Pos - Axes %1 Pos - - - - Hats - Hats - - - - <b>Current gamepad: %1</b> - <b>當前手柄: %1</b> - - - - MainWindow - - - PPSSPP - PPSSPP - - - - &File - (&F)文件 - - - - &Emulation - (&E)模擬 - - - - Debu&g - (&G)除錯 - - - - &Options - (&O)選項 - - - - G3D - - - - - HLE - - - - - Default - 默認 - - - - Lo&g Levels - - - - - &Language - - - - - &Video - - - - - &Anisotropic filtering - - - - - &Zoom - - - - - Co&ntrols - - - - - &Core - - - - - &Help - (&H)幫助 - - - - &Open... - (&O)打開... - - - - &Close - (&C)關閉 - - - - - - - - - - - Quickload state - 快速讀檔 - - - - F4 - F4 - - - - Quicksave state - 快速存檔 - - - - F2 - F2 - - - - &Load State File... - (&L)讀取存檔... - - - - &Save State File... - (&S)保存存檔... - - - - E&xit - (&X)退出 - - - - &Run - (&R)運行 - - - - F7 - F7 - - - - &Pause - (&P)暫停 - - - - F8 - F8 - - - - R&eset - (&E)重置 - - - - &Interpreter - (&I)解釋器 - - - - &Slightly Faster Interpreter - (&S)較快的解釋器 - - - - &Dynarec - (&D)動態解釋器 - - - - Load &Map File... - (&M)讀取Map文件... - - - - &Save Map File... - (&S)保存Map文件... - - - - &Reset Symbol Table - (&R)重置符號表 - - - - &Disassembly - (&D)反彙編器 - - - - Ctrl+D - Ctrl+D - - - - &Log Console - (&L)查看控制台日誌 - - - - Ctrl+L - Ctrl+L - - - - Memory &View... - (&V)內存視圖... - - - - Ctrl+M - Ctrl+M - - - - &Keyboard - - - - - &Toggle fullscreen - - - - - Show &debug statistics - - - - - I&gnore illegal reads/writes - - - - - &Gamepad - - - - - Run on loa&d - - - - - Show &FPS counter - - - - - S&tretch to display - - - - - &Sound emulation - - - - - F12 - F12 - - - - &Buffered Rendering - (&B)渲染緩衝 - - - - F5 - F5 - - - - &Hardware Transform - (&H)硬件加速 - - - - F6 - F6 - - - - &Linear Filtering - (&L)線性過濾 - - - - &Wireframe (experimental) - (&W)使用線框 (實驗性) - - - - &Display Raw Framebuffer - (&D)顯示原始?緩衝 - - - - Screen &1x - &1倍窗口 - - - - Ctrl+1 - Ctrl+1 - - - - Screen &2x - &2倍窗口 - - - - Ctrl+2 - Ctrl+2 - - - - Screen &3x - &3倍窗口 - - - - Ctrl+3 - Ctrl+3 - - - - Screen &4x - &4倍窗口 - - - - Ctrl+4 - Ctrl+4 - - - - &Fast Memory (dynarec, unstable) - (&F)高速閃存 (動態重編譯,不穩定) - - - - &Go to http://www.ppsspp.org/ - (&G)轉到 http://www.ppsspp.org/ - - - - &About PPSSPP... - (&A)關於 PPSSPP... - - - - &Use VBO - (&U)使用 VBO - - - - - - Debug - 除錯 - - - - - - Warning - 警告 - - - - - - Error - 錯誤 - - - - - - Info - 信息 - - - - D&ump next frame to log - (&U)將下一幀轉儲至日誌 - - - - &Vertex Cache - (&V)頂點緩存 - - - - Memory View Texture... - 內存紋理視圖... - - - - Simple 2xAA - - - - - Off - - - - - 2x - - - - - 4x - - - - - 8x - - - - - 16x - - - - - No translations - 未翻譯 - - - - gamepadMapping - - - Cross - × - - - - Circle - ○ - - - - Square - □ - - - - Triangle - △ - - - - Left Trigger - L - - - - Right Trigger - R - - - - Start - 開始 - - - - Select - 選擇 - - - - Up - ↑ - - - - Down - ↓ - - - - Left - ← - - - - Right - → - - - - Home - Home - - - - Stick left - 搖桿左 - - - - Stick right - 搖桿右 - - - - Stick up - 搖桿上 - - - - Stick bottom - 搖桿下 - - - + + + + + Controls + + + Controls + Controls window title + 控制器 + + + + CtrlDisAsmView + + + Copy &address + (&A)複製地址 + + + + Copy instruction (&hex) + (&H)複製指令(十六進制型) + + + + Copy instruction (&disasm) + (&D)複製指令(彙編型) + + + + &Run to here + (&R)執行到此處 + + + + &Set Next Statement + (&S)設置下一語句 + + + + &Toggle breakpoint + (&T)鎖定斷點 + + + + &Follow branch + (&F)跟隨分支 + + + + Go to in &Memory View + (&M)轉到內存視圖 + + + + &Rename function... + (&R)重命名函數... + + + + New function name + 新函數名稱 + + + + New function name: + 新函數名稱: + + + + CtrlMemView + + + Go to in &disasm + (&D)轉到彙編視圖 + + + + &Copy value + (&C)複製值 + + + + Dump... + 轉儲... + + + + CtrlRegisterList + + + Go to in &memory view + (&M)轉到內存視圖 + + + + Go to in &disasm + (&D)轉到彙編視圖 + + + + &Copy value + (&C)複製值 + + + + C&hange... + (&H)更改... + + + + Set new value + 設置新值 + + + + Set new value: + 設置新值: + + + + Debugger_Disasm + + + Disassembler + Window title + 反彙編器 + + + + Ctr: + 計數器: + + + + &Go to + (&G)轉到 + + + + &PC + (&P)PC寄存器 + + + + &LR + (&L)連接寄存器 + + + + Show VFPU + 顯示VFPU + + + + Regs + 寄存器 + + + + Funcs + 函數 + + + + &Go + (&G)轉到 + + + + Stop + 停止 + + + + Step &Into + (&I)單步跟進 + + + + Step &Over + (&O)單步步過 + + + + S&kip + (&K)跳過 + + + + Next &HLE + (&H)下一HLE + + + + Breakpoints + 斷點 + + + + Address + 地址 + + + + Clear All + 清空所有 + + + + Callstack + 調用棧 + + + + Display Lists + 顯示列表 + + + + + Id + Id + + + + + Status + 狀態 + + + + Start Address + 起始地址 + + + + Current Address + 當前地址 + + + + Run + 執行 + + + + Step + 單步執行 + + + + Threads + 線程 + + + + Name + 名稱 + + + + Current PC + 當前PC寄存器 + + + + Entry point + 入口點 + + + + Remove breakpoint + 移除斷點 + + + + Go to entry point + 轉到入口點 + + + + Running + 執行中 + + + + Wait + 等待 + + + + Suspend + 掛起 + + + + Show code + 顯示代碼 + + + + Debugger_Memory + + + Dialog + 對話框 + + + + Goto: + 轉到: + + + + Mode + 模式 + + + + Normal + 普通模式 + + + + Symbols + 特徵符模式 + + + + Memory Viewer - %1 + 內存查看器 - %1 + + + + Debugger_VFPU + + + VFPU + VFPU + + + + Float + 浮點型 + + + + HalfFloat + 半浮點型 + + + + Hex + 十六進制型 + + + + Bytes + 字節型 + + + + Shorts + 短整型 + + + + Ints + 整型 + + + + GamePadDialog + + + Gamepad Configuration + 手柄設置 + + + + GamePad List + 手柄列表 + + + + Refresh + 刷新 + + + + Select + 選中 + + + + Gamepad Values : + 手柄值: + + + + TextLabel + TextLabel + TextLabel + + + + Assign Gamepad input + 指定該手柄 + + + + to PSP button/axis + 作為PSP按鍵/搖桿輸入 + + + + Assign + 指定 + + + + Press buttons on your gamePad to verify mapping : + 按下手柄按鍵來確認鍵位映射: + + + + + <b>No gamepad</b> + <b>未發現手柄</b> + + + + <b>Unknown gamepad</b> + <b>未識別的手柄</b> + + + + Buttons + 按鈕 + + + + + Button %1 + 按鈕 %1 + + + + Axes + 搖桿 + + + + %1 Neg + %1 Neg + + + + Axes %1 Neg + Axes %1 Neg + + + + %1 Pos + %1 Pos + + + + Axes %1 Pos + Axes %1 Pos + + + + Hats + Hats + + + + <b>Current gamepad: %1</b> + <b>當前手柄: %1</b> + + + + MainWindow + + + PPSSPP + PPSSPP + + + + &File + (&F)文件 + + + + &Emulation + (&E)模擬 + + + + Debu&g + (&G)調試 + + + + &Options + (&O)選項 + + + + G3D + + + + + HLE + + + + + Default + 默認 + + + + Lo&g Levels + (&G)日誌級別 + + + + &Language + (&L)語言選擇 + + + + &Video + (&V)視頻 + + + + &Anisotropic filtering + (&A)各向異性過濾 + + + + &Zoom + (&Z)縮放 + + + + Co&ntrols + (&N)控制 + + + + &Core + (&C)核心 + + + + &Help + (&H)幫助 + + + + &Open... + (&O)打開... + + + + &Close + (&C)關閉 + + + + - + - + + + + Quickload state + 快速讀檔 + + + + F4 + F4 + + + + Quicksave state + 快速存檔 + + + + F2 + F2 + + + + &Load State File... + (&L)讀取存檔... + + + + &Save State File... + (&S)保存存檔... + + + + E&xit + (&X)退出 + + + + &Run + (&R)運行 + + + + F7 + F7 + + + + &Pause + (&P)暫停 + + + + F8 + F8 + + + + R&eset + (&E)重置 + + + + &Interpreter + (&I)解釋器 + + + + &Slightly Faster Interpreter + (&S)較快的解釋器 + + + + &Dynarec + (&D)動態重編譯 + + + + Load &Map File... + (&M)讀取Map文件... + + + + &Save Map File... + (&S)保存Map文件... + + + + &Reset Symbol Table + (&R)重置符號表 + + + + &Disassembly + (&D)彙編視圖 + + + + Ctrl+D + Ctrl+D + + + + &Log Console + (&L)查看控制台日誌 + + + + Ctrl+L + Ctrl+L + + + + Memory &View... + (&V)內存視圖... + + + + Ctrl+M + Ctrl+M + + + + &Keyboard + (&K)鍵盤 + + + + &Toggle fullscreen + (&T)全屏 + + + + Show &debug statistics + (&D)顯示調試信息 + + + + I&gnore illegal reads/writes + (&G)忽略非法讀寫 + + + + &Gamepad + (&G)手柄 + + + + Run on loa&d + (&D)載入時運行 + + + + Show &FPS counter + (&F)顯示幀率計數器 + + + + S&tretch to display + (&T)拉伸顯示 + + + + &Sound emulation + (&S)模擬聲音 + + + + F12 + F12 + + + + &Buffered Rendering + (&B)渲染緩衝 + + + + F5 + F5 + + + + &Hardware Transform + (&H)硬件加速 + + + + F6 + F6 + + + + &Linear Filtering + (&L)線性過濾 + + + + &Wireframe (experimental) + (&W)使用線框 (實驗性選項) + + + + &Display Raw Framebuffer + (&D)顯示 Raw 原始緩衝 + + + + Screen &1x + &1倍窗口 + + + + Ctrl+1 + Ctrl+1 + + + + Screen &2x + &2倍窗口 + + + + Ctrl+2 + Ctrl+2 + + + + Screen &3x + &3倍窗口 + + + + Ctrl+3 + Ctrl+3 + + + + Screen &4x + &4倍窗口 + + + + Ctrl+4 + Ctrl+4 + + + + &Fast Memory (dynarec, unstable) + (&F)高速閃存 (動態重編譯,不穩定) + + + + &Go to http://www.ppsspp.org/ + (&G)轉到 http://www.ppsspp.org/ + + + + &About PPSSPP... + (&A)關於 PPSSPP... + + + + &Use VBO + (&U)使用 VBO + + + + + + Debug + 調試 + + + + + + Warning + 警告 + + + + + + Error + 錯誤 + + + + + + Info + 信息 + + + + D&ump next frame to log + (&U)將下一幀轉儲至日誌 + + + + &Vertex Cache + (&V)頂點緩存 + + + + Memory View Texture... + 內存紋理視圖... + + + + Simple 2xAA + + + + + Off + 關閉 + + + + 2x + 2x + + + + 4x + 4x + + + + 8x + 8x + + + + 16x + 16x + + + + No translations + 未翻譯 + + + + gamepadMapping + + + Cross + × + + + + Circle + ○ + + + + Square + □ + + + + Triangle + △ + + + + Left Trigger + L + + + + Right Trigger + R + + + + Start + 開始 + + + + Select + 選擇 + + + + Up + ↑ + + + + Down + ↓ + + + + Left + ← + + + + Right + → + + + + Home + Home + + + + Stick left + 搖桿左 + + + + Stick right + 搖桿右 + + + + Stick up + 搖桿上 + + + + Stick bottom + 搖桿下 + + + diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index c6b45a5dcc..498aaf4f41 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -16,13 +16,14 @@ #include "ConsoleListener.h" #include "base/display.h" #include "GPU/GPUInterface.h" -#include "GPU/GPUState.h" #include "QtHost.h" #include "EmuThread.h" const char *stateToLoad = NULL; +// TODO: Make this class thread-aware. Can't send events to a different thread. Currently only works on X11. +// Needs to use QueuedConnection for signals/slots. MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), @@ -33,7 +34,6 @@ MainWindow::MainWindow(QWidget *parent) : displaylistWindow(0) { ui->setupUi(this); - qApp->installEventFilter(this); controls = new Controls(this); #if QT_HAS_SDL @@ -57,25 +57,23 @@ MainWindow::MainWindow(QWidget *parent) : SetZoom(zoom); EmuThread_Start(emugl); + SetGameTitle(fileToStart); if (!fileToStart.isNull()) { - SetGameTitle(fileToStart); - UpdateMenus(); - EmuThread_StartGame(fileToStart); + UpdateMenus(); if (stateToLoad != NULL) SaveState::Load(stateToLoad); } - else - SetGameTitle(""); } MainWindow::~MainWindow() { delete ui; } + void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID) { std::string config_filename; @@ -154,10 +152,10 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co if (g_Config.currentDirectory == "") { - g_Config.currentDirectory = getenv("HOME"); + g_Config.currentDirectory = QDir::homePath().toStdString(); } - g_Config.memCardDirectory = std::string(getenv("HOME"))+"/.ppsspp/"; + g_Config.memCardDirectory = QDir::homePath().toStdString()+"/.ppsspp/"; g_Config.flashDirectory = g_Config.memCardDirectory+"/flash/"; LogManager::Init(); @@ -173,31 +171,130 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co #endif } -void MainWindow::SetNextState(CoreState state) +void MainWindow::ShowMemory(u32 addr) { - nextState = state; + if(memoryWindow) + memoryWindow->Goto(addr); } -void MainWindow::SetGameTitle(QString text) +void MainWindow::Update() { - QString title = "PPSSPP " + QString(PPSSPP_VERSION_STR); - if (text != "") - title += QString(" - %1").arg(text); + UpdateInputState(&input_state); - setWindowTitle(title); -} - -void MainWindow::BrowseAndBoot(void) -{ - QString filename = QFileDialog::getOpenFileName(NULL, "Load File", g_Config.currentDirectory.c_str(), "PSP ROMs (*.pbp *.elf *.iso *.cso *.prx)"); - if (QFile::exists(filename)) + for (int i = 0; i < controllistCount; i++) { - QFileInfo info(filename); - g_Config.currentDirectory = info.absolutePath().toStdString(); - EmuThread_StartGame(filename); + if (pressedKeys.contains(controllist[i].key) || + input_state.pad_buttons_down & controllist[i].emu_id) + __CtrlButtonDown(controllist[i].psp_id); + else + __CtrlButtonUp(controllist[i].psp_id); } + __CtrlSetAnalog(input_state.pad_lstick_x, input_state.pad_lstick_y); } +void MainWindow::UpdateMenus() +{ + // enabling + bool enable = g_State.bEmuThreadStarted ? false : true; + ui->action_FileLoad->setEnabled(enable); + ui->action_FileClose->setEnabled(!enable); + ui->action_FileSaveStateFile->setEnabled(!enable); + ui->action_FileLoadStateFile->setEnabled(!enable); + ui->action_FileQuickloadState->setEnabled(!enable); + ui->action_FileQuickSaveState->setEnabled(!enable); + ui->action_CPUDynarec->setEnabled(enable); + ui->action_CPUInterpreter->setEnabled(enable); + ui->action_DebugDumpFrame->setEnabled(!enable); + ui->action_DebugDisassembly->setEnabled(!enable); + ui->action_DebugMemoryView->setEnabled(!enable); + ui->action_DebugMemoryViewTexture->setEnabled(!enable); + ui->action_DebugDisplayList->setEnabled(!enable); + + enable = !Core_IsStepping() ? false : true; + ui->action_EmulationRun->setEnabled(g_State.bEmuThreadStarted ? enable : false); + ui->action_EmulationPause->setEnabled(g_State.bEmuThreadStarted ? !enable : false); + ui->action_EmulationReset->setEnabled(g_State.bEmuThreadStarted ? true : false); + + // checking + ui->action_EmulationRunLoad->setChecked(g_Config.bAutoRun); + + ui->action_CPUInterpreter->setChecked(!g_Config.bJit); + ui->action_CPUDynarec->setChecked(g_Config.bJit); + ui->action_OptionsFastMemory->setChecked(g_Config.bFastMemory); + ui->action_OptionsIgnoreIllegalReadsWrites->setChecked(g_Config.bIgnoreBadMemAccess); + + ui->action_AFOff->setChecked(g_Config.iAnisotropyLevel == 0); + ui->action_AF2x->setChecked(g_Config.iAnisotropyLevel == 2); + ui->action_AF4x->setChecked(g_Config.iAnisotropyLevel == 4); + ui->action_AF8x->setChecked(g_Config.iAnisotropyLevel == 8); + ui->action_AF16x->setChecked(g_Config.iAnisotropyLevel == 16); + + ui->action_OptionsBufferedRendering->setChecked(g_Config.bBufferedRendering); + ui->action_OptionsLinearFiltering->setChecked(g_Config.bLinearFiltering); + ui->action_Simple_2xAA->setChecked(g_Config.SSAntiAliasing); + + ui->action_OptionsScreen1x->setChecked(0 == (g_Config.iWindowZoom - 1)); + ui->action_OptionsScreen2x->setChecked(1 == (g_Config.iWindowZoom - 1)); + ui->action_OptionsScreen3x->setChecked(2 == (g_Config.iWindowZoom - 1)); + ui->action_OptionsScreen4x->setChecked(3 == (g_Config.iWindowZoom - 1)); + + ui->action_Stretch_to_display->setChecked(g_Config.bStretchToDisplay); + ui->action_OptionsHardwareTransform->setChecked(g_Config.bHardwareTransform); + ui->action_OptionsUseVBO->setChecked(g_Config.bUseVBO); + ui->action_OptionsVertexCache->setChecked(g_Config.bVertexCache); + ui->action_OptionsWireframe->setChecked(g_Config.bDrawWireframe); + ui->action_OptionsDisplayRawFramebuffer->setChecked(g_Config.bDisplayFramebuffer); + ui->actionFrameskip->setChecked(g_Config.iFrameSkip != 0); + + ui->action_Sound->setChecked(g_Config.bEnableSound); + + ui->action_OptionsShowDebugStatistics->setChecked(g_Config.bShowDebugStats); + ui->action_Show_FPS_counter->setChecked(g_Config.bShowFPSCounter); + + ui->actionLogDefDebug->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::COMMON) == LogTypes::LDEBUG); + ui->actionLogDefInfo->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::COMMON) == LogTypes::LINFO); + ui->actionLogDefWarning->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::COMMON) == LogTypes::LWARNING); + ui->actionLogDefError->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::COMMON) == LogTypes::LERROR); + + ui->actionLogG3DDebug->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::G3D) == LogTypes::LDEBUG); + ui->actionLogG3DInfo->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::G3D) == LogTypes::LINFO); + ui->actionLogG3DWarning->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::G3D) == LogTypes::LWARNING); + ui->actionLogG3DError->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::G3D) == LogTypes::LERROR); + + ui->actionLogHLEDebug->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::HLE) == LogTypes::LDEBUG); + ui->actionLogHLEInfo->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::HLE) == LogTypes::LINFO); + ui->actionLogHLEWarning->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::HLE) == LogTypes::LWARNING); + ui->actionLogHLEError->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::HLE) == LogTypes::LERROR); +} + +void MainWindow::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) + ui->retranslateUi(this); +} + +void MainWindow::closeEvent(QCloseEvent *) +{ + on_action_FileExit_triggered(); +} + +void MainWindow::keyPressEvent(QKeyEvent *e) +{ + if(isFullScreen() && e->key() == Qt::Key_F12) + { + on_action_OptionsFullScreen_triggered(); + return; + } + + pressedKeys.insert(e->key()); +} + +void MainWindow::keyReleaseEvent(QKeyEvent *e) +{ + pressedKeys.remove(e->key()); +} + +/* SLOTS */ void MainWindow::Boot() { dialogDisasm = new Debugger_Disasm(currentDebugMIPS, this, this); @@ -211,10 +308,7 @@ void MainWindow::Boot() memoryTexWindow = new Debugger_MemoryTex(this); displaylistWindow = new Debugger_DisplayList(currentDebugMIPS, this, this); - if (dialogDisasm) - dialogDisasm->NotifyMapLoaded(); - if (memoryWindow) - memoryWindow->NotifyMapLoaded(); + notifyMapsLoaded(); if (nextState == CORE_RUNNING) on_action_EmulationRun_triggered(); @@ -227,130 +321,22 @@ void MainWindow::CoreEmitWait(bool isWaiting) EmuThread_LockDraw(!isWaiting); } -void MainWindow::UpdateMenus() -{ - ui->action_OptionsDisplayRawFramebuffer->setChecked(g_Config.bDisplayFramebuffer); - ui->action_OptionsIgnoreIllegalReadsWrites->setChecked(g_Config.bIgnoreBadMemAccess); - ui->action_CPUInterpreter->setChecked(!g_Config.bJit); - ui->action_CPUDynarec->setChecked(g_Config.bJit); - ui->action_OptionsBufferedRendering->setChecked(g_Config.bBufferedRendering); - ui->action_OptionsShowDebugStatistics->setChecked(g_Config.bShowDebugStats); - ui->action_OptionsWireframe->setChecked(g_Config.bDrawWireframe); - ui->action_OptionsHardwareTransform->setChecked(g_Config.bHardwareTransform); - ui->action_OptionsFastMemory->setChecked(g_Config.bFastMemory); - ui->action_OptionsLinearFiltering->setChecked(g_Config.bLinearFiltering); - ui->action_EmulationRunLoad->setChecked(g_Config.bAutoRun); - ui->action_OptionsUseVBO->setChecked(g_Config.bUseVBO); - ui->action_OptionsVertexCache->setChecked(g_Config.bVertexCache); - ui->action_AFOff->setChecked(g_Config.iAnisotropyLevel == 0); - ui->action_AF2x->setChecked(g_Config.iAnisotropyLevel == 2); - ui->action_AF4x->setChecked(g_Config.iAnisotropyLevel == 4); - ui->action_AF8x->setChecked(g_Config.iAnisotropyLevel == 8); - ui->action_AF16x->setChecked(g_Config.iAnisotropyLevel == 16); - ui->action_Simple_2xAA->setChecked(g_Config.SSAntiAliasing); - ui->action_Show_FPS_counter->setChecked(g_Config.bShowFPSCounter); - ui->action_Stretch_to_display->setChecked(g_Config.bStretchToDisplay); - ui->action_Sound->setChecked(g_Config.bEnableSound); - - bool enable = !Core_IsStepping() ? false : true; - ui->action_EmulationRun->setEnabled(g_State.bEmuThreadStarted ? enable : false); - ui->action_EmulationPause->setEnabled(g_State.bEmuThreadStarted ? !enable : false); - ui->action_EmulationReset->setEnabled(g_State.bEmuThreadStarted ? true : false); - - enable = g_State.bEmuThreadStarted ? false : true; - ui->action_FileLoad->setEnabled(enable); - ui->action_FileSaveStateFile->setEnabled(!enable); - ui->action_FileLoadStateFile->setEnabled(!enable); - ui->action_FileQuickloadState->setEnabled(!enable); - ui->action_FileQuickSaveState->setEnabled(!enable); - ui->action_CPUDynarec->setEnabled(enable); - ui->action_CPUInterpreter->setEnabled(enable); - ui->action_EmulationStop->setEnabled(!enable); - ui->action_DebugDumpFrame->setEnabled(!enable); - ui->action_DebugDisassembly->setEnabled(!enable); - ui->action_DebugMemoryView->setEnabled(!enable); - ui->action_DebugMemoryViewTexture->setEnabled(!enable); - ui->action_DebugDisplayList->setEnabled(!enable); - - ui->action_OptionsScreen1x->setChecked(0 == (g_Config.iWindowZoom - 1)); - ui->action_OptionsScreen2x->setChecked(1 == (g_Config.iWindowZoom - 1)); - ui->action_OptionsScreen3x->setChecked(2 == (g_Config.iWindowZoom - 1)); - ui->action_OptionsScreen4x->setChecked(3 == (g_Config.iWindowZoom - 1)); - - ui->actionLogG3DDebug->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::G3D) == LogTypes::LDEBUG); - ui->actionLogG3DInfo->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::G3D) == LogTypes::LINFO); - ui->actionLogG3DWarning->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::G3D) == LogTypes::LWARNING); - ui->actionLogG3DError->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::G3D) == LogTypes::LERROR); - - ui->actionLogHLEDebug->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::HLE) == LogTypes::LDEBUG); - ui->actionLogHLEInfo->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::HLE) == LogTypes::LINFO); - ui->actionLogHLEWarning->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::HLE) == LogTypes::LWARNING); - ui->actionLogHLEError->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::HLE) == LogTypes::LERROR); - - ui->actionLogDefDebug->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::COMMON) == LogTypes::LDEBUG); - ui->actionLogDefInfo->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::COMMON) == LogTypes::LINFO); - ui->actionLogDefWarning->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::COMMON) == LogTypes::LWARNING); - ui->actionLogDefError->setChecked(LogManager::GetInstance()->GetLogLevel(LogTypes::COMMON) == LogTypes::LERROR); -} - -void MainWindow::SetZoom(float zoom) { - if (zoom < 5) - g_Config.iWindowZoom = (int) zoom; - - pixel_xres = 480 * zoom; - pixel_yres = 272 * zoom; - dp_xres = pixel_xres; - dp_yres = pixel_yres; - - emugl->resize(pixel_xres, pixel_yres); - emugl->setMinimumSize(pixel_xres, pixel_yres); - emugl->setMaximumSize(pixel_xres, pixel_yres); - - ui->centralwidget->setFixedSize(pixel_xres, pixel_yres); - ui->centralwidget->resize(pixel_xres, pixel_yres); - - setFixedSize(sizeHint()); - resize(sizeHint()); - - PSP_CoreParameter().pixelWidth = pixel_xres; - PSP_CoreParameter().pixelHeight = pixel_yres; - PSP_CoreParameter().outputWidth = pixel_xres; - PSP_CoreParameter().outputHeight = pixel_yres; - - if (g_Config.SSAntiAliasing) - { - zoom *= 2; - PSP_CoreParameter().renderWidth = 480 * zoom; - PSP_CoreParameter().renderHeight = 272 * zoom; - } - - if (gpu) - gpu->Resized(); -} - void MainWindow::on_action_FileLoad_triggered() { - BrowseAndBoot(); -} - -void MainWindow::on_action_EmulationRun_triggered() -{ - if (g_State.bEmuThreadStarted) + QString filename = QFileDialog::getOpenFileName(NULL, "Load File", g_Config.currentDirectory.c_str(), "PSP ROMs (*.pbp *.elf *.iso *.cso *.prx)"); + if (QFile::exists(filename)) { - if(dialogDisasm) - { - dialogDisasm->Stop(); - dialogDisasm->Go(); - } + QFileInfo info(filename); + g_Config.currentDirectory = info.absolutePath().toStdString(); + EmuThread_StartGame(filename); } } -void MainWindow::on_action_EmulationStop_triggered() +void MainWindow::on_action_FileClose_triggered() { if(dialogDisasm) - { dialogDisasm->Stop(); - } + // This will wait for ppsspp to pause EmuThread_LockDraw(true); EmuThread_LockDraw(false); @@ -369,12 +355,6 @@ void MainWindow::on_action_EmulationStop_triggered() UpdateMenus(); } -void MainWindow::on_action_EmulationPause_triggered() -{ - if(dialogDisasm) - dialogDisasm->Stop(); -} - void SaveStateActionFinished(bool result, void *userdata) { // TODO: Improve messaging? @@ -386,89 +366,258 @@ void SaveStateActionFinished(bool result, void *userdata) msgBox.exec(); return; } +} - MainWindow* mainWindow = (MainWindow*)userdata; +void MainWindow::on_action_FileQuickloadState_triggered() +{ + SaveState::LoadSlot(0, SaveStateActionFinished, this); +} - if (g_State.bEmuThreadStarted && mainWindow->GetNextState() == CORE_RUNNING) - { - if(mainWindow->GetDialogDisasm()) - mainWindow->GetDialogDisasm()->Go(); - } +void MainWindow::on_action_FileQuickSaveState_triggered() +{ + SaveState::SaveSlot(0, SaveStateActionFinished, this); } void MainWindow::on_action_FileLoadStateFile_triggered() { - if (g_State.bEmuThreadStarted) - { - nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; - if(dialogDisasm) - { - dialogDisasm->Stop(); - } - } QFileDialog dialog(0,"Load state"); dialog.setFileMode(QFileDialog::ExistingFile); QStringList filters; filters << "Save States (*.ppst)" << "|All files (*.*)"; dialog.setNameFilters(filters); dialog.setAcceptMode(QFileDialog::AcceptOpen); - QStringList fileNames; if (dialog.exec()) { - fileNames = dialog.selectedFiles(); + QStringList fileNames = dialog.selectedFiles(); SaveState::Load(fileNames[0].toStdString(), SaveStateActionFinished, this); } } - void MainWindow::on_action_FileSaveStateFile_triggered() { - if (g_State.bEmuThreadStarted) - { - nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; - if(dialogDisasm) - { - dialogDisasm->Stop(); - } - } QFileDialog dialog(0,"Save state"); dialog.setFileMode(QFileDialog::AnyFile); dialog.setAcceptMode(QFileDialog::AcceptSave); QStringList filters; filters << "Save States (*.ppst)" << "|All files (*.*)"; dialog.setNameFilters(filters); - QStringList fileNames; if (dialog.exec()) { - fileNames = dialog.selectedFiles(); + QStringList fileNames = dialog.selectedFiles(); SaveState::Save(fileNames[0].toStdString(), SaveStateActionFinished, this); } } -void MainWindow::on_action_FileQuickloadState_triggered() +void MainWindow::on_action_FileExit_triggered() { - if (g_State.bEmuThreadStarted) - { - nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; - if(dialogDisasm) - { - dialogDisasm->Stop(); - } - } - SaveState::LoadSlot(0, SaveStateActionFinished, this); + on_action_FileClose_triggered(); + EmuThread_Stop(); + QApplication::exit(0); } -void MainWindow::on_action_FileQuickSaveState_triggered() +void MainWindow::on_action_EmulationRun_triggered() { if (g_State.bEmuThreadStarted) { - nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; if(dialogDisasm) { dialogDisasm->Stop(); + dialogDisasm->Go(); } } - SaveState::SaveSlot(0, SaveStateActionFinished, this); +} + +void MainWindow::on_action_EmulationPause_triggered() +{ + if(dialogDisasm) + dialogDisasm->Stop(); +} + +void MainWindow::on_action_EmulationReset_triggered() +{ + if(dialogDisasm) + dialogDisasm->Stop(); + + EmuThread_LockDraw(true); + EmuThread_LockDraw(false); + + if(dialogDisasm) + dialogDisasm->close(); + if(memoryWindow) + memoryWindow->close(); + if(memoryTexWindow) + memoryTexWindow->close(); + if(displaylistWindow) + displaylistWindow->close(); + + EmuThread_StopGame(); + + EmuThread_StartGame(GetCurrentFilename()); +} + +void MainWindow::on_action_EmulationRunLoad_triggered() +{ + g_Config.bAutoRun = !g_Config.bAutoRun; + UpdateMenus(); +} + +void MainWindow::on_action_DebugLoadMapFile_triggered() +{ + QFileDialog dialog(0,"Load .MAP"); + dialog.setFileMode(QFileDialog::ExistingFile); + QStringList filters; + filters << "Maps (*.map)" << "|All files (*.*)"; + dialog.setNameFilters(filters); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + QStringList fileNames; + if (dialog.exec()) + { + fileNames = dialog.selectedFiles(); + symbolMap.LoadSymbolMap(fileNames[0].toStdString().c_str()); + notifyMapsLoaded(); + } +} + +void MainWindow::on_action_DebugSaveMapFile_triggered() +{ + QFileDialog dialog(0,"Save .MAP"); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setAcceptMode(QFileDialog::AcceptSave); + QStringList filters; + filters << "Save .MAP (*.map)" << "|All files (*.*)"; + dialog.setNameFilters(filters); + QStringList fileNames; + if (dialog.exec()) + { + fileNames = dialog.selectedFiles(); + symbolMap.SaveSymbolMap(fileNames[0].toStdString().c_str()); + } +} + +void MainWindow::on_action_DebugResetSymbolTable_triggered() +{ + symbolMap.ResetSymbolMap(); + notifyMapsLoaded(); +} + +void MainWindow::on_action_DebugDumpFrame_triggered() +{ + gpu->DumpNextFrame(); +} + +void MainWindow::on_action_DebugDisassembly_triggered() +{ + if(dialogDisasm) + dialogDisasm->show(); +} + +void MainWindow::on_action_DebugDisplayList_triggered() +{ + if(displaylistWindow) + displaylistWindow->show(); +} + +void MainWindow::on_action_DebugLog_triggered() +{ + LogManager::GetInstance()->GetConsoleListener()->Show(LogManager::GetInstance()->GetConsoleListener()->Hidden()); +} + +void MainWindow::on_action_DebugMemoryView_triggered() +{ + if (memoryWindow) + memoryWindow->show(); +} + +void MainWindow::on_action_DebugMemoryViewTexture_triggered() +{ + if(memoryTexWindow) + memoryTexWindow->show(); +} + +void MainWindow::on_action_CPUDynarec_triggered() +{ + g_Config.bJit = true; + UpdateMenus(); +} + +void MainWindow::on_action_CPUInterpreter_triggered() +{ + g_Config.bJit = false; + UpdateMenus(); +} + +void MainWindow::on_action_OptionsFastMemory_triggered() +{ + g_Config.bFastMemory = !g_Config.bFastMemory; + UpdateMenus(); +} + +void MainWindow::on_action_OptionsIgnoreIllegalReadsWrites_triggered() +{ + g_Config.bIgnoreBadMemAccess = !g_Config.bIgnoreBadMemAccess; + UpdateMenus(); +} + +void MainWindow::on_action_OptionsControls_triggered() +{ + controls->show(); +} + +void MainWindow::on_action_OptionsGamePadControls_triggered() +{ +#if QT_HAS_SDL + gamePadDlg->show(); +#else + QMessageBox::information(this,tr("Gamepad"),tr("You need to compile with SDL to have Gamepad support."), QMessageBox::Ok); +#endif +} + +void MainWindow::on_action_AFOff_triggered() +{ + g_Config.iAnisotropyLevel = 0; + UpdateMenus(); +} + +void MainWindow::on_action_AF2x_triggered() +{ + g_Config.iAnisotropyLevel = 2; + UpdateMenus(); +} + +void MainWindow::on_action_AF4x_triggered() +{ + g_Config.iAnisotropyLevel = 4; + UpdateMenus(); +} + +void MainWindow::on_action_AF8x_triggered() +{ + g_Config.iAnisotropyLevel = 8; + UpdateMenus(); +} + +void MainWindow::on_action_AF16x_triggered() +{ + g_Config.iAnisotropyLevel = 16; + UpdateMenus(); +} + +void MainWindow::on_action_OptionsBufferedRendering_triggered() +{ + g_Config.bBufferedRendering = !g_Config.bBufferedRendering; + UpdateMenus(); +} + +void MainWindow::on_action_OptionsLinearFiltering_triggered() +{ + g_Config.bLinearFiltering = !g_Config.bLinearFiltering; + UpdateMenus(); +} + +void MainWindow::on_action_Simple_2xAA_triggered() +{ + g_Config.SSAntiAliasing = !g_Config.SSAntiAliasing; + UpdateMenus(); } void MainWindow::on_action_OptionsScreen1x_triggered() @@ -495,16 +644,12 @@ void MainWindow::on_action_OptionsScreen4x_triggered() UpdateMenus(); } -void MainWindow::on_action_OptionsBufferedRendering_triggered() +void MainWindow::on_action_Stretch_to_display_triggered() { - g_Config.bBufferedRendering = !g_Config.bBufferedRendering; - UpdateMenus(); -} - -void MainWindow::on_action_OptionsShowDebugStatistics_triggered() -{ - g_Config.bShowDebugStats = !g_Config.bShowDebugStats; + g_Config.bStretchToDisplay = !g_Config.bStretchToDisplay; UpdateMenus(); + if (gpu) + gpu->Resized(); } void MainWindow::on_action_OptionsHardwareTransform_triggered() @@ -513,90 +658,39 @@ void MainWindow::on_action_OptionsHardwareTransform_triggered() UpdateMenus(); } -void MainWindow::on_action_FileExit_triggered() +void MainWindow::on_action_OptionsUseVBO_triggered() { - on_action_EmulationStop_triggered(); - EmuThread_Stop(); - QApplication::exit(0); -} - -void MainWindow::on_action_CPUDynarec_triggered() -{ - g_Config.bJit = true; + g_Config.bUseVBO = !g_Config.bUseVBO; UpdateMenus(); } -void MainWindow::on_action_CPUInterpreter_triggered() +void MainWindow::on_action_OptionsVertexCache_triggered() { - g_Config.bJit = false; + g_Config.bVertexCache = !g_Config.bVertexCache; UpdateMenus(); } -void MainWindow::on_action_DebugLoadMapFile_triggered() +void MainWindow::on_action_OptionsWireframe_triggered() { - QFileDialog dialog(0,"Load .MAP"); - dialog.setFileMode(QFileDialog::ExistingFile); - QStringList filters; - filters << "Maps (*.map)" << "|All files (*.*)"; - dialog.setNameFilters(filters); - dialog.setAcceptMode(QFileDialog::AcceptOpen); - QStringList fileNames; - if (dialog.exec()) - { - fileNames = dialog.selectedFiles(); - symbolMap.LoadSymbolMap(fileNames[0].toStdString().c_str()); - if (dialogDisasm) - dialogDisasm->NotifyMapLoaded(); - if (memoryWindow) - memoryWindow->NotifyMapLoaded(); - } + g_Config.bDrawWireframe = !g_Config.bDrawWireframe; + UpdateMenus(); } -void MainWindow::on_action_DebugSaveMapFile_triggered() +void MainWindow::on_action_OptionsDisplayRawFramebuffer_triggered() { - QFileDialog dialog(0,"Save .MAP"); - dialog.setFileMode(QFileDialog::AnyFile); - dialog.setAcceptMode(QFileDialog::AcceptSave); - QStringList filters; - filters << "Save .MAP (*.map)" << "|All files (*.*)"; - dialog.setNameFilters(filters); - QStringList fileNames; - if (dialog.exec()) - { - fileNames = dialog.selectedFiles(); - symbolMap.SaveSymbolMap(fileNames[0].toStdString().c_str()); - } + g_Config.bDisplayFramebuffer = !g_Config.bDisplayFramebuffer; + UpdateMenus(); } -void MainWindow::on_action_DebugResetSymbolTable_triggered() +void MainWindow::on_actionFrameskip_triggered() { - symbolMap.ResetSymbolMap(); - if (dialogDisasm) - dialogDisasm->NotifyMapLoaded(); - if (memoryWindow) - memoryWindow->NotifyMapLoaded(); + g_Config.iFrameSkip = !g_Config.iFrameSkip; + UpdateMenus(); } -void MainWindow::on_action_DebugDisassembly_triggered() +void MainWindow::on_action_Sound_triggered() { - if(dialogDisasm) - dialogDisasm->show(); -} - -void MainWindow::on_action_DebugMemoryView_triggered() -{ - if (memoryWindow) - memoryWindow->show(); -} - -void MainWindow::on_action_DebugLog_triggered() -{ - LogManager::GetInstance()->GetConsoleListener()->Show(LogManager::GetInstance()->GetConsoleListener()->Hidden()); -} - -void MainWindow::on_action_OptionsIgnoreIllegalReadsWrites_triggered() -{ - g_Config.bIgnoreBadMemAccess = !g_Config.bIgnoreBadMemAccess; + g_Config.bEnableSound = !g_Config.bEnableSound; UpdateMenus(); } @@ -643,69 +737,50 @@ void MainWindow::on_action_OptionsFullScreen_triggered() } } -void MainWindow::on_action_OptionsWireframe_triggered() +void MainWindow::on_action_OptionsShowDebugStatistics_triggered() { - g_Config.bDrawWireframe = !g_Config.bDrawWireframe; + g_Config.bShowDebugStats = !g_Config.bShowDebugStats; UpdateMenus(); } -void MainWindow::on_action_OptionsDisplayRawFramebuffer_triggered() +void MainWindow::on_action_Show_FPS_counter_triggered() { - g_Config.bDisplayFramebuffer = !g_Config.bDisplayFramebuffer; + g_Config.bShowFPSCounter = !g_Config.bShowFPSCounter; UpdateMenus(); } -void MainWindow::on_action_OptionsFastMemory_triggered() +void setDefLogLevel(LogTypes::LOG_LEVELS level) { - g_Config.bFastMemory = !g_Config.bFastMemory; - UpdateMenus(); -} - -void MainWindow::on_action_OptionsLinearFiltering_triggered() -{ - g_Config.bLinearFiltering = !g_Config.bLinearFiltering; - UpdateMenus(); -} - -void MainWindow::on_action_OptionsControls_triggered() -{ - controls->show(); -} - -void MainWindow::on_action_HelpOpenWebsite_triggered() -{ - QDesktopServices::openUrl(QUrl("http://www.ppsspp.org/")); -} - -void MainWindow::on_action_HelpAbout_triggered() -{ - // TODO display about -} - -void MainWindow::closeEvent(QCloseEvent *event) -{ - on_action_FileExit_triggered(); -} - -void MainWindow::keyPressEvent(QKeyEvent *e) -{ - if(isFullScreen() && e->key() == Qt::Key_F12) + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) { - on_action_OptionsFullScreen_triggered(); - return; + LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i; + if(type == LogTypes::G3D || type == LogTypes::HLE) continue; + LogManager::GetInstance()->SetLogLevel(type, level); } - - pressedKeys.insert(e->key()); } -void MainWindow::keyReleaseEvent(QKeyEvent *e) +void MainWindow::on_actionLogDefDebug_triggered() { - pressedKeys.remove(e->key()); + setDefLogLevel(LogTypes::LDEBUG); + UpdateMenus(); } -void MainWindow::on_MainWindow_destroyed() +void MainWindow::on_actionLogDefWarning_triggered() { + setDefLogLevel(LogTypes::LWARNING); + UpdateMenus(); +} +void MainWindow::on_actionLogDefInfo_triggered() +{ + setDefLogLevel(LogTypes::LINFO); + UpdateMenus(); +} + +void MainWindow::on_actionLogDefError_triggered() +{ + setDefLogLevel(LogTypes::LERROR); + UpdateMenus(); } void MainWindow::on_actionLogG3DDebug_triggered() @@ -756,65 +831,64 @@ void MainWindow::on_actionLogHLEError_triggered() UpdateMenus(); } -void MainWindow::on_actionLogDefDebug_triggered() +void MainWindow::on_action_HelpOpenWebsite_triggered() { - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) - { - LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i; - if(type == LogTypes::G3D || type == LogTypes::HLE) continue; - LogManager::GetInstance()->SetLogLevel(type, LogTypes::LDEBUG); - } - UpdateMenus(); + QDesktopServices::openUrl(QUrl("http://www.ppsspp.org/")); } -void MainWindow::on_actionLogDefWarning_triggered() +void MainWindow::on_action_HelpAbout_triggered() { - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) - { - LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i; - if(type == LogTypes::G3D || type == LogTypes::HLE) continue; - LogManager::GetInstance()->SetLogLevel(type, LogTypes::LWARNING); - } - UpdateMenus(); -} - -void MainWindow::on_actionLogDefInfo_triggered() -{ - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) - { - LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i; - if(type == LogTypes::G3D || type == LogTypes::HLE) continue; - LogManager::GetInstance()->SetLogLevel(type, LogTypes::LINFO); - } - UpdateMenus(); -} - -void MainWindow::on_actionLogDefError_triggered() -{ - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) - { - LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i; - if(type == LogTypes::G3D || type == LogTypes::HLE) continue; - LogManager::GetInstance()->SetLogLevel(type, LogTypes::LERROR); - } - UpdateMenus(); -} - -void MainWindow::on_action_OptionsGamePadControls_triggered() -{ -#if QT_HAS_SDL - gamePadDlg->show(); -#else - QMessageBox::information(this,"Gamepad","You need to compile with SDL to have Gamepad support.", QMessageBox::Ok); -#endif + // TODO display about } void MainWindow::on_language_changed(QAction *action) { - if (0 != action) + loadLanguage(action->data().toString()); +} + +/* Private functions */ +void MainWindow::SetZoom(float zoom) { + if (zoom < 5) + g_Config.iWindowZoom = (int) zoom; + + pixel_xres = 480 * zoom; + pixel_yres = 272 * zoom; + dp_xres = pixel_xres; + dp_yres = pixel_yres; + + emugl->resize(pixel_xres, pixel_yres); + emugl->setMinimumSize(pixel_xres, pixel_yres); + emugl->setMaximumSize(pixel_xres, pixel_yres); + + ui->centralwidget->setFixedSize(pixel_xres, pixel_yres); + ui->centralwidget->resize(pixel_xres, pixel_yres); + + setFixedSize(sizeHint()); + resize(sizeHint()); + + PSP_CoreParameter().pixelWidth = pixel_xres; + PSP_CoreParameter().pixelHeight = pixel_yres; + PSP_CoreParameter().outputWidth = pixel_xres; + PSP_CoreParameter().outputHeight = pixel_yres; + + if (g_Config.SSAntiAliasing) { - loadLanguage(action->data().toString()); + zoom *= 2; + PSP_CoreParameter().renderWidth = 480 * zoom; + PSP_CoreParameter().renderHeight = 272 * zoom; } + + if (gpu) + gpu->Resized(); +} + +void MainWindow::SetGameTitle(QString text) +{ + QString title = "PPSSPP " + QString(PPSSPP_VERSION_STR); + if (text != "") + title += QString(" - %1").arg(text); + + setWindowTitle(title); } void switchTranslator(QTranslator &translator, const QString &filename) @@ -830,9 +904,7 @@ void MainWindow::loadLanguage(const QString& language) if (currentLanguage != language) { currentLanguage = language; - QLocale locale = QLocale(currentLanguage); - QLocale::setDefault(locale); - QString languageName = QLocale::languageToString(locale.language()); + QLocale::setDefault(QLocale(currentLanguage)); switchTranslator(translator, QString(":/languages/ppsspp_%1.qm").arg(language)); } } @@ -844,8 +916,6 @@ void MainWindow::createLanguageMenu() connect(langGroup, SIGNAL(triggered(QAction *)), this, SLOT(on_language_changed(QAction *))); - QString defaultLocale = QLocale::system().name(); - defaultLocale.truncate(defaultLocale.lastIndexOf('_')); QStringList fileNames = QDir(":/languages").entryList(QStringList("ppsspp_*.qm")); if (fileNames.size() == 0) @@ -884,160 +954,10 @@ void MainWindow::createLanguageMenu() } } -void MainWindow::changeEvent(QEvent *event) +void MainWindow::notifyMapsLoaded() { - QMainWindow::changeEvent(event); - - if (0 != event) - { - switch (event->type()) - { - case QEvent::LanguageChange: - ui->retranslateUi(this); - break; - case QEvent::LocaleChange: - { - QString locale = QLocale::system().name(); - locale.truncate(locale.lastIndexOf('_')); - loadLanguage(locale); - } - break; - default: - break; - } - } -} - -void MainWindow::ShowMemory(u32 addr) -{ - if(memoryWindow) - memoryWindow->Goto(addr); -} - -void MainWindow::Update() -{ - UpdateInputState(&input_state); - - for (int i = 0; i < controllistCount; i++) - { - if (pressedKeys.contains(controllist[i].key) || - input_state.pad_buttons_down & controllist[i].emu_id) - __CtrlButtonDown(controllist[i].psp_id); - else - __CtrlButtonUp(controllist[i].psp_id); - } - __CtrlSetAnalog(input_state.pad_lstick_x, input_state.pad_lstick_y); -} - -void MainWindow::on_action_EmulationReset_triggered() -{ - if(dialogDisasm) - dialogDisasm->Stop(); - - EmuThread_LockDraw(true); - EmuThread_LockDraw(false); - - if(dialogDisasm) - dialogDisasm->close(); - if(memoryWindow) - memoryWindow->close(); - if(memoryTexWindow) - memoryTexWindow->close(); - if(displaylistWindow) - displaylistWindow->close(); - - EmuThread_StopGame(); - - EmuThread_StartGame(GetCurrentFilename()); -} - -void MainWindow::on_action_DebugDumpFrame_triggered() -{ - gpu->DumpNextFrame(); -} - -void MainWindow::on_action_EmulationRunLoad_triggered() -{ - g_Config.bAutoRun = !g_Config.bAutoRun; - UpdateMenus(); -} - -void MainWindow::on_action_OptionsVertexCache_triggered() -{ - g_Config.bVertexCache = !g_Config.bVertexCache; - UpdateMenus(); -} - -void MainWindow::on_action_OptionsUseVBO_triggered() -{ - g_Config.bUseVBO = !g_Config.bUseVBO; - UpdateMenus(); -} - -void MainWindow::on_action_Simple_2xAA_triggered() -{ - g_Config.SSAntiAliasing = !g_Config.SSAntiAliasing; - UpdateMenus(); -} - -void MainWindow::on_action_AFOff_triggered() -{ - g_Config.iAnisotropyLevel = 0; - UpdateMenus(); -} - -void MainWindow::on_action_AF2x_triggered() -{ - g_Config.iAnisotropyLevel = 2; - UpdateMenus(); -} - -void MainWindow::on_action_AF4x_triggered() -{ - g_Config.iAnisotropyLevel = 4; - UpdateMenus(); -} - -void MainWindow::on_action_AF8x_triggered() -{ - g_Config.iAnisotropyLevel = 8; - UpdateMenus(); -} - -void MainWindow::on_action_AF16x_triggered() -{ - g_Config.iAnisotropyLevel = 16; - UpdateMenus(); -} - -void MainWindow::on_action_Show_FPS_counter_triggered() -{ - g_Config.bShowFPSCounter = !g_Config.bShowFPSCounter; - UpdateMenus(); -} - -void MainWindow::on_action_Stretch_to_display_triggered() -{ - g_Config.bStretchToDisplay = !g_Config.bStretchToDisplay; - UpdateMenus(); - if (gpu) - gpu->Resized(); -} - -void MainWindow::on_action_Sound_triggered() -{ - g_Config.bEnableSound = !g_Config.bEnableSound; - UpdateMenus(); -} - -void MainWindow::on_action_DebugMemoryViewTexture_triggered() -{ - if(memoryTexWindow) - memoryTexWindow->show(); -} - -void MainWindow::on_action_DebugDisplayList_triggered() -{ - if(displaylistWindow) - displaylistWindow->show(); + if (dialogDisasm) + dialogDisasm->NotifyMapLoaded(); + if (memoryWindow) + memoryWindow->NotifyMapLoaded(); } diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index d2de287927..cb0af14bb0 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -24,182 +24,142 @@ class MainWindow : public QMainWindow public: explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - - void UpdateMenus(); - void SetZoom(float zoom); - void Create(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID); - void BrowseAndBoot(); - void SetNextState(CoreState state); - void SetGameTitle(QString text); + ~MainWindow(); Debugger_Disasm* GetDialogDisasm() { return dialogDisasm; } Debugger_Memory* GetDialogMemory() { return memoryWindow; } Debugger_MemoryTex* GetDialogMemoryTex() { return memoryTexWindow; } Debugger_DisplayList* GetDialogDisplaylist() { return displaylistWindow; } CoreState GetNextState() { return nextState; } - void closeEvent(QCloseEvent *event); - void keyPressEvent(QKeyEvent *); - void keyReleaseEvent(QKeyEvent *e); + void ShowMemory(u32 addr); void Update(); -public slots: + void UpdateMenus(); +protected: + void changeEvent(QEvent *e); + void closeEvent(QCloseEvent *); + void keyPressEvent(QKeyEvent *e); + void keyReleaseEvent(QKeyEvent *e); + +public slots: void Boot(); void CoreEmitWait(bool); private slots: + // File void on_action_FileLoad_triggered(); - - void on_action_EmulationRun_triggered(); - - void on_action_EmulationStop_triggered(); - - void on_action_EmulationPause_triggered(); - - void on_action_FileLoadStateFile_triggered(); - - void on_action_FileSaveStateFile_triggered(); - + void on_action_FileClose_triggered(); void on_action_FileQuickloadState_triggered(); - void on_action_FileQuickSaveState_triggered(); - - void on_action_OptionsScreen1x_triggered(); - - void on_action_OptionsScreen2x_triggered(); - - void on_action_OptionsScreen3x_triggered(); - - void on_action_OptionsScreen4x_triggered(); - - void on_action_OptionsBufferedRendering_triggered(); - - void on_action_OptionsShowDebugStatistics_triggered(); - - void on_action_OptionsHardwareTransform_triggered(); - + void on_action_FileLoadStateFile_triggered(); + void on_action_FileSaveStateFile_triggered(); void on_action_FileExit_triggered(); - void on_action_CPUDynarec_triggered(); - - void on_action_CPUInterpreter_triggered(); + // Emulation + void on_action_EmulationRun_triggered(); + void on_action_EmulationPause_triggered(); + void on_action_EmulationReset_triggered(); + void on_action_EmulationRunLoad_triggered(); + // Debug void on_action_DebugLoadMapFile_triggered(); - void on_action_DebugSaveMapFile_triggered(); - void on_action_DebugResetSymbolTable_triggered(); - + void on_action_DebugDumpFrame_triggered(); void on_action_DebugDisassembly_triggered(); - - void on_action_DebugMemoryView_triggered(); - + void on_action_DebugDisplayList_triggered(); void on_action_DebugLog_triggered(); + void on_action_DebugMemoryView_triggered(); + void on_action_DebugMemoryViewTexture_triggered(); + // Options + // Core + void on_action_CPUDynarec_triggered(); + void on_action_CPUInterpreter_triggered(); + void on_action_OptionsFastMemory_triggered(); void on_action_OptionsIgnoreIllegalReadsWrites_triggered(); - void on_action_OptionsFullScreen_triggered(); - - void on_action_OptionsWireframe_triggered(); - - void on_action_OptionsDisplayRawFramebuffer_triggered(); - - void on_action_OptionsFastMemory_triggered(); - - void on_action_OptionsLinearFiltering_triggered(); - + // Controls void on_action_OptionsControls_triggered(); + void on_action_OptionsGamePadControls_triggered(); - void on_action_HelpOpenWebsite_triggered(); + // Video + void on_action_AFOff_triggered(); + void on_action_AF2x_triggered(); + void on_action_AF4x_triggered(); + void on_action_AF8x_triggered(); + void on_action_AF16x_triggered(); - void on_action_HelpAbout_triggered(); + void on_action_OptionsBufferedRendering_triggered(); + void on_action_OptionsLinearFiltering_triggered(); + void on_action_Simple_2xAA_triggered(); - void on_MainWindow_destroyed(); + void on_action_OptionsScreen1x_triggered(); + void on_action_OptionsScreen2x_triggered(); + void on_action_OptionsScreen3x_triggered(); + void on_action_OptionsScreen4x_triggered(); + + void on_action_Stretch_to_display_triggered(); + void on_action_OptionsHardwareTransform_triggered(); + void on_action_OptionsUseVBO_triggered(); + void on_action_OptionsVertexCache_triggered(); + void on_action_OptionsWireframe_triggered(); + void on_action_OptionsDisplayRawFramebuffer_triggered(); + void on_actionFrameskip_triggered(); + + // Sound + void on_action_Sound_triggered(); + + void on_action_OptionsFullScreen_triggered(); + void on_action_OptionsShowDebugStatistics_triggered(); + void on_action_Show_FPS_counter_triggered(); + + // Logs + void on_actionLogDefDebug_triggered(); + void on_actionLogDefWarning_triggered(); + void on_actionLogDefInfo_triggered(); + void on_actionLogDefError_triggered(); void on_actionLogG3DDebug_triggered(); - void on_actionLogG3DWarning_triggered(); - void on_actionLogG3DError_triggered(); - void on_actionLogG3DInfo_triggered(); void on_actionLogHLEDebug_triggered(); - void on_actionLogHLEWarning_triggered(); - void on_actionLogHLEInfo_triggered(); - void on_actionLogHLEError_triggered(); - void on_actionLogDefDebug_triggered(); - - void on_actionLogDefWarning_triggered(); - - void on_actionLogDefInfo_triggered(); - - void on_actionLogDefError_triggered(); - - void on_action_OptionsGamePadControls_triggered(); + // Help + void on_action_HelpOpenWebsite_triggered(); + void on_action_HelpAbout_triggered(); + // Others void on_language_changed(QAction *action); - void on_action_EmulationReset_triggered(); - - void on_action_DebugDumpFrame_triggered(); - - void on_action_EmulationRunLoad_triggered(); - - void on_action_OptionsVertexCache_triggered(); - - void on_action_OptionsUseVBO_triggered(); - - void on_action_Simple_2xAA_triggered(); - - void on_action_AFOff_triggered(); - - void on_action_AF2x_triggered(); - - void on_action_AF4x_triggered(); - - void on_action_AF8x_triggered(); - - void on_action_AF16x_triggered(); - - void on_action_Show_FPS_counter_triggered(); - - void on_action_Stretch_to_display_triggered(); - - void on_action_Sound_triggered(); - - void on_action_DebugMemoryViewTexture_triggered(); - - void on_action_DebugDisplayList_triggered(); - private: + void SetZoom(float zoom); + void SetGameTitle(QString text); void loadLanguage(const QString &language); void createLanguageMenu(); - void changeEvent(QEvent *); + void notifyMapsLoaded(); QTranslator translator; - QTranslator qtTranslator; QString currentLanguage; - QString languagePath; Ui::MainWindow *ui; - QtEmuGL* emugl; + QtEmuGL *emugl; CoreState nextState; - InputState input_state; Debugger_Disasm *dialogDisasm; Debugger_Memory *memoryWindow; Debugger_MemoryTex *memoryTexWindow; Debugger_DisplayList *displaylistWindow; - Controls* controls; - GamePadDialog* gamePadDlg; + Controls *controls; + GamePadDialog *gamePadDlg; QSet pressedKeys; }; diff --git a/Qt/mainwindow.ui b/Qt/mainwindow.ui index a6ef9df025..6cabbd9838 100644 --- a/Qt/mainwindow.ui +++ b/Qt/mainwindow.ui @@ -44,7 +44,7 @@ 0 0 800 - 23 + 21 @@ -52,7 +52,7 @@ &File - + @@ -169,6 +169,7 @@ + @@ -220,7 +221,7 @@ &Open... - + &Close @@ -695,6 +696,14 @@ &Sound emulation + + + true + + + Frameskip + + diff --git a/Qt/resources.qrc b/Qt/resources.qrc index a6d411f82e..1eee7d4c45 100644 --- a/Qt/resources.qrc +++ b/Qt/resources.qrc @@ -22,5 +22,7 @@ languages/ppsspp_en.qm languages/ppsspp_fr.qm languages/ppsspp_pl.qm + languages/ppsspp_de.qm + languages/ppsspp_tc.qm diff --git a/README.md b/README.md index 6131a815d8..7b644667cf 100644 --- a/README.md +++ b/README.md @@ -103,8 +103,6 @@ other than Microsoft's, but `NMake Makefiles` works fine. Building for iOS ---------------- -Note: This does not work yet. - Create a `build-ios` directory and inside it run: cmake -DCMAKE_TOOLCHAIN_FILE=../ios/ios.toolchain.cmake -GXcode .. diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp index 6692978d96..7f0d044c5d 100644 --- a/Windows/Debugger/Debugger_Disasm.cpp +++ b/Windows/Debugger/Debugger_Disasm.cpp @@ -66,11 +66,11 @@ CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Di tcItem.mask = TCIF_TEXT; tcItem.dwState = 0; tcItem.pszText = "Regs"; - tcItem.cchTextMax = strlen(tcItem.pszText)+1; + tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; tcItem.iImage = 0; int result1 = TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); tcItem.pszText = "Funcs"; - tcItem.cchTextMax = strlen(tcItem.pszText)+1; + tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; int result2 = TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); ShowWindow(GetDlgItem(m_hDlg, IDC_REGLIST), SW_NORMAL); ShowWindow(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), SW_HIDE); diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index ac7e4fc153..ed65398786 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -79,7 +79,6 @@ DWORD TheThread(LPVOID x) coreParameter.pixelWidth = 480 * g_Config.iWindowZoom; coreParameter.pixelHeight = 272 * g_Config.iWindowZoom; coreParameter.startPaused = !g_Config.bAutoRun; - coreParameter.disableG3Dlog = g_Config.bDisableG3DLog; coreParameter.useMediaEngine = false; std::string error_string; diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index b97678aad5..57208e3872 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -73,7 +73,8 @@ namespace MainWindow void Init(HINSTANCE hInstance) { -#ifdef THEMES WTL::CTheme::IsThemingSupported(); +#ifdef THEMES + WTL::CTheme::IsThemingSupported(); #endif //Register classes WNDCLASSEX wcex; @@ -307,7 +308,7 @@ namespace MainWindow if (disasmWindow[i]) SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0); - Sleep(100);//UGLY wait for event instead + Core_WaitInactive(); for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_STOP, 0); - Sleep(100);//UGLY wait for event instead + Core_WaitInactive(); for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_STOP, 0); - } if (W32Util::BrowseForFileName(true, hWnd, "Load state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn)) { SetCursor(LoadCursor(0,IDC_WAIT)); @@ -368,13 +362,6 @@ namespace MainWindow break; case ID_FILE_SAVESTATEFILE: - if (g_State.bEmuThreadStarted) - { - nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; - for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_STOP, 0); - } if (W32Util::BrowseForFileName(false, hWnd, "Save state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn)) { SetCursor(LoadCursor(0,IDC_WAIT)); @@ -385,25 +372,11 @@ namespace MainWindow // TODO: Add UI for multiple slots case ID_FILE_QUICKLOADSTATE: - if (g_State.bEmuThreadStarted) - { - nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; - for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_STOP, 0); - } SetCursor(LoadCursor(0,IDC_WAIT)); SaveState::LoadSlot(0, SaveStateActionFinished); break; case ID_FILE_QUICKSAVESTATE: - if (g_State.bEmuThreadStarted) - { - nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; - for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_STOP, 0); - } SetCursor(LoadCursor(0,IDC_WAIT)); SaveState::SaveSlot(0, SaveStateActionFinished); break; @@ -560,14 +533,6 @@ namespace MainWindow UpdateMenus(); ResizeDisplay(true); break; - case ID_OPTIONS_DISABLEG3DLOG: - g_Config.bDisableG3DLog = !g_Config.bDisableG3DLog; - if (!g_Config.bDisableG3DLog ) - LogManager::GetInstance()->SetEnable(LogTypes::G3D, true); - else - LogManager::GetInstance()->SetEnable(LogTypes::G3D, false); - UpdateMenus(); - break; case ID_OPTIONS_CONTROLS: DialogManager::EnableAll(FALSE); DialogBox(hInst, (LPCTSTR)IDD_CONTROLS, hWnd, (DLGPROC)Controls); @@ -642,7 +607,8 @@ namespace MainWindow break; case WM_CLOSE: - Sleep(100);//UGLY wait for event instead + Core_Stop(); + Core_WaitInactive(200); EmuThread_Stop(); /* @@ -713,7 +679,6 @@ namespace MainWindow CHECKITEM(ID_OPTIONS_STRETCHDISPLAY, g_Config.bStretchToDisplay); CHECKITEM(ID_EMULATION_RUNONLOAD, g_Config.bAutoRun); CHECKITEM(ID_OPTIONS_USEVBO, g_Config.bUseVBO); - CHECKITEM(ID_OPTIONS_DISABLEG3DLOG, g_Config.bDisableG3DLog); CHECKITEM(ID_OPTIONS_VERTEXCACHE, g_Config.bVertexCache); CHECKITEM(ID_OPTIONS_SHOWFPS, g_Config.bShowFPSCounter); CHECKITEM(ID_OPTIONS_FRAMESKIP, g_Config.iFrameSkip != 0); @@ -895,13 +860,6 @@ namespace MainWindow if (!result) MessageBox(0, "Savestate failure. Please try again later.", "Sorry", MB_OK); SetCursor(LoadCursor(0, IDC_ARROW)); - - if (g_State.bEmuThreadStarted && nextState == CORE_RUNNING) - { - for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_GO, 0); - } } void SetNextState(CoreState state) diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 8d0a8e1004..bcde41f217 100644 Binary files a/Windows/ppsspp.rc and b/Windows/ppsspp.rc differ diff --git a/android/ab.cmd b/android/ab.cmd index a3ca5c5b51..36eecad802 100644 --- a/android/ab.cmd +++ b/android/ab.cmd @@ -1,3 +1,4 @@ +xcopy ..\flash0 assets\flash0 /s /y SET NDK=C:\AndroidNDK SET NDK_MODULE_PATH=..;..\native\ext REM Need to force target-platform to android-9 to get access to OpenSL headers. diff --git a/android/ab.sh b/android/ab.sh index 6190b3e541..cf79aab3bc 100755 --- a/android/ab.sh +++ b/android/ab.sh @@ -1 +1,2 @@ +cp -r ../flash0 assets NDK_MODULE_PATH=..:../native/ext $NDK/ndk-build -j3 TARGET_PLATFORM=android-9 $* diff --git a/android/jni/Android.mk b/android/jni/Android.mk index f1ea86ef5c..236dcdb4cd 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -54,6 +54,7 @@ LOCAL_SRC_FILES := \ $(SRC)/native/android/app-android.cpp \ $(SRC)/ext/disarm.cpp \ $(SRC)/ext/libkirk/AES.c \ + $(SRC)/ext/libkirk/amctrl.c \ $(SRC)/ext/libkirk/SHA1.c \ $(SRC)/ext/libkirk/bn.c \ $(SRC)/ext/libkirk/ec.c \ @@ -115,6 +116,7 @@ LOCAL_SRC_FILES := \ $(SRC)/Core/Dialog/PSPPlaceholderDialog.cpp \ $(SRC)/Core/Dialog/PSPSaveDialog.cpp \ $(SRC)/Core/Dialog/SavedataParam.cpp \ + $(SRC)/Core/Font/PGF.cpp \ $(SRC)/Core/HLE/HLETables.cpp \ $(SRC)/Core/HLE/HLE.cpp \ $(SRC)/Core/HLE/sceAtrac.cpp \ @@ -157,6 +159,7 @@ LOCAL_SRC_FILES := \ $(SRC)/Core/HLE/sceUsb.cpp \ $(SRC)/Core/HLE/sceUtility.cpp \ $(SRC)/Core/HLE/sceVaudio.cpp \ + $(SRC)/Core/HLE/scePspNpDrm_user.cpp \ $(SRC)/Core/FileSystems/BlockDevices.cpp \ $(SRC)/Core/FileSystems/ISOFileSystem.cpp \ $(SRC)/Core/FileSystems/MetaFileSystem.cpp \ diff --git a/android/jni/GamepadEmu.cpp b/android/jni/GamepadEmu.cpp index 83e0b53429..826c1900b1 100644 --- a/android/jni/GamepadEmu.cpp +++ b/android/jni/GamepadEmu.cpp @@ -32,7 +32,7 @@ TouchButton buttonLeft(&ui_atlas, I_DIR, I_ARROW, PAD_BUTTON_LEFT, 0); TouchButton buttonUp(&ui_atlas, I_DIR, I_ARROW, PAD_BUTTON_UP, 90); TouchButton buttonRight(&ui_atlas, I_DIR, I_ARROW, PAD_BUTTON_RIGHT, 180); TouchButton buttonDown(&ui_atlas, I_DIR, I_ARROW, PAD_BUTTON_DOWN, 270); -#ifdef __SYMBIAN32__ +#if defined(__SYMBIAN32__) || defined(IOS) TouchButton buttonPause(&ui_atlas, I_RECT, I_ARROW, PAD_BUTTON_BACK, 90); #endif @@ -75,7 +75,7 @@ void LayoutGamepad(int w, int h) buttonLShoulder.setPos(button_spacing + 10 * controlScale, 15 * controlScale, controlScale); buttonRShoulder.setPos(w - button_spacing - 10 * controlScale, 15 * controlScale, controlScale); -#ifdef __SYMBIAN32__ +#if defined(__SYMBIAN32__) || defined(IOS) buttonPause.setPos(halfW, 15 * controlScale, controlScale); #endif @@ -101,7 +101,7 @@ void UpdateGamepad(InputState &input_state) buttonLShoulder.update(input_state); buttonRShoulder.update(input_state); -#ifdef __SYMBIAN32__ +#if defined(__SYMBIAN32__) || defined(IOS) buttonPause.update(input_state); #endif @@ -128,7 +128,7 @@ void DrawGamepad(DrawBuffer &db) buttonLShoulder.draw(db, color, colorOverlay); buttonRShoulder.draw(db, color, colorOverlay); -#ifdef __SYMBIAN32__ +#if defined(__SYMBIAN32__) || defined(IOS) buttonPause.draw(db, color, colorOverlay); #endif diff --git a/android/jni/MenuScreens.cpp b/android/jni/MenuScreens.cpp index c170f74a2a..a858667588 100644 --- a/android/jni/MenuScreens.cpp +++ b/android/jni/MenuScreens.cpp @@ -24,6 +24,7 @@ #include "base/timeutil.h" #include "base/NativeApp.h" #include "gfx_es2/glsl_program.h" +#include "gfx_es2/gl_state.h" #include "input/input_state.h" #include "math/curves.h" #include "ui/ui.h" @@ -83,6 +84,8 @@ static void DrawBackground(float alpha) { ybase[i] = rng.F() * dp_yres; } } + glstate.depthWrite.set(GL_TRUE); + glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearColor(0.1f,0.2f,0.43f,1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); ui_draw2d.DrawImageStretch(I_BG, 0, 0, dp_xres, dp_yres); @@ -256,13 +259,12 @@ void InGameMenuScreen::render() { g_Config.iFrameSkip = fs ? 1 : 0; // TODO: Add UI for more than one slot. - VLinear vlinear1(x, y + 80, 20); - UIText(UBUNTU24, vlinear1, "Save states are experimental (and large)", 0xFFFFFFFF); - if (UIButton(GEN_ID, vlinear1, LARGE_BUTTON_WIDTH, "Save State", ALIGN_LEFT)) { + HLinear hlinear1(x, y + 80, 20); + if (UIButton(GEN_ID, hlinear1, LARGE_BUTTON_WIDTH, "Save State", ALIGN_LEFT)) { SaveState::SaveSlot(0, 0, 0); screenManager()->finishDialog(this, DR_CANCEL); } - if (UIButton(GEN_ID, vlinear1, LARGE_BUTTON_WIDTH, "Load State", ALIGN_LEFT)) { + if (UIButton(GEN_ID, hlinear1, LARGE_BUTTON_WIDTH, "Load State", ALIGN_LEFT)) { SaveState::LoadSlot(0, 0, 0); screenManager()->finishDialog(this, DR_CANCEL); } diff --git a/android/jni/NativeApp.cpp b/android/jni/NativeApp.cpp index e00c491560..4d16aaa787 100644 --- a/android/jni/NativeApp.cpp +++ b/android/jni/NativeApp.cpp @@ -166,6 +166,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co #ifdef BLACKBERRY // Packed assets are included in app/native/ dir VFSRegister("", new DirectoryAssetReader("app/native/assets/")); +#elif defined(IOS) + VFSRegister("", new DirectoryAssetReader(external_directory)); #else VFSRegister("", new DirectoryAssetReader("assets/")); #endif @@ -179,7 +181,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co LogManager *logman = LogManager::GetInstance(); ILOG("Logman: %p", logman); - config_filename = user_data_path + "ppsspp.ini"; + config_filename = user_data_path + "/ppsspp.ini"; g_Config.Load(config_filename.c_str()); @@ -231,8 +233,10 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co LogManager::GetInstance()->ChangeFileLog(fileToLog); if (g_Config.currentDirectory == "") { -#if defined(ANDROID) || defined(BLACKBERRY) || defined(__SYMBIAN32__) +#if defined(ANDROID) g_Config.currentDirectory = external_directory; +#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(IOS) + g_Config.currentDirectory = savegame_directory; #else g_Config.currentDirectory = getenv("HOME"); #endif @@ -244,7 +248,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co // most sense. g_Config.memCardDirectory = std::string(external_directory) + "/"; g_Config.flashDirectory = std::string(external_directory)+"/flash/"; -#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) +#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(IOS) g_Config.memCardDirectory = user_data_path; g_Config.flashDirectory = user_data_path+"/flash/"; #else @@ -316,6 +320,9 @@ void NativeInitGraphics() void NativeRender() { EnableFZ(); + glstate.depthWrite.set(GL_TRUE); + glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + // Clearing the screen at the start of the frame is an optimization for tiled mobile GPUs, as it then doesn't need to keep it around between frames. glClearColor(0,0,0,1); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); diff --git a/ext/libkirk/AES.c b/ext/libkirk/AES.c index c75748510b..c7a84621f2 100644 --- a/ext/libkirk/AES.c +++ b/ext/libkirk/AES.c @@ -37,11 +37,11 @@ //CMAC GLOBS #define AES_128 0 -const unsigned char const_Rb[16] = { +static const unsigned char const_Rb[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 }; -const unsigned char const_Zero[16] = { +static const unsigned char const_Zero[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/ext/libkirk/amctrl.c b/ext/libkirk/amctrl.c new file mode 100644 index 0000000000..c499e7cff8 --- /dev/null +++ b/ext/libkirk/amctrl.c @@ -0,0 +1,679 @@ +/* + * amctrl.c -- Reverse engineering of amctrl.prx + * written by tpu. + */ + + +#include +#include +#include + +#include "kirk_engine.h" +#include "AES.h" +#include "SHA1.h" +#include "amctrl.h" + +/*************************************************************/ + +static const u8 loc_1CD4[16] = {0xE3, 0x50, 0xED, 0x1D, 0x91, 0x0A, 0x1F, 0xD0, 0x29, 0xBB, 0x1C, 0x3E, 0xF3, 0x40, 0x77, 0xFB}; +static const u8 loc_1CE4[16] = {0x13, 0x5F, 0xA4, 0x7C, 0xAB, 0x39, 0x5B, 0xA4, 0x76, 0xB8, 0xCC, 0xA9, 0x8F, 0x3A, 0x04, 0x45}; +static const u8 loc_1CF4[16] = {0x67, 0x8D, 0x7F, 0xA3, 0x2A, 0x9C, 0xA0, 0xD1, 0x50, 0x8A, 0xD8, 0x38, 0x5E, 0x4B, 0x01, 0x7E}; + +static u8 kirk_buf[0x0814]; // 1DC0 1DD4 + +/*************************************************************/ + +static int kirk4(u8 *buf, int size, int type) +{ + int retv; + u32 *header = (u32*)buf; + + header[0] = 4; + header[1] = 0; + header[2] = 0; + header[3] = type; + header[4] = size; + + retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 4); + + if(retv) + return 0x80510311; + + return 0; +} + +static int kirk7(u8 *buf, int size, int type) +{ + int retv; + u32 *header = (u32*)buf; + + header[0] = 5; + header[1] = 0; + header[2] = 0; + header[3] = type; + header[4] = size; + + retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 7); + if(retv) + return 0x80510311; + + return 0; +} + +static int kirk5(u8 *buf, int size) +{ + int retv; + u32 *header = (u32*)buf; + + header[0] = 4; + header[1] = 0; + header[2] = 0; + header[3] = 0x0100; + header[4] = size; + + retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 5); + if(retv) + return 0x80510312; + + return 0; +} + +static int kirk8(u8 *buf, int size) +{ + int retv; + u32 *header = (u32*)buf; + + header[0] = 5; + header[1] = 0; + header[2] = 0; + header[3] = 0x0100; + header[4] = size; + + retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 8); + if(retv) + return 0x80510312; + + return 0; +} + +static int kirk14(u8 *buf) +{ + int retv; + + retv = sceUtilsBufferCopyWithRange(buf, 0x14, 0, 0, 14); + if(retv) + return 0x80510315; + + return 0; +} + +/*************************************************************/ + +// Called by sceDrmBBMacUpdate +// encrypt_buf +static int sub_158(u8 *buf, int size, u8 *key, int key_type) +{ + int i, retv; + + for(i=0; i<16; i++){ + buf[0x14+i] ^= key[i]; + } + + retv = kirk4(buf, size, key_type); + if(retv) + return retv; + + // copy last 16 bytes to keys + memcpy(key, buf+size+4, 16); + + return 0; +} + + +// type: +// 2: use fuse id +// 3: use fixed id +int sceDrmBBMacInit(MAC_KEY *mkey, int type) +{ + mkey->type = type; + mkey->pad_size = 0; + + memset(mkey->key, 0, 16); + memset(mkey->pad, 0, 16); + + return 0; +} + +int sceDrmBBMacUpdate(MAC_KEY *mkey, u8 *buf, int size) +{ + int retv = 0, ksize, p, type; + u8 *kbuf; + + if(mkey->pad_size>16){ + retv = 0x80510302; + goto _exit; + } + + if(mkey->pad_size+size<=16){ + memcpy(mkey->pad+mkey->pad_size, buf, size); + mkey->pad_size += size; + retv = 0; + }else{ + kbuf = kirk_buf+0x14; + // copy pad data first + memcpy(kbuf, mkey->pad, mkey->pad_size); + + p = mkey->pad_size; + + mkey->pad_size += size; + mkey->pad_size &= 0x0f; + if(mkey->pad_size==0) + mkey->pad_size = 16; + + size -= mkey->pad_size; + // save last data to pad buf + memcpy(mkey->pad, buf+size, mkey->pad_size); + + type = (mkey->type==2)? 0x3A : 0x38; + + while(size){ + ksize = (size+p>=0x0800)? 0x0800 : size+p; + memcpy(kbuf+p, buf, ksize-p); + retv = sub_158(kirk_buf, ksize, mkey->key, type); + if(retv) + goto _exit; + size -= (ksize-p); + buf += ksize-p; + p = 0; + } + } + +_exit: + return retv; + +} + +int sceDrmBBMacFinal(MAC_KEY *mkey, u8 *buf, u8 *vkey) +{ + int i, retv, code; + u8 *kbuf, tmp[16], tmp1[16]; + u32 t0, v0, v1; + + if(mkey->pad_size>16) + return 0x80510302; + + code = (mkey->type==2)? 0x3A : 0x38; + kbuf = kirk_buf+0x14; + + memset(kbuf, 0, 16); + retv = kirk4(kirk_buf, 16, code); + if(retv) + goto _exit; + memcpy(tmp, kbuf, 16); + + // left shift tmp 1 bit + t0 = (tmp[0]&0x80)? 0x87 : 0; + for(i=0; i<15; i++){ + v1 = tmp[i+0]; + v0 = tmp[i+1]; + v1 <<= 1; + v0 >>= 7; + v0 |= v1; + tmp[i+0] = v0; + } + v0 = tmp[15]; + v0 <<= 1; + v0 ^= t0; + tmp[15] = v0; + + // padding remain data + if(mkey->pad_size<16){ + // left shift tmp 1 bit + t0 = (tmp[0]&0x80)? 0x87 : 0; + for(i=0; i<15; i++){ + v1 = tmp[i+0]; + v0 = tmp[i+1]; + v1 <<= 1; + v0 >>= 7; + v0 |= v1; + tmp[i+0] = v0; + } + v0 = tmp[15]; + v0 <<= 1; + v0 ^= t0; + tmp[15] = v0; + + mkey->pad[mkey->pad_size] = 0x80; + if(mkey->pad_size+1<16) + memset(mkey->pad+mkey->pad_size+1, 0, 16-mkey->pad_size-1); + } + + for(i=0; i<16; i++){ + mkey->pad[i] ^= tmp[i]; + } + + memcpy(kbuf, mkey->pad, 16); + memcpy(tmp1, mkey->key, 16); + + retv = sub_158(kirk_buf, 0x10, tmp1, code); + if(retv) + return retv; + + for(i=0; i<0x10; i++){ + tmp1[i] ^= loc_1CD4[i]; + } + + if(mkey->type==2){ + memcpy(kbuf, tmp1, 16); + + retv = kirk5(kirk_buf, 0x10); + if(retv) + goto _exit; + + retv = kirk4(kirk_buf, 0x10, code); + if(retv) + goto _exit; + + memcpy(tmp1, kbuf, 16); + } + + if(vkey){ + for(i=0; i<0x10; i++){ + tmp1[i] ^= vkey[i]; + } + memcpy(kbuf, tmp1, 16); + + retv = kirk4(kirk_buf, 0x10, code); + if(retv) + goto _exit; + + memcpy(tmp1, kbuf, 16); + } + + memcpy(buf, tmp1, 16); + + memset(mkey->key, 0, 16); + memset(mkey->pad, 0, 16); + + mkey->pad_size = 0; + mkey->type = 0; + retv = 0; + +_exit: + return retv; +} + +int sceDrmBBMacFinal2(MAC_KEY *mkey, u8 *out, u8 *vkey) +{ + int i, retv, type; + u8 *kbuf, tmp[16]; + + type = mkey->type; + retv = sceDrmBBMacFinal(mkey, tmp, vkey); + if(retv) + return retv; + + kbuf = kirk_buf+0x14; + + // decrypt bbmac + if(type==3){ + memcpy(kbuf, out, 0x10); + kirk7(kirk_buf, 0x10, 0x63); + }else{ + memcpy(kirk_buf, out, 0x10); + } + + retv = 0; + for(i=0; i<0x10; i++){ + if(kirk_buf[i]!=tmp[i]){ + retv = 0x80510300; + break; + } + } + + return retv; +} + +/*************************************************************/ + +static int sub_1F8(u8 *buf, int size, u8 *key, int key_type) +{ + int i, retv; + u8 tmp[16]; + + // copy last 16 bytes to tmp + memcpy(tmp, buf+size+0x14-16, 16); + + retv = kirk7(buf, size, key_type); + if(retv) + return retv; + + for(i=0; i<16; i++){ + buf[i] ^= key[i]; + } + + // copy last 16 bytes to keys + memcpy(key, tmp, 16); + + return 0; +} + + +static int sub_428(u8 *kbuf, u8 *dbuf, int size, CIPHER_KEY *ckey) +{ + int i, retv; + u8 tmp1[16], tmp2[16]; + + memcpy(kbuf+0x14, ckey->key, 16); + + for(i=0; i<16; i++){ + kbuf[0x14+i] ^= loc_1CF4[i]; + } + + if(ckey->type==2) + retv = kirk8(kbuf, 16); + else + retv = kirk7(kbuf, 16, 0x39); + if(retv) + return retv; + + for(i=0; i<16; i++){ + kbuf[i] ^= loc_1CE4[i]; + } + + memcpy(tmp2, kbuf, 0x10); + + if(ckey->seed==1){ + memset(tmp1, 0, 0x10); + }else{ + memcpy(tmp1, tmp2, 0x10); + *(u32*)(tmp1+0x0c) = ckey->seed-1; + } + + for(i=0; iseed; + ckey->seed += 1; + } + + retv = sub_1F8(kbuf, size, tmp1, 0x63); + if(retv) + return retv; + + for(i=0; itype = type; + if(mode==2){ + ckey->seed = seed+1; + for(i=0; i<16; i++){ + ckey->key[i] = header_key[i]; + } + if(version_key){ + for(i=0; i<16; i++){ + ckey->key[i] ^= version_key[i]; + } + } + retv = 0; + }else if(mode==1){ + ckey->seed = 1; + retv = kirk14(kirk_buf); + if(retv) + return retv; + + memcpy(kbuf, kirk_buf, 0x10); + memset(kbuf+0x0c, 0, 4); + + if(ckey->type==2){ + for(i=0; i<16; i++){ + kbuf[i] ^= loc_1CE4[i]; + } + retv = kirk5(kirk_buf, 0x10); + for(i=0; i<16; i++){ + kbuf[i] ^= loc_1CF4[i]; + } + }else{ + for(i=0; i<16; i++){ + kbuf[i] ^= loc_1CE4[i]; + } + retv = kirk4(kirk_buf, 0x10, 0x39); + for(i=0; i<16; i++){ + kbuf[i] ^= loc_1CF4[i]; + } + } + if(retv) + return retv; + + memcpy(ckey->key, kbuf, 0x10); + memcpy(header_key, kbuf, 0x10); + + if(version_key){ + for(i=0; i<16; i++){ + ckey->key[i] ^= version_key[i]; + } + } + }else{ + retv = 0; + } + + return retv; +} + +int sceDrmBBCipherUpdate(CIPHER_KEY *ckey, u8 *data, int size) +{ + int p, retv, dsize; + + retv = 0; + p = 0; + + while(size>0){ + dsize = (size>=0x0800)? 0x0800 : size; + retv = sub_428(kirk_buf, data+p, dsize, ckey); + if(retv) + break; + size -= dsize; + p += dsize; + } + + return retv; +} + +int sceDrmBBCipherFinal(CIPHER_KEY *ckey) +{ + memset(ckey->key, 0, 16); + ckey->type = 0; + ckey->seed = 0; + + return 0; +} + +/*************************************************************/ + +// AES128 encrypt key +static const u8 key_357C[0x30] = { + 0x07,0x3D,0x9E,0x9D,0xA8,0xFD,0x3B,0x2F,0x63,0x18,0x93,0x2E,0xF8,0x57,0xA6,0x64, + 0x37,0x49,0xB7,0x01,0xCA,0xE2,0xE0,0xC5,0x44,0x2E,0x06,0xB6,0x1E,0xFF,0x84,0xF2, + 0x9D,0x31,0xB8,0x5A,0xC8,0xFA,0x16,0x80,0x73,0x60,0x18,0x82,0x18,0x77,0x91,0x9D, +}; + +static const u8 key_363C[16] = { + 0x38,0x20,0xD0,0x11,0x07,0xA3,0xFF,0x3E,0x0A,0x4C,0x20,0x85,0x39,0x10,0xB5,0x54, +}; + +int sceNpDrmGetFixedKey(u8 *key, char *npstr, int type) +{ + AES_ctx akey; + MAC_KEY mkey; + char strbuf[0x30]; + int retv; + + if((type&0x01000000)==0) + return 0x80550901; + type &= 0x000000ff; + + memset(strbuf, 0, 0x30); + strncpy(strbuf, npstr, 0x30); + + retv = sceDrmBBMacInit(&mkey, 1); + if(retv) + return retv; + + retv = sceDrmBBMacUpdate(&mkey, (u8*)strbuf, 0x30); + if(retv) + return retv; + + retv = sceDrmBBMacFinal(&mkey, key, (u8*)key_363C); + if(retv) + return 0x80550902; + + if(type==0) + return 0; + if(type>3) + return 0x80550901; + type = (type-1)*16; + + AES_set_key(&akey, &key_357C[type], 128); + AES_encrypt(&akey, key, key); + + return 0; +} + + +/*************************************************************/ + + +static const u8 dnas_key1A90[] = {0xED,0xE2,0x5D,0x2D,0xBB,0xF8,0x12,0xE5,0x3C,0x5C,0x59,0x32,0xFA,0xE3,0xE2,0x43}; +static const u8 dnas_key1AA0[] = {0x27,0x74,0xFB,0xEB,0xA4,0xA0, 1,0xD7, 2,0x56,0x9E,0x33,0x8C,0x19,0x57,0x83}; + +PGD_DESC *pgd_open(u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey) +{ + PGD_DESC *pgd; + MAC_KEY mkey; + CIPHER_KEY ckey; + u8 *fkey; + int retv; + + //DEBUG_LOG(HLE, "Open PGD ..."); + + pgd = (PGD_DESC*)malloc(sizeof(PGD_DESC)); + memset(pgd, 0, sizeof(PGD_DESC)); + + pgd->key_index = *(u32*)(pgd_buf+4); + pgd->drm_type = *(u32*)(pgd_buf+8); + + if(pgd->drm_type==1){ + pgd->mac_type = 1; + pgd_flag |= 4; + if(pgd->key_index>1){ + pgd->mac_type = 3; + pgd_flag |= 8; + } + pgd->cipher_type = 1; + }else{ + pgd->mac_type = 2; + pgd->cipher_type = 2; + } + pgd->open_flag = pgd_flag; + + // select fixed key + fkey = NULL; + if(pgd_flag&2) + fkey = (u8*)dnas_key1A90; + if(pgd_flag&1) + fkey = (u8*)dnas_key1AA0; + if(fkey==NULL){ + //ERROR_LOG(HLE, "pgd_open: invalid pgd_flag! %08x\n", pgd_flag); + free(pgd); + return NULL; + } + + // MAC_0x80 check + sceDrmBBMacInit(&mkey, pgd->mac_type); + sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x80); + retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x80, fkey); + if(retv){ + //ERROR_LOG(HLE, "pgd_open: MAC_80 check failed!: %08x(%d)\n", retv, retv); + free(pgd); + return NULL; + } + + // MAC_0x70 + sceDrmBBMacInit(&mkey, pgd->mac_type); + sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x70); + if(pgd_vkey){ + // use given vkey + retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x70, pgd_vkey); + if(retv){ + //ERROR_LOG(HLE, "pgd_open: MAC_70 check failed!: %08x(%d)\n", retv, retv); + free(pgd); + return NULL; + }else{ + memcpy(pgd->vkey, pgd_vkey, 16); + } + }else{ + //ERROR_LOG(HLE, "pgd_open: need key!\n"); + free(pgd); + return NULL; + } + + + // decrypt PGD_DESC + sceDrmBBCipherInit(&ckey, pgd->cipher_type, 2, pgd_buf+0x10, pgd->vkey, 0); + sceDrmBBCipherUpdate(&ckey, pgd_buf+0x30, 0x30); + sceDrmBBCipherFinal(&ckey); + + pgd->data_size = *(u32*)(pgd_buf+0x44); + pgd->block_size = *(u32*)(pgd_buf+0x48); + pgd->data_offset = *(u32*)(pgd_buf+0x4c); + memcpy(pgd->dkey, pgd_buf+0x30, 16); + + pgd->align_size = (pgd->data_size+15)&~15; + pgd->table_offset = pgd->data_offset+pgd->align_size; + pgd->block_nr = (pgd->align_size+pgd->block_size-1)&~(pgd->block_size-1); + pgd->block_nr = pgd->block_nr/pgd->block_size; + + pgd->file_offset = 0; + pgd->current_block = -1; + pgd->block_buf = (u8*)malloc(pgd->block_size*2); + + return pgd; +} + +int pgd_decrypt_block(PGD_DESC *pgd, int block) +{ + CIPHER_KEY ckey; + u32 block_offset; + + block_offset = block*pgd->block_size; + + // decrypt block data + sceDrmBBCipherInit(&ckey, pgd->cipher_type, 2, pgd->dkey, pgd->vkey, block_offset>>4); + sceDrmBBCipherUpdate(&ckey, pgd->block_buf, pgd->block_size); + sceDrmBBCipherFinal(&ckey); + + return pgd->block_size; +} + +int pgd_close(PGD_DESC *pgd) +{ + free(pgd->block_buf); + free(pgd); + return 0; +} + +/*************************************************************/ + diff --git a/ext/libkirk/amctrl.h b/ext/libkirk/amctrl.h new file mode 100644 index 0000000000..9a22ac9567 --- /dev/null +++ b/ext/libkirk/amctrl.h @@ -0,0 +1,65 @@ +#ifndef AMCTRL_H +#define AMCTRL_H + +typedef struct { + int type; + u8 key[16]; + u8 pad[16]; + int pad_size; +} MAC_KEY; + +typedef struct +{ + u32 type; + u32 seed; + u8 key[16]; +} CIPHER_KEY; + +typedef struct { + u8 vkey[16]; // key to decrypt PGD header + u8 dkey[16]; // key to decrypt PGD data + + u32 open_flag; + u32 key_index; + u32 drm_type; + u32 mac_type; + u32 cipher_type; + + u32 data_size; + u32 align_size; + u32 block_size; + u32 block_nr; + u32 data_offset; + u32 table_offset; + + u8 *block_buf; + u32 current_block; + u32 file_offset; +}PGD_DESC; + + +// type: +// 2: use fuse id +// 3: use fixed key. MAC need encrypt again +int sceDrmBBMacInit(MAC_KEY *mkey, int type); +int sceDrmBBMacUpdate(MAC_KEY *mkey, u8 *buf, int size); +int sceDrmBBMacFinal(MAC_KEY *mkey, u8 *buf, u8 *vkey); +int sceDrmBBMacFinal2(MAC_KEY *mkey, u8 *out, u8 *vkey); + +// type: 1 use fixed key +// 2 use fuse id +// mode: 1 for encrypt +// 2 for decrypt +int sceDrmBBCipherInit(CIPHER_KEY *ckey, int type, int mode, u8 *header_key, u8 *version_key, u32 seed); +int sceDrmBBCipherUpdate(CIPHER_KEY *ckey, u8 *data, int size); +int sceDrmBBCipherFinal(CIPHER_KEY *ckey); + +// npdrm.prx +int sceNpDrmGetFixedKey(u8 *key, char *npstr, int type); + +PGD_DESC *pgd_open(u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey); +int pgd_decrypt_block(PGD_DESC *pgd, int block); +int pgd_close(PGD_DESC *pgd); + +#endif + diff --git a/ext/libkirk/kirk_engine.h b/ext/libkirk/kirk_engine.h index e89fa54689..7edbe4a8df 100644 --- a/ext/libkirk/kirk_engine.h +++ b/ext/libkirk/kirk_engine.h @@ -184,7 +184,7 @@ typedef struct 0x0C: Mul1 0x0D: Mul2 0x0E: Random Number Gen - 0x0F: (absolutely no idea – could be KIRK initialization) + 0x0F: (absolutely no idea ?could be KIRK initialization) 0x10: Signature Gen // Sig Checks 0x11: Signature Check (checks for generated sigs) diff --git a/ext/libkirk/libkirk.vcxproj b/ext/libkirk/libkirk.vcxproj index 3c248e88ea..20cba7c8c2 100644 --- a/ext/libkirk/libkirk.vcxproj +++ b/ext/libkirk/libkirk.vcxproj @@ -71,6 +71,7 @@ Level3 Disabled Default + _MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS true @@ -116,6 +117,7 @@ + @@ -123,6 +125,7 @@ + diff --git a/ext/libkirk/libkirk.vcxproj.filters b/ext/libkirk/libkirk.vcxproj.filters index b43b401d6d..cea5d1c8cd 100644 --- a/ext/libkirk/libkirk.vcxproj.filters +++ b/ext/libkirk/libkirk.vcxproj.filters @@ -30,6 +30,9 @@ Source Files + + Source Files + @@ -41,6 +44,9 @@ Header Files + + Header Files + diff --git a/flash0/font/jpn0.pgf b/flash0/font/jpn0.pgf new file mode 100644 index 0000000000..913bd73b11 Binary files /dev/null and b/flash0/font/jpn0.pgf differ diff --git a/flash0/font/kr0.pgf b/flash0/font/kr0.pgf new file mode 100644 index 0000000000..5d4f615b9c Binary files /dev/null and b/flash0/font/kr0.pgf differ diff --git a/flash0/font/ltn0.pgf b/flash0/font/ltn0.pgf new file mode 100644 index 0000000000..bf710feef0 Binary files /dev/null and b/flash0/font/ltn0.pgf differ diff --git a/flash0/font/ltn1.pgf b/flash0/font/ltn1.pgf new file mode 100644 index 0000000000..7b9dede484 Binary files /dev/null and b/flash0/font/ltn1.pgf differ diff --git a/flash0/font/ltn10.pgf b/flash0/font/ltn10.pgf new file mode 100644 index 0000000000..a12d1814ca Binary files /dev/null and b/flash0/font/ltn10.pgf differ diff --git a/flash0/font/ltn11.pgf b/flash0/font/ltn11.pgf new file mode 100644 index 0000000000..402bf6084c Binary files /dev/null and b/flash0/font/ltn11.pgf differ diff --git a/flash0/font/ltn12.pgf b/flash0/font/ltn12.pgf new file mode 100644 index 0000000000..092d5ef041 Binary files /dev/null and b/flash0/font/ltn12.pgf differ diff --git a/flash0/font/ltn13.pgf b/flash0/font/ltn13.pgf new file mode 100644 index 0000000000..89b28d366a Binary files /dev/null and b/flash0/font/ltn13.pgf differ diff --git a/flash0/font/ltn14.pgf b/flash0/font/ltn14.pgf new file mode 100644 index 0000000000..873afb3d05 Binary files /dev/null and b/flash0/font/ltn14.pgf differ diff --git a/flash0/font/ltn15.pgf b/flash0/font/ltn15.pgf new file mode 100644 index 0000000000..c517fe05cd Binary files /dev/null and b/flash0/font/ltn15.pgf differ diff --git a/flash0/font/ltn2.pgf b/flash0/font/ltn2.pgf new file mode 100644 index 0000000000..9ee2763f85 Binary files /dev/null and b/flash0/font/ltn2.pgf differ diff --git a/flash0/font/ltn3.pgf b/flash0/font/ltn3.pgf new file mode 100644 index 0000000000..805c286330 Binary files /dev/null and b/flash0/font/ltn3.pgf differ diff --git a/flash0/font/ltn4.pgf b/flash0/font/ltn4.pgf new file mode 100644 index 0000000000..12b075101d Binary files /dev/null and b/flash0/font/ltn4.pgf differ diff --git a/flash0/font/ltn5.pgf b/flash0/font/ltn5.pgf new file mode 100644 index 0000000000..d12e9eccc3 Binary files /dev/null and b/flash0/font/ltn5.pgf differ diff --git a/flash0/font/ltn6.pgf b/flash0/font/ltn6.pgf new file mode 100644 index 0000000000..0f626ddff2 Binary files /dev/null and b/flash0/font/ltn6.pgf differ diff --git a/flash0/font/ltn7.pgf b/flash0/font/ltn7.pgf new file mode 100644 index 0000000000..ba9afda58c Binary files /dev/null and b/flash0/font/ltn7.pgf differ diff --git a/flash0/font/ltn8.pgf b/flash0/font/ltn8.pgf new file mode 100644 index 0000000000..a07a1f718e Binary files /dev/null and b/flash0/font/ltn8.pgf differ diff --git a/flash0/font/ltn9.pgf b/flash0/font/ltn9.pgf new file mode 100644 index 0000000000..11132d1a32 Binary files /dev/null and b/flash0/font/ltn9.pgf differ diff --git a/headless/Headless.cpp b/headless/Headless.cpp index d9289c8cba..f8db1ff0fb 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -10,13 +10,13 @@ #include "Core/System.h" #include "Core/MIPS/MIPS.h" #include "Core/Host.h" -#include "Windows/OpenGLBase.h" #include "Log.h" #include "LogManager.h" #include "Compare.h" #include "StubHost.h" #ifdef _WIN32 +#include "Windows/OpenGLBase.h" #include "WindowsHeadlessHost.h" #endif @@ -78,7 +78,7 @@ void printUsage(const char *progname, const char *reason) int main(int argc, const char* argv[]) { bool fullLog = false; - bool useJit = false; + bool useJit = true; bool autoCompare = false; bool useGraphics = false; @@ -197,8 +197,8 @@ int main(int argc, const char* argv[]) // If we were rendering, this might be a nice time to do something about it. if (coreState == CORE_NEXTFRAME) { - headlessHost->SwapBuffers(); coreState = CORE_RUNNING; + headlessHost->SwapBuffers(); } } diff --git a/ios/PPSSPP-Info.plist b/ios/PPSSPP-Info.plist index 5fe1a739c6..0f42d9ca8a 100644 --- a/ios/PPSSPP-Info.plist +++ b/ios/PPSSPP-Info.plist @@ -5,15 +5,15 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - ${PRODUCT_NAME} + PPSSPP CFBundleExecutable - ${EXECUTABLE_NAME} + PPSSPP CFBundleIdentifier - com.rock88dev.${PRODUCT_NAME:rfc1034identifier} + com.rock88dev.PPSSPP CFBundleInfoDictionaryVersion 6.0 CFBundleName - ${PRODUCT_NAME} + PPSSPP CFBundlePackageType APPL CFBundleShortVersionString @@ -37,10 +37,15 @@ UISupportedInterfaceOrientations~ipad - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + CFBundleIconFiles + + assets/Icon-72.png + assets/Icon-72@2x.png + assets/Icon.png + assets/Icon@2x.png + diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 576d3b68ca..4b53a3e612 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -13,10 +13,9 @@ #include "file/zip_read.h" #include "input/input_state.h" #include "net/resolve.h" -#include "ui_atlas.h" #include "ui/screen.h" -#include "Config.h" +#include "Core/Config.h" #include "gfx_es2/fbo.h" #define IS_IPAD() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) @@ -34,6 +33,8 @@ InputState input_state; extern std::string ram_temp_file; +ViewController* sharedViewController; + @interface ViewController () @property (strong, nonatomic) EAGLContext *context; @@ -50,17 +51,18 @@ extern std::string ram_temp_file; { self = [super init]; if (self) { + sharedViewController = self; self.touches = [[[NSMutableArray alloc] init] autorelease]; self.documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - self.bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/"]; + self.bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/assets/"]; memset(&input_state, 0, sizeof(input_state)); net::Init(); ram_temp_file = [[NSTemporaryDirectory() stringByAppendingPathComponent:@"ram_tmp.file"] fileSystemRepresentation]; - NativeInit(0, NULL, [self.bundlePath UTF8String], [self.documentsPath UTF8String], NULL); + NativeInit(0, NULL, [self.documentsPath UTF8String], [self.bundlePath UTF8String], NULL); } return self; @@ -230,11 +232,21 @@ extern std::string ram_temp_file; } } +- (void)bindDefaultFBO +{ + [(GLKView*)self.view bindDrawable]; +} + void LaunchBrowser(char const* url) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]]]; } +void bindDefaultFBO() +{ + [sharedViewController bindDefaultFBO]; +} + void EnableFZ(){}; void DisableFZ(){}; diff --git a/ios/assets/Icon-72.png b/ios/assets/Icon-72.png new file mode 100644 index 0000000000..1ae6c46557 Binary files /dev/null and b/ios/assets/Icon-72.png differ diff --git a/ios/assets/Icon-72@2x.png b/ios/assets/Icon-72@2x.png new file mode 100644 index 0000000000..3fe685c43e Binary files /dev/null and b/ios/assets/Icon-72@2x.png differ diff --git a/ios/assets/Icon.png b/ios/assets/Icon.png new file mode 100644 index 0000000000..5852d4fb0a Binary files /dev/null and b/ios/assets/Icon.png differ diff --git a/ios/assets/Icon@2x.png b/ios/assets/Icon@2x.png new file mode 100644 index 0000000000..fa0829e926 Binary files /dev/null and b/ios/assets/Icon@2x.png differ diff --git a/ios/ios.toolchain.cmake b/ios/ios.toolchain.cmake index 9af6cb06e6..7c0e2a778f 100644 --- a/ios/ios.toolchain.cmake +++ b/ios/ios.toolchain.cmake @@ -31,9 +31,12 @@ # Standard settings set (CMAKE_SYSTEM_NAME Darwin) set (CMAKE_SYSTEM_VERSION 1) +set (CMAKE_SYSTEM_PROCESSOR arm) set (UNIX True) set (APPLE True) set (IOS True) +set (APP_TYPE MACOSX_BUNDLE) +set (CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET 5.0) # Determine the cmake host system version so we know where to find the iOS SDKs find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) @@ -42,12 +45,13 @@ if (CMAKE_UNAME) string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") endif (CMAKE_UNAME) -# Force the compilers to gcc for iOS +# Force the compilers to clang for iOS include (CMakeForceCompiler) CMAKE_FORCE_C_COMPILER (gcc gcc) CMAKE_FORCE_CXX_COMPILER (g++ g++) # Skip the platform compiler checks for cross compiling +set (CMAKE_CROSSCOMPILING TRUE) set (CMAKE_CXX_COMPILER_WORKS TRUE) set (CMAKE_C_COMPILER_WORKS TRUE) @@ -105,12 +109,9 @@ endif (${IOS_PLATFORM} STREQUAL "OS") # Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT # Note Xcode 4.3 changed the installation location, choose the most recent one available set (XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) if (EXISTS ${XCODE_POST_43_ROOT}) set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) - elseif(EXISTS ${XCODE_PRE_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) endif (EXISTS ${XCODE_POST_43_ROOT}) endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") diff --git a/native b/native index f807e225f7..3f6353af5a 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit f807e225f75b131e614c92770fb93a5e902be22b +Subproject commit 3f6353af5afe1542a50c33eb0bb554ea25653258 diff --git a/pspautotests b/pspautotests index c4427bd55d..a9c949b87d 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit c4427bd55d57af2484f5ccd4ec1bed2bcf674395 +Subproject commit a9c949b87dc69d4d6cde854b73455a170a2aaff4 diff --git a/test.py b/test.py index 2d98e03079..d2836664b5 100755 --- a/test.py +++ b/test.py @@ -60,13 +60,14 @@ tests_good = [ "misc/testgp", "misc/libc", "misc/dcache", + "mstick/mstick", "string/string", "gpu/callbacks/ge_callbacks", - "gpu/displaylist/state", "threads/alarm/alarm", "threads/alarm/cancel/cancel", "threads/alarm/refer/refer", "threads/alarm/set/set", + "threads/callbacks/callbacks", "threads/events/events", "threads/events/cancel/cancel", "threads/events/clear/clear", @@ -77,13 +78,14 @@ tests_good = [ "threads/events/set/set", "threads/events/wait/wait", "threads/k0/k0", - "threads/lwmutex/create/create", - "threads/lwmutex/delete/delete", - "threads/lwmutex/lock/lock", - "threads/lwmutex/priority/priority", - "threads/lwmutex/try/try", - "threads/lwmutex/try600/try600", - "threads/lwmutex/unlock/unlock", + "threads/lwmutex/create", + "threads/lwmutex/delete", + "threads/lwmutex/lock", + "threads/lwmutex/priority", + "threads/lwmutex/refer", + "threads/lwmutex/try", + "threads/lwmutex/try600", + "threads/lwmutex/unlock", "threads/mbx/mbx", "threads/mbx/cancel/cancel", "threads/mbx/create/create", @@ -93,13 +95,14 @@ tests_good = [ "threads/mbx/receive/receive", "threads/mbx/refer/refer", "threads/mbx/send/send", + "threads/mutex/create", + "threads/mutex/delete", + "threads/mutex/lock", "threads/mutex/mutex", - "threads/mutex/create/create", - "threads/mutex/delete/delete", - "threads/mutex/lock/lock", - "threads/mutex/priority/priority", - "threads/mutex/try/try", - "threads/mutex/unlock/unlock", + "threads/mutex/priority", + "threads/mutex/refer", + "threads/mutex/try", + "threads/mutex/unlock", "threads/semaphores/semaphores", "threads/semaphores/cancel/cancel", "threads/semaphores/create/create", @@ -109,12 +112,17 @@ tests_good = [ "threads/semaphores/refer/refer", "threads/semaphores/signal/signal", "threads/semaphores/wait/wait", - "threads/vpl/vpl", + "threads/threads/release", + "threads/threads/rotate", + "threads/threads/threadend", + "threads/threads/threads", + "threads/vpl/cancel", "threads/vpl/delete", "threads/vpl/free", "threads/vpl/priority", "threads/vpl/refer", "threads/vpl/try", + "threads/vpl/vpl", "power/power", "umd/callbacks/umd", "umd/wait/wait", @@ -122,42 +130,49 @@ tests_good = [ ] tests_next = [ - "audio/sascore/sascore", - "malloc/malloc", # These are the next tests up for fixing. These run by default. + "audio/atrac/atractest", + "audio/mp3/mp3test", + "audio/sascore/sascore", + "display/vblankmulti", + "malloc/malloc", "threads/fpl/fpl", "threads/k0/k0", "threads/msgpipe/msgpipe", "threads/scheduling/scheduling", - "threads/threads/threads", + "threads/threads/create", "threads/vtimers/vtimer", "threads/vpl/allocate", "threads/vpl/create", "threads/wakeup/wakeup", + "gpu/commands/basic", + "gpu/complex/complex", + "gpu/displaylist/state", + "gpu/reflection/reflection", + "gpu/rendertarget/rendertarget", + "gpu/signals/jumps", + "gpu/signals/simple", "gpu/simple/simple", "gpu/triangle/triangle", - "gpu/commands/basic", "hle/check_not_used_uids", "font/fonttest", "io/cwd/cwd", + "io/file/file", "io/io/io", "io/iodrv/iodrv", "modules/loadexec/loader", "rtc/rtc", + "sysmem/partition", + "sysmem/sysmem", "umd/io/umd_io", "umd/raw_access/raw_access", "utility/systemparam/systemparam", "video/pmf/pmf", "video/pmf_simple/pmf_simple", - - # Currently hang or crash. - "audio/atrac/atractest", ] # These don't even run (or run correctly) on the real PSP test_broken = [ - "sysmem/sysmem", - "mstick/mstick", ]