Merge branch 'master' of github.com:hrydgard/ppsspp

This commit is contained in:
Henrik Rydgård 2012-12-01 16:28:38 +01:00
commit ae0b5c8b05
33 changed files with 417 additions and 190 deletions

View File

@ -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

View File

@ -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();} \
}

View File

@ -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

View File

@ -120,6 +120,7 @@
<ClCompile Include="Debugger\Breakpoints.cpp" />
<ClCompile Include="Debugger\SymbolMap.cpp" />
<ClCompile Include="ELF\ElfReader.cpp" />
<ClCompile Include="ELF\ParamSFO.cpp" />
<ClCompile Include="ELF\PrxDecrypter.cpp" />
<ClCompile Include="FileSystems\BlockDevices.cpp" />
<ClCompile Include="FileSystems\DirectoryFileSystem.cpp" />
@ -251,6 +252,7 @@
<ClInclude Include="Debugger\SymbolMap.h" />
<ClInclude Include="ELF\ElfReader.h" />
<ClInclude Include="ELF\ElfTypes.h" />
<ClInclude Include="ELF\ParamSFO.h" />
<ClInclude Include="ELF\PrxDecrypter.h" />
<ClInclude Include="FileSystems\BlockDevices.h" />
<ClInclude Include="FileSystems\DirectoryFileSystem.h" />

View File

@ -300,6 +300,9 @@
<ClCompile Include="HLE\sceFont.cpp">
<Filter>HLE\Libraries</Filter>
</ClCompile>
<ClCompile Include="ELF\ParamSFO.cpp">
<Filter>ELF</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -548,6 +551,9 @@
<ClInclude Include="HLE\sceFont.h">
<Filter>HLE\Libraries</Filter>
</ClInclude>
<ClInclude Include="ELF\ParamSFO.h">
<Filter>ELF</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -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;
}

101
Core/ELF/ParamSFO.cpp Normal file
View File

@ -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 <stdio.h>
#include <string.h>
#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;
}

28
Core/ELF/ParamSFO.h Normal file
View File

@ -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);

View File

@ -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 <algorithm>
#include <map>
#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<Mutex>(id, error);
if (mutex)
{
bool wokeThreads = false;
std::vector<SceUID>::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<Mutex>(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<SceUID>::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<Mutex>(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<Mutex>(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<LwMutex>(workarea.uid, error);
if (mutex)
{
bool wokeThreads = false;
std::vector<SceUID>::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<LwMutex>(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<SceUID>::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<LwMutex>(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);

View File

@ -78,11 +78,15 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason)
// TODO: PSP_SEMA_ATTR_PRIORITY
std::vector<SceUID>::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<Semaphore>(id, error);
if (s)
{
__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE);
bool wokeThreads = __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE);
RETURN(kernelObjects.Destroy<Semaphore>(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<Semaphore>(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<SceUID>::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<Semaphore>(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
{

View File

@ -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(&currentThread->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();
}

View File

@ -58,6 +58,7 @@ public:
virtual bool IsDebuggingEnabled() {return true;}
virtual bool AttemptLoadSymbolMap() {return false;}
virtual void SetWindowTitle(const char *message) {}
};
extern Host *host;

View File

@ -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

View File

@ -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;}

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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?
}

View File

@ -21,7 +21,7 @@
#include <vector>
#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_;

View File

@ -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;

View File

@ -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;
};

View File

@ -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);

View File

@ -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)
{

View File

@ -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<std::shared_ptr<InputDevice>> input;
};

View File

@ -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 <windows.h>

View File

@ -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);

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.ppsspp.ppsspp"
android:versionCode="3"
android:versionName="0.31" >
android:versionCode="4"
android:versionName="0.4" >
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8"/>

View File

@ -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 \

View File

@ -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",

View File

@ -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;

View File

@ -15,4 +15,4 @@ public class PpssppActivity extends NativeActivity {
{
return false;
}
}
}

2
native

@ -1 +1 @@
Subproject commit 8b6adf4cd698227dfc51cbbed4f26cf2baffe69c
Subproject commit 92bd22ffe5fd90b1441660b9136fc6dc230399ec

@ -1 +1 @@
Subproject commit 9b0212641a161ae45be8617cd001dbd9a287c4a6
Subproject commit 3c81649c4b4056ddabaca293c093ba0d6989502b

35
test.py
View File

@ -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",