Merge branch 'master' into framebuffer-texture

Conflicts:
	GPU/GLES/StateMapping.cpp
This commit is contained in:
Henrik Rydgard 2013-02-04 23:55:11 +01:00
commit ac7ffa5e03
103 changed files with 2009 additions and 661 deletions

View File

@ -122,6 +122,10 @@ if(NOT MSVC)
add_definitions(-D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64)
endif()
if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
if(BLACKBERRY)
add_definitions(-D_QNX_SOURCE=1 -D_C99=1)
endif()

View File

@ -33,11 +33,18 @@
#include <string>
#include <list>
#include <set>
#include <type_traits>
#include "Common.h"
#include "FileUtil.h"
#include "../ext/snappy/snappy-c.h"
#ifdef ANDROID
namespace std {
using tr1::is_pointer;
}
#endif
template <class T>
struct LinkedListItem : public T
{
@ -47,6 +54,41 @@ struct LinkedListItem : public T
// Wrapper class
class PointerWrap
{
// This makes it a compile error if you forget to define DoState() on non-POD.
// Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
#ifdef _MSC_VER
template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value>
#else
template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value>
#endif
struct DoHelper
{
static void DoArray(PointerWrap *p, T *x, int count)
{
for (int i = 0; i < count; ++i)
p->DoClass(x[i]);
}
static void Do(PointerWrap *p, T &x)
{
p->DoClass(x);
}
};
template<typename T>
struct DoHelper<T, true, false>
{
static void DoArray(PointerWrap *p, T *x, int count)
{
p->DoVoid((void *)x, sizeof(T) * count);
}
static void Do(PointerWrap *p, T &x)
{
p->DoVoid((void *)&x, sizeof(x));
}
};
public:
enum Mode {
MODE_READ = 1, // load
@ -77,9 +119,31 @@ public:
}
(*ptr) += size;
}
template<class K, class T>
void Do(std::map<K, T *> &x)
{
if (mode == MODE_READ)
{
for (auto it = x.begin(), end = x.end(); it != end; ++it)
{
if (it->second != NULL)
delete it->second;
}
}
T *dv = NULL;
DoMap(x, dv);
}
template<class T>
void Do(std::map<unsigned int, T> &x)
template<class K, class T>
void Do(std::map<K, T> &x)
{
T dv;
DoMap(x, dv);
}
template<class K, class T>
void DoMap(std::map<K, T> &x, T &default_val)
{
unsigned int number = (unsigned int)x.size();
Do(number);
@ -89,9 +153,9 @@ public:
x.clear();
while (number > 0)
{
unsigned int first = 0;
K first = 0;
Do(first);
T second;
T second = default_val;
Do(second);
x[first] = second;
--number;
@ -102,7 +166,7 @@ public:
case MODE_MEASURE:
case MODE_VERIFY:
{
typename std::map<unsigned int, T>::iterator itr = x.begin();
typename std::map<K, T>::iterator itr = x.begin();
while (number > 0)
{
Do(itr->first);
@ -115,8 +179,30 @@ public:
}
}
template<class K, class T>
void Do(std::multimap<K, T *> &x)
{
if (mode == MODE_READ)
{
for (auto it = x.begin(), end = x.end(); it != end; ++it)
{
if (it->second != NULL)
delete it->second;
}
}
T *dv = NULL;
DoMultimap(x, dv);
}
template<class K, class T>
void Do(std::multimap<K, T> &x)
{
T dv;
DoMultimap(x, dv);
}
template<class K, class T>
void DoMultimap(std::multimap<K, T> &x, T &default_val)
{
unsigned int number = (unsigned int)x.size();
Do(number);
@ -128,7 +214,7 @@ public:
{
K first;
Do(first);
T second;
T second = default_val;
Do(second);
x.insert(std::make_pair(first, second));
--number;
@ -153,15 +239,46 @@ public:
}
// Store vectors.
template<class T>
void Do(std::vector<T *> &x)
{
T *dv = NULL;
DoVector(x, dv);
}
template<class T>
void Do(std::vector<T> &x)
{
T dv;
Do(x, dv);
DoVector(x, dv);
}
template<class T>
void DoPOD(std::vector<T> &x)
{
T dv;
DoVectorPOD(x, dv);
}
template<class T>
void Do(std::vector<T> &x, T &default_val)
{
DoVector(x, default_val);
}
template<class T>
void DoVector(std::vector<T> &x, T &default_val)
{
u32 vec_size = (u32)x.size();
Do(vec_size);
x.resize(vec_size, default_val);
if (vec_size > 0)
DoArray(&x[0], vec_size);
}
template<class T>
void DoVectorPOD(std::vector<T> &x, T &default_val)
{
u32 vec_size = (u32)x.size();
Do(vec_size);
@ -171,27 +288,54 @@ public:
}
// Store deques.
template<class T>
void Do(std::deque<T *> &x)
{
T *dv = NULL;
DoDeque(x, dv);
}
template<class T>
void Do(std::deque<T> &x)
{
T dv;
DoDeque(x, dv);
}
template<class T>
void DoDeque(std::deque<T> &x, T &default_val)
{
u32 deq_size = (u32)x.size();
Do(deq_size);
x.resize(deq_size);
x.resize(deq_size, default_val);
u32 i;
for(i = 0; i < deq_size; i++)
DoVoid(&x[i],sizeof(T));
Do(x[i]);
}
// Store STL lists.
template<class T>
void Do(std::list<T> &x)
void Do(std::list<T *> &x)
{
T dv;
T *dv = NULL;
Do(x, dv);
}
template<class T>
void Do(std::list<T> &x)
{
T dv;
DoList(x, dv);
}
template<class T>
void Do(std::list<T> &x, T &default_val)
{
DoList(x, default_val);
}
template<class T>
void DoList(std::list<T> &x, T &default_val)
{
u32 list_size = (u32)x.size();
Do(list_size);
@ -202,9 +346,30 @@ public:
Do(*itr);
}
// Store STL sets.
template <class T>
void Do(std::set<T *> &x)
{
if (mode == MODE_READ)
{
for (auto it = x.begin(), end = x.end(); it != end; ++it)
{
if (*it != NULL)
delete *it;
}
}
DoSet(x);
}
template <class T>
void Do(std::set<T> &x)
{
DoSet(x);
}
template <class T>
void DoSet(std::set<T> &x)
{
unsigned int number = (unsigned int)x.size();
Do(number);
@ -266,14 +431,35 @@ public:
(*ptr) += stringLen;
}
template<class T>
template<class T>
void DoClass(T &x) {
x.DoState(*this);
}
template<class T>
void DoClass(T *&x) {
if (mode == MODE_READ)
{
if (x != NULL)
delete x;
x = new T();
}
x->DoState(*this);
}
template<class T>
void DoArray(T *x, int count) {
DoVoid((void *)x, sizeof(T) * count);
}
DoHelper<T>::DoArray(this, x, count);
}
template<class T>
void Do(T &x) {
DoVoid((void *)&x, sizeof(x));
DoHelper<T>::Do(this, x);
}
template<class T>
void DoPOD(T &x) {
DoHelper<T>::Do(this, x);
}
template<class T>

View File

@ -19,6 +19,7 @@
#define _FIXED_SIZE_QUEUE_H_
#include <cstring>
#include "ChunkFile.h"
// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the
// real STL classes.

View File

@ -47,7 +47,7 @@ public:
void Log(LogTypes::LOG_LEVELS, const char *msg);
bool IsValid() { return (m_logfile != NULL); }
bool IsValid() { if (!m_logfile) return false; else return true; }
bool IsEnabled() const { return m_enable; }
void SetEnable(bool enable) { m_enable = enable; }

View File

@ -5,7 +5,7 @@
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !defined(ANDROID) && !defined(__SYMBIAN32__)
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !defined(ANDROID) && !defined(__SYMBIAN32__) || defined(__APPLE__)
// GCC 4.4 provides <mutex>
#include <mutex>
#else

View File

@ -32,10 +32,11 @@
// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
#include "../Globals.h"
#include "../Common/ChunkFile.h"
#include <string>
class PointerWrap;
//const int CPU_HZ = 222000000;
extern int CPU_HZ;

View File

@ -17,6 +17,7 @@
#include "../Util/PPGeDraw.h"
#include "PSPDialog.h"
#include "ChunkFile.h"
#define FADE_TIME 0.5

View File

@ -17,9 +17,10 @@
#pragma once
#include "../Globals.h"
#include "../Config.h"
#include "../../Common/ChunkFile.h"
class PointerWrap;
#define SCE_UTILITY_DIALOG_RESULT_SUCCESS 0
#define SCE_UTILITY_DIALOG_RESULT_CANCEL 1

View File

@ -19,6 +19,7 @@
#include "../Util/PPGeDraw.h"
#include "../HLE/sceCtrl.h"
#include "../Core/MemMap.h"
#include "ChunkFile.h"
PSPMsgDialog::PSPMsgDialog()
: PSPDialog()
@ -246,7 +247,7 @@ void PSPMsgDialog::DoState(PointerWrap &p)
p.Do(flag);
p.Do(messageDialog);
p.Do(messageDialogAddr);
p.Do(msgText);
p.DoArray(msgText, sizeof(msgText));
p.Do(yesnoChoice);
p.Do(okButtonImg);
p.Do(cancelButtonImg);

View File

@ -18,6 +18,7 @@
#include "PSPOskDialog.h"
#include "../Util/PPGeDraw.h"
#include "../HLE/sceCtrl.h"
#include "ChunkFile.h"
#define NUMKEYROWS 4
#define KEYSPERROW 12

View File

@ -1178,9 +1178,16 @@ void SavedataParam::DoState(PointerWrap &p)
{
if (saveDataList != NULL)
delete [] saveDataList;
saveDataList = new SaveFileInfo[saveDataListCount];
if (saveDataListCount != 0)
{
saveDataList = new SaveFileInfo[saveDataListCount];
p.DoArray(saveDataList, saveDataListCount);
}
else
saveDataList = NULL;
}
p.DoArray(saveDataList, saveDataListCount);
else
p.DoArray(saveDataList, saveDataListCount);
p.DoMarker("SavedataParam");
}

View File

@ -140,6 +140,22 @@ struct SaveFileInfo
u32 textureData;
int textureWidth;
int textureHeight;
void DoState(PointerWrap &p)
{
p.Do(size);
p.Do(saveName);
p.Do(idx);
p.DoArray(title, sizeof(title));
p.DoArray(saveTitle, sizeof(saveTitle));
p.DoArray(saveDetail, sizeof(saveDetail));
p.Do(modif_time);
p.Do(textureData);
p.Do(textureWidth);
p.Do(textureHeight);
}
};
class SavedataParam

View File

@ -15,6 +15,11 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "ChunkFile.h"
#include "FileUtil.h"
#include "DirectoryFileSystem.h"
#ifdef _WIN32
#include <windows.h>
#include <sys/stat.h>
@ -25,8 +30,8 @@
#include <ctype.h>
#endif
#include "FileUtil.h"
#include "DirectoryFileSystem.h"
#undef DeleteFile
#if HOST_IS_CASE_SENSITIVE
@ -246,7 +251,7 @@ bool DirectoryFileSystem::RenameFile(const std::string &from, const std::string
bool DirectoryFileSystem::DeleteFile(const std::string &filename) {
std::string fullName = GetLocalPath(filename);
#ifdef _WIN32
bool retValue = (::DeleteFile(fullName.c_str()) == TRUE);
bool retValue = (::DeleteFileA(fullName.c_str()) == TRUE);
#else
bool retValue = (0 == unlink(fullName.c_str()));
#endif

View File

@ -18,7 +18,7 @@
#pragma once
#include "../../Globals.h"
#include "../../Common/ChunkFile.h"
#include "ChunkFile.h"
#include <string>
enum FileAccess

View File

@ -416,34 +416,11 @@ void MetaFileSystem::DoState(PointerWrap &p)
p.Do(current);
// Save/load per-thread current directory map
u32 n = (u32) currentDir.size();
p.Do(n);
if (p.mode == p.MODE_READ)
{
std::string dir;
currentDir.clear();
for (u32 i = 0; i < n; ++i)
{
int threadID;
p.Do(threadID);
p.Do(dir);
p.Do(currentDir);
currentDir[threadID] = dir;
}
}
else
{
currentDir_t::iterator i = currentDir.begin(), end = currentDir.end();
for (; i != end; ++i)
{
p.Do(i->first);
p.Do(i->second);
}
}
n = (u32) fileSystems.size();
u32 n = (u32) fileSystems.size();
p.Do(n);
if (n != fileSystems.size())
if (n != (u32) fileSystems.size())
{
ERROR_LOG(FILESYS, "Savestate failure: number of filesystems doesn't match.");
return;

View File

@ -25,6 +25,7 @@
#include "../MemMap.h"
#include "../Host.h"
#include "../Config.h"
#include "ChunkFile.h"
#include "FixedSizeQueue.h"
#include "Common/Thread.h"

View File

@ -22,6 +22,7 @@
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../CoreTiming.h"
#include "ChunkFile.h"
#include "sceKernel.h"
#include "sceUtility.h"
@ -61,6 +62,8 @@ struct Atrac {
p.DoMarker("Atrac");
}
void Analyze();
u32 decodePos;
u32 decodeEnd;
int loopNum;
@ -76,27 +79,7 @@ void __AtracInit()
}
void __AtracDoState(PointerWrap &p) {
int n = (int) atracMap.size();
p.Do(n);
if (p.mode == p.MODE_READ) {
for (auto it = atracMap.begin(), end = atracMap.end(); it != end; ++it) {
delete it->second;
}
atracMap.clear();
for (int i = 0; i < n; ++i) {
int key;
p.Do(key);
Atrac *atrac = new Atrac;
atrac->DoState(p);
atracMap[key] = atrac;
}
} else {
for (auto it = atracMap.begin(), end = atracMap.end(); it != end; ++it) {
p.Do(it->first);
it->second->DoState(p);
}
}
p.Do(atracMap);
p.DoMarker("sceAtrac");
}
@ -139,6 +122,38 @@ int getCodecType(int addr) {
return 0;
}
void Atrac::Analyze()
{
// This is an ugly approximation of song length, in case we can't do better.
this->decodeEnd = first.size * 3;
if (first.size < 0x100)
{
ERROR_LOG(HLE, "Atrac buffer very small: %d", first.size);
return;
}
// TODO: Validate stuff.
// RIFF size excluding chunk header.
first.filesize = Memory::Read_U32(first.addr + 4) + 8;
u32 offset = 12;
while (first.size > offset + 8)
{
u32 magic = Memory::Read_U32(first.addr + offset);
u32 size = Memory::Read_U32(first.addr + offset + 4);
offset += 8;
if (magic == *(u32 *) "fmt " && size > 14 && first.size > offset + 14)
{
u16 bytesPerFrame = Memory::Read_U16(first.addr + offset + 12);
// TODO: This is probably still wrong?
this->decodeEnd = (first.filesize / bytesPerFrame) * ATRAC_MAX_SAMPLES;
}
}
}
u32 sceAtracGetAtracID(int codecType)
{
ERROR_LOG(HLE, "FAKE sceAtracGetAtracID(%i)", codecType);
@ -343,6 +358,7 @@ u32 sceAtracGetRemainFrame(int atracID, u32 remainAddr)
//return -1;
Memory::Write_U32(12, remainAddr); // outpos
} else {
// TODO: Seems like this is the number of bytes remaining to read from the file (or -1 if none)?
Memory::Write_U32(-1, remainAddr);
}
return 0;
@ -429,8 +445,7 @@ u32 sceAtracSetData(int atracID, u32 buffer, u32 bufferSize)
if (atrac != NULL) {
atrac->first.addr = buffer;
atrac->first.size = bufferSize;
// TODO: This is an ugly approximation of song length.
atrac->decodeEnd = bufferSize * 3;
atrac->Analyze();
}
return 0;
}
@ -443,8 +458,7 @@ int sceAtracSetDataAndGetID(u32 buffer, u32 bufferSize)
Atrac *atrac = new Atrac();
atrac->first.addr = buffer;
atrac->first.size = bufferSize;
// TODO: This is an ugly approximation of song length.
atrac->decodeEnd = bufferSize * 3;
atrac->Analyze();
return createAtrac(atrac);
}
@ -456,8 +470,7 @@ int sceAtracSetHalfwayBufferAndGetID(int atracID, u32 halfBuffer, u32 readSize,
Atrac *atrac = new Atrac();
atrac->first.addr = halfBuffer;
atrac->first.size = halfBufferSize;
// TODO: This is an ugly approximation of song length.
atrac->decodeEnd = halfBufferSize * 3;
atrac->Analyze();
return createAtrac(atrac);
}
@ -519,8 +532,7 @@ int sceAtracSetAA3DataAndGetID(u32 buffer, int bufferSize, int fileSize, u32 met
Atrac *atrac = new Atrac();
atrac->first.addr = buffer;
atrac->first.size = bufferSize;
// TODO: This is an ugly approximation of song length.
atrac->decodeEnd = bufferSize * 3;
atrac->Analyze();
return createAtrac(atrac);
}

View File

@ -17,7 +17,7 @@
#pragma once
#include "../Common/ChunkFile.h"
class PointerWrap;
void Register_sceAtrac3plus();
void __AtracInit();

View File

@ -17,12 +17,25 @@
#include "../MIPS/MIPS.h"
#include "../Host.h"
#include "../../Core/CoreTiming.h"
#include "Core/CoreTiming.h"
#include "ChunkFile.h"
#include "sceAudio.h"
#include "__sceAudio.h"
#include "HLE.h"
void AudioChannel::DoState(PointerWrap &p)
{
p.Do(reserved);
p.Do(sampleAddress);
p.Do(sampleCount);
p.Do(leftVolume);
p.Do(rightVolume);
p.Do(format);
p.Do(waitingThread);
sampleQueue.DoState(p);
p.DoMarker("AudioChannel");
}
// There's a second Audio api called Audio2 that only has one channel, I guess the 8 channel api was overkill.
// We simply map it to the first of the 8 channels.

View File

@ -23,6 +23,8 @@
#include "sceKernel.h"
#include "FixedSizeQueue.h"
class PointerWrap;
enum PspAudioFormats { PSP_AUDIO_FORMAT_STEREO = 0, PSP_AUDIO_FORMAT_MONO = 0x10 };
enum PspAudioFrequencies { PSP_AUDIO_FREQ_44K = 44100, PSP_AUDIO_FREQ_48K = 48000 };
@ -63,17 +65,7 @@ struct AudioChannel
// Might try something more efficient later.
FixedSizeQueue<s16, 32768 * 8> sampleQueue;
void DoState(PointerWrap &p) {
p.Do(reserved);
p.Do(sampleAddress);
p.Do(sampleCount);
p.Do(leftVolume);
p.Do(rightVolume);
p.Do(format);
p.Do(waitingThread);
sampleQueue.DoState(p);
p.DoMarker("AudioChannel");
}
void DoState(PointerWrap &p);
void clear() {
reserved = false;

View File

@ -18,6 +18,7 @@
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../CoreTiming.h"
#include "ChunkFile.h"
#include "StdMutex.h"
#include "sceCtrl.h"
#include "sceDisplay.h"

View File

@ -17,7 +17,9 @@
#pragma once
#include "../../Common/ChunkFile.h"
#include "Common/CommonTypes.h"
class PointerWrap;
void Register_sceCtrl();
@ -45,4 +47,4 @@ void __CtrlSetAnalog(float x, float y);
// For use by internal UI like MsgDialog
u32 __CtrlPeekButtons();
u32 __CtrlReadLatch();
u32 __CtrlReadLatch();

View File

@ -57,6 +57,12 @@ struct WaitVBlankInfo
WaitVBlankInfo(u32 tid) : threadID(tid), vcountUnblock(0) {}
u32 threadID;
int vcountUnblock; // what was this for again?
void DoState(PointerWrap &p)
{
p.Do(threadID);
p.Do(vcountUnblock);
}
};
// STATE BEGIN
@ -182,8 +188,8 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
}
vblankWaitingThreads.clear();
// Trigger VBlank interrupt handlers - and resched even if there's none registered.
__TriggerInterrupt(PSP_INTR_IMMEDIATE | PSP_INTR_ONLY_IF_ENABLED | PSP_INTR_ALWAYS_RESCHED, PSP_VBLANK_INTR);
// Trigger VBlank interrupt handlers.
__TriggerInterrupt(PSP_INTR_IMMEDIATE | PSP_INTR_ONLY_IF_ENABLED | PSP_INTR_ALWAYS_RESCHED, PSP_VBLANK_INTR, PSP_INTR_SUB_ALL);
CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount+1);

