mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-24 00:29:57 +00:00
Merge branch 'master' of github.com:hrydgard/ppsspp
This commit is contained in:
commit
ae0b5c8b05
@ -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
|
||||
|
@ -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();} \
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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" />
|
||||
|
@ -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" />
|
||||
|
@ -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
101
Core/ELF/ParamSFO.cpp
Normal 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
28
Core/ELF/ParamSFO.h
Normal 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);
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,7 @@ public:
|
||||
|
||||
virtual bool IsDebuggingEnabled() {return true;}
|
||||
virtual bool AttemptLoadSymbolMap() {return false;}
|
||||
virtual void SetWindowTitle(const char *message) {}
|
||||
};
|
||||
|
||||
extern Host *host;
|
||||
|
@ -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
|
||||
|
@ -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;}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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?
|
||||
}
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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"/>
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -15,4 +15,4 @@ public class PpssppActivity extends NativeActivity {
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
2
native
2
native
@ -1 +1 @@
|
||||
Subproject commit 8b6adf4cd698227dfc51cbbed4f26cf2baffe69c
|
||||
Subproject commit 92bd22ffe5fd90b1441660b9136fc6dc230399ec
|
@ -1 +1 @@
|
||||
Subproject commit 9b0212641a161ae45be8617cd001dbd9a287c4a6
|
||||
Subproject commit 3c81649c4b4056ddabaca293c093ba0d6989502b
|
35
test.py
35
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",
|
||||
|
Loading…
Reference in New Issue
Block a user