diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f376a937c..8de40af433 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/Common/Log.h b/Common/Log.h index 742a96d912..ff788063e6 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(__VA_ARGS__); \ ERROR_LOG(_t_, __VA_ARGS__); \ if (!PanicYesNo(__VA_ARGS__)) {Crash();} \ } 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/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/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp new file mode 100644 index 0000000000..a86e6c77b8 --- /dev/null +++ b/Core/ELF/ParamSFO.cpp @@ -0,0 +1,101 @@ +// 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 +#include +#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, 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 = data; + } else if (!strcmp(key, "TITLE")) { + sfodata->title = data; + } +} + +// 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 (u32 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, indexTables[i].param_len); + } + 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, indexTables[i].param_len); + } + break; + } + } + + return true; +} diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h new file mode 100644 index 0000000000..f92bef1a5a --- /dev/null +++ b/Core/ELF/ParamSFO.h @@ -0,0 +1,28 @@ +// 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; + 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/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 50ed950f12..bf024fbd44 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,10 +210,15 @@ 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) { 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) @@ -228,13 +229,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); @@ -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); } @@ -386,7 +390,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 +398,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 +413,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 +422,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 +435,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 +473,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 +523,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,10 +542,15 @@ 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) { 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) @@ -559,14 +561,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); @@ -635,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); @@ -673,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); } @@ -689,8 +693,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()); } @@ -706,7 +717,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 +736,6 @@ void sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) { Memory::WriteStruct(workareaPtr, &workarea); RETURN(0); - __KernelReSchedule("lwmutex trylocked"); } else if (error) RETURN(error); @@ -746,7 +755,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 +766,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 +785,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 +797,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 +834,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..b82f9f8efe 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -78,11 +78,15 @@ 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; - 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) { @@ -94,7 +98,7 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason) __KernelResumeThreadFromWait(threadID, reason); wokeThreads = true; } - s->waitingThreads.empty(); + s->waitingThreads.clear(); return wokeThreads; } @@ -129,8 +133,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 +174,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 +186,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 +210,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,12 +222,11 @@ 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) { - 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; @@ -237,13 +239,20 @@ 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; + 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); @@ -261,17 +270,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 { @@ -293,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--; } @@ -306,8 +311,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()); } @@ -336,9 +348,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 +399,6 @@ void sceKernelPollSema(SceUID id, int wantedCount) } else RETURN(SCE_KERNEL_ERROR_SEMA_ZERO); - - __KernelReSchedule("semaphore polled"); } else { diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index c6bee53c8f..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(); @@ -1545,6 +1553,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(); } 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/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;} diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index 49750d3fbc..ae628e760a 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,17 +52,42 @@ 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); - 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 sfoPath("disc0:/PSP_GAME/PARAM.SFO"); + PSPFileInfo fileInfo = pspFileSystem.GetFileInfo(sfoPath.c_str()); + if (fileInfo.exists) + { + 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, (size_t)fileInfo.size, &data)) + { + 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; + } + std::string bootpath("disc0:/PSP_GAME/SYSDIR/EBOOT.BIN"); // bypass patchers @@ -78,6 +103,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/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 diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index d667f768a1..9ad2685657 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 { @@ -46,16 +47,20 @@ static TexCache cache; 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]; tmpTexBufRearrange = new u32[1024 * 512]; + clutBuf32 = new u32[4096]; + clutBuf16 = new u16[4096]; } void TextureCache_Shutdown() @@ -66,6 +71,8 @@ void TextureCache_Shutdown() tmpTexBuf16 = 0; 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); diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 1ae42e6b08..9c56f14567 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.4 - "; + 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/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/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/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/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 \ 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/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/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 diff --git a/native b/native index 8b6adf4cd6..92bd22ffe5 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 8b6adf4cd698227dfc51cbbed4f26cf2baffe69c +Subproject commit 92bd22ffe5fd90b1441660b9136fc6dc230399ec diff --git a/pspautotests b/pspautotests index 9b0212641a..3c81649c4b 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 9b0212641a161ae45be8617cd001dbd9a287c4a6 +Subproject commit 3c81649c4b4056ddabaca293c093ba0d6989502b diff --git a/test.py b/test.py index b316e2b36e..1378ed3018 100755 --- a/test.py +++ b/test.py @@ -49,44 +49,52 @@ tests_good = [ "display/display", "dmac/dmactest", + "loader/bss/bss", "intr/intr", "intr/vblank/vblank", "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", ] 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/lwmutex/lock/lock", + "threads/lwmutex/try/try", + "threads/lwmutex/try600/try600", + "threads/lwmutex/unlock/unlock", "threads/msgpipe/msgpipe", - "threads/mutex/create/create", + "threads/mutex/mutex", "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", "threads/wakeup/wakeup", - "audio/sascore/sascore", "ctrl/ctrl", "gpu/simple/simple", "gpu/triangle/triangle", @@ -97,20 +105,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",