View File

@ -4,8 +4,7 @@
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "sceFont.h"
#include "ChunkFile.h"
typedef u32 FontLibraryHandle;

View File

@ -1,6 +1,6 @@
#pragma once
#include "../../Common/ChunkFile.h"
class PointerWrap;
void Register_sceFont();

View File

@ -20,6 +20,7 @@
#include "../System.h"
#include "../CoreParameter.h"
#include "sceGe.h"
#include "sceKernelMemory.h"
#include "sceKernelThread.h"
#include "sceKernelInterrupt.h"
#include "../GPU/GPUState.h"
@ -28,15 +29,77 @@
static PspGeCallbackData ge_callback_data[16];
static bool ge_used_callbacks[16] = {0};
struct GeInterruptData
{
int listid;
u32 pc;
};
static std::list<GeInterruptData> ge_pending_cb;
class GeIntrHandler : public IntrHandler
{
public:
GeIntrHandler() : IntrHandler(PSP_GE_INTR) {}
bool run(PendingInterrupt& pend)
{
GeInterruptData intrdata = ge_pending_cb.front();
DisplayList* dl = gpu->getList(intrdata.listid);
if (dl == NULL)
{
WARN_LOG(HLE, "Unable to run GE interrupt: list doesn't exist: %d", intrdata.listid);
return false;
}
gpu->InterruptStart();
u32 cmd = Memory::ReadUnchecked_U32(intrdata.pc) >> 24;
int subintr = dl->subIntrBase | (cmd == GE_CMD_FINISH ? PSP_GE_SUBINTR_FINISH : PSP_GE_SUBINTR_SIGNAL);
SubIntrHandler* handler = get(subintr);
if(handler != NULL)
{
DEBUG_LOG(CPU, "Entering interrupt handler %08x", handler->handlerAddress);
currentMIPS->pc = handler->handlerAddress;
u32 data = dl->subIntrToken;
currentMIPS->r[MIPS_REG_A0] = data & 0xFFFF;
currentMIPS->r[MIPS_REG_A1] = handler->handlerArg;
currentMIPS->r[MIPS_REG_A2] = sceKernelGetCompiledSdkVersion() <= 0x02000010 ? 0 : intrdata.pc + 4;
// RA is already taken care of in __RunOnePendingInterrupt
return true;
}
ge_pending_cb.pop_front();
gpu->InterruptEnd();
WARN_LOG(HLE, "Ignoring interrupt for display list %d, already been released.", intrdata.listid);
return false;
}
virtual void handleResult(PendingInterrupt& pend)
{
GeInterruptData intrdata = ge_pending_cb.front();
ge_pending_cb.pop_front();
gpu->InterruptEnd();
}
};
void __GeInit()
{
memset(&ge_used_callbacks, 0, sizeof(ge_used_callbacks));
ge_pending_cb.clear();
__RegisterIntrHandler(PSP_GE_INTR, new GeIntrHandler());
}
void __GeDoState(PointerWrap &p)
{
p.DoArray(ge_callback_data, ARRAY_SIZE(ge_callback_data));
p.DoArray(ge_used_callbacks, ARRAY_SIZE(ge_used_callbacks));
p.Do(ge_pending_cb);
// Everything else is done in sceDisplay.
p.DoMarker("sceGe");
}
@ -46,6 +109,20 @@ void __GeShutdown()
}
void __GeTriggerInterrupt(int listid, u32 pc)
{
GeInterruptData intrdata;
intrdata.listid = listid;
intrdata.pc = pc;
ge_pending_cb.push_back(intrdata);
__TriggerInterrupt(PSP_INTR_HLE, PSP_GE_INTR, PSP_INTR_SUB_NONE);
}
bool __GeHasPendingInterrupt()
{
return !ge_pending_cb.empty();
}
// The GE is implemented wrong - it should be parallel to the CPU execution instead of
// synchronous.
@ -63,26 +140,9 @@ u32 sceGeEdramGetSize()
return retVal;
}
// TODO: Probably shouldn't use an interrupt?
int __GeSubIntrBase(int callbackId)
{
// Negative means don't use.
if (callbackId < 0)
return 0;
if (callbackId >= (int)(ARRAY_SIZE(ge_used_callbacks)))
{
WARN_LOG(HLE, "Unexpected (too high) GE callback id %d, ignoring", callbackId);
return 0;
}
if (!ge_used_callbacks[callbackId])
{
WARN_LOG(HLE, "Unregistered GE callback id %d, ignoring", callbackId);
return 0;
}
return (callbackId + 1) << 16;
return callbackId * 2;
}
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId,

View File

@ -39,10 +39,16 @@ void Register_sceGe_user();
void __GeInit();
void __GeDoState(PointerWrap &p);
void __GeShutdown();
void __GeTriggerInterrupt(int listid, u32 pc);
bool __GeHasPendingInterrupt();
// Export functions for use by Util/PPGe
u32 sceGeRestoreContext(u32 ctxAddr);
u32 sceGeSaveContext(u32 ctxAddr);
int sceGeBreak(u32 mode);
int sceGeContinue();
int sceGeListSync(u32 displayListID, u32 mode);
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr);
u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr);

View File

@ -18,6 +18,7 @@
#include "HLE.h"
#include "FunctionWrappers.h"
#include "../MIPS/MIPS.h"
#include "ChunkFile.h"
const int PSP_LANGUAGE_JAPANESE = 0;

View File

@ -17,7 +17,7 @@
#pragma once
#include "../../Common/ChunkFile.h"
class PointerWrap;
void Register_sceImpose();
void __ImposeInit();

View File

@ -18,8 +18,11 @@
#pragma once
#include "../../Globals.h"
#include "../../Common/ChunkFile.h"
#include "Common.h"
#include <cstring>
#include <map>
class PointerWrap;
enum
{

View File

@ -19,10 +19,14 @@
#include "sceKernelAlarm.h"
#include "sceKernelInterrupt.h"
#include "HLE.h"
#include "../../Core/CoreTiming.h"
#include "Core/CoreTiming.h"
#include "ChunkFile.h"
#include <list>
const int NATIVEALARM_SIZE = 20;
std::list<SceUID> triggeredAlarm;
struct NativeAlarm
{
SceSize size;
@ -49,35 +53,33 @@ struct Alarm : public KernelObject
void __KernelScheduleAlarm(Alarm *alarm, u64 ticks);
class AlarmIntrHandler : public SubIntrHandler
class AlarmIntrHandler : public IntrHandler
{
public:
static SubIntrHandler *Create()
{
return new AlarmIntrHandler();
}
AlarmIntrHandler() : IntrHandler(PSP_SYSTIMER0_INTR) {}
void setAlarm(Alarm *alarm)
virtual bool run(PendingInterrupt& pend)
{
alarmID = alarm->GetUID();
handlerAddress = alarm->alm.handlerPtr;
enabled = true;
}
virtual void copyArgsToCPU(const PendingInterrupt &pend)
{
SubIntrHandler::copyArgsToCPU(pend);
u32 error;
int alarmID = triggeredAlarm.front();
Alarm *alarm = kernelObjects.Get<Alarm>(alarmID, error);
if (alarm)
currentMIPS->r[MIPS_REG_A0] = alarm->alm.commonPtr;
else
ERROR_LOG(HLE, "sceKernelAlarm: Unable to send interrupt args: alarm deleted?");
if(error)
return false;
currentMIPS->pc = alarm->alm.handlerPtr;
currentMIPS->r[MIPS_REG_A0] = alarm->alm.commonPtr;
return true;
}
virtual void handleResult(int result)
virtual void handleResult(PendingInterrupt& pend)
{
int result = currentMIPS->r[MIPS_REG_V0];
int alarmID = triggeredAlarm.front();
triggeredAlarm.pop_front();
// A non-zero result means to reschedule.
if (result > 0)
{
@ -92,18 +94,8 @@ public:
// Delete the alarm if it's not rescheduled.
kernelObjects.Destroy<Alarm>(alarmID);
__ReleaseSubIntrHandler(PSP_SYSTIMER0_INTR, alarmID);
}
}
virtual void DoState(PointerWrap &p)
{
SubIntrHandler::DoState(p);
p.Do(alarmID);
p.DoMarker("AlarmIntrHandler");
}
SceUID alarmID;
};
static int alarmTimer = -1;
@ -115,18 +107,23 @@ void __KernelTriggerAlarm(u64 userdata, int cyclesLate)
u32 error;
Alarm *alarm = kernelObjects.Get<Alarm>(uid, error);
if (alarm)
__TriggerInterrupt(PSP_INTR_IMMEDIATE, PSP_SYSTIMER0_INTR, uid);
{
triggeredAlarm.push_back(uid);
__TriggerInterrupt(PSP_INTR_IMMEDIATE, PSP_SYSTIMER0_INTR);
}
}
void __KernelAlarmInit()
{
triggeredAlarm.clear();
__RegisterIntrHandler(PSP_SYSTIMER0_INTR, new AlarmIntrHandler());
alarmTimer = CoreTiming::RegisterEvent("Alarm", __KernelTriggerAlarm);
__RegisterSubIntrCreator(PSP_SYSTIMER0_INTR, AlarmIntrHandler::Create);
}
void __KernelAlarmDoState(PointerWrap &p)
{
p.Do(alarmTimer);
p.Do(triggeredAlarm);
CoreTiming::RestoreRegisterEvent(alarmTimer, "Alarm", __KernelTriggerAlarm);
p.DoMarker("sceKernelAlarm");
}
@ -155,15 +152,6 @@ SceUID __KernelSetAlarm(u64 ticks, u32 handlerPtr, u32 commonPtr)
alarm->alm.handlerPtr = handlerPtr;
alarm->alm.commonPtr = commonPtr;
u32 error;
AlarmIntrHandler *handler = (AlarmIntrHandler *) __RegisterSubIntrHandler(PSP_SYSTIMER0_INTR, uid, error);
if (error != 0)
{
kernelObjects.Destroy<Alarm>(uid);
return error;
}
handler->setAlarm(alarm);
__KernelScheduleAlarm(alarm, ticks);
return uid;
}
@ -192,7 +180,6 @@ int sceKernelCancelAlarm(SceUID uid)
DEBUG_LOG(HLE, "sceKernelCancelAlarm(%08x)", uid);
CoreTiming::UnscheduleEvent(alarmTimer, uid);
__ReleaseSubIntrHandler(PSP_SYSTIMER0_INTR, uid);
return kernelObjects.Destroy<Alarm>(uid);
}

