From 82abb1e296cc01b7b94bd3be6ef6567d45b12d0f Mon Sep 17 00:00:00 2001 From: Kevin Armstrong Date: Fri, 30 Nov 2012 16:47:04 +0000 Subject: [PATCH 01/20] at least one game expects the UMD to be on UMD: --- Core/PSPLoaders.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index 49750d3fbc..526aa60a0e 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -59,10 +59,12 @@ bool Load_PSP_ISO(const char *filename, std::string *error_string) //pspFileSystem.Mount("host0:",umd2); pspFileSystem.Mount("umd0:", umd2); pspFileSystem.Mount("umd1:", umd2); - pspFileSystem.Mount("disc0:", umd2); + pspFileSystem.Mount("disc0:", umd2); + pspFileSystem.Mount("umd:", umd2); pspFileSystem.Mount("UMD0:", umd2); pspFileSystem.Mount("UMD1:", umd2); pspFileSystem.Mount("DISC0:", umd2); + pspFileSystem.Mount("UMD:", umd2); std::string bootpath("disc0:/PSP_GAME/SYSDIR/EBOOT.BIN"); // bypass patchers From e4c0d2d5cd4f0b3ad880cb02620c12c52d987827 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 29 Nov 2012 15:04:32 +0100 Subject: [PATCH 02/20] printf Asserts, so they end up in the test logs. --- Common/Log.h | 1 + native | 2 +- pspautotests | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Common/Log.h b/Common/Log.h index 742a96d912..d1047ec59e 100644 --- a/Common/Log.h +++ b/Common/Log.h @@ -101,6 +101,7 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, } #define _dbg_assert_msg_(_t_, _a_, ...)\ if (!(_a_)) {\ + printf(_t_, __VA_ARGS__); \ ERROR_LOG(_t_, __VA_ARGS__); \ if (!PanicYesNo(__VA_ARGS__)) {Crash();} \ } diff --git a/native b/native index 8b6adf4cd6..294ad623c5 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 8b6adf4cd698227dfc51cbbed4f26cf2baffe69c +Subproject commit 294ad623c5e23e9d9203606d720ff9ff2e490255 diff --git a/pspautotests b/pspautotests index 9b0212641a..9ac7e33512 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 9b0212641a161ae45be8617cd001dbd9a287c4a6 +Subproject commit 9ac7e335127c2829aeb040e97fd6c6116a4269bb From aa04eaec31107064c7fd6fe88a61c321083b1f63 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 29 Nov 2012 15:06:54 +0100 Subject: [PATCH 03/20] TextureCache: Cleanup, memory savings --- GPU/GLES/TextureCache.cpp | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index d667f768a1..77a8f71f70 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -26,6 +26,7 @@ // If a texture hasn't been seen for 200 frames, get rid of it. #define TEXTURE_KILL_AGE 200 +// TODO: Speed up by switching to ReadUnchecked*. struct TexCacheEntry { @@ -44,28 +45,34 @@ struct TexCacheEntry typedef std::map TexCache; static TexCache cache; +// These two share memory, just different types for convenience. u32 *tmpTexBuf32; u16 *tmpTexBuf16; + u32 *tmpTexBufRearrange; -u32 clutBuf32[4096]; -u16 clutBuf16[4096]; +u32 *clutBuf32; +u16 *clutBuf16; void TextureCache_Init() { + // TODO: Switch to aligned allocations for alignment. AllocateMemoryPages would do the trick. tmpTexBuf32 = new u32[1024 * 512]; - tmpTexBuf16 = new u16[1024 * 512]; + tmpTexBuf16 = (u16 *)tmpTexBuf32; tmpTexBufRearrange = new u32[1024 * 512]; + clutBuf32 = new u32[4096]; + clutBuf16 = new u16[4096]; } void TextureCache_Shutdown() { delete [] tmpTexBuf32; tmpTexBuf32 = 0; - delete [] tmpTexBuf16; - tmpTexBuf16 = 0; + tmpTexBuf16 = 0; //shares memory with tmpTexBuf32 delete [] tmpTexBufRearrange; tmpTexBufRearrange = 0; + delete [] clutBuf32; + delete [] clutBuf16; } void TextureCache_Clear(bool delete_them) @@ -421,6 +428,10 @@ u16 convert5551(u16 c) { return ((c & 0x8000) >> 15) | (c << 1); } + +// All these DXT structs are in the reverse order, as compared to PC. +// On PC, alpha comes before color, and interpolants are before the tile data. + struct DXT1Block { u8 lines[4]; @@ -447,6 +458,7 @@ inline u32 makecol(int r, int g, int b, int a) return (a << 24)|(r << 16)|(g << 8)|b; } +// This could probably be done faster by decoding two or four blocks at a time with SSE/NEON. void decodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, bool ignore1bitAlpha = false) { // S3TC Decoder @@ -545,6 +557,8 @@ void decodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch) void convertColors(u8 *finalBuf, GLuint dstFmt, int numPixels) { + // TODO: All these can be massively sped up with SSE, or even + // somewhat sped up using "manual simd" in 32 or 64-bit gprs. switch (dstFmt) { case GL_UNSIGNED_SHORT_4_4_4_4: { @@ -575,10 +589,7 @@ void convertColors(u8 *finalBuf, GLuint dstFmt, int numPixels) break; default: { - //u32 *p = (u32 *)finalBuf; - //for (int i = 0; i < numPixels; i++) { - // p[i] = _byteswap_ulong(p[i]); - //} + // No need to convert RGBA8888, right order already } break; } @@ -687,6 +698,7 @@ void PSPSetTexture() { case GE_TFMT_CLUT4: dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3)); + switch (clutformat) { case GE_CMODE_16BIT_BGR5650: @@ -816,10 +828,8 @@ void PSPSetTexture() break; case GE_TFMT_DXT1: - ERROR_LOG(G3D, "Partial DXT1 texture decoding. swizzle=%i w=%i h=%i bufw=%i", gstate.texmode & 1, w, h, bufw); dstFmt = GL_UNSIGNED_BYTE; { - // THIS IS VERY BROKEN but can be debugged! :) u32 *dst = tmpTexBuf32; DXT1Block *src = (DXT1Block*)texptr; @@ -840,10 +850,10 @@ void PSPSetTexture() case GE_TFMT_DXT3: dstFmt = GL_UNSIGNED_BYTE; { - // THIS IS VERY BROKEN but can be debugged! :) u32 *dst = tmpTexBuf32; DXT3Block *src = (DXT3Block*)texptr; + // Alpha is off for (int y = 0; y < h; y += 4) { u32 blockIndex = (y / 4) * (bufw / 4); @@ -862,10 +872,10 @@ void PSPSetTexture() ERROR_LOG(G3D, "Unhandled compressed texture, format %i! swizzle=%i", format, gstate.texmode & 1); dstFmt = GL_UNSIGNED_BYTE; { - // THIS IS VERY BROKEN but can be debugged! :) u32 *dst = tmpTexBuf32; DXT5Block *src = (DXT5Block*)texptr; + // Alpha is almost right for (int y = 0; y < h; y += 4) { u32 blockIndex = (y / 4) * (bufw / 4); From 6102e0f1433db0fbda464a5543156eea5a240a65 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 30 Nov 2012 19:33:01 +0100 Subject: [PATCH 04/20] Fix silly issue with logging in debug mode --- Common/Log.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/Log.h b/Common/Log.h index d1047ec59e..ff788063e6 100644 --- a/Common/Log.h +++ b/Common/Log.h @@ -101,7 +101,7 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, } #define _dbg_assert_msg_(_t_, _a_, ...)\ if (!(_a_)) {\ - printf(_t_, __VA_ARGS__); \ + printf(__VA_ARGS__); \ ERROR_LOG(_t_, __VA_ARGS__); \ if (!PanicYesNo(__VA_ARGS__)) {Crash();} \ } From a5e35ad6d94245e36ad4a81a10dba8c08d4c4cb2 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 30 Nov 2012 21:49:59 +0100 Subject: [PATCH 05/20] Parse PARAM.SFO to get the disc ID, show in title bar on Windows --- CMakeLists.txt | 2 + Core/CMakeLists.txt | 1 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 +++ Core/ELF/ParamSFO.cpp | 93 +++++++++++++++++++++++++++++++++++++++ Core/ELF/ParamSFO.h | 27 ++++++++++++ Core/Host.h | 1 + Core/MIPS/MIPSTables.cpp | 2 +- Core/PSPLoaders.cpp | 24 +++++++++- Windows/WindowsHost.cpp | 7 +++ Windows/WindowsHost.h | 9 ++-- Windows/main.cpp | 2 +- android/jni/Android.mk | 1 + 13 files changed, 171 insertions(+), 6 deletions(-) create mode 100644 Core/ELF/ParamSFO.cpp create mode 100644 Core/ELF/ParamSFO.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d694d2146e..e4a2362661 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -588,6 +588,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/ELF/ElfTypes.h Core/ELF/PrxDecrypter.cpp Core/ELF/PrxDecrypter.h + Core/ELF/ParamSFO.cpp + Core/ELF/ParamSFO.h Core/FileSystems/BlockDevices.cpp Core/FileSystems/BlockDevices.h Core/FileSystems/DirectoryFileSystem.cpp diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index a8b41ce75d..8428959a2f 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -13,6 +13,7 @@ set(SRCS MIPS/MIPSVFPUUtils.cpp MIPS/JitCommon/JitCommon.cpp ELF/ElfReader.cpp + ELF/ParamSFO.cpp ELF/PrxDecrypter.cpp HLE/HLE.cpp HLE/HLETables.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 8fafb7cdf6..6b8f518c3d 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -120,6 +120,7 @@ + @@ -251,6 +252,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index defdfee2b5..65452343d1 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -300,6 +300,9 @@ HLE\Libraries + + ELF + @@ -548,6 +551,9 @@ HLE\Libraries + + ELF + diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp new file mode 100644 index 0000000000..32395e6b74 --- /dev/null +++ b/Core/ELF/ParamSFO.cpp @@ -0,0 +1,93 @@ +// 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 "../Globals.h" +#include "ParamSFO.h" + +struct Header +{ + u32 magic; /* Always PSF */ + u32 version; /* Usually 1.1 */ + u32 key_table_start; /* Start position of key_table */ + u32 data_table_start; /* Start position of data_table */ + u32 index_table_entries; /* Number of entries in index_table*/ +}; + +struct IndexTable +{ + u16 key_table_offset; /* Offset of the param_key from start of key_table */ + u16 param_fmt; /* Type of data of param_data in the data_table */ + u32 param_len; /* Used Bytes by param_data in the data_table */ + u32 param_max_len; /* Total bytes reserved for param_data in the data_table */ + u32 data_table_offset; /* Offset of the param_data from start of data_table */ +}; + +void ParseDataString(const char *key, const char *utfdata, ParamSFOData *sfodata) +{ + if (!strcmp(key, "DISC_ID")) + { + sfodata->discID = utfdata; + } +} + +// I'm so sorry Ced but this is highly endian unsafe :( +bool ParseParamSFO(const u8 *paramsfo, size_t size, ParamSFOData *data) +{ + const Header *header = (const Header *)paramsfo; + if (header->magic != 0x46535000) + return false; + if (header->version != 0x00000101) + WARN_LOG(LOADER, "Unexpected SFO header version: %08x", header->version); + + const IndexTable *indexTables = (const IndexTable *)(paramsfo + sizeof(Header)); + + const u8 *key_start = paramsfo + header->key_table_start; + const u8 *data_start = paramsfo + header->data_table_start; + + for (int i = 0; i < header->index_table_entries; i++) + { + const char *key = (const char *)(key_start + indexTables[i].key_table_offset); + + switch (indexTables[i].param_fmt) { + case 0x0404: + { + // Unsigned int + const u32 *data = (const u32 *)(data_start + indexTables[i].data_table_offset); + DEBUG_LOG(LOADER, "%s %08x", key, *data); + } + break; + case 0x0004: + // Special format UTF-8 + { + const char *utfdata = (const char *)(data_start + indexTables[i].data_table_offset); + DEBUG_LOG(LOADER, "%s %s", key, utfdata); + ParseDataString(key, utfdata, data); + } + break; + case 0x0204: + // Regular UTF-8 + { + const char *utfdata = (const char *)(data_start + indexTables[i].data_table_offset); + DEBUG_LOG(LOADER, "%s %s", key, utfdata); + ParseDataString(key, utfdata, data); + } + break; + } + } + + return true; +} \ No newline at end of file diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h new file mode 100644 index 0000000000..7840513604 --- /dev/null +++ b/Core/ELF/ParamSFO.h @@ -0,0 +1,27 @@ +// 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 + + +struct ParamSFOData +{ + std::string discID; +}; + +bool ParseParamSFO(const u8 *paramsfo, size_t size, ParamSFOData *data); \ No newline at end of file diff --git a/Core/Host.h b/Core/Host.h index b0860c24c6..9936e8db8f 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -58,6 +58,7 @@ public: virtual bool IsDebuggingEnabled() {return true;} virtual bool AttemptLoadSymbolMap() {return false;} + virtual void SetWindowTitle(const char *message) {} }; extern Host *host; diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 758856ca27..67d9b70e92 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -950,7 +950,7 @@ int MIPSInterpret_RunUntil(u64 globalTicks) // int cycles = 0; { again: - u32 op = Memory::ReadUnchecked_U32(curMips->pc); + u32 op = Memory::Read_U32(curMips->pc); //u32 op = Memory::Read_Opcode_JIT(mipsr4k.pc); /* // Choke on VFPU diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index 526aa60a0e..22b0aa5d15 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -37,7 +37,7 @@ #include "HLE/sceKernelThread.h" #include "HLE/sceKernelModule.h" #include "HLE/sceKernelMemory.h" - +#include "ELF/ParamSFO.h" BlockDevice *constructBlockDevice(const char *filename) { @@ -52,10 +52,13 @@ BlockDevice *constructBlockDevice(const char *filename) } } + bool Load_PSP_ISO(const char *filename, std::string *error_string) { ISOFileSystem *umd2 = new ISOFileSystem(&pspFileSystem, constructBlockDevice(filename)); + // Parse PARAM.SFO + //pspFileSystem.Mount("host0:",umd2); pspFileSystem.Mount("umd0:", umd2); pspFileSystem.Mount("umd1:", umd2); @@ -66,6 +69,24 @@ bool Load_PSP_ISO(const char *filename, std::string *error_string) pspFileSystem.Mount("DISC0:", umd2); pspFileSystem.Mount("UMD:", umd2); + std::string sfoPath("disc0:/PSP_GAME/PARAM.SFO"); + PSPFileInfo fileInfo = pspFileSystem.GetFileInfo(sfoPath.c_str()); + if (fileInfo.exists) + { + u8 *paramsfo = new u8[fileInfo.size]; + u32 fd = pspFileSystem.OpenFile(sfoPath, FILEACCESS_READ); + pspFileSystem.ReadFile(fd, paramsfo, fileInfo.size); + pspFileSystem.CloseFile(fd); + ParamSFOData data; + if (ParseParamSFO(paramsfo, fileInfo.size, &data)) + { + INFO_LOG(LOADER, "Disc ID: %s", data.discID.c_str()); + host->SetWindowTitle(data.discID.c_str()); + } + delete [] paramsfo; + } + + std::string bootpath("disc0:/PSP_GAME/SYSDIR/EBOOT.BIN"); // bypass patchers if (pspFileSystem.GetFileInfo("disc0:/PSP_GAME/SYSDIR/EBOOT.OLD").exists) { @@ -80,6 +101,7 @@ bool Load_PSP_ISO(const char *filename, std::string *error_string) if (memcmp(head, "~PSP", 4) == 0 || memcmp(head, "\x7F""ELF", 4) == 0) { hasEncrypted = true; } + pspFileSystem.CloseFile(fd); } if (!hasEncrypted) { diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 1ae42e6b08..3837d59501 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -35,6 +35,13 @@ void WindowsHost::ShutdownGL() GL_Shutdown(); } +void WindowsHost::SetWindowTitle(const char *message) +{ + // Really need a better way to deal with versions. + std::string title = "PPSSPP v0.31 - "; + title += message; + SetWindowText(mainWindow_, title.c_str()); +} void WindowsHost::InitSound(PMixer *mixer) { diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index adbb24a876..c46c888543 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -6,9 +6,10 @@ class WindowsHost : public Host { public: - WindowsHost(HWND _displayWindow) + WindowsHost(HWND mainWindow, HWND displayWindow) { - displayWindow = _displayWindow; + mainWindow_ = mainWindow; + displayWindow_ = displayWindow; input = getInputDevices(); } void UpdateMemView(); @@ -31,8 +32,10 @@ public: void BootDone(); void PrepareShutdown(); bool AttemptLoadSymbolMap(); + void SetWindowTitle(const char *message); private: - HWND displayWindow; + HWND displayWindow_; + HWND mainWindow_; std::list> input; }; \ No newline at end of file diff --git a/Windows/main.cpp b/Windows/main.cpp index a64c1aad90..aa2d422de1 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -75,12 +75,12 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin InitCommonControlsEx(&comm); MainWindow::Init(_hInstance); - host = new WindowsHost(MainWindow::GetDisplayHWND()); HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS); g_hPopupMenus = LoadMenu(_hInstance, (LPCSTR)IDR_POPUPMENUS); MainWindow::Show(_hInstance, iCmdShow); + host = new WindowsHost(MainWindow::GetHWND(), MainWindow::GetDisplayHWND()); HWND hwndMain = MainWindow::GetHWND(); HMENU menu = GetMenu(hwndMain); diff --git a/android/jni/Android.mk b/android/jni/Android.mk index aba59148fe..15039a4ee4 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -80,6 +80,7 @@ LOCAL_SRC_FILES := \ $(SRC)/GPU/Null/NullGpu.cpp \ $(SRC)/Core/ELF/ElfReader.cpp \ $(SRC)/Core/ELF/PrxDecrypter.cpp \ + $(SRC)/Core/ELF/ParamSFO.cpp \ $(SRC)/Core/HW/MemoryStick.cpp \ $(SRC)/Core/Core.cpp \ $(SRC)/Core/Config.cpp \ From e255550a8e2260282015f12f5f20a9eaf4394e87 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 30 Nov 2012 21:50:52 +0100 Subject: [PATCH 06/20] Update tests --- pspautotests | 2 +- test.py | 20 +++++++------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/pspautotests b/pspautotests index 9ac7e33512..3c81649c4b 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 9ac7e335127c2829aeb040e97fd6c6116a4269bb +Subproject commit 3c81649c4b4056ddabaca293c093ba0d6989502b diff --git a/test.py b/test.py index b316e2b36e..e4ca54c4d8 100755 --- a/test.py +++ b/test.py @@ -49,6 +49,7 @@ tests_good = [ "display/display", "dmac/dmactest", + "loader/bss/bss", "intr/intr", "intr/vblank/vblank", "misc/testgp", @@ -68,10 +69,13 @@ tests_good = [ ] tests_next = [ + "audio/sascore/sascore", "malloc/malloc", # These are the next tests up for fixing. These run by default. "threads/fpl/fpl", + "threads/k0/k0", "threads/msgpipe/msgpipe", + "threads/mutex/mutex", "threads/mutex/create/create", "threads/mutex/lock/lock", "threads/mutex/priority/priority", @@ -86,7 +90,6 @@ tests_next = [ "threads/vpl/vpl", "threads/vtimers/vtimer", "threads/wakeup/wakeup", - "audio/sascore/sascore", "ctrl/ctrl", "gpu/simple/simple", "gpu/triangle/triangle", @@ -97,20 +100,11 @@ tests_next = [ "io/iodrv/iodrv", "modules/loadexec/loader", "rtc/rtc", - "threads/k0/k0", - "threads/fpl/fpl", - "threads/msgpipe/msgpipe", - "threads/mutex/mutex", - "threads/scheduling/scheduling", - "threads/threads/threads", - "threads/vpl/vpl", - "threads/vtimers/vtimers", - "threads/wakeup/wakeup", "umd/io/umd_io", - "umd/raw_access/raw_acess", + "umd/raw_access/raw_access", "utility/systemparam/systemparam", - "video/pmf", - "video/pmf_simple", + "video/pmf/pmf", + "video/pmf_simple/pmf_simple", # Currently hang or crash. "threads/events/events", From 1189da826ca8c4fc09e909f661de9069cd57c904 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 30 Nov 2012 22:32:15 +0100 Subject: [PATCH 07/20] Also get TITLE from PARAM.SFO --- Core/ELF/ParamSFO.cpp | 13 +++++++------ Core/ELF/ParamSFO.h | 1 + Core/PSPLoaders.cpp | 10 ++++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index 32395e6b74..9119f162a5 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -38,9 +38,10 @@ struct IndexTable void ParseDataString(const char *key, const char *utfdata, ParamSFOData *sfodata) { - if (!strcmp(key, "DISC_ID")) - { + if (!strcmp(key, "DISC_ID")) { sfodata->discID = utfdata; + } else if (!strcmp(key, "TITLE")) { + sfodata->title = utfdata; } } @@ -48,17 +49,17 @@ void ParseDataString(const char *key, const char *utfdata, ParamSFOData *sfodata bool ParseParamSFO(const u8 *paramsfo, size_t size, ParamSFOData *data) { const Header *header = (const Header *)paramsfo; - if (header->magic != 0x46535000) + if (header->magic != 0x46535000) return false; if (header->version != 0x00000101) WARN_LOG(LOADER, "Unexpected SFO header version: %08x", header->version); - + const IndexTable *indexTables = (const IndexTable *)(paramsfo + sizeof(Header)); const u8 *key_start = paramsfo + header->key_table_start; const u8 *data_start = paramsfo + header->data_table_start; - for (int i = 0; i < header->index_table_entries; i++) + for (int i = 0; i < header->index_table_entries; i++) { const char *key = (const char *)(key_start + indexTables[i].key_table_offset); @@ -69,7 +70,7 @@ bool ParseParamSFO(const u8 *paramsfo, size_t size, ParamSFOData *data) const u32 *data = (const u32 *)(data_start + indexTables[i].data_table_offset); DEBUG_LOG(LOADER, "%s %08x", key, *data); } - break; + break; case 0x0004: // Special format UTF-8 { diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index 7840513604..f92bef1a5a 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -22,6 +22,7 @@ struct ParamSFOData { std::string discID; + std::string title; // utf-8 }; bool ParseParamSFO(const u8 *paramsfo, size_t size, ParamSFOData *data); \ No newline at end of file diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index 22b0aa5d15..ae628e760a 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -73,15 +73,17 @@ bool Load_PSP_ISO(const char *filename, std::string *error_string) PSPFileInfo fileInfo = pspFileSystem.GetFileInfo(sfoPath.c_str()); if (fileInfo.exists) { - u8 *paramsfo = new u8[fileInfo.size]; + u8 *paramsfo = new u8[(size_t)fileInfo.size]; u32 fd = pspFileSystem.OpenFile(sfoPath, FILEACCESS_READ); pspFileSystem.ReadFile(fd, paramsfo, fileInfo.size); pspFileSystem.CloseFile(fd); ParamSFOData data; - if (ParseParamSFO(paramsfo, fileInfo.size, &data)) + if (ParseParamSFO(paramsfo, (size_t)fileInfo.size, &data)) { - INFO_LOG(LOADER, "Disc ID: %s", data.discID.c_str()); - host->SetWindowTitle(data.discID.c_str()); + char title[1024]; + sprintf(title, "%s : %s", data.discID.c_str(), data.title.c_str()); + INFO_LOG(LOADER, "%s", title); + host->SetWindowTitle(title); } delete [] paramsfo; } From 3ab41e515d189c7dd1c2c74a69322393a846b0bd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 26 Nov 2012 00:41:55 -0800 Subject: [PATCH 08/20] Mutexes and semaphores don't always reschedule. It's just the normal rescheduling happening. Previous tests weren't correct. Also some minor cleanup. --- Core/HLE/sceKernelMutex.cpp | 44 ++++++++++++++------------------- Core/HLE/sceKernelSemaphore.cpp | 39 ++++++++++++----------------- 2 files changed, 35 insertions(+), 48 deletions(-) diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 50ed950f12..5a11d33e08 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -15,8 +15,6 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -// UNFINISHED - #include #include #include "HLE.h" @@ -203,8 +201,6 @@ void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 opti WARN_LOG(HLE,"sceKernelCreateMutex(%s) unsupported options parameter.", name); RETURN(id); - - __KernelReSchedule("mutex created"); } void sceKernelDeleteMutex(SceUID id) @@ -214,6 +210,7 @@ void sceKernelDeleteMutex(SceUID id) Mutex *mutex = kernelObjects.Get(id, error); if (mutex) { + bool wokeThreads = false; std::vector::iterator iter, end; for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { @@ -228,13 +225,16 @@ void sceKernelDeleteMutex(SceUID id) } __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); + wokeThreads = true; } if (mutex->nm.lockThread != -1) __KernelMutexEraseLock(mutex); - mutex->waitingThreads.empty(); + mutex->waitingThreads.clear(); RETURN(kernelObjects.Destroy(id)); - __KernelReSchedule("mutex deleted"); + + if (wokeThreads) + __KernelReSchedule("mutex deleted"); } else RETURN(error); @@ -386,7 +386,6 @@ void sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) if (__KernelLockMutex(mutex, count, error)) { RETURN(0); - __KernelReSchedule("mutex locked"); } else if (error) RETURN(error); @@ -395,6 +394,7 @@ void sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) mutex->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false); + __KernelReSchedule("mutex locked"); } } @@ -409,7 +409,6 @@ void sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) if (__KernelLockMutex(mutex, count, error)) { RETURN(0); - __KernelReSchedule("mutex locked"); } else if (error) RETURN(error); @@ -419,9 +418,8 @@ void sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) __KernelWaitMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, true); __KernelCheckCallbacks(); + __KernelReSchedule("mutex locked"); } - - __KernelReSchedule("mutex locked"); } // int sceKernelTryLockMutex(SceUID id, int count) @@ -433,10 +431,7 @@ void sceKernelTryLockMutex(SceUID id, int count) Mutex *mutex = kernelObjects.Get(id, error); if (__KernelLockMutex(mutex, count, error)) - { RETURN(0); - __KernelReSchedule("mutex trylocked"); - } else if (error) RETURN(error); else @@ -474,8 +469,8 @@ void sceKernelUnlockMutex(SceUID id, int count) if (mutex->nm.lockLevel == 0) { - __KernelUnlockMutex(mutex, error); - __KernelReSchedule("mutex unlocked"); + if (__KernelUnlockMutex(mutex, error)) + __KernelReSchedule("mutex locked"); } } @@ -524,8 +519,6 @@ void sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int ini WARN_LOG(HLE,"sceKernelCreateLwMutex(%s) unsupported options parameter.", name); RETURN(0); - - __KernelReSchedule("lwmutex created"); } void sceKernelDeleteLwMutex(u32 workareaPtr) @@ -545,6 +538,7 @@ void sceKernelDeleteLwMutex(u32 workareaPtr) LwMutex *mutex = kernelObjects.Get(workarea.uid, error); if (mutex) { + bool wokeThreads = false; std::vector::iterator iter, end; for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { @@ -559,14 +553,16 @@ void sceKernelDeleteLwMutex(u32 workareaPtr) } __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); + wokeThreads = true; } - mutex->waitingThreads.empty(); + mutex->waitingThreads.clear(); RETURN(kernelObjects.Destroy(workarea.uid)); workarea.clear(); Memory::WriteStruct(workareaPtr, &workarea); - __KernelReSchedule("mutex deleted"); + if (wokeThreads) + __KernelReSchedule("lwmutex deleted"); } else RETURN(error); @@ -706,7 +702,6 @@ void sceKernelTryLockLwMutex(u32 workareaPtr, int count) { Memory::WriteStruct(workareaPtr, &workarea); RETURN(0); - __KernelReSchedule("lwmutex trylocked"); } else if (error) RETURN(PSP_MUTEX_ERROR_TRYLOCK_FAILED); @@ -726,7 +721,6 @@ void sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) { Memory::WriteStruct(workareaPtr, &workarea); RETURN(0); - __KernelReSchedule("lwmutex trylocked"); } else if (error) RETURN(error); @@ -746,7 +740,6 @@ void sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) { Memory::WriteStruct(workareaPtr, &workarea); RETURN(0); - __KernelReSchedule("lwmutex locked"); } else if (error) RETURN(error); @@ -758,6 +751,7 @@ void sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) mutex->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitLwMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, false); + __KernelReSchedule("lwmutex locked"); } else RETURN(error); @@ -776,7 +770,6 @@ void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) { Memory::WriteStruct(workareaPtr, &workarea); RETURN(0); - __KernelReSchedule("lwmutex locked"); } else if (error) RETURN(error); @@ -789,6 +782,7 @@ void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) __KernelWaitLwMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, true); __KernelCheckCallbacks(); + __KernelReSchedule("lwmutex locked"); } else RETURN(error); @@ -825,9 +819,9 @@ void sceKernelUnlockLwMutex(u32 workareaPtr, int count) if (workarea.lockLevel == 0) { - __KernelUnlockLwMutex(workarea, error); + if (__KernelUnlockLwMutex(workarea, error)) + __KernelReSchedule("lwmutex unlocked"); Memory::WriteStruct(workareaPtr, &workarea); - __KernelReSchedule("lwmutex unlocked"); } else Memory::WriteStruct(workareaPtr, &workarea); diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 2cb1a8b9c1..94abccb2ef 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -78,7 +78,7 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason) // TODO: PSP_SEMA_ATTR_PRIORITY std::vector::iterator iter; - for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); iter++) + for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter) { SceUID threadID = *iter; @@ -94,7 +94,7 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason) __KernelResumeThreadFromWait(threadID, reason); wokeThreads = true; } - s->waitingThreads.empty(); + s->waitingThreads.clear(); return wokeThreads; } @@ -129,8 +129,8 @@ void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) // We need to set the return value BEFORE rescheduling threads. RETURN(0); - __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL); - __KernelReSchedule("semaphore cancelled"); + if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL)) + __KernelReSchedule("semaphore canceled"); } else { @@ -170,8 +170,6 @@ void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u3 WARN_LOG(HLE,"sceKernelCreateSema(%s) unsupported options parameter.", name); RETURN(id); - - __KernelReSchedule("semaphore created"); } //int sceKernelDeleteSema(SceUID semaid); @@ -184,9 +182,11 @@ void sceKernelDeleteSema(SceUID id) Semaphore *s = kernelObjects.Get(id, error); if (s) { - __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE); + bool wokeThreads = __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE); RETURN(kernelObjects.Destroy(id)); - __KernelReSchedule("semaphore deleted"); + + if (wokeThreads) + __KernelReSchedule("semaphore deleted"); } else { @@ -206,7 +206,6 @@ void sceKernelReferSemaStatus(SceUID id, u32 infoPtr) DEBUG_LOG(HLE,"sceKernelReferSemaStatus(%i, %08x)", id, infoPtr); Memory::WriteStruct(infoPtr, &s->ns); RETURN(0); - __KernelReSchedule("semaphore refer status"); } else { @@ -219,7 +218,6 @@ void sceKernelReferSemaStatus(SceUID id, u32 infoPtr) // void because it changes threads. void sceKernelSignalSema(SceUID id, int signal) { - //TODO: check that this thing really works :) u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) @@ -237,11 +235,11 @@ void sceKernelSignalSema(SceUID id, int signal) // We need to set the return value BEFORE processing other threads. RETURN(0); - bool wokeThreads = false; -retry: // TODO: PSP_SEMA_ATTR_PRIORITY + bool wokeThreads = false; std::vector::iterator iter; - for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); iter++) +retry: + for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter) { SceUID threadID = *iter; @@ -261,17 +259,14 @@ retry: } __KernelResumeThreadFromWait(threadID, 0); - wokeThreads = true; s->waitingThreads.erase(iter); + wokeThreads = true; goto retry; } - else - { - break; - } } - __KernelReSchedule("semaphore signalled"); + if (wokeThreads) + __KernelReSchedule("semaphore signaled"); } else { @@ -336,9 +331,9 @@ void __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *ba __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks); if (processCallbacks) __KernelCheckCallbacks(); - } - __KernelReSchedule("semaphore waited"); + __KernelReSchedule("semaphore waited"); + } } else { @@ -387,8 +382,6 @@ void sceKernelPollSema(SceUID id, int wantedCount) } else RETURN(SCE_KERNEL_ERROR_SEMA_ZERO); - - __KernelReSchedule("semaphore polled"); } else { From 71646387990186a85836cd7c29939f510ec9262a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 27 Nov 2012 23:22:49 -0800 Subject: [PATCH 09/20] Allow semaphores with waiters to signal. If the max is 1, but there's 1 waiting, it's okay to signal 2. Really, the final result is what matters. --- Core/HLE/sceKernelSemaphore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 94abccb2ef..fdd19b94b7 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -222,7 +222,7 @@ void sceKernelSignalSema(SceUID id, int signal) Semaphore *s = kernelObjects.Get(id, error); if (s) { - if (s->ns.currentCount + signal > s->ns.maxCount) + if (s->ns.currentCount + signal - s->ns.numWaitThreads > s->ns.maxCount) { RETURN(SCE_KERNEL_ERROR_SEMA_OVF); return; From 48c5efd0c2f2a9cb1a6783dc10574349eb278140 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 30 Nov 2012 22:20:14 -0800 Subject: [PATCH 10/20] Match hw timing of mutex/sema timeouts better. Affects some tests passing/not passing due to minor timing issues, ugh. --- Core/HLE/sceKernelMutex.cpp | 9 ++++++++- Core/HLE/sceKernelSemaphore.cpp | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 5a11d33e08..8a0224cb7d 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -685,8 +685,15 @@ void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr) if (timeoutPtr == 0 || lwMutexWaitTimer == 0) return; - // This should call __KernelMutexTimeout() later, unless we cancel it. int micro = (int) Memory::Read_U32(timeoutPtr); + + // This happens to be how the hardware seems to time things. + if (micro <= 3) + micro = 15; + else if (micro <= 249) + micro = 250; + + // This should call __KernelMutexTimeout() later, unless we cancel it. CoreTiming::ScheduleEvent(usToCycles(micro), lwMutexWaitTimer, __KernelGetCurThread()); } diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index fdd19b94b7..ccbc46c035 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -301,8 +301,15 @@ void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr) if (timeoutPtr == 0 || semaWaitTimer == 0) return; - // This should call __KernelMutexTimeout() later, unless we cancel it. int micro = (int) Memory::Read_U32(timeoutPtr); + + // This happens to be how the hardware seems to time things. + if (micro <= 3) + micro = 15; + else if (micro <= 249) + micro = 250; + + // This should call __KernelSemaTimeout() later, unless we cancel it. CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread()); } From 998104e2eb9f12ca4cbd4a4ac5565c15fe7f6f0a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 30 Nov 2012 23:04:24 -0800 Subject: [PATCH 11/20] Consider threads still waiting until they wake. This seems to match the actual behavior of timeouts much better. --- Core/HLE/sceKernelMutex.cpp | 40 ++++++++++++++++++++------------- Core/HLE/sceKernelSemaphore.cpp | 18 +++++++++++---- Core/HLE/sceKernelThread.cpp | 4 ++++ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 8a0224cb7d..bf024fbd44 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -215,6 +215,10 @@ void sceKernelDeleteMutex(SceUID id) for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); + // The waitID may be different after a timeout. + if (waitID != id) + continue; u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); if (timeoutPtr != 0 && mutexWaitTimer != 0) @@ -288,9 +292,17 @@ bool __KernelUnlockMutex(Mutex *mutex, u32 &error) // TODO: PSP_MUTEX_ATTR_PRIORITY bool wokeThreads = false; std::vector::iterator iter, end; +retry: for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + { + mutex->waitingThreads.erase(iter); + goto retry; + } int wVal = (int)__KernelGetWaitValue(threadID, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); @@ -325,14 +337,6 @@ void __KernelMutexTimeout(u64 userdata, int cyclesLate) if (timeoutPtr != 0) Memory::Write_U32(0, timeoutPtr); - SceUID mutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); - Mutex *mutex = kernelObjects.Get(mutexID, error); - if (mutex) - { - // This thread isn't waiting anymore. - mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end()); - } - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); } @@ -543,6 +547,10 @@ void sceKernelDeleteLwMutex(u32 workareaPtr) for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + continue; u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); if (timeoutPtr != 0 && lwMutexWaitTimer != 0) @@ -631,9 +639,17 @@ bool __KernelUnlockLwMutex(NativeLwMutexWorkarea &workarea, u32 &error) // TODO: PSP_MUTEX_ATTR_PRIORITY bool wokeThreads = false; std::vector::iterator iter, end; +retry: for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + { + mutex->waitingThreads.erase(iter); + goto retry; + } int wVal = (int)__KernelGetWaitValue(threadID, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); @@ -669,14 +685,6 @@ void __KernelLwMutexTimeout(u64 userdata, int cyclesLate) if (timeoutPtr != 0) Memory::Write_U32(0, timeoutPtr); - SceUID mutexID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); - LwMutex *mutex = kernelObjects.Get(mutexID, error); - if (mutex) - { - // This thread isn't waiting anymore. - mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end()); - } - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); } diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index ccbc46c035..b82f9f8efe 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -80,9 +80,13 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason) std::vector::iterator iter; for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter) { - SceUID threadID = *iter; - u32 error; + SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); + // The waitID may be different after a timeout. + if (waitID != s->GetUID()) + continue; + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); if (timeoutPtr != 0 && semaWaitTimer != 0) { @@ -242,6 +246,13 @@ retry: for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); + // The waitID may be different after a timeout. + if (waitID != s->GetUID()) + { + s->waitingThreads.erase(iter); + goto retry; + } int wVal = (int)__KernelGetWaitValue(threadID, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); @@ -288,8 +299,7 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate) Semaphore *s = kernelObjects.Get(semaID, error); if (s) { - // This thread isn't waiting anymore. - s->waitingThreads.erase(std::remove(s->waitingThreads.begin(), s->waitingThreads.end(), threadID), s->waitingThreads.end()); + // This thread isn't waiting anymore, but we'll remove it from waitingThreads later. s->ns.numWaitThreads--; } diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index c6bee53c8f..c20a70c951 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1545,6 +1545,10 @@ void __KernelSwitchContext(Thread *target, const char *reason) __KernelLoadContext(¤tThread->context); DEBUG_LOG(HLE,"Context loaded (%s): %i - %s - pc: %08x", reason, currentThread->GetUID(), currentThread->GetName(), currentMIPS->pc); + // No longer waiting. + currentThread->nt.waitType = WAITTYPE_NONE; + currentThread->nt.waitID = 0; + __KernelExecutePendingMipsCalls(); } From a2ee73679353dc9d97eb61a7e1624a0f7ca76bec Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 30 Nov 2012 23:06:27 -0800 Subject: [PATCH 12/20] Process events when idle or switching threads. Fixes hrydgard/ppsspp#104, so things execute more accurately. --- Core/CoreTiming.cpp | 16 +++++++++++++++- Core/HLE/sceKernelThread.cpp | 8 ++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index d5b71ec237..57a79e581d 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -500,6 +500,20 @@ void Idle(int maxIdle) if (maxIdle != 0 && cyclesDown > maxIdle) cyclesDown = maxIdle; + if (first && cyclesDown > 0) + { + int cyclesExecuted = slicelength - downcount; + int cyclesNextEvent = (int) (first->time - globalTimer); + + if (cyclesNextEvent < cyclesExecuted + cyclesDown) + { + cyclesDown = cyclesNextEvent - cyclesExecuted; + // Now, now... no time machines, please. + if (cyclesDown < 0) + cyclesDown = 0; + } + } + DEBUG_LOG(CPU, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(CPU_HZ * 0.001f)); idledCycles += cyclesDown; @@ -520,7 +534,7 @@ std::string GetScheduledEventsSummary() if (!name) name = "[unknown]"; char temp[512]; - sprintf(temp, "%s : %i %08x%08x\n", event_types[ptr->type].name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); + sprintf(temp, "%s : %i %08x%08x\n", name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); text += temp; ptr = ptr->next; } diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index c20a70c951..3d15e657b9 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -730,6 +730,14 @@ void __KernelReSchedule(const char *reason) return; } + // Execute any pending events while we're doing scheduling. + CoreTiming::Advance(); + if (__IsInInterrupt() || __KernelInCallback()) + { + reason = "In Interrupt Or Callback"; + return; + } + retry: Thread *nextThread = __KernelNextThread(); From f8629c514477a0dbc76427c506e9a976b3e963cf Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 30 Nov 2012 23:22:55 -0800 Subject: [PATCH 13/20] Update tests. --- test.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/test.py b/test.py index e4ca54c4d8..1378ed3018 100755 --- a/test.py +++ b/test.py @@ -55,14 +55,19 @@ tests_good = [ "misc/testgp", "string/string", "gpu/callbacks/ge_callbacks", + "threads/lwmutex/create/create", + "threads/lwmutex/delete/delete", "threads/mbx/mbx", - "threads/mutex/mutex", + "threads/mutex/create/create", "threads/mutex/delete/delete", "threads/semaphores/semaphores", + "threads/semaphores/cancel/cancel", + "threads/semaphores/create/create", "threads/semaphores/delete/delete", "threads/semaphores/poll/poll", "threads/semaphores/refer/refer", "threads/semaphores/signal/signal", + "threads/semaphores/wait/wait", "power/power", "umd/callbacks/umd", "io/directory/directory", @@ -74,18 +79,18 @@ tests_next = [ # These are the next tests up for fixing. These run by default. "threads/fpl/fpl", "threads/k0/k0", + "threads/lwmutex/lock/lock", + "threads/lwmutex/try/try", + "threads/lwmutex/try600/try600", + "threads/lwmutex/unlock/unlock", "threads/msgpipe/msgpipe", "threads/mutex/mutex", - "threads/mutex/create/create", "threads/mutex/lock/lock", "threads/mutex/priority/priority", "threads/mutex/try/try", "threads/mutex/unlock/unlock", "threads/scheduling/scheduling", - "threads/semaphores/cancel/cancel", - "threads/semaphores/create/create", "threads/semaphores/priority/priority", - "threads/semaphores/wait/wait", "threads/threads/threads", "threads/vpl/vpl", "threads/vtimers/vtimer", From d4cc0bada7c4e88237f006eb2b1e1b23054b5543 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 1 Dec 2012 02:12:30 +0100 Subject: [PATCH 14/20] Revert broken optimization in TextureCache (there are still memory savings to be had though) --- GPU/GLES/TextureCache.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 77a8f71f70..9ad2685657 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -45,7 +45,6 @@ struct TexCacheEntry typedef std::map TexCache; static TexCache cache; -// These two share memory, just different types for convenience. u32 *tmpTexBuf32; u16 *tmpTexBuf16; @@ -58,7 +57,7 @@ void TextureCache_Init() { // TODO: Switch to aligned allocations for alignment. AllocateMemoryPages would do the trick. tmpTexBuf32 = new u32[1024 * 512]; - tmpTexBuf16 = (u16 *)tmpTexBuf32; + tmpTexBuf16 = new u16[1024 * 512]; tmpTexBufRearrange = new u32[1024 * 512]; clutBuf32 = new u32[4096]; clutBuf16 = new u16[4096]; @@ -68,7 +67,8 @@ void TextureCache_Shutdown() { delete [] tmpTexBuf32; tmpTexBuf32 = 0; - tmpTexBuf16 = 0; //shares memory with tmpTexBuf32 + delete [] tmpTexBuf16; + tmpTexBuf16 = 0; delete [] tmpTexBufRearrange; tmpTexBufRearrange = 0; delete [] clutBuf32; From cdc94a6cad9d59bde9ac74d5c8707ea521bf781e Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 1 Dec 2012 02:13:42 +0100 Subject: [PATCH 15/20] Halve the kernel memory so that the "volatile" 4MB fits without overlapping --- Core/MemMap.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/MemMap.h b/Core/MemMap.h index 7d34d61abf..0e5fe2a20e 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -53,7 +53,9 @@ typedef void (*readFn64)(u64&, const u32); inline u32 PSP_GetKernelMemoryBase() { return 0x08000000;} -inline u32 PSP_GetKernelMemoryEnd() { return 0x08800000;} +inline u32 PSP_GetKernelMemoryEnd() { return 0x08400000;} +// "Volatile" RAM is between 0x08400000 and 0x08800000, can be requested by the +// game through sceKernelVolatileMemTryLock. inline u32 PSP_GetUserMemoryBase() { return 0x08800000;} inline u32 PSP_GetUserMemoryEnd() { return 0x0A000000;} From 6e32b30afdf7b662f3139ae21a390a65944d5ae6 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 1 Dec 2012 02:15:46 +0100 Subject: [PATCH 16/20] DisplayDrawer->FramebufferManager --- Core/System.cpp | 9 ---- GPU/GLES/DisplayListInterpreter.cpp | 19 +++++--- GPU/GLES/DisplayListInterpreter.h | 4 +- GPU/GLES/Framebuffer.cpp | 71 ++++++++--------------------- GPU/GLES/Framebuffer.h | 28 ++++++++++-- 5 files changed, 59 insertions(+), 72 deletions(-) diff --git a/Core/System.cpp b/Core/System.cpp index d5b6522a28..da48ca9969 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -76,11 +76,6 @@ bool PSP_Init(const CoreParameter &coreParam, std::string *error_string) return false; } - if (coreParameter.gpuCore != GPU_NULL) - { - DisplayDrawer_Init(); - } - shaderManager.DirtyShader(); shaderManager.DirtyUniform(DIRTY_ALL); @@ -113,10 +108,6 @@ void PSP_Shutdown() } __KernelShutdown(); HLEShutdown(); - if (coreParameter.gpuCore != GPU_NULL) - { - DisplayDrawer_Shutdown(); - } Memory::Shutdown() ; currentCPU = 0; } diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index a5fa595a6f..efcad63c1f 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -85,11 +85,16 @@ void GLES_GPU::BeginFrame() { TextureCache_Decimate(); + // NOTE - this is all wrong. At the beginning of the frame is a TERRIBLE time to draw the fb. if (g_Config.bDisplayFramebuffer && displayFramebufPtr_) { INFO_LOG(HLE, "Drawing the framebuffer"); - u8 *pspframebuf = Memory::GetPointer((0x44000000)|(displayFramebufPtr_ & 0x1FFFFF)); // TODO - check - DisplayDrawer_DrawFramebuffer(pspframebuf, displayFormat_, displayStride_); + const u8 *pspframebuf = Memory::GetPointer((0x44000000) | (displayFramebufPtr_ & 0x1FFFFF)); // TODO - check + glstate.cullFace.disable(); + glstate.depthTest.disable(); + glstate.blend.disable(); + framebufferManager.DrawPixels(pspframebuf, displayFormat_, displayStride_); + // TODO: restore state? } currentRenderVfb_ = 0; } @@ -101,7 +106,7 @@ void GLES_GPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, int format) displayStride_ = stride; displayFormat_ = format; } else { - DEBUG_LOG(HLE, "Bogus framebufffer address: %08x", framebuf); + DEBUG_LOG(HLE, "Bogus framebuffer address: %08x", framebuf); } } @@ -133,8 +138,8 @@ void GLES_GPU::CopyDisplayToOutput() fbo_bind_color_as_texture(vfb->fbo, 0); - // These are in the output pixel coordinates - DrawActiveTexture(480, 272, true); + // These are in the output display coordinates + framebufferManager.DrawActiveTexture(480, 272, true); shaderManager.DirtyShader(); shaderManager.DirtyUniform(DIRTY_ALL); @@ -320,7 +325,7 @@ void EnterClearMode(u32 data) bool colMask = (data >> 8) & 1; bool alphaMask = (data >> 9) & 1; bool updateZ = (data >> 10) & 1; - glColorMask(colMask, colMask, colMask, alphaMask); + glstate.colorMask.set(colMask, colMask, colMask, alphaMask); glstate.depthWrite.set(updateZ ? GL_TRUE : GL_FALSE); } @@ -332,7 +337,7 @@ void LeaveClearMode() // Fogging // Antialiasing // Alpha test - glColorMask(1,1,1,1); + glstate.colorMask.set(1,1,1,1); glstate.depthWrite.set(!(gstate.zmsk & 1) ? GL_TRUE : GL_FALSE); // dirtyshader? } diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index 66d0ea9d44..a105ca7818 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -21,7 +21,7 @@ #include #include "../GPUInterface.h" - +#include "Framebuffer.h" #include "gfx_es2/fbo.h" class ShaderManager; @@ -56,6 +56,8 @@ private: void DoBlockTransfer(); bool ProcessDLQueue(); + FramebufferManager framebufferManager; + ShaderManager *shaderManager_; bool interruptsEnabled_; diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index b4e52ec029..f458916fb4 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -26,18 +26,6 @@ #include "Framebuffer.h" -////////////////////////////////////////////////////////////////////////// -// STATE BEGIN -static GLuint backbufTex; -u8 *realFB; -GLSLProgram *draw2dprogram; - -// STATE END -////////////////////////////////////////////////////////////////////////// - -#if defined(__APPLE__) -#endif - const char tex_fs[] = "#ifdef GL_ES\n" "precision mediump float;\n" @@ -59,22 +47,7 @@ const char basic_vs[] = " gl_Position = u_viewproj * a_position;\n" "}\n"; -void DisplayDrawer_Init() -{ -#if !defined(USING_GLES2) - // Old OpenGL stuff that probably has no effect - - glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); //GL_FILL); - glShadeModel(GL_SMOOTH); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); -#endif - - glstate.cullFace.disable(); - glstate.depthTest.disable(); - glstate.blend.disable(); - - glEnable(GL_TEXTURE_2D); - +FramebufferManager::FramebufferManager() { glGenTextures(1, &backbufTex); //initialize backbuffer texture @@ -98,26 +71,24 @@ void DisplayDrawer_Init() glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - realFB = new u8[480*272*4]; + convBuf = new u8[480 * 272 * 4]; } -void DisplayDrawer_Shutdown() -{ - glDeleteTextures(1,&backbufTex); +FramebufferManager::~FramebufferManager() { + glDeleteTextures(1, &backbufTex); glsl_destroy(draw2dprogram); - delete [] realFB; + delete [] convBuf; } -void DisplayDrawer_DrawFramebuffer(u8 *framebuf, int pixelFormat, int linesize) -{ - for (int y = 0; y < 272; y++) - { - switch (pixelFormat) - { +void FramebufferManager::DrawPixels(const u8 *framebuf, int pixelFormat, int linesize) { + // TODO: We can trivially do these in the shader, and there's no need to + // upconvert to 8888 for the 16-bit formats. + for (int y = 0; y < 272; y++) { + switch (pixelFormat) { case PSP_DISPLAY_PIXEL_FORMAT_565: { - u16 *src = (u16 *)framebuf + linesize * y; - u8 *dst = realFB + 4 * 480 * y; + const u16 *src = (const u16 *)framebuf + linesize * y; + u8 *dst = convBuf + 4 * 480 * y; for (int x = 0; x < 480; x++) { u16 col = src[x]; @@ -131,8 +102,8 @@ void DisplayDrawer_DrawFramebuffer(u8 *framebuf, int pixelFormat, int linesize) case PSP_DISPLAY_PIXEL_FORMAT_5551: { - u16 *src = (u16 *)framebuf + linesize * y; - u8 *dst = realFB + 4 * 480 * y; + const u16 *src = (const u16 *)framebuf + linesize * y; + u8 *dst = convBuf + 4 * 480 * y; for (int x = 0; x < 480; x++) { u16 col = src[x]; @@ -146,8 +117,8 @@ void DisplayDrawer_DrawFramebuffer(u8 *framebuf, int pixelFormat, int linesize) case PSP_DISPLAY_PIXEL_FORMAT_8888: { - u8 *src = framebuf + linesize * 4 * y; - u8 *dst = realFB + 4 * 480 * y; + const u8 *src = framebuf + linesize * 4 * y; + u8 *dst = convBuf + 4 * 480 * y; for (int x = 0; x < 480; x++) { dst[x * 4] = src[x * 4]; @@ -160,8 +131,8 @@ void DisplayDrawer_DrawFramebuffer(u8 *framebuf, int pixelFormat, int linesize) case PSP_DISPLAY_PIXEL_FORMAT_4444: { - u16 *src = (u16 *)framebuf + linesize * y; - u8 *dst = realFB + 4 * 480 * y; + const u16 *src = (const u16 *)framebuf + linesize * y; + u8 *dst = convBuf + 4 * 480 * y; for (int x = 0; x < 480; x++) { u16 col = src[x]; @@ -176,13 +147,11 @@ void DisplayDrawer_DrawFramebuffer(u8 *framebuf, int pixelFormat, int linesize) } glBindTexture(GL_TEXTURE_2D,backbufTex); - glTexSubImage2D(GL_TEXTURE_2D,0,0,0,480,272, GL_RGBA, GL_UNSIGNED_BYTE, realFB); - + glTexSubImage2D(GL_TEXTURE_2D,0,0,0,480,272, GL_RGBA, GL_UNSIGNED_BYTE, convBuf); DrawActiveTexture(480, 272); } -void DrawActiveTexture(float w, float h, bool flip) -{ +void FramebufferManager::DrawActiveTexture(float w, float h, bool flip) { float u2 = 1.0f; float v1 = flip ? 1.0f : 0.0f; float v2 = flip ? 0.0f : 1.0f; diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index 9803bc2889..098c6b6361 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -22,6 +22,8 @@ #include "../Globals.h" +struct GLSLProgram; + enum PspDisplayPixelFormat { PSP_DISPLAY_PIXEL_FORMAT_565 = 0, PSP_DISPLAY_PIXEL_FORMAT_5551 = 1, @@ -29,7 +31,25 @@ enum PspDisplayPixelFormat { PSP_DISPLAY_PIXEL_FORMAT_8888 = 3, }; -void DisplayDrawer_Init(); -void DisplayDrawer_DrawFramebuffer(u8 *framebuf, int pixelFormat, int linesize); -void DisplayDrawer_Shutdown(); -void DrawActiveTexture(float w, float h, bool flip = false); +class FramebufferManager { +public: + FramebufferManager(); + ~FramebufferManager(); + + /* Better do this first: + glstate.cullFace.disable(); + glstate.depthTest.disable(); + glstate.blend.disable(); + */ + + void DrawPixels(const u8 *framebuf, int pixelFormat, int linesize); + void DrawActiveTexture(float w, float h, bool flip = false); + +private: + + // Used by DrawPixels + unsigned int backbufTex; + + u8 *convBuf; + GLSLProgram *draw2dprogram; +}; \ No newline at end of file From ab4482a0a435cd3c113c2548c62abe6c4ac6c46a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 1 Dec 2012 10:33:05 +0100 Subject: [PATCH 17/20] Respect param len in PARAM.SFO parser --- Core/ELF/ParamSFO.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index 9119f162a5..4518ec5ecd 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -36,12 +36,17 @@ struct IndexTable u32 data_table_offset; /* Offset of the param_data from start of data_table */ }; -void ParseDataString(const char *key, const char *utfdata, ParamSFOData *sfodata) +void ParseDataString(const char *key, const char *utfdata, ParamSFOData *sfodata, int maxlen = 0) { + std::string data; + if (maxlen) + data = std::string(utfdata, maxlen); + else + data = std::string(utfdata); if (!strcmp(key, "DISC_ID")) { - sfodata->discID = utfdata; + sfodata->discID = data; } else if (!strcmp(key, "TITLE")) { - sfodata->title = utfdata; + sfodata->title = data; } } @@ -59,7 +64,7 @@ bool ParseParamSFO(const u8 *paramsfo, size_t size, ParamSFOData *data) const u8 *key_start = paramsfo + header->key_table_start; const u8 *data_start = paramsfo + header->data_table_start; - for (int i = 0; i < header->index_table_entries; i++) + for (u32 i = 0; i < header->index_table_entries; i++) { const char *key = (const char *)(key_start + indexTables[i].key_table_offset); @@ -76,7 +81,7 @@ bool ParseParamSFO(const u8 *paramsfo, size_t size, ParamSFOData *data) { const char *utfdata = (const char *)(data_start + indexTables[i].data_table_offset); DEBUG_LOG(LOADER, "%s %s", key, utfdata); - ParseDataString(key, utfdata, data); + ParseDataString(key, utfdata, data, indexTables[i].param_len); } break; case 0x0204: @@ -84,7 +89,7 @@ bool ParseParamSFO(const u8 *paramsfo, size_t size, ParamSFOData *data) { const char *utfdata = (const char *)(data_start + indexTables[i].data_table_offset); DEBUG_LOG(LOADER, "%s %s", key, utfdata); - ParseDataString(key, utfdata, data); + ParseDataString(key, utfdata, data, indexTables[i].param_len); } break; } From 3de1259eb887a61eb5fe6bfe0c49a2b58572b08a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 1 Dec 2012 10:39:20 +0100 Subject: [PATCH 18/20] Upgrade native --- android/jni/NativeApp.cpp | 5 +++++ native | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/android/jni/NativeApp.cpp b/android/jni/NativeApp.cpp index 66d27ae616..b3ce01036f 100644 --- a/android/jni/NativeApp.cpp +++ b/android/jni/NativeApp.cpp @@ -297,6 +297,11 @@ void NativeTouch(int finger, float x, float y, double time, TouchEvent event) } } +void NativeMessageReceived(const char *message, const char *value) +{ + // Unused +} + void NativeShutdownGraphics() { delete uiTexture; diff --git a/native b/native index 294ad623c5..92bd22ffe5 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 294ad623c5e23e9d9203606d720ff9ff2e490255 +Subproject commit 92bd22ffe5fd90b1441660b9136fc6dc230399ec From 815c3240bcb2767b5eee19510a42926e3ef7c5f5 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 1 Dec 2012 10:44:37 +0100 Subject: [PATCH 19/20] V4 --- Windows/WindowsHost.cpp | 2 +- Windows/WndMainWindow.cpp | 2 +- android/AndroidManifest.xml | 4 ++-- android/jni/MenuScreens.cpp | 8 ++++---- android/src/org/ppsspp/ppsspp/PpssppActivity.java | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 3837d59501..9c56f14567 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -38,7 +38,7 @@ void WindowsHost::ShutdownGL() void WindowsHost::SetWindowTitle(const char *message) { // Really need a better way to deal with versions. - std::string title = "PPSSPP v0.31 - "; + std::string title = "PPSSPP v0.4 - "; title += message; SetWindowText(mainWindow_, title.c_str()); } diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index d836d76e96..51cd5df02a 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -1,7 +1,7 @@ // NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003. -#define programname "PPSSPP v0.31" +#define programname "PPSSPP v0.4" #include diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index c5498809b1..719be33b5a 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="4" + android:versionName="0.4" > diff --git a/android/jni/MenuScreens.cpp b/android/jni/MenuScreens.cpp index b885bc3acb..9fc656b229 100644 --- a/android/jni/MenuScreens.cpp +++ b/android/jni/MenuScreens.cpp @@ -148,7 +148,7 @@ void MenuScreen::render() { ui_draw2d.DrawTextShadow(UBUNTU48, "PPSSPP", dp_xres + xoff - w/2, 80, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_BOTTOM); ui_draw2d.SetFontScale(0.7f, 0.7f); - ui_draw2d.DrawTextShadow(UBUNTU24, "V0.31", dp_xres + xoff, 80, 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_BOTTOM); + ui_draw2d.DrawTextShadow(UBUNTU24, "V0.4", dp_xres + xoff, 80, 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_BOTTOM); ui_draw2d.SetFontScale(1.0f, 1.0f); VLinear vlinear(dp_xres + xoff, 95, 20); @@ -360,7 +360,7 @@ void CreditsScreen::update(InputState &input_state) { static const char *credits[] = { - "PPSSPP v0.31", + "PPSSPP v0.4", "", "", "A fast and portable PSP emulator", @@ -368,8 +368,8 @@ static const char *credits[] = "", "Created by Henrik Rydgard", "", - "Top contributors:", - "kev", + "Contributors:", + "unknownbrackets", "tmaul", "orphis", "artart78", diff --git a/android/src/org/ppsspp/ppsspp/PpssppActivity.java b/android/src/org/ppsspp/ppsspp/PpssppActivity.java index bd287150fa..be46ac6038 100644 --- a/android/src/org/ppsspp/ppsspp/PpssppActivity.java +++ b/android/src/org/ppsspp/ppsspp/PpssppActivity.java @@ -15,4 +15,4 @@ public class PpssppActivity extends NativeActivity { { return false; } -} \ No newline at end of file +} \ No newline at end of file From 4393dc02a64b953edec81c183a563402c11b13cd Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 1 Dec 2012 12:36:52 +0100 Subject: [PATCH 20/20] Buildfix --- Core/ELF/ParamSFO.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index 4518ec5ecd..a86e6c77b8 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -15,6 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include +#include #include "../Globals.h" #include "ParamSFO.h" @@ -96,4 +98,4 @@ bool ParseParamSFO(const u8 *paramsfo, size_t size, ParamSFOData *data) } return true; -} \ No newline at end of file +}