Merge branch 'master' into framebuffer-texture
Conflicts: GPU/GLES/StateMapping.cpp
@ -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()
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "../Util/PPGeDraw.h"
|
||||
#include "PSPDialog.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
#define FADE_TIME 0.5
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "PSPOskDialog.h"
|
||||
#include "../Util/PPGeDraw.h"
|
||||
#include "../HLE/sceCtrl.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
#define NUMKEYROWS 4
|
||||
#define KEYSPERROW 12
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -18,7 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "../../Common/ChunkFile.h"
|
||||
#include "ChunkFile.h"
|
||||
#include <string>
|
||||
|
||||
enum FileAccess
|
||||
|
@ -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;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "../MemMap.h"
|
||||
#include "../Host.h"
|
||||
#include "../Config.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "FixedSizeQueue.h"
|
||||
#include "Common/Thread.h"
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Common/ChunkFile.h"
|
||||
class PointerWrap;
|
||||
|
||||
void Register_sceAtrac3plus();
|
||||
void __AtracInit();
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -4,8 +4,7 @@
|
||||
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
|
||||
#include "sceFont.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
|
||||
typedef u32 FontLibraryHandle;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Common/ChunkFile.h"
|
||||
class PointerWrap;
|
||||
|
||||
void Register_sceFont();
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "HLE.h"
|
||||
#include "FunctionWrappers.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
|
||||
const int PSP_LANGUAGE_JAPANESE = 0;
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Common/ChunkFile.h"
|
||||
class PointerWrap;
|
||||
|
||||
void Register_sceImpose();
|
||||
void __ImposeInit();
|
||||
|
@ -18,8 +18,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "../../Common/ChunkFile.h"
|
||||
#include "Common.h"
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -75,6 +75,7 @@ static const char *blacklistedModules[] = {
|
||||
"sceNetInet_Library",
|
||||
"sceNetResolver_Library",
|
||||
"sceNet_Library",
|
||||
"sceSsl_Module",
|
||||
};
|
||||
|
||||
struct NativeModule {
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "sceKernelTime.h"
|
||||
|
||||
#include "../CoreTiming.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// State
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "../CoreTiming.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
#include "scePower.h"
|
||||
#include "sceKernelThread.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Common/ChunkFile.h"
|
||||
class PointerWrap;
|
||||
|
||||
void __PowerInit();
|
||||
void __PowerDoState(PointerWrap &p);
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "HLE.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
#include "sceSsl.h"
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Common/ChunkFile.h"
|
||||
class PointerWrap;
|
||||
|
||||
void Register_sceSsl();
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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;
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Common/ChunkFile.h"
|
||||
class PointerWrap;
|
||||
|
||||
/**
|
||||
* Valid values for PSP_SYSTEMPARAM_ID_INT_LANGUAGE
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "../HLE/sceMpeg.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
class MediaEngine
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "MemoryStick.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
// MS and FatMS states.
|
||||
static MemStickState memStickState = PSP_MEMORYSTICK_STATE_DRIVER_READY;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "../../Globals.h"
|
||||
#include "../../Common/ChunkFile.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
// mscmhc0 states
|
||||
enum MemStickState {
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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++);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -251,7 +251,6 @@ struct GPUStateCache
|
||||
float vpWidth;
|
||||
float vpHeight;
|
||||
|
||||
|
||||
u32 getRelativeAddress(u32 data) const;
|
||||
};
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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
@ -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
@ -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
@ -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>
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>&Controls</string>
|
||||
<string>Keyboard &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>
|
||||
|
@ -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
After Width: | Height: | Size: 304 B |
BIN
Qt/resources/psp_aleft.png
Normal file
After Width: | Height: | Size: 322 B |
BIN
Qt/resources/psp_aright.png
Normal file
After Width: | Height: | Size: 321 B |
BIN
Qt/resources/psp_aup.png
Normal file
After Width: | Height: | Size: 319 B |
BIN
Qt/resources/psp_down_red.png
Normal file
After Width: | Height: | Size: 278 B |
BIN
Qt/resources/psp_left_red.png
Normal file
After Width: | Height: | Size: 295 B |
BIN
Qt/resources/psp_lt_red.png
Normal file
After Width: | Height: | Size: 349 B |
BIN
Qt/resources/psp_right_red.png
Normal file
After Width: | Height: | Size: 312 B |
BIN
Qt/resources/psp_rightbtn_red.png
Normal file
After Width: | Height: | Size: 399 B |
BIN
Qt/resources/psp_rt_red.png
Normal file
After Width: | Height: | Size: 350 B |
BIN
Qt/resources/psp_smallbtn_red.png
Normal file
After Width: | Height: | Size: 290 B |