View File

@ -19,7 +19,8 @@
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../../Core/CoreTiming.h"
#include "Core/CoreTiming.h"
#include "ChunkFile.h"
#include "sceKernel.h"
#include "sceKernelThread.h"

View File

@ -21,6 +21,7 @@
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "ChunkFile.h"
#include "sceKernel.h"
#include "sceKernelThread.h"
@ -35,6 +36,34 @@ bool __InterruptsEnabled();
//////////////////////////////////////////////////////////////////////////
// INTERRUPT MANAGEMENT
//////////////////////////////////////////////////////////////////////////
class InterruptState
{
public:
void save();
void restore();
void clear();
void DoState(PointerWrap &p)
{
p.Do(savedCpu);
p.DoMarker("InterruptState");
}
ThreadContext savedCpu;
};
// STATE
InterruptState intState;
IntrHandler* intrHandlers[PSP_NUMBER_INTERRUPTS];
std::list<PendingInterrupt> pendingInterrupts;
// Yeah, this bit is a bit silly.
static int interruptsEnabled = 1;
static bool inInterrupt;
void sceKernelCpuSuspendIntr()
{
//LOG(HLE,"sceKernelCpuSuspendIntr"); // very spammy
@ -84,154 +113,108 @@ void sceKernelCpuResumeIntrWithSync(u32 enable)
sceKernelCpuResumeIntr(enable);
}
class IntrHandler {
public:
IntrHandler()
: subIntrCreator(NULL)
{
}
SubIntrHandler *add(int subIntrNum)
{
SubIntrHandler *handler;
if (subIntrCreator != NULL)
handler = subIntrCreator();
else
handler = new SubIntrHandler();
subIntrHandlers[subIntrNum] = handler;
return handler;
}
void remove(int subIntrNum)
{
if (has(subIntrNum))
{
delete subIntrHandlers[subIntrNum];
subIntrHandlers.erase(subIntrNum);
}
}
bool has(int subIntrNum) const
{
return subIntrHandlers.find(subIntrNum) != subIntrHandlers.end();
}
SubIntrHandler *get(int subIntrNum)
{
if (has(subIntrNum))
return subIntrHandlers[subIntrNum];
else
return NULL;
}
void clear()
{
std::map<int, SubIntrHandler *>::iterator it, end;
for (it = subIntrHandlers.begin(), end = subIntrHandlers.end(); it != end; ++it)
delete it->second;
subIntrHandlers.clear();
}
void queueUp(int subintr)
{
// Just call execute on all the subintr handlers for this interrupt.
// They will get queued up.
for (std::map<int, SubIntrHandler *>::iterator iter = subIntrHandlers.begin(); iter != subIntrHandlers.end(); ++iter)
{
if (subintr == -1 || iter->first == subintr)
iter->second->queueUp();
}
}
void queueUpWithArg(int subintr, int arg)
{
// Just call execute on all the subintr handlers for this interrupt.
// They will get queued up.
for (std::map<int, SubIntrHandler *>::iterator iter = subIntrHandlers.begin(); iter != subIntrHandlers.end(); ++iter)
{
if (subintr == -1 || iter->first == subintr)
iter->second->queueUpWithArg(arg);
}
}
void setCreator(SubIntrCreator creator)
{
subIntrCreator = creator;
}
void DoState(PointerWrap &p)
{
// We assume that the same creator has already been registered.
bool hasCreator = subIntrCreator != NULL;
p.Do(hasCreator);
if (hasCreator != (subIntrCreator != NULL))
{
ERROR_LOG(HLE, "Savestate failure: incompatible sub interrupt handler.");
return;
}
int n = (int) subIntrHandlers.size();
p.Do(n);
if (p.mode == p.MODE_READ)
{
clear();
for (int i = 0; i < n; ++i)
{
int subIntrNum;
p.Do(subIntrNum);
SubIntrHandler *handler = add(subIntrNum);
handler->DoState(p);
}
}
else
{
std::map<int, SubIntrHandler *>::iterator it, end;
for (it = subIntrHandlers.begin(), end = subIntrHandlers.end(); it != end; ++it)
{
p.Do(it->first);
it->second->DoState(p);
}
}
}
private:
SubIntrCreator subIntrCreator;
std::map<int, SubIntrHandler *> subIntrHandlers;
};
class InterruptState
bool IntrHandler::run(PendingInterrupt& pend)
{
public:
void save();
void restore();
void clear();
void DoState(PointerWrap &p)
SubIntrHandler *handler = get(pend.subintr);
if (handler == NULL)
{
p.Do(insideInterrupt);
p.Do(savedCpu);
p.DoMarker("InterruptState");
WARN_LOG(HLE, "Ignoring interrupt, already been released.");
return false;
}
bool insideInterrupt;
ThreadContext savedCpu;
// Action afterInterruptAction;
// Action afterHandlerAction;
};
copyArgsToCPU(pend);
// STATE
return true;
}
InterruptState intState;
IntrHandler intrHandlers[PSP_NUMBER_INTERRUPTS];
std::list<PendingInterrupt> pendingInterrupts;
void IntrHandler::copyArgsToCPU(PendingInterrupt& pend)
{
SubIntrHandler* handler = get(pend.subintr);
DEBUG_LOG(CPU, "Entering interrupt handler %08x", handler->handlerAddress);
currentMIPS->pc = handler->handlerAddress;
currentMIPS->r[MIPS_REG_A0] = handler->subIntrNumber;
currentMIPS->r[MIPS_REG_A1] = handler->handlerArg;
// RA is already taken care of
}
// Yeah, this bit is a bit silly.
static int interruptsEnabled = 1;
static bool inInterrupt;
void IntrHandler::handleResult(PendingInterrupt& pend)
{
//u32 result = currentMIPS->r[MIPS_REG_V0];
}
SubIntrHandler* IntrHandler::add(int subIntrNum)
{
return &subIntrHandlers[subIntrNum];
}
void IntrHandler::remove(int subIntrNum)
{
if (has(subIntrNum))
{
subIntrHandlers.erase(subIntrNum);
}
}
bool IntrHandler::has(int subIntrNum) const
{
return subIntrHandlers.find(subIntrNum) != subIntrHandlers.end();
}
void IntrHandler::enable(int subIntrNum)
{
subIntrHandlers[subIntrNum].enabled = true;
}
void IntrHandler::disable(int subIntrNum)
{
subIntrHandlers[subIntrNum].enabled = true;
}
SubIntrHandler* IntrHandler::get(int subIntrNum)
{
if (has(subIntrNum))
return &subIntrHandlers[subIntrNum];
else
return NULL;
}
void IntrHandler::clear()
{
subIntrHandlers.clear();
}
void IntrHandler::queueUp(int subintr)
{
if(subintr == PSP_INTR_SUB_NONE)
{
pendingInterrupts.push_back(PendingInterrupt(intrNumber, subintr));
}
else
{
// Just call execute on all the subintr handlers for this interrupt.
// They will get queued up.
for (std::map<int, SubIntrHandler>::iterator iter = subIntrHandlers.begin(); iter != subIntrHandlers.end(); ++iter)
{
if ((subintr == PSP_INTR_SUB_ALL || iter->first == subintr) && iter->second.enabled)
pendingInterrupts.push_back(PendingInterrupt(intrNumber, iter->first));
}
}
}
void IntrHandler::DoState(PointerWrap &p)
{
p.Do(intrNumber);
p.Do<int, SubIntrHandler>(subIntrHandlers);
p.DoMarker("IntrHandler");
}
void PendingInterrupt::DoState(PointerWrap &p)
{
p.Do(intr);
p.Do(subintr);
p.DoMarker("PendingInterrupt");
}
void __InterruptsInit()
{
interruptsEnabled = 1;
inInterrupt = false;
for(int i = 0; i < ARRAY_SIZE(intrHandlers); ++i)
intrHandlers[i] = new IntrHandler(i);
intState.clear();
}
@ -257,14 +240,22 @@ void __InterruptsDoStateLate(PointerWrap &p)
{
// We do these later to ensure the handlers have been registered.
for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)
intrHandlers[i].DoState(p);
intrHandlers[i]->DoState(p);
p.DoMarker("sceKernelInterrupt Late");
}
void __InterruptsShutdown()
{
for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)
intrHandlers[i].clear();
for (int i = 0; i < ARRAY_SIZE(intrHandlers); ++i)
intrHandlers[i]->clear();
for(int i = 0; i < ARRAY_SIZE(intrHandlers); ++i)
{
if(intrHandlers[i])
{
delete intrHandlers[i];
intrHandlers[i] = 0;
}
}
pendingInterrupts.clear();
}
@ -295,50 +286,22 @@ bool __CanExecuteInterrupt()
void InterruptState::save()
{
insideInterrupt = __IsInInterrupt();
__KernelSaveContext(&savedCpu);
}
void InterruptState::restore()
{
::inInterrupt = insideInterrupt;
__KernelLoadContext(&savedCpu);
}
void InterruptState::clear()
{
insideInterrupt = false;
}
// http://forums.ps2dev.org/viewtopic.php?t=5687
// http://www.google.se/url?sa=t&rct=j&q=&esrc=s&source=web&cd=7&ved=0CFYQFjAG&url=http%3A%2F%2Fdev.psnpt.com%2Fredmine%2Fprojects%2Fuofw%2Frepository%2Frevisions%2F65%2Fraw%2Ftrunk%2Finclude%2Finterruptman.h&ei=J4pCUKvyK4nl4QSu-YC4Cg&usg=AFQjCNFxJcgzQnv6dK7aiQlht_BM9grfQQ&sig2=GGk5QUEWI6qouYDoyE07YQ
void SubIntrHandler::queueUp()
{
if (!enabled)
return;
pendingInterrupts.push_back(PendingInterrupt(intrNumber, number));
};
void SubIntrHandler::queueUpWithArg(int arg)
{
if (!enabled)
return;
pendingInterrupts.push_back(PendingInterrupt(intrNumber, number, arg));
}
void SubIntrHandler::copyArgsToCPU(const PendingInterrupt &pend)
{
DEBUG_LOG(CPU, "Entering interrupt handler %08x", handlerAddress);
currentMIPS->pc = handlerAddress;
currentMIPS->r[MIPS_REG_A0] = pend.hasArg ? pend.arg : number;
currentMIPS->r[MIPS_REG_A1] = handlerArg;
// RA is already taken care of
}
// Returns true if anything was executed.
bool __RunOnePendingInterrupt()
@ -350,26 +313,32 @@ bool __RunOnePendingInterrupt()
}
// Can easily prioritize between different kinds of interrupts if necessary.
retry:
if (pendingInterrupts.size())
if (!pendingInterrupts.empty())
{
// If we came from CoreTiming::Advance(), we might've come from a waiting thread's callback.
// To avoid "injecting" return values into our saved state, we context switch here.
__KernelSwitchOffThread("interrupt");
PendingInterrupt pend = pendingInterrupts.front();
SubIntrHandler *handler = intrHandlers[pend.intr].get(pend.subintr);
if (handler == NULL)
IntrHandler* handler = intrHandlers[pend.intr];
if(handler == NULL)
{
WARN_LOG(HLE, "Ignoring interrupt, already been released.");
WARN_LOG(HLE, "Ignoring interrupt");
pendingInterrupts.pop_front();
goto retry;
}
intState.save();
handler->copyArgsToCPU(pend);
inInterrupt = true;
if(!handler->run(pend)) {
pendingInterrupts.pop_front();
inInterrupt = false;
goto retry;
}
currentMIPS->r[MIPS_REG_RA] = __KernelInterruptReturnAddress();
inInterrupt = true;
return true;
}
else
@ -400,37 +369,22 @@ void __TriggerInterrupt(int type, PSPInterrupt intno, int subintr)
{
if (interruptsEnabled || (type & PSP_INTR_ONLY_IF_ENABLED) == 0)
{
intrHandlers[intno].queueUp(subintr);
intrHandlers[intno]->queueUp(subintr);
DEBUG_LOG(HLE, "Triggering subinterrupts for interrupt %i sub %i (%i in queue)", intno, subintr, (u32)pendingInterrupts.size());
__TriggerRunInterrupts(type);
}
}
void __TriggerInterruptWithArg(int type, PSPInterrupt intno, int subintr, int arg)
{
if (interruptsEnabled || (type & PSP_INTR_ONLY_IF_ENABLED) == 0)
{
intrHandlers[intno].queueUpWithArg(subintr, arg);
DEBUG_LOG(HLE, "Triggering subinterrupts for interrupt %i sub %i with arg %i (%i in queue)", intno, subintr, arg,
(u32)pendingInterrupts.size());
__TriggerRunInterrupts(type);
}
}
void __KernelReturnFromInterrupt()
{
DEBUG_LOG(CPU, "Left interrupt handler at %08x", currentMIPS->pc);
inInterrupt = false;
// This is what we just ran.
PendingInterrupt pend = pendingInterrupts.front();
pendingInterrupts.pop_front();
SubIntrHandler *handler = intrHandlers[pend.intr].get(pend.subintr);
if (handler != NULL)
handler->handleResult(currentMIPS->r[MIPS_REG_V0]);
else
ERROR_LOG(HLE, "Interrupt released itself? Should not happen.");
intrHandlers[pend.intr]->handleResult(pend);
inInterrupt = false;
// Restore context after running the interrupt.
intState.restore();
@ -441,15 +395,17 @@ void __KernelReturnFromInterrupt()
__KernelReSchedule("return from interrupt");
}
void __RegisterSubIntrCreator(u32 intrNumber, SubIntrCreator creator)
void __RegisterIntrHandler(u32 intrNumber, IntrHandler* handler)
{
intrHandlers[intrNumber].setCreator(creator);
if(intrHandlers[intrNumber])
delete intrHandlers[intrNumber];
intrHandlers[intrNumber] = handler;
}
SubIntrHandler *__RegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 &error)
{
SubIntrHandler *subIntrHandler = intrHandlers[intrNumber].add(subIntrNumber);
subIntrHandler->number = subIntrNumber;
SubIntrHandler *subIntrHandler = intrHandlers[intrNumber]->add(subIntrNumber);
subIntrHandler->subIntrNumber = subIntrNumber;
subIntrHandler->intrNumber = intrNumber;
error = 0;
return subIntrHandler;
@ -457,7 +413,7 @@ SubIntrHandler *__RegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32
u32 __ReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber)
{
if (!intrHandlers[intrNumber].has(subIntrNumber))
if (!intrHandlers[intrNumber]->has(subIntrNumber))
return -1;
for (std::list<PendingInterrupt>::iterator it = pendingInterrupts.begin(); it != pendingInterrupts.end(); )
@ -468,7 +424,7 @@ u32 __ReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber)
++it;
}
intrHandlers[intrNumber].remove(subIntrNumber);
intrHandlers[intrNumber]->remove(subIntrNumber);
return 0;
}
@ -506,10 +462,10 @@ u32 sceKernelEnableSubIntr(u32 intrNumber, u32 subIntrNumber)
if (intrNumber >= PSP_NUMBER_INTERRUPTS)
return -1;
if (!intrHandlers[intrNumber].has(subIntrNumber))
if (!intrHandlers[intrNumber]->has(subIntrNumber))
return -1;
intrHandlers[intrNumber].get(subIntrNumber)->enabled = true;
intrHandlers[intrNumber]->enable(subIntrNumber);
return 0;
}
@ -519,10 +475,10 @@ u32 sceKernelDisableSubIntr(u32 intrNumber, u32 subIntrNumber)
if (intrNumber >= PSP_NUMBER_INTERRUPTS)
return -1;
if (!intrHandlers[intrNumber].has(subIntrNumber))
if (!intrHandlers[intrNumber]->has(subIntrNumber))
return -1;
intrHandlers[intrNumber].get(subIntrNumber)->enabled = false;
intrHandlers[intrNumber]->disable(subIntrNumber);
return 0;
}

View File

@ -17,7 +17,9 @@
#pragma once
#include "../../Common/ChunkFile.h"
#include <map>
class PointerWrap;
enum PSPInterrupt {
PSP_GPIO_INTR = 4,
@ -52,8 +54,8 @@ enum PSPInterrupt {
// These are invented for PPSSPP:
enum PSPGeSubInterrupts {
PSP_GE_SUBINTR_FINISH = 14,
PSP_GE_SUBINTR_SIGNAL = 15
PSP_GE_SUBINTR_SIGNAL = 0,
PSP_GE_SUBINTR_FINISH = 1,
};
enum PSPInterruptTriggerType {
@ -68,46 +70,63 @@ enum PSPInterruptTriggerType {
PSP_INTR_ALWAYS_RESCHED = 0x4,
};
struct PendingInterrupt {
PendingInterrupt(int intr_, int subintr_)
: intr(intr_), subintr(subintr_), hasArg(false) {}
PendingInterrupt(int intr_, int subintr_, int arg_)
: intr(intr_), subintr(subintr_), hasArg(true), arg(arg_) {}
u32 intr;
u32 subintr;
bool hasArg;
int arg;
enum PSPSubInterruptTriggerType {
// Trigger all sub intr
PSP_INTR_SUB_ALL = -2,
// Trigger code at the interrupt handler level
PSP_INTR_SUB_NONE = -1,
// Trigger specific sub interrupt
PSP_INTR_SUB_NUMBER = 0,
};
class SubIntrHandler
struct PendingInterrupt {
PendingInterrupt(int intr_, int subintr_)
: intr(intr_), subintr(subintr_) {}
void DoState(PointerWrap &p);
int intr;
int subintr;
};
struct SubIntrHandler
{
public:
SubIntrHandler() {}
virtual ~SubIntrHandler() {}
virtual void queueUp();
virtual void queueUpWithArg(int arg);
virtual void copyArgsToCPU(const PendingInterrupt &pend);
virtual void handleResult(int result) {}
virtual void DoState(PointerWrap &p)
{
p.Do(enabled);
p.Do(intrNumber);
p.Do(number);
p.Do(handlerAddress);
p.Do(handlerArg);
p.DoMarker("SubIntrHandler");
}
bool enabled;
int intrNumber;
int number;
int subIntrNumber;
u32 handlerAddress;
u32 handlerArg;
};
typedef SubIntrHandler *(*SubIntrCreator)();
class IntrHandler
{
public:
IntrHandler(int intrNumber_)
: intrNumber(intrNumber_)
{
}
virtual ~IntrHandler() {}
virtual bool run(PendingInterrupt& pend);
virtual void copyArgsToCPU(PendingInterrupt& pend);
virtual void handleResult(PendingInterrupt& pend);
void queueUp(int subintr);
SubIntrHandler* add(int subIntrNum);
void remove(int subIntrNum);
bool has(int subIntrNum) const;
void enable(int subIntrNum);
void disable(int subIntrNum);
SubIntrHandler *get(int subIntrNum);
void clear();
void DoState(PointerWrap &p);
private:
int intrNumber;
std::map<int, SubIntrHandler> subIntrHandlers;
};
bool __IsInInterrupt();
void __InterruptsInit();
@ -115,11 +134,10 @@ void __InterruptsDoState(PointerWrap &p);
void __InterruptsDoStateLate(PointerWrap &p);
void __InterruptsShutdown();
void __TriggerInterrupt(int type, PSPInterrupt intno, int subInterrupts = -1);
void __TriggerInterruptWithArg(int type, PSPInterrupt intno, int subintr, int arg); // For GE "callbacks"
bool __RunOnePendingInterrupt();
void __KernelReturnFromInterrupt();
void __RegisterSubIntrCreator(u32 intrNumber, SubIntrCreator creator);
void __RegisterIntrHandler(u32 intrNumber, IntrHandler* handler);
SubIntrHandler *__RegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 &error);
u32 __ReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber);

View File

@ -19,7 +19,8 @@
#include "sceKernelThread.h"
#include "sceKernelMbx.h"
#include "HLE.h"
#include "../../Core/CoreTiming.h"
#include "Core/CoreTiming.h"
#include "ChunkFile.h"
#define SCE_KERNEL_MBA_THPRI 0x100
#define SCE_KERNEL_MBA_MSPRI 0x400
@ -27,7 +28,11 @@
const int PSP_MBX_ERROR_DUPLICATE_MSG = 0x800201C9;
typedef std::pair<SceUID, u32> MbxWaitingThread;
struct MbxWaitingThread
{
SceUID first;
u32 second;
};
void __KernelMbxTimeout(u64 userdata, int cyclesLate);
static int mbxWaitTimer = -1;
@ -58,14 +63,18 @@ struct Mbx : public KernelObject
{
if (__KernelGetThreadPrio(id) < __KernelGetThreadPrio((*it).first))
{
waitingThreads.insert(it, std::make_pair(id, addr));
MbxWaitingThread waiting = {id, addr};
waitingThreads.insert(it, waiting);
inserted = true;
break;
}
}
}
if (!inserted)
waitingThreads.push_back(std::make_pair(id, addr));
{
MbxWaitingThread waiting = {id, addr};
waitingThreads.push_back(waiting);
}
}
inline void AddInitialMessage(u32 ptr)
@ -156,7 +165,7 @@ struct Mbx : public KernelObject
virtual void DoState(PointerWrap &p)
{
p.Do(nmb);
MbxWaitingThread mwt(0,0);
MbxWaitingThread mwt = {0};
p.Do(waitingThreads, mwt);
p.DoMarker("Mbx");
}

View File

@ -108,7 +108,12 @@ struct FPL : public KernelObject
u32 address;
};
typedef std::pair<SceUID, u32> VplWaitingThread;
struct VplWaitingThread
{
SceUID threadID;
u32 addrPtr;
};
struct SceKernelVplInfo
{
SceSize size;
@ -132,7 +137,7 @@ struct VPL : public KernelObject
{
p.Do(nv);
p.Do(address);
VplWaitingThread dv(0, 0);
VplWaitingThread dv = {0};
p.Do(waitingThreads, dv);
alloc.DoState(p);
p.DoMarker("VPL");
@ -507,7 +512,7 @@ void sceKernelPrintf()
void sceKernelSetCompiledSdkVersion(int sdkVersion)
{
int sdkMainVersion = sdkVersion & 0xFFFF0000;
/* int sdkMainVersion = sdkVersion & 0xFFFF0000;
bool valiSDK = false;
switch(sdkMainVersion)
{
@ -532,15 +537,15 @@ void sceKernelSetCompiledSdkVersion(int sdkVersion)
}
if(valiSDK)
{
{*/
sdkVersion_ = sdkVersion;
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
}
/* }
else
{
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion unknown SDK : %x\n",sdkVersion);
}
return;
return;*/
}
void sceKernelSetCompiledSdkVersion370(int sdkVersion)
@ -730,7 +735,7 @@ enum SceKernelVplAttr
bool __KernelUnlockVplForThread(VPL *vpl, VplWaitingThread &threadInfo, u32 &error, int result, bool &wokeThreads)
{
const SceUID threadID = threadInfo.first;
const SceUID threadID = threadInfo.threadID;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_VPL, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
@ -747,7 +752,7 @@ bool __KernelUnlockVplForThread(VPL *vpl, VplWaitingThread &threadInfo, u32 &err
u32 allocSize = size + 8;
u32 addr = vpl->alloc.Alloc(allocSize, true);
if (addr != (u32) -1)
Memory::Write_U32(addr, threadInfo.second);
Memory::Write_U32(addr, threadInfo.addrPtr);
else
return false;
@ -771,7 +776,7 @@ void __KernelVplRemoveThread(VPL *vpl, SceUID threadID)
for (size_t i = 0; i < vpl->waitingThreads.size(); i++)
{
VplWaitingThread *t = &vpl->waitingThreads[i];
if (t->first == threadID)
if (t->threadID == threadID)
{
vpl->waitingThreads.erase(vpl->waitingThreads.begin() + i);
break;
@ -781,7 +786,7 @@ void __KernelVplRemoveThread(VPL *vpl, SceUID threadID)
bool __VplThreadSortPriority(VplWaitingThread thread1, VplWaitingThread thread2)
{
return __KernelThreadSortPriority(thread1.first, thread2.first);
return __KernelThreadSortPriority(thread1.threadID, thread2.threadID);
}
bool __KernelClearVplThreads(VPL *vpl, int reason)
@ -972,7 +977,8 @@ int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
SceUID threadID = __KernelGetCurThread();
__KernelVplRemoveThread(vpl, threadID);
vpl->waitingThreads.push_back(std::make_pair(threadID, addrPtr));
VplWaitingThread waiting = {threadID, addrPtr};
vpl->waitingThreads.push_back(waiting);
}
__KernelSetVplTimeout(timeoutPtr);
@ -998,7 +1004,8 @@ int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
SceUID threadID = __KernelGetCurThread();
__KernelVplRemoveThread(vpl, threadID);
vpl->waitingThreads.push_back(std::make_pair(threadID, addrPtr));
VplWaitingThread waiting = {threadID, addrPtr};
vpl->waitingThreads.push_back(waiting);
}
__KernelSetVplTimeout(timeoutPtr);

View File

@ -75,6 +75,7 @@ static const char *blacklistedModules[] = {
"sceNetInet_Library",
"sceNetResolver_Library",
"sceNet_Library",
"sceSsl_Module",
};
struct NativeModule {

View File

@ -19,6 +19,7 @@
#include "sceKernel.h"
#include "sceKernelMsgPipe.h"
#include "sceKernelThread.h"
#include "ChunkFile.h"
#define SCE_KERNEL_MPA_THFIFO_S 0x0000
#define SCE_KERNEL_MPA_THPRI_S 0x0100

View File

@ -19,7 +19,8 @@
#include <map>
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../../Core/CoreTiming.h"
#include "Core/CoreTiming.h"
#include "ChunkFile.h"
#include "sceKernel.h"
#include "sceKernelMutex.h"
#include "sceKernelThread.h"

View File

@ -18,7 +18,8 @@
#include <algorithm>
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../../Core/CoreTiming.h"
#include "Core/CoreTiming.h"
#include "ChunkFile.h"
#include "sceKernel.h"
#include "sceKernelThread.h"
#include "sceKernelSemaphore.h"

View File

@ -27,6 +27,7 @@
#include "../MIPS/MIPS.h"
#include "../../Core/CoreTiming.h"
#include "../../Core/MemMap.h"
#include "ChunkFile.h"
#include "sceAudio.h"
#include "sceKernel.h"
@ -197,27 +198,7 @@ public:
}
void DoState(PointerWrap &p) {
int n = (int) calls_.size();
p.Do(n);
if (p.mode == p.MODE_READ) {
clear();
for (int i = 0; i < n; ++i) {
int k;
p.Do(k);
MipsCall *call = new MipsCall();
call->DoState(p);
calls_[k] = call;
}
} else {
std::map<int, MipsCall *>::iterator it, end;
for (it = calls_.begin(), end = calls_.end(); it != end; ++it) {
p.Do(it->first);
it->second->DoState(p);
}
}
p.Do(calls_);
p.Do(idGen_);
p.DoMarker("MipsCallManager");
}
@ -630,28 +611,7 @@ void __KernelThreadingDoState(PointerWrap &p)
p.Do(dispatchEnabled);
p.Do(curModule);
int n = (int) threadReadyQueue.size();
p.Do(n);
if (p.mode == p.MODE_READ)
{
threadReadyQueue.clear();
for (int i = 0; i < n; ++i)
{
u32 prio;
p.Do(prio);
ThreadList threads;
p.Do(threads, dv);
threadReadyQueue[prio] = threads;
}
}
else
{
for (auto it = threadReadyQueue.begin(), end = threadReadyQueue.end(); it != end; ++it)
{
p.Do(it->first);
p.Do(it->second, dv);
}
}
p.Do(threadReadyQueue);
p.Do(eventScheduledWakeup);
CoreTiming::RestoreRegisterEvent(eventScheduledWakeup, "ScheduledWakeup", &hleScheduledWakeup);

View File

@ -29,6 +29,7 @@
#include "sceKernelTime.h"
#include "../CoreTiming.h"
#include "ChunkFile.h"
//////////////////////////////////////////////////////////////////////////
// State

View File

@ -19,6 +19,7 @@
#include "sceKernelThread.h"
#include "sceKernelVTimer.h"
#include "HLE.h"
#include "ChunkFile.h"
// Using ERROR_LOG liberally when this is in development. When done,
// should be changed to DEBUG_LOG wherever applicable.

View File

@ -95,6 +95,13 @@ struct AvcContext {
};
struct Mp3Context {
Mp3Context() : mediaengine(NULL) {}
~Mp3Context() {
if (mediaengine != NULL) {
delete mediaengine;
}
}
void DoState(PointerWrap &p) {
p.Do(mp3StreamStart);
p.Do(mp3StreamEnd);
@ -114,7 +121,7 @@ struct Mp3Context {
p.Do(mp3Channels);
p.Do(mp3SamplingRate);
p.Do(mp3Version);
mediaengine->DoState(p);
p.DoClass(mediaengine);
p.DoMarker("Mp3Context");
}
@ -153,6 +160,13 @@ typedef std::map<u32, StreamInfo> StreamInfoMap;
// Internal structure
struct MpegContext {
MpegContext() : mediaengine(NULL) {}
~MpegContext() {
if (mediaengine != NULL) {
delete mediaengine;
}
}
void DoState(PointerWrap &p) {
p.Do(defaultFrameWidth);
p.Do(videoFrameCount);
@ -181,8 +195,8 @@ struct MpegContext {
p.Do(ignorePcm);
p.Do(ignoreAvc);
p.Do(isAnalyzed);
p.Do<StreamInfo>(streamMap);
mediaengine->DoState(p);
p.Do<u32, StreamInfo>(streamMap);
p.DoClass(mediaengine);
p.DoMarker("MpegContext");
}
@ -369,31 +383,7 @@ void __MpegDoState(PointerWrap &p) {
p.Do(actionPostPut);
__KernelRestoreActionType(actionPostPut, PostPutAction::Create);
int n = (int) mpegMap.size();
p.Do(n);
if (p.mode == p.MODE_READ) {
std::map<u32, MpegContext *>::iterator it, end;
for (it = mpegMap.begin(), end = mpegMap.end(); it != end; ++it) {
delete it->second->mediaengine;
delete it->second;
}
mpegMap.clear();
for (int i = 0; i < n; ++i) {
u32 key;
p.Do(key);
MpegContext *ctx = new MpegContext;
ctx->mediaengine = new MediaEngine;
ctx->DoState(p);
mpegMap[key] = ctx;
}
} else {
std::map<u32, MpegContext *>::iterator it, end;
for (it = mpegMap.begin(), end = mpegMap.end(); it != end; ++it) {
p.Do(it->first);
it->second->DoState(p);
}
}
p.Do(mpegMap);
p.DoMarker("sceMpeg");
}
@ -401,7 +391,6 @@ void __MpegDoState(PointerWrap &p) {
void __MpegShutdown() {
std::map<u32, MpegContext *>::iterator it, end;
for (it = mpegMap.begin(), end = mpegMap.end(); it != end; ++it) {
delete it->second->mediaengine;
delete it->second;
}
mpegMap.clear();
@ -496,7 +485,6 @@ int sceMpegDelete(u32 mpeg)
DEBUG_LOG(HLE, "sceMpegDelete(%08x)", mpeg);
delete ctx->mediaengine;
delete ctx;
mpegMap.erase(Memory::Read_U32(mpeg));
@ -565,8 +553,6 @@ u32 sceMpegQueryStreamSize(u32 bufferAddr, u32 sizeAddr)
AnalyzeMpeg(bufferAddr, &temp);
delete temp.mediaengine;
if (temp.mpegMagic != PSMF_MAGIC) {
ERROR_LOG(HLE, "sceMpegQueryStreamOffset: Bad PSMF magic");
return ERROR_MPEG_INVALID_VALUE;

View File

@ -18,9 +18,10 @@
#pragma once
#include "../../Globals.h"
#include "../../Common/ChunkFile.h"
#include "../MIPS/MIPS.h"
class PointerWrap;
enum {
ERROR_MPEG_BAD_VERSION = 0x80610002,
ERROR_MPEG_NO_MEMORY = 0x80610022,

View File

@ -18,6 +18,7 @@
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../CoreTiming.h"
#include "ChunkFile.h"
#include "scePower.h"
#include "sceKernelThread.h"

View File

@ -17,7 +17,7 @@
#pragma once
#include "../../Common/ChunkFile.h"
class PointerWrap;
void __PowerInit();
void __PowerDoState(PointerWrap &p);

View File

@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "HLE.h"
#include "ChunkFile.h"
#include "scePsmf.h"
#include "sceMpeg.h"
@ -102,6 +103,8 @@ typedef std::map<int, PsmfStream *> PsmfStreamMap;
class Psmf {
public:
// For savestates only.
Psmf() {}
Psmf(u32 data);
~Psmf();
void DoState(PointerWrap &p);
@ -141,6 +144,8 @@ public:
class PsmfPlayer {
public:
// For savestates only.
PsmfPlayer() {}
PsmfPlayer(u32 data);
void DoState(PointerWrap &p);
@ -163,6 +168,10 @@ public:
class PsmfStream {
public:
// Used for save states.
PsmfStream() {
}
PsmfStream(int type, int channel) {
this->type = type;
this->channel = channel;
@ -277,23 +286,7 @@ void Psmf::DoState(PointerWrap &p) {
p.Do(audioChannels);
p.Do(audioFrequency);
int n = (int) streamMap.size();
p.Do(n);
if (p.mode == p.MODE_READ) {
// Already empty, if we're reading this is brand new.
for (int i = 0; i < n; ++i) {
int key;
p.Do(key);
PsmfStream *stream = new PsmfStream(0, 0);
stream->DoState(p);
streamMap[key] = stream;
}
} else {
for (auto it = streamMap.begin(), end = streamMap.end(); it != end; ++it) {
p.Do(it->first);
it->second->DoState(p);
}
}
p.Do(streamMap);
p.DoMarker("Psmf");
}
@ -345,58 +338,14 @@ void __PsmfInit()
void __PsmfDoState(PointerWrap &p)
{
int n = (int) psmfMap.size();
p.Do(n);
if (p.mode == p.MODE_READ) {
std::map<u32, Psmf *>::iterator it, end;
for (it = psmfMap.begin(), end = psmfMap.end(); it != end; ++it) {
delete it->second;
}
psmfMap.clear();
for (int i = 0; i < n; ++i) {
u32 key;
p.Do(key);
Psmf *psmf = new Psmf(0);
psmf->DoState(p);
psmfMap[key] = psmf;
}
} else {
std::map<u32, Psmf *>::iterator it, end;
for (it = psmfMap.begin(), end = psmfMap.end(); it != end; ++it) {
p.Do(it->first);
it->second->DoState(p);
}
}
p.Do(psmfMap);
p.DoMarker("scePsmf");
}
void __PsmfPlayerDoState(PointerWrap &p)
{
int n = (int) psmfPlayerMap.size();
p.Do(n);
if (p.mode == p.MODE_READ) {
std::map<u32, PsmfPlayer *>::iterator it, end;
for (it = psmfPlayerMap.begin(), end = psmfPlayerMap.end(); it != end; ++it) {
delete it->second;
}
psmfMap.clear();
for (int i = 0; i < n; ++i) {
u32 key;
p.Do(key);
PsmfPlayer *psmfplayer = new PsmfPlayer(0);
psmfplayer->DoState(p);
psmfPlayerMap[key] = psmfplayer;
}
} else {
std::map<u32, PsmfPlayer *>::iterator it, end;
for (it = psmfPlayerMap.begin(), end = psmfPlayerMap.end(); it != end; ++it) {
p.Do(it->first);
it->second->DoState(p);
}
}
p.Do(psmfPlayerMap);
// TODO: Actually load this from a map.
psmfPlayerStatus = PSMF_PLAYER_STATUS_NONE;

View File

@ -44,16 +44,14 @@ enum {
// TODO - allow more than one, associating each with one Core pointer (passed in to all the functions)
// No known games use more than one instance of Sas though.
SasInstance *sas;
static SasInstance *sas = NULL;
void __SasInit() {
sas = new SasInstance();
}
void __SasDoState(PointerWrap &p) {
if (sas != NULL) {
sas->DoState(p);
}
p.DoClass(sas);
p.DoMarker("sceSas");
}

View File

@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "HLE.h"
#include "ChunkFile.h"
#include "sceSsl.h"

View File

@ -17,7 +17,7 @@
#pragma once
#include "../../Common/ChunkFile.h"
class PointerWrap;
void Register_sceSsl();

View File

@ -17,7 +17,8 @@
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../../Core/CoreTiming.h"
#include "Core/CoreTiming.h"
#include "ChunkFile.h"
#include "sceUmd.h"
#include "sceKernelThread.h"

View File

@ -17,7 +17,8 @@
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../../Core/CoreTiming.h"
#include "Core/CoreTiming.h"
#include "ChunkFile.h"
#include "sceUsb.h"
bool usbActivated = false;

View File

@ -17,7 +17,7 @@
#pragma once
#include "../../Common/ChunkFile.h"
class PointerWrap;
/**
* Valid values for PSP_SYSTEMPARAM_ID_INT_LANGUAGE

View File

@ -27,6 +27,7 @@
#include "../../Globals.h"
#include "../HLE/sceMpeg.h"
#include "ChunkFile.h"
class MediaEngine
{

View File

@ -1,4 +1,5 @@
#include "MemoryStick.h"
#include "ChunkFile.h"
// MS and FatMS states.
static MemStickState memStickState = PSP_MEMORYSTICK_STATE_DRIVER_READY;

View File

@ -1,5 +1,6 @@
#include "../../Globals.h"
#include "../../Common/ChunkFile.h"
class PointerWrap;
// mscmhc0 states
enum MemStickState {

View File

@ -112,6 +112,25 @@ void VagDecoder::GetSamples(s16 *outSamples, int numSamples) {
}
}
void VagDecoder::DoState(PointerWrap &p)
{
p.DoArray(samples, ARRAY_SIZE(samples));
p.Do(curSample);
p.Do(data_);
p.Do(read_);
p.Do(curBlock_);
p.Do(loopStartBlock_);
p.Do(numBlocks_);
p.Do(s_1);
p.Do(s_2);
p.Do(loopEnabled_);
p.Do(loopAtNextBlock_);
p.Do(end_);
}
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/sceSasCore.java
int simpleRate(int n) {
@ -418,6 +437,40 @@ void SasVoice::ChangedParams(bool changedVag) {
// TODO: restart VAG somehow
}
void SasVoice::DoState(PointerWrap &p)
{
p.Do(playing);
p.Do(paused);
p.Do(on);
p.Do(type);
p.Do(vagAddr);
p.Do(vagSize);
p.Do(pcmAddr);
p.Do(pcmSize);
p.Do(sampleRate);
p.Do(sampleFrac);
p.Do(pitch);
p.Do(loop);
p.Do(noiseFreq);
p.Do(volumeLeft);
p.Do(volumeRight);
p.Do(volumeLeftSend);
p.Do(volumeRightSend);
p.Do(effectLeft);
p.Do(effectRight);
p.DoArray(resampleHist, ARRAY_SIZE(resampleHist));
p.DoMarker("SasVoice");
envelope.DoState(p);
vag.DoState(p);
}
// This is horribly stolen from JPCSP.
// Need to find a real solution.
static const short expCurve[] = {
@ -583,3 +636,19 @@ void ADSREnvelope::KeyOff() {
SetState(STATE_RELEASE);
height_ = sustainLevel;
}
void ADSREnvelope::DoState(PointerWrap &p) {
p.Do(attackRate);
p.Do(decayRate);
p.Do(sustainRate);
p.Do(releaseRate);
p.Do(attackType);
p.Do(decayType);
p.Do(sustainType);
p.Do(sustainLevel);
p.Do(releaseType);
p.Do(state_);
p.Do(steps_);
p.Do(height_);
p.DoMarker("ADSREnvelope");
}

View File

@ -23,7 +23,7 @@
#pragma once
#include "../Globals.h"
#include "../../Common/ChunkFile.h"
#include "ChunkFile.h"
enum {
PSP_SAS_VOICES_MAX = 32,
@ -83,6 +83,8 @@ public:
void DecodeBlock(u8 *&readp);
bool End() const { return end_; }
void DoState(PointerWrap &p);
private:
int samples[28];
int curSample;
@ -132,6 +134,8 @@ public:
int sustainLevel;
int releaseType;
void DoState(PointerWrap &p);
private:
enum ADSRState {
STATE_ATTACK,
@ -175,6 +179,8 @@ struct SasVoice
void KeyOff();
void ChangedParams(bool changedVag);
void DoState(PointerWrap &p);
bool playing;
bool paused; // a voice can be playing AND paused. In that case, it won't play.
bool on; // key-on, key-off.

View File

@ -98,6 +98,13 @@ void MIPSState::Reset()
rng.Init(0x1337);
}
void GMRng::DoState(PointerWrap &p)
{
p.Do(m_w);
p.Do(m_z);
p.DoMarker("GMRng");
}
void MIPSState::DoState(PointerWrap &p)
{
// Reset the jit if we're loading.

View File

@ -18,7 +18,6 @@
#pragma once
#include "../../Globals.h"
#include "../../Common/ChunkFile.h"
#include "../CPU.h"
enum
@ -93,11 +92,7 @@ public:
return (m_z << 16) + m_w;
}
void DoState(PointerWrap &p) {
p.Do(m_w);
p.Do(m_z);
p.DoMarker("GMRng");
}
void DoState(PointerWrap &p);
private:
u32 m_w;

View File

@ -301,29 +301,27 @@ void JitBlockCache::LinkBlock(int i)
{
LinkBlockExits(i);
JitBlock &b = blocks[i];
std::map<u32, int>::iterator iter;
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
// equal_range(b) returns pair<iterator,iterator> representing the range
// of element with key b
ppp = links_to.equal_range(b.originalAddress);
if (ppp.first == ppp.second)
return;
for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) {
// PanicAlert("Linking block %i to block %i", iter2->second, i);
LinkBlockExits(iter2->second);
for (multimap<u32, int>::iterator iter = ppp.first; iter != ppp.second; ++iter) {
// PanicAlert("Linking block %i to block %i", iter->second, i);
LinkBlockExits(iter->second);
}
}
void JitBlockCache::UnlinkBlock(int i)
{
JitBlock &b = blocks[i];
std::map<u32, int>::iterator iter;
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
ppp = links_to.equal_range(b.originalAddress);
if (ppp.first == ppp.second)
return;
for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) {
JitBlock &sourceBlock = blocks[iter2->second];
for (multimap<u32, int>::iterator iter = ppp.first; iter != ppp.second; ++iter) {
JitBlock &sourceBlock = blocks[iter->second];
for (int e = 0; e < 2; e++)
{
if (sourceBlock.exitAddress[e] == b.originalAddress)
@ -374,7 +372,7 @@ void JitBlockCache::InvalidateICache(u32 address, const u32 length)
// destroy JIT blocks
// !! this works correctly under assumption that any two overlapping blocks end at the same address
std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1, it;
std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1;
while (it2 != block_map.end() && it2->first.second < pAddr + length)
{
DestroyBlock(it2->second, true);

View File

@ -15,9 +15,10 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "../Common/ChunkFile.h"
#include <string>
class PointerWrap;
namespace SaveState
{
typedef void (*Callback)(bool status, void *cbUserData);

View File

@ -1,5 +1,6 @@
#include "Log.h"
#include "BlockAllocator.h"
#include "ChunkFile.h"
// Slow freaking thing but works (eventually) :)
@ -331,3 +332,12 @@ void BlockAllocator::DoState(PointerWrap &p)
p.Do(grain_);
p.DoMarker("BlockAllocator");
}
void BlockAllocator::Block::DoState(PointerWrap &p)
{
p.Do(start);
p.Do(size);
p.Do(taken);
p.DoArray(tag, sizeof(tag));
p.DoMarker("Block");
}

View File

@ -2,12 +2,12 @@
#pragma once
#include "../../Globals.h"
#include "../../Common/ChunkFile.h"
#include <vector>
#include <list>
#include <cstring>
class PointerWrap;
// Generic allocator thingy
// Allocates blocks from a range
@ -63,6 +63,7 @@ private:
strncpy(tag, "---", 32);
tag[31] = 0;
}
void DoState(PointerWrap &p);
u32 start;
u32 size;
bool taken;

View File

@ -229,15 +229,15 @@ void PPGeEnd()
WriteCmd(GE_CMD_END, 0);
if (dataWritePtr > dataPtr) {
sceGeBreak(0);
sceGeSaveContext(savedContextPtr);
gpu->EnableInterrupts(false);
// We actually drew something
u32 list = sceGeListEnQueue(dlPtr, dlWritePtr, 0, 0);
u32 list = sceGeListEnQueueHead(dlPtr, dlWritePtr, -1, 0);
DEBUG_LOG(HLE, "PPGe enqueued display list %i", list);
// TODO: Might need to call some internal trickery function when this is actually synchronous.
// sceGeListSync(u32 displayListID, 1); //0 : wait for completion 1:check and return
gpu->EnableInterrupts(true);
sceGeContinue();
sceGeRestoreContext(savedContextPtr);
}
}

View File

@ -18,9 +18,10 @@
#pragma once
#include "../../Globals.h"
#include "../../Common/ChunkFile.h"
#include "ppge_atlas.h"
class PointerWrap;
/////////////////////////////////////////////////////////////////////////////////////////////
// PPGeDraw: Super simple internal drawing API for 2D overlays like sceUtility messageboxes
// etc. Goes through the Ge emulation so that it's 100% portable - will work

View File

@ -33,6 +33,7 @@
#include "../../Core/HLE/sceKernelThread.h"
#include "../../Core/HLE/sceKernelInterrupt.h"
#include "../../Core/HLE/sceGe.h"
extern u32 curTextureWidth;
extern u32 curTextureHeight;
@ -442,13 +443,15 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
case GE_CMD_SIGNAL:
{
// Processed in GE_END. Has data.
currentList->subIntrToken = data & 0xFFFF;
}
break;
case GE_CMD_FINISH:
currentList->subIntrToken = data & 0xFFFF;
// TODO: Should this run while interrupts are suspended?
if (interruptsEnabled_)
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_FINISH, 0);
__GeTriggerInterrupt(currentList->id, currentList->pc);
break;
case GE_CMD_END:
@ -486,7 +489,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
}
// TODO: Should this run while interrupts are suspended?
if (interruptsEnabled_)
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_SIGNAL, signal);
__GeTriggerInterrupt(currentList->id, currentList->pc);
}
break;
case GE_CMD_FINISH:
@ -959,7 +962,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
{
int num = gstate.texmtxnum & 0xF;
float newVal = getFloat24(data);
if (newVal != gstate.tgenMatrix[num] && num < 12) {
if (num < 12 && newVal != gstate.tgenMatrix[num]) {
Flush();
gstate.tgenMatrix[num] = newVal;
shaderManager_->DirtyUniform(DIRTY_TEXMATRIX);
@ -977,7 +980,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
{
int num = gstate.boneMatrixNumber & 0x7F;
float newVal = getFloat24(data);
if (newVal != gstate.boneMatrix[num] && num < 96) {
if (num < 96 && newVal != gstate.boneMatrix[num]) {
Flush();
gstate.boneMatrix[num] = newVal;
shaderManager_->DirtyUniform(DIRTY_BONEMATRIX0 << (num / 12));

View File

@ -315,6 +315,15 @@ void LinkedShader::updateUniforms() {
dirtyUniforms = 0;
}
ShaderManager::ShaderManager() : lastShader(NULL), globalDirty(0xFFFFFFFF), shaderSwitchDirty(0) {
codeBuffer_ = new char[16384];
}
ShaderManager::~ShaderManager() {
delete [] codeBuffer_;
}
void ShaderManager::DirtyUniform(u32 what) {
globalDirty |= what;
}
@ -353,10 +362,9 @@ void ShaderManager::DirtyShader()
LinkedShader *ShaderManager::ApplyShader(int prim)
{
if (globalDirty) {
// Deferred dirtying! Let's see if we can make this even more clever later.
for (LinkedShaderCache::iterator iter = linkedShaderCache.begin(); iter != linkedShaderCache.end(); ++iter) {
iter->second->dirtyUniforms |= globalDirty;
}
if (lastShader)
lastShader->dirtyUniforms |= globalDirty;
shaderSwitchDirty |= globalDirty;
globalDirty = 0;
}
@ -376,6 +384,12 @@ LinkedShader *ShaderManager::ApplyShader(int prim)
lastShader->stop();
}
// Deferred dirtying! Let's see if we can make this even more clever later.
for (LinkedShaderCache::iterator iter = linkedShaderCache.begin(); iter != linkedShaderCache.end(); ++iter) {
iter->second->dirtyUniforms |= shaderSwitchDirty;
}
shaderSwitchDirty = 0;
lastVSID = VSID;
lastFSID = FSID;

View File

@ -133,12 +133,8 @@ private:
class ShaderManager
{
public:
ShaderManager() : lastShader(NULL), globalDirty(0xFFFFFFFF) {
codeBuffer_ = new char[16384];
}
~ShaderManager() {
delete [] codeBuffer_;
}
ShaderManager();
~ShaderManager();
void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected
LinkedShader *ApplyShader(int prim);
@ -160,6 +156,7 @@ private:
LinkedShader *lastShader;
u32 globalDirty;
u32 shaderSwitchDirty;
char *codeBuffer_;
typedef std::map<FragmentShaderID, Shader *> FSCache;

View File

@ -1,10 +1,11 @@
#include "StateMapping.h"
#include "../../native/gfx_es2/gl_state.h"
#include "native/gfx_es2/gl_state.h"
#include "../Math3D.h"
#include "../GPUState.h"
#include "../../Core/System.h"
#include "../ge_constants.h"
#include "GPU/Math3D.h"
#include "GPU/GPUState.h"
#include "GPU/ge_constants.h"
#include "Core/System.h"
#include "Core/Config.h"
#include "DisplayListInterpreter.h"
#include "ShaderManager.h"
#include "TextureCache.h"
@ -214,8 +215,15 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
}
void TransformDrawEngine::UpdateViewportAndProjection() {
int renderWidth = framebufferManager_->GetRenderWidth();
int renderHeight = framebufferManager_->GetRenderHeight();
int renderWidth, renderHeight;
if (g_Config.bBufferedRendering) {
renderWidth = framebufferManager_->GetRenderWidth();
renderHeight = framebufferManager_->GetRenderHeight();
} else {
// TODO: Aspect-ratio aware and centered
renderWidth = PSP_CoreParameter().pixelWidth;
renderHeight = PSP_CoreParameter().pixelHeight;
}
float renderWidthFactor = (float)renderWidth / framebufferManager_->GetTargetWidth();
float renderHeightFactor = (float)renderHeight / framebufferManager_->GetTargetHeight();
bool throughmode = (gstate.vertType & GE_VTYPE_THROUGH_MASK) != 0;

View File

@ -298,12 +298,12 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[
}
struct GlTypeInfo {
GLuint type;
int count;
GLboolean normalized;
u16 type;
u8 count;
u8 normalized;
};
const GlTypeInfo GLComp[] = {
static const GlTypeInfo GLComp[] = {
{0}, // DEC_NONE,
{GL_FLOAT, 1, GL_FALSE}, // DEC_FLOAT_1,
{GL_FLOAT, 2, GL_FALSE}, // DEC_FLOAT_2,
@ -311,8 +311,10 @@ const GlTypeInfo GLComp[] = {
{GL_FLOAT, 4, GL_FALSE}, // DEC_FLOAT_4,
{GL_BYTE, 4, GL_TRUE}, // DEC_S8_3,
{GL_SHORT, 4, GL_TRUE},// DEC_S16_3,
{GL_UNSIGNED_BYTE, 4, GL_TRUE},// DEC_U8_4,
{GL_UNSIGNED_BYTE, 1, GL_TRUE},// DEC_U8_1,
{GL_UNSIGNED_BYTE, 2, GL_TRUE},// DEC_U8_2,
{GL_UNSIGNED_BYTE, 3, GL_TRUE},// DEC_U8_3,
{GL_UNSIGNED_BYTE, 4, GL_TRUE},// DEC_U8_4,
};
static inline void VertexAttribSetup(int attrib, int fmt, int stride, u8 *ptr) {
@ -838,8 +840,9 @@ void TransformDrawEngine::ClearTrackedVertexArrays() {
}
void TransformDrawEngine::DecimateTrackedVertexArrays() {
int threshold = gpuStats.numFrames - VAI_KILL_AGE;
for (auto iter = vai_.begin(); iter != vai_.end(); ) {
if (iter->second->lastFrame + VAI_KILL_AGE < gpuStats.numFrames) {
if (iter->second->lastFrame < threshold ) {
delete iter->second;
vai_.erase(iter++);
}

View File

@ -69,6 +69,9 @@ int DecFmtSize(u8 fmt) {
case DEC_FLOAT_4: return 16;
case DEC_S8_3: return 4;
case DEC_S16_3: return 8;
case DEC_U8_1: return 4;
case DEC_U8_2: return 4;
case DEC_U8_3: return 4;
case DEC_U8_4: return 4;
default:
return 0;
@ -107,10 +110,10 @@ DecVtxFormat GetTransformedVtxFormat(const DecVtxFormat &fmt) {
void VertexDecoder::Step_WeightsU8() const
{
float *wt = (float *)(decoded_ + decFmt.w0off);
u8 *wt = (u8 *)(decoded_ + decFmt.w0off);
const u8 *wdata = (const u8*)(ptr_);
for (int j = 0; j < nweights; j++)
wt[j] = (float)wdata[j] / 128.0f;
wt[j] = wdata[j];
}
void VertexDecoder::Step_WeightsU16() const
@ -118,14 +121,19 @@ void VertexDecoder::Step_WeightsU16() const
float *wt = (float *)(decoded_ + decFmt.w0off);
const u16 *wdata = (const u16*)(ptr_);
for (int j = 0; j < nweights; j++)
wt[j] = (float)wdata[j] / 32768.0f;
wt[j] = (float)wdata[j] / 65535.0f;
}
// Float weights should be uncommon, we can live with having to multiply these by 2.0
// to avoid special checks in the vertex shader generator.
// (PSP uses 0.0-2.0 fixed point numbers for weights)
void VertexDecoder::Step_WeightsFloat() const
{
float *wt = (float *)(decoded_ + decFmt.w0off);
const float *wdata = (const float*)(ptr_);
memcpy(wt, wdata, nweights * sizeof(float));
for (int i = 0; i < nweights; i++) {
wt[i] = wdata[i] * 0.5f;
}
}
void VertexDecoder::Step_TcU8() const
@ -544,14 +552,21 @@ void VertexDecoder::SetVertexType(u32 fmt) {
steps_[numSteps_++] = wtstep[weighttype];
int fmtBase = DEC_FLOAT_1;
int weightSize = 4;
if (weighttype == GE_VTYPE_WEIGHT_8BIT >> GE_VTYPE_WEIGHT_SHIFT) {
fmtBase = DEC_U8_1;
weightSize = 1;
}
if (nweights < 5) {
decFmt.w0off = decOff;
decFmt.w0fmt = DEC_FLOAT_1 + nweights - 1;
decFmt.w0fmt = fmtBase + nweights - 1;
} else {
decFmt.w0off = decOff;
decFmt.w0fmt = DEC_FLOAT_4;
decFmt.w1off = decOff + 4 * 4;
decFmt.w1fmt = DEC_FLOAT_1 + nweights - 5;
decFmt.w0fmt = fmtBase + 3;
decFmt.w1off = decOff + 4 * weightSize;
decFmt.w1fmt = fmtBase + nweights - 5;
}
decOff += nweights * 4;
}

View File

@ -34,6 +34,9 @@ enum {
DEC_FLOAT_4,
DEC_S8_3,
DEC_S16_3,
DEC_U8_1,
DEC_U8_2,
DEC_U8_3,
DEC_U8_4,
};
@ -243,7 +246,7 @@ public:
switch (decFmt_.c0fmt) {
case DEC_U8_4:
{
u8 *p = (u8 *)(data_ + decFmt_.c0off);
const u8 *p = (const u8 *)(data_ + decFmt_.c0off);
for (int i = 0; i < 4; i++)
color[i] = p[i] / 255.0f;
}
@ -260,7 +263,7 @@ public:
switch (decFmt_.c1fmt) {
case DEC_U8_4:
{
u8 *p = (u8 *)(data_ + decFmt_.c1off);
const u8 *p = (const u8 *)(data_ + decFmt_.c1off);
for (int i = 0; i < 3; i++)
color[i] = p[i] / 255.0f;
}
@ -274,15 +277,22 @@ public:
}
void ReadWeights(float weights[8]) {
const u8 *p = (const u8 *)(data_ + decFmt_.w0off);
switch (decFmt_.w0fmt) {
case DEC_FLOAT_1: memcpy(weights, data_ + decFmt_.w0off, 4); break;
case DEC_FLOAT_2: memcpy(weights, data_ + decFmt_.w0off, 8); break;
case DEC_FLOAT_3: memcpy(weights, data_ + decFmt_.w0off, 12); break;
case DEC_FLOAT_4: memcpy(weights, data_ + decFmt_.w0off, 16); break;
case DEC_U8_1: weights[0] = p[0] / 128.f; break;
case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i] = p[i] / 128.f; break;
case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i] = p[i] / 128.f; break;
case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i] = p[i] / 128.f; break;
default:
ERROR_LOG(G3D, "Reader: Unsupported W0 Format");
break;
}
p = (const u8 *)(data_ + decFmt_.w1off);
switch (decFmt_.w1fmt) {
case 0:
// It's fine for there to be w0 weights but not w1.
@ -291,6 +301,10 @@ public:
case DEC_FLOAT_2: memcpy(weights + 4, data_ + decFmt_.w1off, 8); break;
case DEC_FLOAT_3: memcpy(weights + 4, data_ + decFmt_.w1off, 12); break;
case DEC_FLOAT_4: memcpy(weights + 4, data_ + decFmt_.w1off, 16); break;
case DEC_U8_1: weights[4] = p[0] / 128.f; break;
case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i+4] = p[i] / 128.f; break;
case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i+4] = p[i] / 128.f; break;
case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i+4] = p[i] / 128.f; break;
default:
ERROR_LOG(G3D, "Reader: Unsupported W1 Format");
break;

View File

@ -275,7 +275,7 @@ void GenerateVertexShader(int prim, char *buffer) {
WRITE(p, " worldnormal += %s * (u_bone%i * vec4(a_normal, 0.0)).xyz;\n", weightAttr, i);
}
// Finally, multiply by world matrix (yes, we have to).
WRITE(p, " worldpos = (u_world * vec4(worldpos, 1.0)).xyz;\n");
WRITE(p, " worldpos = (u_world * vec4(worldpos * 2.0, 1.0)).xyz;\n");
if (hasNormal)
WRITE(p, " worldnormal = (u_world * vec4(worldnormal, 0.0)).xyz;\n");
}
@ -292,7 +292,7 @@ void GenerateVertexShader(int prim, char *buffer) {
}
// TODO: Declare variables for dots for shade mapping if needed.
const char *ambient = (gstate.materialupdate & 1) ? "unlitColor" : "u_matambientalpha.rgb";
const char *ambient = (gstate.materialupdate & 1) ? (hasColor ? "a_color0" : "u_matambientalpha") : "u_matambientalpha";
const char *diffuse = (gstate.materialupdate & 2) ? "unlitColor" : "u_matdiffuse";
const char *specular = (gstate.materialupdate & 4) ? "unlitColor" : "u_matspecular.rgb";
@ -345,11 +345,7 @@ void GenerateVertexShader(int prim, char *buffer) {
if (gstate.lightingEnable & 1) {
// Sum up ambient, emissive here.
if (hasColor) {
WRITE(p, " v_color0 = clamp(lightSum0 + u_ambient * vec4(%s, a_color0.a) + vec4(u_matemissive, 0.0), 0.0, 1.0);\n", ambient);
} else {
WRITE(p, " v_color0 = clamp(lightSum0 + u_ambient * vec4(%s, u_matambientalpha.a) + vec4(u_matemissive, 0.0), 0.0, 1.0);\n", ambient);
}
WRITE(p, " v_color0 = clamp(lightSum0 + u_ambient * %s + vec4(u_matemissive, 0.0), 0.0, 1.0);\n", ambient);
if (lmode) {
WRITE(p, " v_color1 = clamp(lightSum1, 0.0, 1.0);\n");
} else {

View File

@ -3,7 +3,7 @@
#include "GeDisasm.h"
#include "GPUCommon.h"
#include "GPUState.h"
#include "ChunkFile.h"
static int dlIdGenerator = 1;
@ -135,3 +135,13 @@ void GPUCommon::DoState(PointerWrap &p) {
p.Do<DisplayList>(dlQueue);
p.DoMarker("GPUCommon");
}
void GPUCommon::InterruptStart()
{
interruptRunning = true;
}
void GPUCommon::InterruptEnd()
{
interruptRunning = false;
ProcessDLQueue();
}

View File

@ -13,6 +13,9 @@ public:
dumpThisFrame_(false)
{}
virtual void InterruptStart();
virtual void InterruptEnd();
virtual void PreExecuteOp(u32 op, u32 diff);
virtual bool InterpretList(DisplayList &list);
virtual bool ProcessDLQueue();
@ -28,6 +31,7 @@ protected:
DisplayList *currentList;
DisplayListQueue dlQueue;
bool interruptRunning;
u32 prev;
u32 stack[2];
u32 stackptr;
@ -35,4 +39,18 @@ protected:
bool dumpNextFrame_;
bool dumpThisFrame_;
};
public:
virtual DisplayList* getList(int listid)
{
if(currentList->id == listid)
return currentList;
for(auto it = dlQueue.begin(); it != dlQueue.end(); ++it)
{
if(it->id == listid)
return &*it;
}
return NULL;
}
};

View File

@ -18,9 +18,10 @@
#pragma once
#include "../Globals.h"
#include "../Common/ChunkFile.h"
#include <deque>
class PointerWrap;
enum DisplayListStatus
{
PSP_GE_LIST_DONE = 0, // reached finish+end
@ -38,6 +39,7 @@ struct DisplayList
u32 stall;
DisplayListStatus status;
int subIntrBase;
u16 subIntrToken;
};
class GPUInterface
@ -49,12 +51,16 @@ public:
virtual void InitClear() = 0;
// Draw queue management
virtual DisplayList* getList(int listid) = 0;
// TODO: Much of this should probably be shared between the different GPU implementations.
virtual u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) = 0;
virtual void UpdateStall(int listid, u32 newstall) = 0;
virtual void DrawSync(int mode) = 0;
virtual void Continue() = 0;
virtual void InterruptStart() = 0;
virtual void InterruptEnd() = 0;
virtual void PreExecuteOp(u32 op, u32 diff) = 0;
virtual void ExecuteOp(u32 op, u32 diff) = 0;
virtual bool InterpretList(DisplayList& list) = 0;

View File

@ -251,7 +251,6 @@ struct GPUStateCache
float vpWidth;
float vpHeight;
u32 getRelativeAddress(u32 data) const;
};

View File

@ -730,15 +730,15 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) {
break;
case GE_CMD_COLORTEST:
sprintf(buffer, "ColorTest: %06", data);
sprintf(buffer, "ColorTest: %06x", data);
break;
case GE_CMD_COLORREF:
sprintf(buffer, "ColorRef: %06", data);
sprintf(buffer, "ColorRef: %06x", data);
break;
case GE_CMD_COLORTESTMASK:
sprintf(buffer, "ColorTestMask: %06", data);
sprintf(buffer, "ColorTestMask: %06x", data);
break;
case GE_CMD_MASKRGB:

View File

@ -21,6 +21,7 @@
#include "../ge_constants.h"
#include "../../Core/MemMap.h"
#include "../../Core/HLE/sceKernelInterrupt.h"
#include "../../Core/HLE/sceGe.h"
NullGPU::NullGPU()
{
@ -149,11 +150,11 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
{
ERROR_LOG(G3D, "DL GE_CMD_SIGNAL %08x", data & 0xFFFFFF);
int behaviour = (data >> 16) & 0xFF;
int signal = data & 0xFFFF;
currentList->subIntrToken = data & 0xFFFF;
// TODO: Should this run while interrupts are suspended?
if (interruptsEnabled_)
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_SIGNAL, signal);
__GeTriggerInterrupt(currentList->id, currentList->pc);
}
break;
@ -184,9 +185,10 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
case GE_CMD_FINISH:
DEBUG_LOG(G3D,"DL CMD FINISH");
currentList->subIntrToken = data & 0xFFFF;
// TODO: Should this run while interrupts are suspended?
if (interruptsEnabled_)
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_FINISH, 0);
__GeTriggerInterrupt(currentList->id, currentList->pc);
break;
case GE_CMD_END:

View File

@ -1,9 +1,10 @@
TARGET = PPSSPPQt
QT += core gui opengl
# Ubuntu user, remove multimedia
QT += core gui opengl multimedia
include(Settings.pri)
linux {
CONFIG += mobility
CONFIG += mobility link_pkgconfig
MOBILITY += multimedia
}
else {
@ -17,14 +18,18 @@ blackberry: LIBS += -L. -lCore -lCommon -lNative -lscreen -lsocket -lstdc++
win32: LIBS += -L. -lCore -lCommon -lNative -lwinmm -lws2_32 -lkernel32 -luser32 -lgdi32 -lshell32 -lcomctl32 -ldsound -lxinput
linux: LIBS += -L. -lCore -lCommon -lNative
linux: PRE_TARGETDEPS += ./libCommon.a ./libCore.a ./libNative.a
linux {
LIBS += -L. -lCore -lCommon -lNative
PRE_TARGETDEPS += ./libCommon.a ./libCore.a ./libNative.a
packagesExist(sdl) {
DEFINES += QT_HAS_SDL
PKGCONFIG += sdl
}
}
# Main
SOURCES += ../native/base/QtMain.cpp \
qkeyedit.cpp
HEADERS += ../native/base/QtMain.h \
qkeyedit.h
SOURCES += ../native/base/QtMain.cpp
HEADERS += ../native/base/QtMain.h
# Native
SOURCES += ../android/jni/EmuScreen.cpp \
@ -44,7 +49,9 @@ linux:!mobile_platform {
qtemugl.cpp \
ctrldisasmview.cpp \
ctrlregisterlist.cpp \
controls.cpp
controls.cpp \
qkeyedit.cpp \
gamepaddialog.cpp
HEADERS += mainwindow.h \
debugger_disasm.h \
EmuThread.h \
@ -52,7 +59,9 @@ linux:!mobile_platform {
qtemugl.h \
ctrldisasmview.h \
ctrlregisterlist.h \
controls.h
controls.h \
qkeyedit.h \
gamepaddialog.h
} else {
SOURCES += ../android/jni/NativeApp.cpp
}
@ -74,7 +83,8 @@ symbian {
linux:!mobile_platform {
FORMS += mainwindow.ui \
debugger_disasm.ui \
controls.ui
controls.ui\
gamepaddialog.ui
RESOURCES += \
resources.qrc

378
Qt/gamepaddialog.cpp Normal file
View File

@ -0,0 +1,378 @@
#include "gamepaddialog.h"
#include "ui_gamepaddialog.h"
#include <QTimer>
#include "Core/Config.h"
// Input
struct GamePadInfo
{
int mapping_type; // 0 : pad button, 1 : pad axis, 2 : pad Hats
int mapping_in;
int mapping_sign;
QString ViewLabelName;
QString Name;
};
// Initial values are PS3 controller
GamePadInfo GamepadPadMapping[] = {
{0, 14, 0, "Prev_X", "Cross"}, //A
{0, 13, 0, "Prev_O", "Circle"}, //B
{0, 15, 0, "Prev_S", "Square"}, //X
{0, 12, 0, "Prev_T", "Triangle"}, //Y
{0, 10, 0, "Prev_LT", "Left Trigger"}, //LBUMPER
{0, 11, 0, "Prev_RT", "Right Trigger"}, //RBUMPER
{0, 3, 0, "Prev_Start", "Start"}, //START
{0, 0, 0, "Prev_Select", "Select"}, //SELECT
{0, 4, 0, "Prev_Up", "Up"}, //UP
{0, 6, 0, "Prev_Down", "Down"}, //DOWN
{0, 7, 0, "Prev_Left", "Left"}, //LEFT
{0, 5, 0, "Prev_Right", "Right"}, //RIGHT
{0, 0, 0, ""}, //MENU (event)
{0, 16, 0, "Prev_Home", "Home"}, //BACK
// Special case for analog stick
{1, 0, -1, "Prev_ALeft", "Stick left"},
{1, 0, 1, "Prev_ARight", "Stick right"},
{1, 1, -1, "Prev_AUp", "Stick up"},
{1, 1, 1, "Prev_ADown", "Stick bottom"}
};
// id for mapping in config start at offset 200 to not get over key mapping
const int configOffset = 200;
GamePadDialog::GamePadDialog(InputState* state, QWidget *parent) :
QDialog(parent),
ui(new Ui::GamePadDialog),
m_inputState(state),
#if QT_HAS_SDL
m_joystick(0),
#endif
m_isInit(false)
{
ui->setupUi(this);
SetViewMode();
#if QT_HAS_SDL
SDL_Init(SDL_INIT_JOYSTICK);
#endif
m_isInit = true;
data_timer = new QTimer();
data_timer->setInterval(50);
connect(data_timer,SIGNAL(timeout()),this,SLOT(pollJoystick()));
data_timer->start();
for(int i=0;i<18;i++)
{
QLabel* labelPreview = findChild<QLabel*>(GamepadPadMapping[i].ViewLabelName);
if(labelPreview)
{
labelPreview->setVisible(false);
}
if(g_Config.iMappingMap.find(i+configOffset) != g_Config.iMappingMap.end())
{
GetMappingFromInt(g_Config.iMappingMap[i+configOffset],
GamepadPadMapping[i].mapping_in,
GamepadPadMapping[i].mapping_type,
GamepadPadMapping[i].mapping_sign);
}
}
on_refreshListBtn_clicked();
}
GamePadDialog::~GamePadDialog()
{
data_timer->stop();
delete data_timer;
#if QT_HAS_SDL
if(m_joystick)
SDL_JoystickClose(m_joystick);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
#endif
delete ui;
}
void GamePadDialog::on_refreshListBtn_clicked()
{
#if QT_HAS_SDL
if(m_joystick)
{
SDL_JoystickClose(m_joystick);
ui->JoyName->setText("<b>No GamePad</b>");
m_joystick = 0;
}
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
SDL_Init(SDL_INIT_JOYSTICK);
int numJoy = SDL_NumJoysticks();
ui->GamePadList->clear();
for(int i = 0; i < numJoy; i++)
{
QListWidgetItem* item = new QListWidgetItem();
QString padName = SDL_JoystickName(i);
if(padName == "") padName = "<b>Unknown GamePad</b>";
item->setText(padName);
item->setData(Qt::UserRole,i);
ui->GamePadList->addItem(item);
}
if(numJoy > 0)
{
ui->GamePadList->setCurrentRow(0);
on_SelectPadBtn_clicked();
}
#endif
}
void GamePadDialog::pollJoystick()
{
#if QT_HAS_SDL
if(!m_joystick)
return;
SDL_JoystickUpdate();
// Update buttons state
for(int i=0;i<14;i++)
{
float val = 0;
if(GamepadPadMapping[i].mapping_type == 0)
val = SDL_JoystickGetButton(m_joystick,GamepadPadMapping[i].mapping_in);
else if(GamepadPadMapping[i].mapping_type == 1)
{
val = SDL_JoystickGetAxis(m_joystick,GamepadPadMapping[i].mapping_in);
if(val*GamepadPadMapping[i].mapping_sign > 16384) val = 1;
else val = 0;
}
else if(GamepadPadMapping[i].mapping_type == 2)
val = SDL_JoystickGetHat(m_joystick,GamepadPadMapping[i].mapping_in);
QLabel* labelPreview = findChild<QLabel*>(GamepadPadMapping[i].ViewLabelName);
if(labelPreview)
{
labelPreview->setVisible(val != 0);
}
if(val)
{
m_inputState->pad_buttons |= (1<<i);
}
else
{
m_inputState->pad_buttons &= ~(1<<i);
}
}
// Update analog stick
m_inputState->pad_lstick_x = 0;
m_inputState->pad_lstick_y = 0;
for(int i = 14; i < 18; i++)
{
float val = 0;
if(GamepadPadMapping[i].mapping_type == 0)
val = SDL_JoystickGetButton(m_joystick,GamepadPadMapping[i].mapping_in);
else if(GamepadPadMapping[i].mapping_type == 1)
{
val = SDL_JoystickGetAxis(m_joystick,GamepadPadMapping[i].mapping_in);
if((val <= 0 && GamepadPadMapping[i].mapping_sign < 0) || (val >= 0 && GamepadPadMapping[i].mapping_sign > 0))
val = abs(val) * 1.0f / 32767;
else
val = 0;
}
else if(GamepadPadMapping[i].mapping_type == 2)
val = SDL_JoystickGetHat(m_joystick,GamepadPadMapping[i].mapping_in);
QLabel* labelPreview = findChild<QLabel*>(GamepadPadMapping[i].ViewLabelName);
if(labelPreview)
{
labelPreview->setVisible(val != 0);
}
switch(i)
{
case 14:
m_inputState->pad_lstick_x -= val;
break;
case 15:
m_inputState->pad_lstick_x += val;
break;
case 16:
m_inputState->pad_lstick_y -= val;
break;
default:
m_inputState->pad_lstick_y += val;
break;
}
}
if(isVisible())
{
for(int i = 0; i < ui->padValues->topLevelItemCount(); i++)
{
QTreeWidgetItem* item = ui->padValues->topLevelItem(i);
for(int j = 0; j < item->childCount(); j++)
{
QTreeWidgetItem* item2 = item->child(j);
if(item2->data(0,Qt::UserRole).toInt() == 0)
{
item2->setText(1,QVariant(SDL_JoystickGetButton(m_joystick,item2->data(0,Qt::UserRole+1).toInt())).toString());
}
else if(item2->data(0,Qt::UserRole).toInt() == 1)
{
int val = SDL_JoystickGetAxis(m_joystick,item2->data(0,Qt::UserRole+1).toInt());
if((val <= 0 && item2->data(0,Qt::UserRole+2).toInt() < 0) || (val >= 0 && item2->data(0,Qt::UserRole+2).toInt() > 0))
item2->setText(1,QVariant(val).toString());
}
else if(item2->data(0,Qt::UserRole).toInt() == 2)
{
item2->setText(1,QVariant(SDL_JoystickGetHat(m_joystick,item2->data(0,Qt::UserRole+1).toInt())).toString());
}
}
}
}
#endif
}
void GamePadDialog::on_SelectPadBtn_clicked()
{
#if QT_HAS_SDL
int selectedJoy = -1;
if(ui->GamePadList->currentItem() == 0)
{
return;
}
selectedJoy = ui->GamePadList->currentItem()->data(Qt::UserRole).toInt();
m_joyId = selectedJoy;
m_joystick = SDL_JoystickOpen(selectedJoy);
ui->padValues->clear();
ui->padValues->setColumnCount(3);
ui->padValues->setColumnWidth(0,100);
ui->padValues->setColumnWidth(1,50);
ui->padValues->setColumnWidth(2,50);
ui->comboPadInput->clear();
ui->comboPSPButton->clear();
QTreeWidgetItem* buttonItem = new QTreeWidgetItem();
buttonItem->setText(0,"Buttons");
ui->padValues->addTopLevelItem(buttonItem);
for(int i = 0; i < SDL_JoystickNumButtons(m_joystick); i++)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,QVariant(i).toString());
item->setText(1,QVariant(0).toString());
item->setData(0, Qt::UserRole,0);
item->setData(0, Qt::UserRole+1,i);
item->setData(0, Qt::UserRole+2,0);
buttonItem->addChild(item);
int id = i << 8;
ui->comboPadInput->addItem("Button "+QVariant(i).toString(),GetIntFromMapping(i,0,0));
}
QTreeWidgetItem* axesItem = new QTreeWidgetItem();
axesItem->setText(0,"Axes");
ui->padValues->addTopLevelItem(axesItem);
for(int i = 0; i < SDL_JoystickNumAxes(m_joystick); i++)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,QVariant(i).toString()+" Neg");
item->setText(1,QVariant(0).toString());
item->setData(0, Qt::UserRole,1);
item->setData(0, Qt::UserRole+1,i);
item->setData(0, Qt::UserRole+2,-1);
axesItem->addChild(item);
ui->comboPadInput->addItem("Axes "+QVariant(i).toString()+" Neg",GetIntFromMapping(i,1,-1));
item = new QTreeWidgetItem();
item->setText(0,QVariant(i).toString()+" Pos");
item->setText(1,QVariant(0).toString());
item->setData(0, Qt::UserRole,1);
item->setData(0, Qt::UserRole+1,i);
item->setData(0, Qt::UserRole+2,1);
axesItem->addChild(item);
ui->comboPadInput->addItem("Axes "+QVariant(i).toString()+" Pos",GetIntFromMapping(i,1,1));
}
QTreeWidgetItem* hatsItem = new QTreeWidgetItem();
hatsItem->setText(0,"Hats");
ui->padValues->addTopLevelItem(hatsItem);
for(int i = 0; i < SDL_JoystickNumHats(m_joystick); i++)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,QVariant(i).toString());
item->setText(1,QVariant(0).toString());
item->setData(0, Qt::UserRole,2);
item->setData(0, Qt::UserRole+1,i);
item->setData(0, Qt::UserRole+2,0);
hatsItem->addChild(item);
ui->comboPadInput->addItem("Button "+QVariant(i).toString(),GetIntFromMapping(i,2,0));
}
for(int i = 0; i < 18; i++)
{
if(GamepadPadMapping[i].Name != "")
{
ui->comboPSPButton->addItem(GamepadPadMapping[i].Name,i);
}
}
SetViewMode();
#endif
}
void GamePadDialog::SetViewMode()
{
#if QT_HAS_SDL
ui->buttonBox->setEnabled(true);
ui->refreshListBtn->setEnabled(true);
ui->SelectPadBtn->setEnabled(true);
if(!m_joystick)
ui->JoyName->setText("<b>No GamePad</b>");
else
ui->JoyName->setText(QString("<b>Current gamepad : ")+SDL_JoystickName(m_joyId)+"</b>");
#endif
}
void GamePadDialog::on_AssignBtn_clicked()
{
int idxPad = ui->comboPadInput->currentIndex();
int idxPSP = ui->comboPSPButton->currentIndex();
int pspButton = ui->comboPSPButton->itemData(idxPSP).toInt();
int padInfo = ui->comboPadInput->itemData(idxPad).toInt();
GetMappingFromInt(padInfo, GamepadPadMapping[pspButton].mapping_in,
GamepadPadMapping[pspButton].mapping_type,
GamepadPadMapping[pspButton].mapping_sign);
}
int GamePadDialog::GetIntFromMapping(int inputId, int type, int sign)
{
sign = (sign == -1 ? 1 : (sign == 1 ? 2 : 0));
return inputId << 8 | sign << 2 | type;
}
void GamePadDialog::GetMappingFromInt(int padInfo, int& inputId, int& type, int& sign)
{
inputId = padInfo >> 8;
type = padInfo & 0x3;
sign = (padInfo >> 2) & 0x3;
sign = (sign == 1 ? -1 : (sign == 2 ? 1 : 0));
}
void GamePadDialog::on_buttonBox_accepted()
{
for(int i = 0; i < 18; i++)
{
g_Config.iMappingMap[i+configOffset] = GetIntFromMapping(GamepadPadMapping[i].mapping_in,
GamepadPadMapping[i].mapping_type,
GamepadPadMapping[i].mapping_sign);
}
}

51
Qt/gamepaddialog.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef GAMEPADDIALOG_H
#define GAMEPADDIALOG_H
#include <QDialog>
#if QT_HAS_SDL
#include "SDL/SDL.h"
#endif
#include "native/input/input_state.h"
namespace Ui {
class GamePadDialog;
}
class QTimer;
class GamePadDialog : public QDialog
{
Q_OBJECT
public:
explicit GamePadDialog(InputState* inputState, QWidget *parent = 0);
~GamePadDialog();
void SetViewMode();
void SetCalibMode();
void CalibNextButton();
private slots:
void on_refreshListBtn_clicked();
void on_SelectPadBtn_clicked();
void pollJoystick();
void on_AssignBtn_clicked();
void on_buttonBox_accepted();
private:
int GetIntFromMapping(int inputId, int type, int sign);
void GetMappingFromInt(int value, int &inputId, int &type, int &sign);
Ui::GamePadDialog *ui;
#if QT_HAS_SDL
SDL_Joystick* m_joystick;
int m_joyId;
#endif
InputState* m_inputState;
bool m_isInit;
QTimer *data_timer;
};
#endif // GAMEPADDIALOG_H

512
Qt/gamepaddialog.ui Normal file
View File

@ -0,0 +1,512 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GamePadDialog</class>
<widget class="QDialog" name="GamePadDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>850</width>
<height>501</height>
</rect>
</property>
<property name="windowTitle">
<string>Gamepad Configuration</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>GamePad List</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QListWidget" name="GamePadList"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="refreshListBtn">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="SelectPadBtn">
<property name="text">
<string>Select</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Gamepad Values :</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="padValues">
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="JoyName">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Assign Gamepad input</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboPadInput"/>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string> to PSP button/axis</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboPSPButton"/>
</item>
<item>
<widget class="QPushButton" name="AssignBtn">
<property name="text">
<string>Assign</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Press buttons on your gamePad to verify mapping :</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="minimumSize">
<size>
<width>500</width>
<height>218</height>
</size>
</property>
<widget class="QLabel" name="PSPImg">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>218</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_Up">
<property name="geometry">
<rect>
<x>110</x>
<y>78</y>
<width>21</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_up_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_Left">
<property name="geometry">
<rect>
<x>92</x>
<y>93</y>
<width>21</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_left_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_Right">
<property name="geometry">
<rect>
<x>122</x>
<y>94</y>
<width>20</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_right_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_Down">
<property name="geometry">
<rect>
<x>109</x>
<y>105</y>
<width>21</width>
<height>30</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_down_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_Home">
<property name="geometry">
<rect>
<x>141</x>
<y>165</y>
<width>30</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_smallbtn_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_Select">
<property name="geometry">
<rect>
<x>312</x>
<y>166</y>
<width>21</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_smallbtn_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_Start">
<property name="geometry">
<rect>
<x>339</x>
<y>166</y>
<width>21</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_smallbtn_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_S">
<property name="geometry">
<rect>
<x>351</x>
<y>92</y>
<width>21</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_rightbtn_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_X">
<property name="geometry">
<rect>
<x>374</x>
<y>114</y>
<width>21</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_rightbtn_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_O">
<property name="geometry">
<rect>
<x>396</x>
<y>93</y>
<width>21</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_rightbtn_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_T">
<property name="geometry">
<rect>
<x>374</x>
<y>71</y>
<width>21</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_rightbtn_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_RT">
<property name="geometry">
<rect>
<x>351</x>
<y>32</y>
<width>61</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_rt_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_LT">
<property name="geometry">
<rect>
<x>93</x>
<y>32</y>
<width>60</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_lt_red.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_ADown">
<property name="geometry">
<rect>
<x>107</x>
<y>144</y>
<width>21</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_adown.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_ALeft">
<property name="geometry">
<rect>
<x>107</x>
<y>139</y>
<width>16</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_aleft.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_AUp">
<property name="geometry">
<rect>
<x>108</x>
<y>134</y>
<width>21</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_aup.png</pixmap>
</property>
</widget>
<widget class="QLabel" name="Prev_ARight">
<property name="geometry">
<rect>
<x>118</x>
<y>138</y>
<width>21</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_aright.png</pixmap>
</property>
</widget>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>GamePadDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>GamePadDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -32,6 +32,10 @@ MainWindow::MainWindow(QWidget *parent) :
qApp->installEventFilter(this);
controls = new Controls(this);
#if QT_HAS_SDL
gamePadDlg = new GamePadDialog(&input_state, this);
#endif
host = new QtHost(this);
w = ui->widget;
w->init(&input_state);
@ -765,3 +769,12 @@ void MainWindow::on_actionLogDefError_triggered()
}
UpdateMenus();
}
void MainWindow::on_action_OptionsGamePadControls_triggered()
{
#if QT_HAS_SDL
gamePadDlg->show();
#else
QMessageBox::information(this,"Gamepad","You need to compile with SDL to have Gamepad support.", QMessageBox::Ok);
#endif
}

View File

@ -7,6 +7,7 @@
#include "input/input_state.h"
#include "debugger_disasm.h"
#include "controls.h"
#include "gamepaddialog.h"
class QtEmuGL;
namespace Ui {
@ -132,6 +133,8 @@ private slots:
void on_actionLogDefError_triggered();
void on_action_OptionsGamePadControls_triggered();
private:
Ui::MainWindow *ui;
@ -139,10 +142,10 @@ private:
CoreState nextState;
InputState input_state;
bool g_bFullScreen;
Debugger_Disasm *dialogDisasm;
Controls* controls;
GamePadDialog* gamePadDlg;
};
#endif // MAINWINDOW_H

View File

@ -136,6 +136,7 @@
<addaction name="action_OptionsScreen4x"/>
</widget>
<addaction name="action_OptionsControls"/>
<addaction name="action_OptionsGamePadControls"/>
<addaction name="separator"/>
<addaction name="action_OptionsFullScreen"/>
<addaction name="action_OptionsBufferedRendering"/>
@ -320,7 +321,7 @@
</action>
<action name="action_OptionsControls">
<property name="text">
<string>&amp;Controls</string>
<string>Keyboard &amp;Controls</string>
</property>
</action>
<action name="action_OptionsFullScreen">
@ -556,6 +557,11 @@
<string>Error</string>
</property>
</action>
<action name="action_OptionsGamePadControls">
<property name="text">
<string>GamePad Controls</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -2,5 +2,17 @@
<qresource prefix="/images">
<file>resources/psp.png</file>
<file>resources/psp_map.png</file>
<file>resources/psp_rightbtn_red.png</file>
<file>resources/psp_smallbtn_red.png</file>
<file>resources/psp_down_red.png</file>
<file>resources/psp_up_red.png</file>
<file>resources/psp_right_red.png</file>
<file>resources/psp_left_red.png</file>
<file>resources/psp_rt_red.png</file>
<file>resources/psp_lt_red.png</file>
<file>resources/psp_aright.png</file>
<file>resources/psp_adown.png</file>
<file>resources/psp_aleft.png</file>
<file>resources/psp_aup.png</file>
</qresource>
</RCC>

BIN
Qt/resources/psp_adown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

BIN
Qt/resources/psp_aleft.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

BIN
Qt/resources/psp_aright.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

BIN
Qt/resources/psp_aup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

BIN
Qt/resources/psp_lt_red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

BIN
Qt/resources/psp_rt_red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Some files were not shown because too many files have changed in this diff Show More