mirror of
https://github.com/libretro/ppsspp.git
synced 2025-01-31 13:52:21 +00:00
merged upstream changes
This commit is contained in:
commit
b50f4d4287
@ -560,6 +560,8 @@ add_library(native STATIC
|
||||
native/gfx_es2/fbo.h
|
||||
native/gfx_es2/gl_state.cpp
|
||||
native/gfx_es2/gl_state.h
|
||||
native/gfx_es2/gpu_features.cpp
|
||||
native/gfx_es2/gpu_features.h
|
||||
native/gfx_es2/glsl_program.cpp
|
||||
native/gfx_es2/glsl_program.h
|
||||
native/gfx_es2/vertex_format.cpp
|
||||
|
@ -58,22 +58,12 @@ void __cpuidex(int regs[4], int cpuid_leaf, int ecxval)
|
||||
ELOG("CPUID %08x failed!", cpuid_leaf);
|
||||
}
|
||||
#else
|
||||
asm volatile (
|
||||
#if defined(__i386__)
|
||||
"pushl %%ebx;\n\t"
|
||||
#endif
|
||||
asm (
|
||||
"cpuid;\n\t"
|
||||
"movl %%ebx, %1;\n\t"
|
||||
#if defined(__i386__)
|
||||
"popl %%ebx;\n\t"
|
||||
#endif
|
||||
:"=a" (regs[0]), "=m" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
|
||||
:"a" (cpuid_leaf), "c" (ecxval)
|
||||
#if !defined(__i386__)
|
||||
:"%ebx");
|
||||
#else
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
void __cpuid(int regs[4], int cpuid_leaf)
|
||||
|
@ -15,16 +15,20 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "file/ini_file.h"
|
||||
#include "input/input_state.h"
|
||||
#include "../Core/Config.h"
|
||||
#include "base/NativeApp.h"
|
||||
|
||||
#include "KeyMap.h"
|
||||
#include "../Core/HLE/sceUtility.h"
|
||||
#include "../Core/Config.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace KeyMap {
|
||||
|
||||
KeyDef AxisDef(int deviceId, int axisId, int direction);
|
||||
@ -37,7 +41,7 @@ struct DefMappingStruct {
|
||||
|
||||
KeyMapping g_controllerMap;
|
||||
|
||||
static const DefMappingStruct defaultKeyboardKeyMap[] = {
|
||||
static const DefMappingStruct defaultQwertyKeyboardKeyMap[] = {
|
||||
{CTRL_SQUARE, NKCODE_A},
|
||||
{CTRL_TRIANGLE, NKCODE_S},
|
||||
{CTRL_CIRCLE, NKCODE_X},
|
||||
@ -65,6 +69,62 @@ static const DefMappingStruct defaultKeyboardKeyMap[] = {
|
||||
{VIRTKEY_PAUSE , NKCODE_ESCAPE},
|
||||
};
|
||||
|
||||
static const DefMappingStruct defaultAzertyKeyboardKeyMap[] = {
|
||||
{CTRL_SQUARE, NKCODE_Q},
|
||||
{CTRL_TRIANGLE, NKCODE_S},
|
||||
{CTRL_CIRCLE, NKCODE_X},
|
||||
{CTRL_CROSS, NKCODE_W},
|
||||
{CTRL_LTRIGGER, NKCODE_Q},
|
||||
{CTRL_RTRIGGER, NKCODE_W},
|
||||
|
||||
{CTRL_START, NKCODE_SPACE},
|
||||
#ifdef _WIN32
|
||||
{CTRL_SELECT, NKCODE_V},
|
||||
#else
|
||||
{CTRL_SELECT, NKCODE_ENTER},
|
||||
#endif
|
||||
{CTRL_UP , NKCODE_DPAD_UP},
|
||||
{CTRL_DOWN , NKCODE_DPAD_DOWN},
|
||||
{CTRL_LEFT , NKCODE_DPAD_LEFT},
|
||||
{CTRL_RIGHT, NKCODE_DPAD_RIGHT},
|
||||
{VIRTKEY_AXIS_Y_MAX, NKCODE_I},
|
||||
{VIRTKEY_AXIS_Y_MIN, NKCODE_K},
|
||||
{VIRTKEY_AXIS_X_MIN, NKCODE_J},
|
||||
{VIRTKEY_AXIS_X_MAX, NKCODE_L},
|
||||
{VIRTKEY_RAPID_FIRE , NKCODE_SHIFT_LEFT},
|
||||
{VIRTKEY_UNTHROTTLE , NKCODE_TAB},
|
||||
{VIRTKEY_SPEED_TOGGLE, NKCODE_GRAVE},
|
||||
{VIRTKEY_PAUSE , NKCODE_ESCAPE},
|
||||
};
|
||||
|
||||
static const DefMappingStruct defaultQwertzKeyboardKeyMap[] = {
|
||||
{CTRL_SQUARE, NKCODE_A},
|
||||
{CTRL_TRIANGLE, NKCODE_S},
|
||||
{CTRL_CIRCLE, NKCODE_X},
|
||||
{CTRL_CROSS, NKCODE_Y},
|
||||
{CTRL_LTRIGGER, NKCODE_Q},
|
||||
{CTRL_RTRIGGER, NKCODE_W},
|
||||
|
||||
{CTRL_START, NKCODE_SPACE},
|
||||
#ifdef _WIN32
|
||||
{CTRL_SELECT, NKCODE_V},
|
||||
#else
|
||||
{CTRL_SELECT, NKCODE_ENTER},
|
||||
#endif
|
||||
{CTRL_UP , NKCODE_DPAD_UP},
|
||||
{CTRL_DOWN , NKCODE_DPAD_DOWN},
|
||||
{CTRL_LEFT , NKCODE_DPAD_LEFT},
|
||||
{CTRL_RIGHT, NKCODE_DPAD_RIGHT},
|
||||
{VIRTKEY_AXIS_Y_MAX, NKCODE_I},
|
||||
{VIRTKEY_AXIS_Y_MIN, NKCODE_K},
|
||||
{VIRTKEY_AXIS_X_MIN, NKCODE_J},
|
||||
{VIRTKEY_AXIS_X_MAX, NKCODE_L},
|
||||
{VIRTKEY_RAPID_FIRE , NKCODE_SHIFT_LEFT},
|
||||
{VIRTKEY_UNTHROTTLE , NKCODE_TAB},
|
||||
{VIRTKEY_SPEED_TOGGLE, NKCODE_GRAVE},
|
||||
{VIRTKEY_PAUSE , NKCODE_ESCAPE},
|
||||
};
|
||||
|
||||
static const DefMappingStruct default360KeyMap[] = {
|
||||
{VIRTKEY_AXIS_X_MIN, JOYSTICK_AXIS_X, -1},
|
||||
{VIRTKEY_AXIS_X_MAX, JOYSTICK_AXIS_X, +1},
|
||||
@ -265,7 +325,34 @@ static void SetDefaultKeyMap(int deviceId, const DefMappingStruct *array, size_t
|
||||
void SetDefaultKeyMap(DefaultMaps dmap, bool replace) {
|
||||
switch (dmap) {
|
||||
case DEFAULT_MAPPING_KEYBOARD:
|
||||
SetDefaultKeyMap(DEVICE_ID_KEYBOARD, defaultKeyboardKeyMap, ARRAY_SIZE(defaultKeyboardKeyMap), replace);
|
||||
{
|
||||
bool azerty = false;
|
||||
bool qwertz = false;
|
||||
#ifdef _WIN32
|
||||
HKL localeId = GetKeyboardLayout(0);
|
||||
|
||||
// TODO: Is this list complete enough?
|
||||
switch ((int)localeId & 0xFFFF) {
|
||||
case 0x407:
|
||||
qwertz = true;
|
||||
break;
|
||||
case 0x040c:
|
||||
case 0x080c:
|
||||
case 0x1009:
|
||||
azerty = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (azerty) {
|
||||
SetDefaultKeyMap(DEVICE_ID_KEYBOARD, defaultAzertyKeyboardKeyMap, ARRAY_SIZE(defaultAzertyKeyboardKeyMap), replace);
|
||||
} else if (qwertz) {
|
||||
SetDefaultKeyMap(DEVICE_ID_KEYBOARD, defaultQwertzKeyboardKeyMap, ARRAY_SIZE(defaultQwertzKeyboardKeyMap), replace);
|
||||
} else {
|
||||
SetDefaultKeyMap(DEVICE_ID_KEYBOARD, defaultQwertyKeyboardKeyMap, ARRAY_SIZE(defaultQwertyKeyboardKeyMap), replace);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DEFAULT_MAPPING_X360:
|
||||
SetDefaultKeyMap(DEVICE_ID_X360_0, default360KeyMap, ARRAY_SIZE(default360KeyMap), replace);
|
||||
|
@ -24,6 +24,10 @@
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
#ifdef BLACKBERRY
|
||||
#include <sys/neutrino.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_BEGINTHREADEX
|
||||
#include <process.h>
|
||||
#endif
|
||||
@ -38,7 +42,7 @@ int CurrentThreadId()
|
||||
#elif defined __APPLE__
|
||||
return mach_thread_self();
|
||||
#else
|
||||
return 0;
|
||||
return pthread_self();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -142,7 +146,11 @@ void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
|
||||
void SetCurrentThreadAffinity(u32 mask)
|
||||
{
|
||||
#ifdef BLACKBERRY
|
||||
ThreadCtl(_NTO_TCTL_RUNMASK, &mask);
|
||||
#else
|
||||
SetThreadAffinity(pthread_self(), mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static pthread_key_t threadname_key;
|
||||
@ -170,6 +178,9 @@ static void ThreadnameKeyAlloc()
|
||||
|
||||
void SetCurrentThreadName(const char* szThreadName)
|
||||
{
|
||||
#ifdef BLACKBERRY
|
||||
pthread_setname_np(pthread_self(), szThreadName);
|
||||
#else
|
||||
pthread_once(&threadname_key_once, ThreadnameKeyAlloc);
|
||||
|
||||
void* threadname;
|
||||
@ -177,6 +188,7 @@ void SetCurrentThreadName(const char* szThreadName)
|
||||
free(threadname);
|
||||
|
||||
pthread_setspecific(threadname_key, strdup(szThreadName));
|
||||
#endif
|
||||
|
||||
INFO_LOG(COMMON, "%s(%s)\n", __FUNCTION__, szThreadName);
|
||||
}
|
||||
|
@ -35,7 +35,12 @@ u32 Timer::GetTimeMs()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return timeGetTime();
|
||||
#elif defined(BLACKBERRY)
|
||||
struct timespec time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &time);
|
||||
return (u32)(time.tv_sec * 1000 + time.tv_nsec / 1000000);
|
||||
#else
|
||||
// REALTIME is probably not a good idea for measuring updates.
|
||||
struct timeval t;
|
||||
(void)gettimeofday(&t, NULL);
|
||||
return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000));
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "Config.h"
|
||||
#include "file/ini_file.h"
|
||||
#include "i18n/i18n.h"
|
||||
#include "gfx_es2/gpu_features.h"
|
||||
#include "HLE/sceUtility.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
|
||||
@ -35,8 +36,7 @@ extern bool isJailed;
|
||||
Config::Config() { }
|
||||
Config::~Config() { }
|
||||
|
||||
void Config::Load(const char *iniFileName, const char *controllerIniFilename)
|
||||
{
|
||||
void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
|
||||
iniFilename_ = FindConfigFile(iniFileName != NULL ? iniFileName : "ppsspp.ini");
|
||||
controllerIniFilename_ = FindConfigFile(controllerIniFilename != NULL ? controllerIniFilename : "controls.ini");
|
||||
|
||||
@ -59,6 +59,9 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename)
|
||||
general->Get("CurrentDirectory", ¤tDirectory, "");
|
||||
general->Get("ShowDebuggerOnLoad", &bShowDebuggerOnLoad, false);
|
||||
|
||||
if (!File::Exists(currentDirectory))
|
||||
currentDirectory = "";
|
||||
|
||||
std::string defaultLangRegion = "en_US";
|
||||
if (bFirstRun) {
|
||||
std::string langRegion = System_GetProperty(SYSPROP_LANGREGION);
|
||||
@ -91,7 +94,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename)
|
||||
|
||||
IniFile::Section *recent = iniFile.GetOrCreateSection("Recent");
|
||||
recent->Get("MaxRecent", &iMaxRecent, 30);
|
||||
|
||||
|
||||
// Fix issue from switching from uint (hex in .ini) to int (dec)
|
||||
if (iMaxRecent == 0)
|
||||
iMaxRecent = 30;
|
||||
@ -119,7 +122,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename)
|
||||
#endif
|
||||
cpu->Get("SeparateCPUThread", &bSeparateCPUThread, false);
|
||||
cpu->Get("AtomicAudioLocks", &bAtomicAudioLocks, false);
|
||||
|
||||
|
||||
#ifdef __SYMBIAN32__
|
||||
cpu->Get("SeparateIOThread", &bSeparateIOThread, false);
|
||||
#else
|
||||
@ -130,14 +133,13 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename)
|
||||
|
||||
IniFile::Section *graphics = iniFile.GetOrCreateSection("Graphics");
|
||||
graphics->Get("ShowFPSCounter", &iShowFPSCounter, false);
|
||||
graphics->Get("RenderingMode", &iRenderingMode,
|
||||
// Many ARMv6 devices have serious problems with buffered rendering.
|
||||
#if defined(ARM) && !defined(ARMV7)
|
||||
0
|
||||
#else
|
||||
1
|
||||
#endif
|
||||
); // default is buffered rendering mode
|
||||
|
||||
int renderingModeDefault = 1; // Buffered
|
||||
if (System_GetProperty(SYSPROP_NAME) == "samsung:GT-S5360") {
|
||||
renderingModeDefault = 0; // Non-buffered
|
||||
}
|
||||
|
||||
graphics->Get("RenderingMode", &iRenderingMode, renderingModeDefault);
|
||||
graphics->Get("SoftwareRendering", &bSoftwareRendering, false);
|
||||
graphics->Get("HardwareTransform", &bHardwareTransform, true);
|
||||
graphics->Get("TextureFiltering", &iTexFiltering, 1);
|
||||
|
@ -130,7 +130,7 @@
|
||||
<Message>Updating git-version.cpp</Message>
|
||||
</PreBuildEvent>
|
||||
<Lib>
|
||||
<AdditionalDependencies>..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avdevice.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -587,4 +587,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -76,6 +76,8 @@ int slicelength;
|
||||
|
||||
MEMORY_ALIGNED16(s64) globalTimer;
|
||||
s64 idledCycles;
|
||||
s64 lastGlobalTimeTicks;
|
||||
s64 lastGlobalTimeUs;
|
||||
|
||||
static std::recursive_mutex externalEventSection;
|
||||
|
||||
@ -84,6 +86,11 @@ void (*advanceCallback)(int cyclesExecuted) = NULL;
|
||||
|
||||
void SetClockFrequencyMHz(int cpuMhz)
|
||||
{
|
||||
// When the mhz changes, we keep track of what "time" it was before hand.
|
||||
// This way, time always moves forward, even if mhz is changed.
|
||||
lastGlobalTimeUs = GetGlobalTimeUs();
|
||||
lastGlobalTimeTicks = GetTicks();
|
||||
|
||||
CPU_HZ = cpuMhz * 1000000;
|
||||
// TODO: Rescale times of scheduled events?
|
||||
}
|
||||
@ -93,6 +100,13 @@ int GetClockFrequencyMHz()
|
||||
return CPU_HZ / 1000000;
|
||||
}
|
||||
|
||||
u64 GetGlobalTimeUs()
|
||||
{
|
||||
s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks;
|
||||
s64 usSinceLast = ticksSinceLast / GetClockFrequencyMHz();
|
||||
return lastGlobalTimeUs + usSinceLast;
|
||||
}
|
||||
|
||||
|
||||
Event* GetNewEvent()
|
||||
{
|
||||
@ -162,6 +176,8 @@ void Init()
|
||||
slicelength = INITIAL_SLICE_LENGTH;
|
||||
globalTimer = 0;
|
||||
idledCycles = 0;
|
||||
lastGlobalTimeTicks = 0;
|
||||
lastGlobalTimeUs = 0;
|
||||
hasTsEvents = 0;
|
||||
}
|
||||
|
||||
@ -624,7 +640,7 @@ void DoState(PointerWrap &p)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
|
||||
|
||||
auto s = p.Section("CoreTiming", 1);
|
||||
auto s = p.Section("CoreTiming", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
@ -640,6 +656,14 @@ void DoState(PointerWrap &p)
|
||||
p.Do(slicelength);
|
||||
p.Do(globalTimer);
|
||||
p.Do(idledCycles);
|
||||
|
||||
if (s >= 2) {
|
||||
p.Do(lastGlobalTimeTicks);
|
||||
p.Do(lastGlobalTimeUs);
|
||||
} else {
|
||||
lastGlobalTimeTicks = 0;
|
||||
lastGlobalTimeUs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -79,6 +79,7 @@ namespace CoreTiming
|
||||
|
||||
u64 GetTicks();
|
||||
u64 GetIdleTicks();
|
||||
u64 GetGlobalTimeUs();
|
||||
|
||||
// Returns the event_type identifier.
|
||||
int RegisterEvent(const char *name, TimedCallback callback);
|
||||
|
@ -260,7 +260,7 @@ struct SaveFileInfo
|
||||
memset(title, 0, 128);
|
||||
memset(saveTitle, 0, 128);
|
||||
memset(saveDetail, 0, 1024);
|
||||
modif_time = {0};
|
||||
memset(&modif_time, 0, sizeof(modif_time));
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
|
@ -34,6 +34,28 @@ template<u64 func(u32)> void WrapU64_U() {
|
||||
currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
template<u64 func(int)> void WrapU64_I() {
|
||||
u64 retval = func(PARAM(0));
|
||||
currentMIPS->r[2] = retval & 0xFFFFFFFF;
|
||||
currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
template<u64 func(u32, u64)> void WrapU64_UU64() {
|
||||
u64 param_one = currentMIPS->r[6];
|
||||
param_one |= (u64)(currentMIPS->r[7]) << 32;
|
||||
u64 retval = func(PARAM(0), param_one);
|
||||
currentMIPS->r[2] = retval & 0xFFFFFFFF;
|
||||
currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
template<u64 func(int, u64)> void WrapU64_IU64() {
|
||||
u64 param_one = currentMIPS->r[6];
|
||||
param_one |= (u64)(currentMIPS->r[7]) << 32;
|
||||
u64 retval = func(PARAM(0), param_one);
|
||||
currentMIPS->r[2] = retval & 0xFFFFFFFF;
|
||||
currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
template<int func(int, u64)> void WrapI_IU64() {
|
||||
u64 param_one = currentMIPS->r[6];
|
||||
param_one |= (u64)(currentMIPS->r[7]) << 32;
|
||||
@ -76,6 +98,13 @@ template<u32 func(u32, u64, u32, u32)> void WrapU_UU64UU() {
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, u64, u32, u32)> void WrapU_IU64UU() {
|
||||
u64 param_one = currentMIPS->r[6];
|
||||
param_one |= (u64)(currentMIPS->r[7]) << 32;
|
||||
u32 retval = func(PARAM(0), param_one, PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, int, const char*, u64)> void WrapI_IICU64() {
|
||||
u64 param_three = currentMIPS->r[8];
|
||||
param_three |= (u64)(currentMIPS->r[9]) << 32;
|
||||
|
@ -120,7 +120,7 @@ void __CtrlUpdateLatch()
|
||||
|
||||
ctrlOldButtons = buttons;
|
||||
|
||||
ctrlBufs[ctrlBuf].frame = (u32) (CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz());
|
||||
ctrlBufs[ctrlBuf].frame = (u32) CoreTiming::GetGlobalTimeUs();
|
||||
if (!analogEnabled)
|
||||
memset(ctrlBufs[ctrlBuf].analog, CTRL_ANALOG_CENTER, sizeof(ctrlBufs[ctrlBuf].analog));
|
||||
|
||||
|
@ -25,6 +25,10 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/timeutil.h"
|
||||
|
||||
#ifndef _XBOX
|
||||
#include "gfx_es2/gl_state.h"
|
||||
#endif
|
||||
|
||||
#include "Common/Thread.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/CoreParameter.h"
|
||||
@ -179,7 +183,7 @@ void __DisplayInit() {
|
||||
}
|
||||
|
||||
void __DisplayDoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceDisplay", 1);
|
||||
auto s = p.Section("sceDisplay", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
@ -205,10 +209,17 @@ void __DisplayDoState(PointerWrap &p) {
|
||||
p.Do(leaveVblankEvent);
|
||||
CoreTiming::RestoreRegisterEvent(leaveVblankEvent, "LeaveVBlank", &hleLeaveVblank);
|
||||
p.Do(afterFlipEvent);
|
||||
CoreTiming::RestoreRegisterEvent(afterFlipEvent, "AfterFlipEVent", &hleAfterFlip);
|
||||
CoreTiming::RestoreRegisterEvent(afterFlipEvent, "AfterFlip", &hleAfterFlip);
|
||||
|
||||
p.Do(gstate);
|
||||
p.Do(gstate_c);
|
||||
#ifndef _XBOX
|
||||
if (s < 2) {
|
||||
// This shouldn't have been savestated anyway, but it was.
|
||||
// It's unlikely to overlap with the first value in gpuStats.
|
||||
p.ExpectVoid(&gl_extensions.gpuVendor, sizeof(gl_extensions.gpuVendor));
|
||||
}
|
||||
#endif
|
||||
p.Do(gpuStats);
|
||||
gpu->DoState(p);
|
||||
|
||||
|
@ -71,6 +71,7 @@ u32 sceDmacMemcpy(u32 dst, u32 src, u32 size) {
|
||||
ERROR_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): illegal size", dst, src, size);
|
||||
return 0x80000023;
|
||||
}
|
||||
|
||||
if (dmacMemcpyDeadline > CoreTiming::GetTicks()) {
|
||||
WARN_LOG_REPORT(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): overlapping read", dst, src, size);
|
||||
// TODO: Should block, seems like copy doesn't start until previous finishes.
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include "sceKernelEventFlag.h"
|
||||
#include "sceKernelVTimer.h"
|
||||
#include "sceKernelTime.h"
|
||||
#include "sceMp3.h"
|
||||
#include "sceMpeg.h"
|
||||
#include "sceNet.h"
|
||||
#include "sceNetAdhoc.h"
|
||||
@ -157,6 +158,7 @@ void __KernelShutdown()
|
||||
__NetAdhocShutdown();
|
||||
__FontShutdown();
|
||||
|
||||
__Mp3Shutdown();
|
||||
__MpegShutdown();
|
||||
__PsmfShutdown();
|
||||
__PPGeShutdown();
|
||||
@ -231,6 +233,7 @@ void __KernelDoState(PointerWrap &p)
|
||||
__ImposeDoState(p);
|
||||
__IoDoState(p);
|
||||
__JpegDoState(p);
|
||||
__Mp3DoState(p);
|
||||
__MpegDoState(p);
|
||||
__NetDoState(p);
|
||||
__NetAdhocDoState(p);
|
||||
@ -833,20 +836,20 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0xA8AA591F,WrapI_IU<sceKernelCancelFpl>, "sceKernelCancelFpl"},
|
||||
{0xD8199E4C,WrapI_IU<sceKernelReferFplStatus>, "sceKernelReferFplStatus"},
|
||||
|
||||
{0x20fff560,WrapU_CU<sceKernelCreateVTimer>,"sceKernelCreateVTimer"},
|
||||
{0x328F9E52,WrapU_U<sceKernelDeleteVTimer>,"sceKernelDeleteVTimer"},
|
||||
{0xc68d9437,WrapU_U<sceKernelStartVTimer>,"sceKernelStartVTimer"},
|
||||
{0xD0AEEE87,WrapU_U<sceKernelStopVTimer>,"sceKernelStopVTimer"},
|
||||
{0xD2D615EF,WrapU_U<sceKernelCancelVTimerHandler>,"sceKernelCancelVTimerHandler"},
|
||||
{0xB3A59970,WrapU_UU<sceKernelGetVTimerBase>,"sceKernelGetVTimerBase"},
|
||||
{0xB7C18B77,WrapU64_U<sceKernelGetVTimerBaseWide>,"sceKernelGetVTimerBaseWide"},
|
||||
{0x034A921F,WrapU_UU<sceKernelGetVTimerTime>,"sceKernelGetVTimerTime"},
|
||||
{0xC0B3FFD2,WrapU64_U<sceKernelGetVTimerTimeWide>,"sceKernelGetVTimerTimeWide"},
|
||||
{0x5F32BEAA,WrapU_UU<sceKernelReferVTimerStatus>,"sceKernelReferVTimerStatus"},
|
||||
{0x542AD630,WrapU_UU<sceKernelSetVTimerTime>,"sceKernelSetVTimerTime"},
|
||||
{0xFB6425C3,WrapU_UU64<sceKernelSetVTimerTimeWide>,"sceKernelSetVTimerTimeWide"},
|
||||
{0xd8b299ae,WrapU_UUUU<sceKernelSetVTimerHandler>,"sceKernelSetVTimerHandler"},
|
||||
{0x53B00E9A,WrapU_UU64UU<sceKernelSetVTimerHandlerWide>,"sceKernelSetVTimerHandlerWide"},
|
||||
{0x20fff560,WrapU_CU<sceKernelCreateVTimer>, "sceKernelCreateVTimer", HLE_NOT_IN_INTERRUPT},
|
||||
{0x328F9E52,WrapU_I<sceKernelDeleteVTimer>, "sceKernelDeleteVTimer", HLE_NOT_IN_INTERRUPT},
|
||||
{0xc68d9437,WrapU_I<sceKernelStartVTimer>, "sceKernelStartVTimer"},
|
||||
{0xD0AEEE87,WrapU_I<sceKernelStopVTimer>, "sceKernelStopVTimer"},
|
||||
{0xD2D615EF,WrapU_I<sceKernelCancelVTimerHandler>, "sceKernelCancelVTimerHandler"},
|
||||
{0xB3A59970,WrapU_IU<sceKernelGetVTimerBase>, "sceKernelGetVTimerBase"},
|
||||
{0xB7C18B77,WrapU64_I<sceKernelGetVTimerBaseWide>, "sceKernelGetVTimerBaseWide"},
|
||||
{0x034A921F,WrapU_IU<sceKernelGetVTimerTime>, "sceKernelGetVTimerTime"},
|
||||
{0xC0B3FFD2,WrapU64_I<sceKernelGetVTimerTimeWide>, "sceKernelGetVTimerTimeWide"},
|
||||
{0x5F32BEAA,WrapU_IU<sceKernelReferVTimerStatus>, "sceKernelReferVTimerStatus"},
|
||||
{0x542AD630,WrapU_IU<sceKernelSetVTimerTime>, "sceKernelSetVTimerTime"},
|
||||
{0xFB6425C3,WrapU64_IU64<sceKernelSetVTimerTimeWide>, "sceKernelSetVTimerTimeWide"},
|
||||
{0xd8b299ae,WrapU_IUUU<sceKernelSetVTimerHandler>, "sceKernelSetVTimerHandler"},
|
||||
{0x53B00E9A,WrapU_IU64UU<sceKernelSetVTimerHandlerWide>, "sceKernelSetVTimerHandlerWide"},
|
||||
|
||||
// Names are just guesses, not correct.
|
||||
{0x8daff657,WrapI_CUUUUU<sceKernelCreateTls>, "sceKernelCreateTls"},
|
||||
|
@ -150,7 +150,7 @@ KernelObject *__KernelAlarmObject()
|
||||
|
||||
void __KernelScheduleAlarm(Alarm *alarm, u64 ticks)
|
||||
{
|
||||
alarm->alm.schedule = (CoreTiming::GetTicks() + ticks) / (u64) CoreTiming::GetClockFrequencyMHz();
|
||||
alarm->alm.schedule = CoreTiming::GetGlobalTimeUs() + ticks / (u64) CoreTiming::GetClockFrequencyMHz();
|
||||
CoreTiming::ScheduleEvent((int) ticks, alarmTimer, alarm->GetUID());
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ void __KernelTimeDoState(PointerWrap &p)
|
||||
|
||||
int sceKernelGetSystemTime(u32 sysclockPtr)
|
||||
{
|
||||
u64 t = CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz();
|
||||
u64 t = CoreTiming::GetGlobalTimeUs();
|
||||
if (Memory::IsValidAddress(sysclockPtr))
|
||||
Memory::Write_U64(t, sysclockPtr);
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelGetSystemTime(out:%16llx)", t);
|
||||
@ -62,7 +62,7 @@ int sceKernelGetSystemTime(u32 sysclockPtr)
|
||||
u32 sceKernelGetSystemTimeLow()
|
||||
{
|
||||
// This clock should tick at 1 Mhz.
|
||||
u64 t = CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz();
|
||||
u64 t = CoreTiming::GetGlobalTimeUs();
|
||||
VERBOSE_LOG(SCEKERNEL,"%08x=sceKernelGetSystemTimeLow()",(u32)t);
|
||||
hleEatCycles(165);
|
||||
hleReSchedule("system time");
|
||||
@ -71,7 +71,7 @@ u32 sceKernelGetSystemTimeLow()
|
||||
|
||||
u64 sceKernelGetSystemTimeWide()
|
||||
{
|
||||
u64 t = CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz();
|
||||
u64 t = CoreTiming::GetGlobalTimeUs();
|
||||
DEBUG_LOG(SCEKERNEL,"%i=sceKernelGetSystemTimeWide()",(u32)t);
|
||||
hleEatCycles(250);
|
||||
hleReSchedule("system time");
|
||||
@ -80,9 +80,9 @@ u64 sceKernelGetSystemTimeWide()
|
||||
|
||||
int sceKernelUSec2SysClock(u32 usec, u32 clockPtr)
|
||||
{
|
||||
DEBUG_LOG(SCEKERNEL,"sceKernelUSec2SysClock(%i, %08x )", usec, clockPtr);
|
||||
DEBUG_LOG(SCEKERNEL,"sceKernelUSec2SysClock(%i, %08x)", usec, clockPtr);
|
||||
if (Memory::IsValidAddress(clockPtr))
|
||||
Memory::Write_U32((usec & 0xFFFFFFFFL), clockPtr);
|
||||
Memory::Write_U64((usec & 0xFFFFFFFFL), clockPtr);
|
||||
hleEatCycles(165);
|
||||
return 0;
|
||||
}
|
||||
@ -125,7 +125,7 @@ int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 high
|
||||
|
||||
u32 sceKernelLibcClock()
|
||||
{
|
||||
u32 retVal = (u32) (CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz());
|
||||
u32 retVal = (u32) CoreTiming::GetGlobalTimeUs();
|
||||
DEBUG_LOG(SCEKERNEL, "%i = sceKernelLibcClock", retVal);
|
||||
hleEatCycles(330);
|
||||
hleReSchedule("libc clock");
|
||||
@ -134,7 +134,7 @@ u32 sceKernelLibcClock()
|
||||
|
||||
u32 sceKernelLibcTime(u32 outPtr)
|
||||
{
|
||||
u32 t = (u32) start_time + (u32) (CoreTiming::GetTicks() / CPU_HZ);
|
||||
u32 t = (u32) start_time + (u32) (CoreTiming::GetGlobalTimeUs() / 1000000ULL);
|
||||
|
||||
DEBUG_LOG(SCEKERNEL, "%i = sceKernelLibcTime(%08X)", t, outPtr);
|
||||
// The PSP sure takes its sweet time on this function.
|
||||
|
@ -15,6 +15,7 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <algorithm>
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "sceKernel.h"
|
||||
@ -25,6 +26,7 @@
|
||||
#include "ChunkFile.h"
|
||||
|
||||
static int vtimerTimer = -1;
|
||||
static SceUID runningVTimer = 0;
|
||||
static std::list<SceUID> vtimers;
|
||||
|
||||
struct NativeVTimer {
|
||||
@ -46,16 +48,18 @@ struct VTimer : public KernelObject {
|
||||
int GetIDType() const { return SCE_KERNEL_TMID_VTimer; }
|
||||
|
||||
virtual void DoState(PointerWrap &p) {
|
||||
auto s = p.Section("VTimer", 1);
|
||||
auto s = p.Section("VTimer", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
p.Do(nvt);
|
||||
p.Do(memoryPtr);
|
||||
if (s < 2) {
|
||||
u32 memoryPtr;
|
||||
p.Do(memoryPtr);
|
||||
}
|
||||
}
|
||||
|
||||
NativeVTimer nvt;
|
||||
u32 memoryPtr;
|
||||
};
|
||||
|
||||
KernelObject *__KernelVTimerObject() {
|
||||
@ -66,24 +70,23 @@ u64 __getVTimerRunningTime(VTimer *vt) {
|
||||
if (vt->nvt.active == 0)
|
||||
return 0;
|
||||
|
||||
return cyclesToUs(CoreTiming::GetTicks()) - vt->nvt.base;
|
||||
return CoreTiming::GetGlobalTimeUs() - vt->nvt.base;
|
||||
}
|
||||
|
||||
u64 __getVTimerCurrentTime(VTimer* vt) {
|
||||
return vt->nvt.current + __getVTimerRunningTime(vt);
|
||||
}
|
||||
|
||||
void __cancelVTimer(SceUID id) {
|
||||
int __KernelCancelVTimer(SceUID id) {
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(id, error);
|
||||
|
||||
if (error)
|
||||
return;
|
||||
if (!vt)
|
||||
return error;
|
||||
|
||||
CoreTiming::UnscheduleEvent(vtimerTimer, id);
|
||||
vt->nvt.schedule = 0;
|
||||
vt->nvt.handlerAddr = 0;
|
||||
vt->nvt.commonAddr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __KernelScheduleVTimer(VTimer *vt, u64 schedule) {
|
||||
@ -91,25 +94,42 @@ void __KernelScheduleVTimer(VTimer *vt, u64 schedule) {
|
||||
|
||||
vt->nvt.schedule = schedule;
|
||||
|
||||
if (vt->nvt.active == 1 && vt->nvt.handlerAddr != 0)
|
||||
CoreTiming::ScheduleEvent(usToCycles((u64)vt->nvt.schedule), vtimerTimer, vt->GetUID());
|
||||
if (vt->nvt.active == 1 && vt->nvt.handlerAddr != 0) {
|
||||
// The "real" base is base + current. But when setting the time, base is important.
|
||||
// The schedule is relative to those.
|
||||
u64 cyclesIntoFuture;
|
||||
// It seems like the minimum is approximately 200us?
|
||||
if (schedule < __getVTimerCurrentTime(vt))
|
||||
cyclesIntoFuture = usToCycles(200);
|
||||
else {
|
||||
u64 goalUs = vt->nvt.base + schedule - vt->nvt.current;
|
||||
if (goalUs < CoreTiming::GetGlobalTimeUs())
|
||||
cyclesIntoFuture = usToCycles(200);
|
||||
else
|
||||
cyclesIntoFuture = usToCycles(goalUs - CoreTiming::GetGlobalTimeUs());
|
||||
}
|
||||
|
||||
CoreTiming::ScheduleEvent(cyclesIntoFuture, vtimerTimer, vt->GetUID());
|
||||
}
|
||||
}
|
||||
|
||||
void __rescheduleVTimer(SceUID id, int delay) {
|
||||
void __rescheduleVTimer(SceUID id, u32 delay) {
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(id, error);
|
||||
|
||||
if (error)
|
||||
return;
|
||||
|
||||
if (delay < 0)
|
||||
if (delay < 100)
|
||||
delay = 100;
|
||||
|
||||
__KernelScheduleVTimer(vt, delay);
|
||||
__KernelScheduleVTimer(vt, vt->nvt.schedule + delay);
|
||||
}
|
||||
|
||||
class VTimerIntrHandler : public IntrHandler
|
||||
{
|
||||
static const int HANDLER_STACK_SPACE = 48;
|
||||
|
||||
public:
|
||||
VTimerIntrHandler() : IntrHandler(PSP_SYSTIMER1_INTR) {}
|
||||
|
||||
@ -122,31 +142,36 @@ public:
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
if (vtimer->memoryPtr == 0) {
|
||||
u32 size = 16;
|
||||
vtimer->memoryPtr = kernelMemory.Alloc(size, true, "VTimer");
|
||||
}
|
||||
// Reserve some stack space for arguments.
|
||||
u32 argArea = currentMIPS->r[MIPS_REG_SP];
|
||||
currentMIPS->r[MIPS_REG_SP] -= HANDLER_STACK_SPACE;
|
||||
|
||||
Memory::Write_U64(vtimer->nvt.schedule, vtimer->memoryPtr);
|
||||
Memory::Write_U64(__getVTimerCurrentTime(vtimer), vtimer->memoryPtr + 8);
|
||||
Memory::Write_U64(vtimer->nvt.schedule, argArea - 16);
|
||||
Memory::Write_U64(__getVTimerCurrentTime(vtimer), argArea - 8);
|
||||
|
||||
currentMIPS->pc = vtimer->nvt.handlerAddr;
|
||||
currentMIPS->r[MIPS_REG_A0] = vtimer->GetUID();
|
||||
currentMIPS->r[MIPS_REG_A1] = vtimer->memoryPtr;
|
||||
currentMIPS->r[MIPS_REG_A2] = vtimer->memoryPtr + 8;
|
||||
currentMIPS->r[MIPS_REG_A1] = argArea - 16;
|
||||
currentMIPS->r[MIPS_REG_A2] = argArea - 8;
|
||||
currentMIPS->r[MIPS_REG_A3] = vtimer->nvt.commonAddr;
|
||||
|
||||
runningVTimer = vtimerID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void handleResult(PendingInterrupt &pend) {
|
||||
int result = currentMIPS->r[MIPS_REG_V0];
|
||||
u32 result = currentMIPS->r[MIPS_REG_V0];
|
||||
|
||||
currentMIPS->r[MIPS_REG_SP] += HANDLER_STACK_SPACE;
|
||||
|
||||
int vtimerID = vtimers.front();
|
||||
vtimers.pop_front();
|
||||
|
||||
runningVTimer = 0;
|
||||
|
||||
if (result == 0)
|
||||
__cancelVTimer(vtimerID);
|
||||
__KernelCancelVTimer(vtimerID);
|
||||
else
|
||||
__rescheduleVTimer(vtimerID, result);
|
||||
}
|
||||
@ -164,19 +189,27 @@ void __KernelTriggerVTimer(u64 userdata, int cyclesLate) {
|
||||
}
|
||||
|
||||
void __KernelVTimerDoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceKernelVTimer", 1);
|
||||
auto s = p.Section("sceKernelVTimer", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
p.Do(vtimerTimer);
|
||||
p.Do(vtimers);
|
||||
CoreTiming::RestoreRegisterEvent(vtimerTimer, "VTimer", __KernelTriggerVTimer);
|
||||
|
||||
if (s >= 2)
|
||||
p.Do(runningVTimer);
|
||||
else
|
||||
runningVTimer = 0;
|
||||
}
|
||||
|
||||
void __KernelVTimerInit() {
|
||||
vtimers.clear();
|
||||
__RegisterIntrHandler(PSP_SYSTIMER1_INTR, new VTimerIntrHandler());
|
||||
vtimerTimer = CoreTiming::RegisterEvent("VTimer", __KernelTriggerVTimer);
|
||||
|
||||
// Intentionally starts at 0. This explains the behavior where 0 is treated differently outside a timer.
|
||||
runningVTimer = 0;
|
||||
}
|
||||
|
||||
u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) {
|
||||
@ -193,7 +226,6 @@ u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) {
|
||||
vtimer->nvt.size = sizeof(NativeVTimer);
|
||||
strncpy(vtimer->nvt.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
vtimer->nvt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
vtimer->memoryPtr = 0;
|
||||
|
||||
if (optParamAddr != 0) {
|
||||
u32 size = Memory::Read_U32(optParamAddr);
|
||||
@ -204,7 +236,7 @@ u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) {
|
||||
return id;
|
||||
}
|
||||
|
||||
u32 sceKernelDeleteVTimer(u32 uid) {
|
||||
u32 sceKernelDeleteVTimer(SceUID uid) {
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelDeleteVTimer(%08x)", uid);
|
||||
|
||||
u32 error;
|
||||
@ -222,13 +254,10 @@ u32 sceKernelDeleteVTimer(u32 uid) {
|
||||
}
|
||||
}
|
||||
|
||||
if (vt->memoryPtr != 0)
|
||||
kernelMemory.Free(vt->memoryPtr);
|
||||
|
||||
return kernelObjects.Destroy<VTimer>(uid);
|
||||
}
|
||||
|
||||
u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr) {
|
||||
u32 sceKernelGetVTimerBase(SceUID uid, u32 baseClockAddr) {
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerBase(%08x, %08x)", uid, baseClockAddr);
|
||||
|
||||
u32 error;
|
||||
@ -245,7 +274,7 @@ u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 sceKernelGetVTimerBaseWide(u32 uid) {
|
||||
u64 sceKernelGetVTimerBaseWide(SceUID uid) {
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerBaseWide(%08x)", uid);
|
||||
|
||||
u32 error;
|
||||
@ -253,13 +282,13 @@ u64 sceKernelGetVTimerBaseWide(u32 uid) {
|
||||
|
||||
if (error) {
|
||||
WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerBaseWide(%08x)", error, uid);
|
||||
return error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return vt->nvt.base;
|
||||
}
|
||||
|
||||
u32 sceKernelGetVTimerTime(u32 uid, u32 timeClockAddr) {
|
||||
u32 sceKernelGetVTimerTime(SceUID uid, u32 timeClockAddr) {
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerTime(%08x, %08x)", uid, timeClockAddr);
|
||||
|
||||
u32 error;
|
||||
@ -277,7 +306,7 @@ u32 sceKernelGetVTimerTime(u32 uid, u32 timeClockAddr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 sceKernelGetVTimerTimeWide(u32 uid) {
|
||||
u64 sceKernelGetVTimerTimeWide(SceUID uid) {
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerTimeWide(%08x)", uid);
|
||||
|
||||
u32 error;
|
||||
@ -285,22 +314,24 @@ u64 sceKernelGetVTimerTimeWide(u32 uid) {
|
||||
|
||||
if (error) {
|
||||
WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerTimeWide(%08x)", error, uid);
|
||||
return error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
u64 time = __getVTimerCurrentTime(vt);
|
||||
return time;
|
||||
}
|
||||
|
||||
u64 __setVTimer(VTimer *vt, u64 time) {
|
||||
u64 __KernelSetVTimer(VTimer *vt, u64 time) {
|
||||
u64 current = __getVTimerCurrentTime(vt);
|
||||
vt->nvt.base = vt->nvt.base + __getVTimerCurrentTime(vt) - time;
|
||||
vt->nvt.current = 0;
|
||||
vt->nvt.current = time - __getVTimerRunningTime(vt);
|
||||
|
||||
// Run if we're now passed the schedule.
|
||||
__KernelScheduleVTimer(vt, vt->nvt.schedule);
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr) {
|
||||
u32 sceKernelSetVTimerTime(SceUID uid, u32 timeClockAddr) {
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTime(%08x, %08x)", uid, timeClockAddr);
|
||||
|
||||
u32 error;
|
||||
@ -313,38 +344,43 @@ u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr) {
|
||||
|
||||
u64 time = Memory::Read_U64(timeClockAddr);
|
||||
if (Memory::IsValidAddress(timeClockAddr))
|
||||
Memory::Write_U64(__setVTimer(vt, time), timeClockAddr);
|
||||
Memory::Write_U64(__KernelSetVTimer(vt, time), timeClockAddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock) {
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu", uid, timeClock);
|
||||
u64 sceKernelSetVTimerTimeWide(SceUID uid, u64 timeClock) {
|
||||
if (__IsInInterrupt()) {
|
||||
WARN_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu): in interrupt", uid, timeClock);
|
||||
return -1;
|
||||
}
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu)", uid, timeClock);
|
||||
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
|
||||
if (error) {
|
||||
if (error || vt == NULL) {
|
||||
WARN_LOG(SCEKERNEL, "%08x=sceKernelSetVTimerTimeWide(%08x, %llu)", error, uid, timeClock);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (vt == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return __setVTimer(vt, timeClock);
|
||||
return __KernelSetVTimer(vt, timeClock);
|
||||
}
|
||||
|
||||
void __startVTimer(VTimer *vt) {
|
||||
vt->nvt.active = 1;
|
||||
vt->nvt.base = cyclesToUs(CoreTiming::GetTicks());
|
||||
vt->nvt.base = CoreTiming::GetGlobalTimeUs();
|
||||
|
||||
if (vt->nvt.handlerAddr != 0)
|
||||
__KernelScheduleVTimer(vt, vt->nvt.schedule);
|
||||
}
|
||||
|
||||
u32 sceKernelStartVTimer(u32 uid) {
|
||||
u32 sceKernelStartVTimer(SceUID uid) {
|
||||
if (uid == runningVTimer) {
|
||||
WARN_LOG(SCEKERNEL, "sceKernelStartVTimer(%08x): invalid vtimer", uid);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_VTID;
|
||||
}
|
||||
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelStartVTimer(%08x)", uid);
|
||||
|
||||
u32 error;
|
||||
@ -362,12 +398,17 @@ u32 sceKernelStartVTimer(u32 uid) {
|
||||
}
|
||||
|
||||
void __stopVTimer(VTimer *vt) {
|
||||
vt->nvt.current += __getVTimerCurrentTime(vt);
|
||||
// This increases (__getVTimerCurrentTime includes nvt.current.)
|
||||
vt->nvt.current = __getVTimerCurrentTime(vt);
|
||||
vt->nvt.active = 0;
|
||||
vt->nvt.base = 0;
|
||||
}
|
||||
|
||||
u32 sceKernelStopVTimer(u32 uid) {
|
||||
u32 sceKernelStopVTimer(SceUID uid) {
|
||||
if (uid == runningVTimer) {
|
||||
WARN_LOG(SCEKERNEL, "sceKernelStopVTimer(%08x): invalid vtimer", uid);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_VTID;
|
||||
}
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelStopVTimer(%08x)", uid);
|
||||
|
||||
u32 error;
|
||||
@ -384,8 +425,8 @@ u32 sceKernelStopVTimer(u32 uid) {
|
||||
return error;
|
||||
}
|
||||
|
||||
u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr) {
|
||||
if (uid == 0) {
|
||||
u32 sceKernelSetVTimerHandler(SceUID uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr) {
|
||||
if (uid == runningVTimer) {
|
||||
WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x): invalid vtimer", uid, scheduleAddr, handlerFuncAddr, commonAddr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_VTID;
|
||||
}
|
||||
@ -402,16 +443,18 @@ u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u3
|
||||
|
||||
u64 schedule = Memory::Read_U64(scheduleAddr);
|
||||
vt->nvt.handlerAddr = handlerFuncAddr;
|
||||
if (handlerFuncAddr)
|
||||
if (handlerFuncAddr) {
|
||||
vt->nvt.commonAddr = commonAddr;
|
||||
|
||||
__KernelScheduleVTimer(vt, schedule);
|
||||
__KernelScheduleVTimer(vt, schedule);
|
||||
} else {
|
||||
__KernelScheduleVTimer(vt, vt->nvt.schedule);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr) {
|
||||
if (uid == 0) {
|
||||
u32 sceKernelSetVTimerHandlerWide(SceUID uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr) {
|
||||
if (uid == runningVTimer) {
|
||||
WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x): invalid vtimer", uid, schedule, handlerFuncAddr, commonAddr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_VTID;
|
||||
}
|
||||
@ -427,24 +470,29 @@ u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u3
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x)", uid, schedule, handlerFuncAddr, commonAddr);
|
||||
|
||||
vt->nvt.handlerAddr = handlerFuncAddr;
|
||||
if (handlerFuncAddr)
|
||||
if (handlerFuncAddr) {
|
||||
vt->nvt.commonAddr = commonAddr;
|
||||
|
||||
__KernelScheduleVTimer(vt, schedule);
|
||||
__KernelScheduleVTimer(vt, schedule);
|
||||
} else {
|
||||
__KernelScheduleVTimer(vt, vt->nvt.schedule);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceKernelCancelVTimerHandler(u32 uid) {
|
||||
u32 sceKernelCancelVTimerHandler(SceUID uid) {
|
||||
if (uid == runningVTimer) {
|
||||
WARN_LOG(SCEKERNEL, "sceKernelCancelVTimerHandler(%08x): invalid vtimer", uid);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_VTID;
|
||||
}
|
||||
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelCancelVTimerHandler(%08x)", uid);
|
||||
|
||||
//__cancelVTimer checks if uid is valid
|
||||
__cancelVTimer(uid);
|
||||
|
||||
return 0;
|
||||
return __KernelCancelVTimer(uid);
|
||||
}
|
||||
|
||||
u32 sceKernelReferVTimerStatus(u32 uid, u32 statusAddr) {
|
||||
u32 sceKernelReferVTimerStatus(SceUID uid, u32 statusAddr) {
|
||||
DEBUG_LOG(SCEKERNEL, "sceKernelReferVTimerStatus(%08x, %08x)", uid, statusAddr);
|
||||
|
||||
u32 error;
|
||||
@ -455,8 +503,12 @@ u32 sceKernelReferVTimerStatus(u32 uid, u32 statusAddr) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (Memory::IsValidAddress(statusAddr))
|
||||
Memory::WriteStruct(statusAddr, &vt->nvt);
|
||||
if (Memory::IsValidAddress(statusAddr)) {
|
||||
NativeVTimer status = vt->nvt;
|
||||
u32 size = Memory::Read_U32(statusAddr);
|
||||
status.current = __getVTimerCurrentTime(vt);
|
||||
Memory::Memcpy(statusAddr, &status, std::min(size, (u32)sizeof(status)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -18,21 +18,20 @@
|
||||
#pragma once
|
||||
|
||||
u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr);
|
||||
u32 sceKernelDeleteVTimer(u32 uid);
|
||||
u32 sceKernelStartVTimer(u32 uid);
|
||||
u32 sceKernelStopVTimer(u32 uid);
|
||||
u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr);
|
||||
u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr);
|
||||
u32 sceKernelCancelVTimerHandler(u32 uid);
|
||||
u32 sceKernelReferVTimerStatus(u32 uid, u32 statusAddr);
|
||||
u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr); //SceKernelSysClock
|
||||
u64 sceKernelGetVTimerBaseWide(u32 uid);
|
||||
u32 sceKernelGetVTimerTime(u32 uid, u32 timeClockAddr);
|
||||
u64 sceKernelGetVTimerTimeWide(u32 uid);
|
||||
u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr);
|
||||
u32 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock);
|
||||
u32 sceKernelDeleteVTimer(SceUID uid);
|
||||
u32 sceKernelStartVTimer(SceUID uid);
|
||||
u32 sceKernelStopVTimer(SceUID uid);
|
||||
u32 sceKernelSetVTimerHandler(SceUID uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr);
|
||||
u32 sceKernelSetVTimerHandlerWide(SceUID uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr);
|
||||
u32 sceKernelCancelVTimerHandler(SceUID uid);
|
||||
u32 sceKernelReferVTimerStatus(SceUID uid, u32 statusAddr);
|
||||
u32 sceKernelGetVTimerBase(SceUID uid, u32 baseClockAddr); //SceKernelSysClock
|
||||
u64 sceKernelGetVTimerBaseWide(SceUID uid);
|
||||
u32 sceKernelGetVTimerTime(SceUID uid, u32 timeClockAddr);
|
||||
u64 sceKernelGetVTimerTimeWide(SceUID uid);
|
||||
u32 sceKernelSetVTimerTime(SceUID uid, u32 timeClockAddr);
|
||||
u64 sceKernelSetVTimerTimeWide(SceUID uid, u64 timeClock);
|
||||
|
||||
// TODO
|
||||
void _sceKernelReturnFromTimerHandler();
|
||||
|
||||
void __KernelVTimerInit();
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "Core/HLE/sceMp3.h"
|
||||
#include "Core/HW/MediaEngine.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/HW/MediaEngine.h"
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
#ifndef PRId64
|
||||
@ -40,11 +39,37 @@ extern "C" {
|
||||
|
||||
static const int MP3_BITRATES[] = {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320};
|
||||
|
||||
struct Mp3Context;
|
||||
int __Mp3InitContext(Mp3Context *ctx);
|
||||
|
||||
struct Mp3Context {
|
||||
Mp3Context()
|
||||
#ifdef USE_FFMPEG
|
||||
: avformat_context(NULL), avio_context(NULL), resampler_context(NULL) {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
}
|
||||
|
||||
~Mp3Context() {
|
||||
#ifdef USE_FFMPEG
|
||||
if (avio_context != NULL) {
|
||||
av_free(avio_context->buffer);
|
||||
av_free(avio_context);
|
||||
}
|
||||
if (avformat_context != NULL) {
|
||||
avformat_free_context(avformat_context);
|
||||
}
|
||||
if (resampler_context != NULL) {
|
||||
swr_free(&resampler_context);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p) {
|
||||
auto s = p.Section("Mp3Context", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
auto s = p.Section("Mp3Context", 1);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
p.Do(mp3StreamStart);
|
||||
p.Do(mp3StreamEnd);
|
||||
@ -52,18 +77,20 @@ struct Mp3Context {
|
||||
p.Do(mp3BufSize);
|
||||
p.Do(mp3PcmBuf);
|
||||
p.Do(mp3PcmBufSize);
|
||||
p.Do(readPosition);
|
||||
p.Do(bufferRead);
|
||||
p.Do(bufferWrite);
|
||||
p.Do(bufferAvailable);
|
||||
p.Do(mp3DecodedBytes);
|
||||
if (s >= 2)
|
||||
p.Do(mp3SumDecodedSamples);
|
||||
else
|
||||
mp3SumDecodedSamples = 0;
|
||||
p.Do(mp3LoopNum);
|
||||
p.Do(mp3MaxSamples);
|
||||
p.Do(mp3Bitrate);
|
||||
p.Do(mp3SumDecodedSamples);
|
||||
p.Do(mp3Channels);
|
||||
p.Do(mp3Bitrate);
|
||||
p.Do(mp3SamplingRate);
|
||||
p.Do(mp3Version);
|
||||
p.DoClass(mediaengine);
|
||||
|
||||
__Mp3InitContext(this);
|
||||
}
|
||||
|
||||
int mp3StreamStart;
|
||||
@ -83,7 +110,6 @@ struct Mp3Context {
|
||||
int mp3LoopNum;
|
||||
int mp3MaxSamples;
|
||||
int mp3SumDecodedSamples;
|
||||
MediaEngine *mediaengine;
|
||||
|
||||
int mp3Channels;
|
||||
int mp3Bitrate;
|
||||
@ -99,19 +125,28 @@ struct Mp3Context {
|
||||
};
|
||||
|
||||
static std::map<u32, Mp3Context *> mp3Map;
|
||||
static u32 lastMp3Handle = 0;
|
||||
|
||||
Mp3Context *getMp3Ctx(u32 mp3) {
|
||||
if (mp3Map.find(mp3) == mp3Map.end()) {
|
||||
ERROR_LOG(ME, "Bad mp3 handle %08x - using last one (%08x) instead", mp3, lastMp3Handle);
|
||||
mp3 = lastMp3Handle;
|
||||
}
|
||||
|
||||
if (mp3Map.find(mp3) == mp3Map.end())
|
||||
return NULL;
|
||||
return mp3Map[mp3];
|
||||
}
|
||||
|
||||
void __Mp3Shutdown() {
|
||||
for (auto it = mp3Map.begin(), end = mp3Map.end(); it != end; ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
mp3Map.clear();
|
||||
}
|
||||
|
||||
void __Mp3DoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceMp3", 0, 1);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
p.Do(mp3Map);
|
||||
}
|
||||
|
||||
/* MP3 */
|
||||
int sceMp3Decode(u32 mp3, u32 outPcmPtr) {
|
||||
DEBUG_LOG(ME, "sceMp3Decode(%08x,%08x)", mp3, outPcmPtr);
|
||||
@ -236,7 +271,7 @@ int sceMp3CheckStreamDataNeeded(u32 mp3) {
|
||||
return ctx->bufferAvailable != ctx->mp3BufSize && ctx->readPosition < ctx->mp3StreamEnd;
|
||||
}
|
||||
|
||||
int readFunc(void *opaque, uint8_t *buf, int buf_size) {
|
||||
static int readFunc(void *opaque, uint8_t *buf, int buf_size) {
|
||||
Mp3Context *ctx = static_cast<Mp3Context*>(opaque);
|
||||
|
||||
int res = 0;
|
||||
@ -300,11 +335,6 @@ u32 sceMp3ReserveMp3Handle(u32 mp3Addr) {
|
||||
ctx->mp3Bitrate = 128;
|
||||
ctx->mp3SamplingRate = 44100;
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
ctx->avformat_context = NULL;
|
||||
ctx->avio_context = NULL;
|
||||
#endif
|
||||
|
||||
mp3Map[mp3Addr] = ctx;
|
||||
return mp3Addr;
|
||||
}
|
||||
@ -321,28 +351,10 @@ int sceMp3TermResource() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceMp3Init(u32 mp3) {
|
||||
DEBUG_LOG(ME, "sceMp3Init(%08x)", mp3);
|
||||
|
||||
Mp3Context *ctx = getMp3Ctx(mp3);
|
||||
if (!ctx) {
|
||||
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read in the header and swap the endian
|
||||
int header = Memory::Read_U32(ctx->mp3Buf);
|
||||
header = (header >> 24) |
|
||||
((header<<8) & 0x00FF0000) |
|
||||
((header>>8) & 0x0000FF00) |
|
||||
(header << 24);
|
||||
|
||||
ctx->mp3Version = ((header >> 19) & 0x3);
|
||||
|
||||
int __Mp3InitContext(Mp3Context *ctx) {
|
||||
#ifdef USE_FFMPEG
|
||||
InitFFmpeg();
|
||||
|
||||
u8* avio_buffer = static_cast<u8*>(av_malloc(ctx->mp3BufSize));
|
||||
u8 *avio_buffer = static_cast<u8*>(av_malloc(ctx->mp3BufSize));
|
||||
ctx->avio_context = avio_alloc_context(avio_buffer, ctx->mp3BufSize, 0, ctx, readFunc, NULL, NULL);
|
||||
ctx->avformat_context = avformat_alloc_context();
|
||||
ctx->avformat_context->pb = ctx->avio_context;
|
||||
@ -384,12 +396,6 @@ int sceMp3Init(u32 mp3) {
|
||||
ctx->decoder_context->sample_rate,
|
||||
0, NULL);
|
||||
|
||||
// Let's just grab this info from FFMPEG, it seems more reliable than the code above.
|
||||
|
||||
ctx->mp3SamplingRate = ctx->decoder_context->sample_rate;
|
||||
ctx->mp3Channels = ctx->decoder_context->channels;
|
||||
ctx->mp3Bitrate = ctx->decoder_context->bit_rate / 1000;
|
||||
|
||||
if (!ctx->resampler_context) {
|
||||
ERROR_LOG(ME, "Could not allocate resampler context %d", ret);
|
||||
return -1;
|
||||
@ -400,6 +406,39 @@ int sceMp3Init(u32 mp3) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int sceMp3Init(u32 mp3) {
|
||||
DEBUG_LOG(ME, "sceMp3Init(%08x)", mp3);
|
||||
|
||||
Mp3Context *ctx = getMp3Ctx(mp3);
|
||||
if (!ctx) {
|
||||
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read in the header and swap the endian
|
||||
int header = Memory::Read_U32(ctx->mp3Buf);
|
||||
header = (header >> 24) |
|
||||
((header<<8) & 0x00FF0000) |
|
||||
((header>>8) & 0x0000FF00) |
|
||||
(header << 24);
|
||||
|
||||
ctx->mp3Version = ((header >> 19) & 0x3);
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
int ret = __Mp3InitContext(ctx);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
// Let's just grab this info from FFMPEG, it seems more reliable than the code above.
|
||||
|
||||
ctx->mp3SamplingRate = ctx->decoder_context->sample_rate;
|
||||
ctx->mp3Channels = ctx->decoder_context->channels;
|
||||
ctx->mp3Bitrate = ctx->decoder_context->bit_rate / 1000;
|
||||
|
||||
av_dump_format(ctx->avformat_context, 0, "mp3", 0);
|
||||
#endif
|
||||
|
||||
@ -549,10 +588,6 @@ int sceMp3ReleaseMp3Handle(u32 mp3) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
av_free(ctx->avio_context->buffer);
|
||||
av_free(ctx->avio_context);
|
||||
#endif
|
||||
mp3Map.erase(mp3Map.find(mp3));
|
||||
|
||||
delete ctx;
|
||||
|
@ -19,4 +19,9 @@
|
||||
|
||||
#include "HLE.h"
|
||||
|
||||
void Register_sceMp3();
|
||||
class PointerWrap;
|
||||
|
||||
void Register_sceMp3();
|
||||
|
||||
void __Mp3Shutdown();
|
||||
void __Mp3DoState(PointerWrap &p);
|
@ -55,7 +55,7 @@ const int PSP_TIME_INVALID_MICROSECONDS = -7;
|
||||
u64 __RtcGetCurrentTick()
|
||||
{
|
||||
// TODO: It's probably expecting ticks since January 1, 0001?
|
||||
return cyclesToUs(CoreTiming::GetTicks()) + rtcBaseTicks;
|
||||
return CoreTiming::GetGlobalTimeUs() + rtcBaseTicks;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
@ -79,7 +79,7 @@ time_t rtc_timegm(struct tm *tm)
|
||||
return _mkgmtime(tm);
|
||||
}
|
||||
|
||||
#elif defined(__GLIBC__) && !defined(ANDROID)
|
||||
#elif (defined(__GLIBC__) && !defined(ANDROID)) || defined(BLACKBERRY) || defined(__SYMBIAN32__)
|
||||
#define rtc_timegm timegm
|
||||
#else
|
||||
|
||||
@ -131,7 +131,7 @@ void __RtcDoState(PointerWrap &p)
|
||||
|
||||
void __RtcTimeOfDay(PSPTimeval *tv)
|
||||
{
|
||||
s64 additionalUs = cyclesToUs(CoreTiming::GetTicks());
|
||||
s64 additionalUs = CoreTiming::GetGlobalTimeUs();
|
||||
*tv = rtcBaseTime;
|
||||
|
||||
s64 adjustedUs = additionalUs + tv->tv_usec;
|
||||
@ -409,7 +409,7 @@ int sceRtcConvertLocalTimeToUTC(u32 tickLocalPtr,u32 tickUTCPtr)
|
||||
{
|
||||
u64 srcTick = Memory::Read_U64(tickLocalPtr);
|
||||
// TODO : Let the user select his timezone / daylight saving instead of taking system param ?
|
||||
#if defined(__GLIBC__) || defined(__SYMBIAN32__)
|
||||
#if defined(__GLIBC__) || defined(BLACKBERRY) || defined(__SYMBIAN32__)
|
||||
time_t timezone = 0;
|
||||
tm *time = localtime(&timezone);
|
||||
srcTick -= time->tm_gmtoff*1000000ULL;
|
||||
@ -432,7 +432,7 @@ int sceRtcConvertUtcToLocalTime(u32 tickUTCPtr,u32 tickLocalPtr)
|
||||
{
|
||||
u64 srcTick = Memory::Read_U64(tickUTCPtr);
|
||||
// TODO : Let the user select his timezone / daylight saving instead of taking system param ?
|
||||
#if defined(__GLIBC__) || defined(__SYMBIAN32__)
|
||||
#if defined(__GLIBC__) || defined(BLACKBERRY) || defined(__SYMBIAN32__)
|
||||
time_t timezone = 0;
|
||||
tm *time = localtime(&timezone);
|
||||
srcTick += time->tm_gmtoff*1000000ULL;
|
||||
|
@ -451,7 +451,6 @@ u32 sceSasSetOutputMode(u32 core, u32 outputMode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) {
|
||||
DEBUG_LOG(SCESAS, "sceSasGetAllEnvelopeHeights(%08x, %i)", core, heightsAddr);
|
||||
|
||||
@ -460,8 +459,8 @@ u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) {
|
||||
}
|
||||
|
||||
for (int i = 0; i < PSP_SAS_VOICES_MAX; i++) {
|
||||
int voiceHeight = sas->voices[i].envelope.GetHeight();
|
||||
Memory::Write_U32(voiceHeight, heightsAddr + i * 4);
|
||||
int voiceHeight = sas->voices[i].envelope.GetHeight();
|
||||
Memory::Write_U32(voiceHeight, heightsAddr + i * 4);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -290,7 +290,7 @@ SasInstance::SasInstance()
|
||||
audioDump = fopen("D:\\audio.raw", "wb");
|
||||
#endif
|
||||
memset(&waveformEffect, 0, sizeof(waveformEffect));
|
||||
waveformEffect.type = -1;
|
||||
waveformEffect.type = PSP_SAS_EFFECT_TYPE_OFF;
|
||||
waveformEffect.isDryOn = 1;
|
||||
}
|
||||
|
||||
@ -338,134 +338,148 @@ static inline s16 clamp_s16(int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
void SasVoice::ReadSamples(s16 *output, int numSamples) {
|
||||
// Read N samples into the resample buffer. Could do either PCM or VAG here.
|
||||
switch (type) {
|
||||
case VOICETYPE_VAG:
|
||||
{
|
||||
vag.GetSamples(output, numSamples);
|
||||
if (vag.End()) {
|
||||
// NOTICE_LOG(SAS, "Hit end of VAG audio");
|
||||
playing = false;
|
||||
on = false; // ??
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VOICETYPE_PCM:
|
||||
{
|
||||
u32 size = std::min(pcmSize * 2 - pcmIndex, (int)(numSamples * sizeof(s16)));
|
||||
if (!on) {
|
||||
pcmIndex = 0;
|
||||
break;
|
||||
}
|
||||
Memory::Memcpy(output, pcmAddr + pcmIndex, size);
|
||||
int remaining = numSamples * sizeof(s16) - size;
|
||||
if (remaining > 0) {
|
||||
memset(output + size, 0, remaining);
|
||||
}
|
||||
pcmIndex += size;
|
||||
if (pcmIndex >= pcmSize * 2) {
|
||||
pcmIndex = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VOICETYPE_ATRAC3:
|
||||
{
|
||||
int ret = atrac3.getNextSamples(output, numSamples);
|
||||
if (ret) {
|
||||
// Hit atrac3 voice end
|
||||
playing = false;
|
||||
on = false; // ??
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
memset(output, 0, numSamples * sizeof(s16));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SasInstance::MixVoice(SasVoice &voice) {
|
||||
switch (voice.type) {
|
||||
case VOICETYPE_VAG:
|
||||
if (voice.type == VOICETYPE_VAG && !voice.vagAddr)
|
||||
break;
|
||||
case VOICETYPE_PCM:
|
||||
if (voice.type == VOICETYPE_PCM && !voice.pcmAddr)
|
||||
break;
|
||||
default:
|
||||
// Load resample history (so we can use a wide filter)
|
||||
resampleBuffer[0] = voice.resampleHist[0];
|
||||
resampleBuffer[1] = voice.resampleHist[1];
|
||||
|
||||
// Figure out number of samples to read.
|
||||
// Actually this is not entirely correct - we need to get one extra sample, and store it
|
||||
// for the next time around. A little complicated...
|
||||
// But for now, see Smoothness HACKERY below :P
|
||||
u32 numSamples = (voice.sampleFrac + grainSize * voice.pitch) / PSP_SAS_PITCH_BASE;
|
||||
if ((int)numSamples > grainSize * 4) {
|
||||
ERROR_LOG(SASMIX, "numSamples too large, clamping: %i vs %i", numSamples, grainSize * 4);
|
||||
numSamples = grainSize * 4;
|
||||
}
|
||||
|
||||
voice.ReadSamples(resampleBuffer + 2, numSamples);
|
||||
|
||||
// Smoothness HACKERY
|
||||
resampleBuffer[2 + numSamples] = resampleBuffer[2 + numSamples - 1];
|
||||
|
||||
// Save resample history
|
||||
voice.resampleHist[0] = resampleBuffer[2 + numSamples - 2];
|
||||
voice.resampleHist[1] = resampleBuffer[2 + numSamples - 1];
|
||||
|
||||
// Resample to the correct pitch, writing exactly "grainSize" samples.
|
||||
// This is a HORRIBLE resampler by the way.
|
||||
// TODO: Special case no-resample case (and 2x and 0.5x) for speed, it's not uncommon
|
||||
|
||||
u32 sampleFrac = voice.sampleFrac;
|
||||
const int MAX_CONFIG_VOLUME = 20;
|
||||
int volumeShift = (MAX_CONFIG_VOLUME - g_Config.iSFXVolume);
|
||||
if (volumeShift < 0) volumeShift = 0;
|
||||
for (int i = 0; i < grainSize; i++) {
|
||||
// For now: nearest neighbour, not even using the resample history at all.
|
||||
int sample = resampleBuffer[sampleFrac / PSP_SAS_PITCH_BASE + 2];
|
||||
sampleFrac += voice.pitch;
|
||||
|
||||
// The maximum envelope height (PSP_SAS_ENVELOPE_HEIGHT_MAX) is (1 << 30) - 1.
|
||||
// Reduce it to 14 bits, by shifting off 15. Round up by adding (1 << 14) first.
|
||||
int envelopeValue = voice.envelope.GetHeight();
|
||||
envelopeValue = (envelopeValue + (1 << 14)) >> 15;
|
||||
|
||||
// We just scale by the envelope before we scale by volumes.
|
||||
// Again, we round up by adding (1 << 14) first (*after* multiplying.)
|
||||
sample = ((sample * envelopeValue) + (1 << 14)) >> 15;
|
||||
|
||||
// We mix into this 32-bit temp buffer and clip in a second loop
|
||||
// Ideally, the shift right should be there too but for now I'm concerned about
|
||||
// not overflowing.
|
||||
mixBuffer[i * 2] += (sample * voice.volumeLeft ) >> volumeShift; // Max = 16 and Min = 12(default)
|
||||
mixBuffer[i * 2 + 1] += (sample * voice.volumeRight) >> volumeShift; // Max = 16 and Min = 12(default)
|
||||
sendBuffer[i * 2] += sample * voice.volumeLeftSend >> 12;
|
||||
sendBuffer[i * 2 + 1] += sample * voice.volumeRightSend >> 12;
|
||||
voice.envelope.Step();
|
||||
}
|
||||
|
||||
voice.sampleFrac = sampleFrac;
|
||||
// Let's hope grainSize is a power of 2.
|
||||
//voice.sampleFrac &= grainSize * PSP_SAS_PITCH_BASE - 1;
|
||||
voice.sampleFrac -= numSamples * PSP_SAS_PITCH_BASE;
|
||||
|
||||
if (voice.envelope.HasEnded())
|
||||
{
|
||||
// NOTICE_LOG(SAS, "Hit end of envelope");
|
||||
voice.playing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) {
|
||||
int voicesPlayingCount = 0;
|
||||
|
||||
for (int v = 0; v < PSP_SAS_VOICES_MAX; v++) {
|
||||
SasVoice &voice = voices[v];
|
||||
if (!voice.playing || voice.paused)
|
||||
continue;
|
||||
voicesPlayingCount++;
|
||||
|
||||
// TODO: Special case no-resample case for speed
|
||||
|
||||
switch (voice.type) {
|
||||
case VOICETYPE_VAG:
|
||||
if (voice.type == VOICETYPE_VAG && !voice.vagAddr)
|
||||
break;
|
||||
case VOICETYPE_PCM:
|
||||
if (voice.type == VOICETYPE_PCM && !voice.pcmAddr)
|
||||
break;
|
||||
default:
|
||||
// Load resample history (so we can use a wide filter)
|
||||
resampleBuffer[0] = voice.resampleHist[0];
|
||||
resampleBuffer[1] = voice.resampleHist[1];
|
||||
|
||||
// Figure out number of samples to read.
|
||||
// Actually this is not entirely correct - we need to get one extra sample, and store it
|
||||
// for the next time around. A little complicated...
|
||||
// But for now, see Smoothness HACKERY below :P
|
||||
u32 numSamples = (voice.sampleFrac + grainSize * voice.pitch) / PSP_SAS_PITCH_BASE;
|
||||
if ((int)numSamples > grainSize * 4) {
|
||||
ERROR_LOG(SASMIX, "numSamples too large, clamping: %i vs %i", numSamples, grainSize * 4);
|
||||
numSamples = grainSize * 4;
|
||||
}
|
||||
|
||||
// Read N samples into the resample buffer. Could do either PCM or VAG here.
|
||||
switch (voice.type) {
|
||||
case VOICETYPE_VAG:
|
||||
{
|
||||
voice.vag.GetSamples(resampleBuffer + 2, numSamples);
|
||||
if (voice.vag.End()) {
|
||||
// NOTICE_LOG(SAS, "Hit end of VAG audio");
|
||||
voice.playing = false;
|
||||
voice.on = false; // ??
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VOICETYPE_PCM:
|
||||
{
|
||||
u32 size = std::min(voice.pcmSize * 2 - voice.pcmIndex, (int)(numSamples * sizeof(s16)));
|
||||
memset(resampleBuffer + 2, 0, numSamples * sizeof(s16));
|
||||
if (!voice.on) {
|
||||
voice.pcmIndex = 0;
|
||||
break;
|
||||
}
|
||||
Memory::Memcpy(resampleBuffer + 2, voice.pcmAddr + voice.pcmIndex, size);
|
||||
voice.pcmIndex += size;
|
||||
if (voice.pcmIndex >= voice.pcmSize * 2) {
|
||||
voice.pcmIndex = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VOICETYPE_ATRAC3:
|
||||
{
|
||||
int ret = voice.atrac3.getNextSamples(resampleBuffer + 2, numSamples);
|
||||
if (ret) {
|
||||
// Hit atrac3 voice end
|
||||
voice.playing = false;
|
||||
voice.on = false; // ??
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
memset(resampleBuffer + 2, 0, numSamples * sizeof(s16));
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Smoothness HACKERY
|
||||
resampleBuffer[2 + numSamples] = resampleBuffer[2 + numSamples - 1];
|
||||
|
||||
// Save resample history
|
||||
voice.resampleHist[0] = resampleBuffer[2 + numSamples - 2];
|
||||
voice.resampleHist[1] = resampleBuffer[2 + numSamples - 1];
|
||||
|
||||
// Resample to the correct pitch, writing exactly "grainSize" samples.
|
||||
u32 sampleFrac = voice.sampleFrac;
|
||||
const int MAX_CONFIG_VOLUME = 20;
|
||||
int volumeShift = (MAX_CONFIG_VOLUME - g_Config.iSFXVolume);
|
||||
if (volumeShift < 0) volumeShift = 0;
|
||||
for (int i = 0; i < grainSize; i++) {
|
||||
// For now: nearest neighbour, not even using the resample history at all.
|
||||
int sample = resampleBuffer[sampleFrac / PSP_SAS_PITCH_BASE + 2];
|
||||
sampleFrac += voice.pitch;
|
||||
|
||||
// The maximum envelope height (PSP_SAS_ENVELOPE_HEIGHT_MAX) is (1 << 30) - 1.
|
||||
// Reduce it to 14 bits, by shifting off 15. Round up by adding (1 << 14) first.
|
||||
int envelopeValue = voice.envelope.GetHeight();
|
||||
envelopeValue = (envelopeValue + (1 << 14)) >> 15;
|
||||
|
||||
// We just scale by the envelope before we scale by volumes.
|
||||
// Again, we round up by adding (1 << 14) first (*after* multiplying.)
|
||||
sample = ((sample * envelopeValue) + (1 << 14)) >> 15;
|
||||
|
||||
// We mix into this 32-bit temp buffer and clip in a second loop
|
||||
// Ideally, the shift right should be there too but for now I'm concerned about
|
||||
// not overflowing.
|
||||
mixBuffer[i * 2] += (sample * voice.volumeLeft ) >> volumeShift; // Max = 16 and Min = 12(default)
|
||||
mixBuffer[i * 2 + 1] += (sample * voice.volumeRight) >> volumeShift; // Max = 16 and Min = 12(default)
|
||||
sendBuffer[i * 2] += sample * voice.volumeLeftSend >> 12;
|
||||
sendBuffer[i * 2 + 1] += sample * voice.volumeRightSend >> 12;
|
||||
voice.envelope.Step();
|
||||
}
|
||||
voice.sampleFrac = sampleFrac;
|
||||
// Let's hope grainSize is a power of 2.
|
||||
//voice.sampleFrac &= grainSize * PSP_SAS_PITCH_BASE - 1;
|
||||
voice.sampleFrac -= numSamples * PSP_SAS_PITCH_BASE;
|
||||
|
||||
if (voice.envelope.HasEnded())
|
||||
{
|
||||
// NOTICE_LOG(SAS, "Hit end of envelope");
|
||||
voice.playing = false;
|
||||
}
|
||||
}
|
||||
MixVoice(voice);
|
||||
}
|
||||
|
||||
//if (voicesPlayingCount)
|
||||
// NOTICE_LOG(SAS, "Sas mixed %i voices", voicesPlayingCount);
|
||||
// Okay, apply effects processing to the Send buffer alone here.
|
||||
// Reverb, echo, what have you.
|
||||
// TODO
|
||||
// Okay, apply effects processing to the Send buffer.
|
||||
//if (waveformEffect.type != PSP_SAS_EFFECT_TYPE_OFF)
|
||||
// ApplyReverb();
|
||||
|
||||
// Then mix the send buffer in with the rest.
|
||||
|
||||
// Alright, all voices mixed. Let's convert and clip, and at the same time, wipe mixBuffer for next time. Could also dither.
|
||||
s16 *outp = (s16 *)Memory::GetPointer(outAddr);
|
||||
@ -500,6 +514,12 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void SasInstance::ApplyReverb() {
|
||||
// for (int i = 0; i < grainSize * 2; i += 2) {
|
||||
// modify sendBuffer
|
||||
// }
|
||||
}
|
||||
|
||||
void SasInstance::DoState(PointerWrap &p) {
|
||||
auto s = p.Section("SasInstance", 1);
|
||||
if (!s)
|
||||
|
@ -50,6 +50,17 @@ enum {
|
||||
|
||||
PSP_SAS_ENVELOPE_HEIGHT_MAX = 0x40000000,
|
||||
PSP_SAS_ENVELOPE_FREQ_MAX = 0x7FFFFFFF,
|
||||
|
||||
PSP_SAS_EFFECT_TYPE_OFF = -1,
|
||||
PSP_SAS_EFFECT_TYPE_ROOM = 0,
|
||||
PSP_SAS_EFFECT_TYPE_UNK1 = 1,
|
||||
PSP_SAS_EFFECT_TYPE_UNK2 = 2,
|
||||
PSP_SAS_EFFECT_TYPE_UNK3 = 3,
|
||||
PSP_SAS_EFFECT_TYPE_HALL = 4,
|
||||
PSP_SAS_EFFECT_TYPE_SPACE = 5,
|
||||
PSP_SAS_EFFECT_TYPE_ECHO = 6,
|
||||
PSP_SAS_EFFECT_TYPE_DELAY = 7,
|
||||
PSP_SAS_EFFECT_TYPE_PIPE = 8,
|
||||
};
|
||||
|
||||
struct WaveformEffect
|
||||
@ -204,6 +215,8 @@ struct SasVoice
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
void ReadSamples(s16 *output, int numSamples);
|
||||
|
||||
bool playing;
|
||||
bool paused; // a voice can be playing AND paused. In that case, it won't play.
|
||||
bool on; // key-on, key-off.
|
||||
@ -225,6 +238,11 @@ struct SasVoice
|
||||
|
||||
int volumeLeft;
|
||||
int volumeRight;
|
||||
|
||||
// I am pretty sure that volumeLeftSend and effectLeft really are the same thing (and same for right of course).
|
||||
// We currently have nothing that ever modifies volume*Send.
|
||||
// One game that uses an effect (probably a reverb) is MHU.
|
||||
|
||||
int volumeLeftSend; // volume to "Send" (audio-lingo) to the effects processing engine, like reverb
|
||||
int volumeRightSend;
|
||||
int effectLeft;
|
||||
@ -258,6 +276,10 @@ public:
|
||||
FILE *audioDump;
|
||||
|
||||
void Mix(u32 outAddr, u32 inAddr = 0, int leftVol = 0, int rightVol = 0);
|
||||
void MixVoice(SasVoice &voice);
|
||||
|
||||
// Applies reverb to send buffer, according to waveformEffect.
|
||||
void ApplyReverb();
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
u32 FPURegCache::tempValues[NUM_TEMPS];
|
||||
|
||||
FPURegCache::FPURegCache() : mips(0), emit(0) {
|
||||
FPURegCache::FPURegCache() : mips(0), initialReady(false), emit(0) {
|
||||
memset(regs, 0, sizeof(regs));
|
||||
memset(xregs, 0, sizeof(xregs));
|
||||
vregs = regs + 32;
|
||||
@ -31,21 +31,31 @@ FPURegCache::FPURegCache() : mips(0), emit(0) {
|
||||
|
||||
void FPURegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) {
|
||||
this->mips = mips;
|
||||
|
||||
if (!initialReady)
|
||||
SetupInitialRegs();
|
||||
|
||||
memcpy(xregs, xregsInitial, sizeof(xregs));
|
||||
memcpy(regs, regsInitial, sizeof(regs));
|
||||
}
|
||||
|
||||
void FPURegCache::SetupInitialRegs() {
|
||||
for (int i = 0; i < NUM_X_FPREGS; i++) {
|
||||
xregs[i].mipsReg = -1;
|
||||
xregs[i].dirty = false;
|
||||
xregsInitial[i].mipsReg = -1;
|
||||
xregsInitial[i].dirty = false;
|
||||
}
|
||||
memset(regs, 0, sizeof(regs));
|
||||
memset(regsInitial, 0, sizeof(regsInitial));
|
||||
OpArg base = GetDefaultLocation(0);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
regs[i].location = base;
|
||||
regsInitial[i].location = base;
|
||||
base.IncreaseOffset(sizeof(float));
|
||||
}
|
||||
base = GetDefaultLocation(32);
|
||||
for (int i = 32; i < NUM_MIPS_FPRS; i++) {
|
||||
regs[i].location = base;
|
||||
regsInitial[i].location = base;
|
||||
base.IncreaseOffset(sizeof(float));
|
||||
}
|
||||
initialReady = true;
|
||||
}
|
||||
|
||||
void FPURegCache::SpillLock(int p1, int p2, int p3, int p4) {
|
||||
|
@ -155,11 +155,16 @@ public:
|
||||
X64Reg GetFreeXReg();
|
||||
private:
|
||||
const int *GetAllocationOrder(int &count);
|
||||
void SetupInitialRegs();
|
||||
|
||||
MIPSCachedFPReg regs[NUM_MIPS_FPRS];
|
||||
X64CachedFPReg xregs[NUM_X_FPREGS];
|
||||
MIPSCachedFPReg *vregs;
|
||||
|
||||
bool initialReady;
|
||||
MIPSCachedFPReg regsInitial[NUM_MIPS_FPRS];
|
||||
X64CachedFPReg xregsInitial[NUM_X_FPREGS];
|
||||
|
||||
// TEMP0, etc. are swapped in here if necessary (e.g. on x86.)
|
||||
static u32 tempValues[NUM_TEMPS];
|
||||
|
||||
|
@ -171,7 +171,6 @@ void CPU_Init() {
|
||||
|
||||
Memory::Init();
|
||||
mipsr4k.Reset();
|
||||
mipsr4k.pc = 0;
|
||||
|
||||
host->AttemptLoadSymbolMap();
|
||||
|
||||
|
@ -83,6 +83,14 @@ void LoadPostShaderInfo(std::vector<std::string> directories) {
|
||||
section.Get("Vertex", &temp, "");
|
||||
info.vertexShaderFile = path + "/" + temp;
|
||||
section.Get("OutputResolution", &info.outputResolution, false);
|
||||
|
||||
#ifdef USING_GLES2
|
||||
// Let's ignore shaders we can't support. TODO: Check for GLES 3.0
|
||||
bool requiresIntegerSupport;
|
||||
section.Get("RequiresIntSupport", &requiresIntegerSupport, false);
|
||||
if (requiresIntegerSupport)
|
||||
continue;
|
||||
#endif
|
||||
shaderInfo.erase(std::find(shaderInfo.begin(), shaderInfo.end(), info.name), shaderInfo.end());
|
||||
shaderInfo.push_back(info);
|
||||
}
|
||||
|
@ -176,10 +176,10 @@ void ComputeFragmentShaderID(FragmentShaderID *id) {
|
||||
}
|
||||
|
||||
id->d[0] |= (lmode & 1) << 7;
|
||||
id->d[0] |= gstate.isAlphaTestEnabled() << 8;
|
||||
id->d[0] |= enableAlphaTest << 8;
|
||||
if (enableAlphaTest)
|
||||
id->d[0] |= gstate.getAlphaTestFunction() << 9;
|
||||
id->d[0] |= gstate.isColorTestEnabled() << 12;
|
||||
id->d[0] |= enableColorTest << 12;
|
||||
if (enableColorTest)
|
||||
id->d[0] |= gstate.getColorTestFunction() << 13; // color test func
|
||||
id->d[0] |= (enableFog & 1) << 15;
|
||||
|
@ -1395,11 +1395,11 @@ void FramebufferManager::DestroyAllFBOs() {
|
||||
vfbs_.clear();
|
||||
}
|
||||
|
||||
void FramebufferManager::UpdateFromMemory(u32 addr, int size) {
|
||||
void FramebufferManager::UpdateFromMemory(u32 addr, int size, bool safe) {
|
||||
addr &= ~0x40000000;
|
||||
// TODO: Could go through all FBOs, but probably not important?
|
||||
// TODO: Could also check for inner changes, but video is most important.
|
||||
if (addr == DisplayFramebufAddr() || addr == PrevDisplayFramebufAddr()) {
|
||||
if (addr == DisplayFramebufAddr() || addr == PrevDisplayFramebufAddr() || safe) {
|
||||
// TODO: Deleting the FBO is a heavy hammer solution, so let's only do it if it'd help.
|
||||
if (!Memory::IsValidAddress(displayFramebufPtr_))
|
||||
return;
|
||||
@ -1416,6 +1416,8 @@ void FramebufferManager::UpdateFromMemory(u32 addr, int size) {
|
||||
// TODO: This without the fbo_unbind() above would be better than destroying the FBO.
|
||||
// However, it doesn't seem to work for Star Ocean, at least
|
||||
if (useBufferedRendering_ && vfb->fbo) {
|
||||
DisableState();
|
||||
glstate.viewport.set(0, 0, vfb->renderWidth, vfb->renderHeight);
|
||||
fbo_bind_as_render_target(vfb->fbo);
|
||||
needUnbind = true;
|
||||
DrawPixels(Memory::GetPointer(addr | 0x04000000), vfb->format, vfb->fb_stride);
|
||||
|
@ -128,7 +128,7 @@ public:
|
||||
void DeviceLost();
|
||||
void CopyDisplayToOutput();
|
||||
void SetRenderFrameBuffer(); // Uses parameters computed from gstate
|
||||
void UpdateFromMemory(u32 addr, int size);
|
||||
void UpdateFromMemory(u32 addr, int size, bool safe);
|
||||
void SetLineWidth();
|
||||
|
||||
#ifdef USING_GLES2
|
||||
|
@ -1436,10 +1436,13 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
||||
case GE_CMD_UNKNOWN_FC:
|
||||
case GE_CMD_UNKNOWN_FD:
|
||||
case GE_CMD_UNKNOWN_FE:
|
||||
case GE_CMD_UNKNOWN_FF:
|
||||
if (data != 0)
|
||||
WARN_LOG_REPORT_ONCE(unknowncmd, G3D, "Unknown GE command : %08x ", op);
|
||||
break;
|
||||
case GE_CMD_UNKNOWN_FF:
|
||||
// This is hit in quite a few games, supposedly it is a no-op.
|
||||
// Might be used for debugging or something?
|
||||
break;
|
||||
|
||||
default:
|
||||
GPUCommon::ExecuteOp(op, diff);
|
||||
@ -1533,7 +1536,7 @@ void GLES_GPU::InvalidateCacheInternal(u32 addr, int size, GPUInvalidationType t
|
||||
textureCache_.InvalidateAll(type);
|
||||
|
||||
if (type != GPU_INVALIDATE_ALL)
|
||||
framebufferManager_.UpdateFromMemory(addr, size);
|
||||
framebufferManager_.UpdateFromMemory(addr, size, type == GPU_INVALIDATE_SAFE);
|
||||
}
|
||||
|
||||
void GLES_GPU::UpdateMemory(u32 dest, u32 src, int size) {
|
||||
|
@ -226,6 +226,17 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
|
||||
}
|
||||
}
|
||||
|
||||
// Some Android devices (especially Mali, it seems) composite badly if there's alpha in the backbuffer.
|
||||
// So in non-buffered rendering, we will simply consider the dest alpha to be zero in blending equations.
|
||||
#ifdef ANDROID
|
||||
if (g_Config.iRenderingMode == 0) {
|
||||
if (glBlendFuncA == GL_DST_ALPHA) glBlendFuncA = GL_ZERO;
|
||||
if (glBlendFuncB == GL_DST_ALPHA) glBlendFuncB = GL_ZERO;
|
||||
if (glBlendFuncA == GL_ONE_MINUS_DST_ALPHA) glBlendFuncA = GL_ONE;
|
||||
if (glBlendFuncB == GL_ONE_MINUS_DST_ALPHA) glBlendFuncB = GL_ONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
// At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set right somehow.
|
||||
if (!gstate.isStencilTestEnabled() && gstate.isDepthWriteEnabled()) {
|
||||
// Fixes some Persona 2 issues, may be correct? (that is, don't change dest alpha at all if blending)
|
||||
|
@ -223,7 +223,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (doTexture && (!prescale || gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP)) {
|
||||
if (doTexture && (!prescale || gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP || gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX)) {
|
||||
WRITE(p, "uniform vec4 u_uvscaleoffset;\n");
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -206,26 +206,25 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer<Ps
|
||||
return SCE_KERNEL_ERROR_INVALID_POINTER;
|
||||
|
||||
int id = -1;
|
||||
bool oldCompatibility = true;
|
||||
u64 currentTicks = CoreTiming::GetTicks();
|
||||
// Check compatibility
|
||||
if (sceKernelGetCompiledSdkVersion() > 0x01FFFFFF) {
|
||||
//numStacks = 0;
|
||||
//stack = NULL;
|
||||
oldCompatibility = false;
|
||||
}
|
||||
|
||||
u64 currentTicks = CoreTiming::GetTicks();
|
||||
for (int i = 0; i < DisplayListMaxCount; ++i) {
|
||||
if (dls[i].state != PSP_GE_DL_STATE_NONE && dls[i].state != PSP_GE_DL_STATE_COMPLETED) {
|
||||
if (dls[i].pc == listpc && !oldCompatibility) {
|
||||
ERROR_LOG(G3D, "sceGeListEnqueue: can't enqueue, list address %08X already used", listpc);
|
||||
return 0x80000021;
|
||||
for (int i = 0; i < DisplayListMaxCount; ++i) {
|
||||
if (dls[i].state != PSP_GE_DL_STATE_NONE && dls[i].state != PSP_GE_DL_STATE_COMPLETED) {
|
||||
if (dls[i].pc == listpc) {
|
||||
ERROR_LOG(G3D, "sceGeListEnqueue: can't enqueue, list address %08X already used", listpc);
|
||||
return 0x80000021;
|
||||
}
|
||||
//if(dls[i].stack == stack) {
|
||||
// ERROR_LOG(G3D, "sceGeListEnqueue: can't enqueue, list stack %08X already used", context);
|
||||
// return 0x80000021;
|
||||
//}
|
||||
}
|
||||
//if(dls[i].stack == stack) {
|
||||
// ERROR_LOG(G3D, "sceGeListEnqueue: can't enqueue, list stack %08X already used", context);
|
||||
// return 0x80000021;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < DisplayListMaxCount; ++i) {
|
||||
int possibleID = (i + nextListID) % DisplayListMaxCount;
|
||||
auto possibleList = dls[possibleID];
|
||||
|
@ -20,7 +20,7 @@ win32|greaterThan(QT_MAJOR_VERSION,4) {
|
||||
greaterThan(QT_MAJOR_VERSION,4): QT += widgets
|
||||
|
||||
mobile_platform: MOBILITY += sensors
|
||||
symbian: MOBILITY += systeminfo
|
||||
symbian: MOBILITY += systeminfo feedback
|
||||
|
||||
# PPSSPP Libs
|
||||
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/release/
|
||||
@ -53,13 +53,17 @@ linux {
|
||||
}
|
||||
}
|
||||
qnx: LIBS += -lscreen
|
||||
symbian: LIBS += -llibglib -lhwrmvibraclient
|
||||
symbian: LIBS += -llibglib -lRemConCoreApi -lRemConInterfaceBase
|
||||
# Avoids problems with some compilers
|
||||
unix:!symbian: LIBS += -lz
|
||||
|
||||
# Main
|
||||
SOURCES += ../native/base/QtMain.cpp
|
||||
HEADERS += ../native/base/QtMain.h
|
||||
symbian {
|
||||
SOURCES += ../native/base/SymbianMediaKeys.cpp
|
||||
HEADERS += ../native/base/SymbianMediaKeys.h
|
||||
}
|
||||
|
||||
# UI
|
||||
SOURCES += ../UI/*Screen.cpp \
|
||||
|
@ -432,8 +432,7 @@ void NativeInitGraphics()
|
||||
|
||||
void NativeRender()
|
||||
{
|
||||
EnableFZ();
|
||||
// Clearing the screen at the start of the frame is an optimization for tiled mobile GPUs, as it then doesn't need to keep it around between frames.
|
||||
// Clearing the screen at the start of the frame is an optimization for tiled mobile GPUs, as it then doesn't need to keep it around between frames.
|
||||
glClearColor(0,0,0,1);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
|
@ -30,9 +30,11 @@ What's new in 0.9.5
|
||||
* Android-x86 support
|
||||
* Unofficial port for modified Xbox 360 consoles
|
||||
* Atrac3+ plugin no longer required. Symbian now supports Atrac3+ audio.
|
||||
* Symbian audio and ffmpeg is now threaded for more consistent media processing.
|
||||
* Haptic feedback support for mobile devices.
|
||||
* Accurate system information for mobile devices.
|
||||
* Qt audio has been fixed.
|
||||
* Analog controller support for Blackberry.
|
||||
|
||||
|
||||
Basic build instructions
|
||||
|
@ -71,10 +71,10 @@ void CwCheatScreen::CreateViews() {
|
||||
|
||||
LinearLayout *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(400, FILL_PARENT));
|
||||
leftColumn->Add(new ItemHeader(k->T("Options")));
|
||||
leftColumn->Add(new Choice(d->T("Back")))->OnClick.Handle<CwCheatScreen>(this, &CwCheatScreen::OnBack);
|
||||
//leftColumn->Add(new Choice(k->T("Add Cheat")))->OnClick.Handle<CwCheatScreen>(this, &CwCheatScreen::OnAddCheat);
|
||||
leftColumn->Add(new Choice(k->T("Import Cheats")))->OnClick.Handle<CwCheatScreen>(this, &CwCheatScreen::OnImportCheat);
|
||||
leftColumn->Add(new Choice(k->T("Enable/Disable All")))->OnClick.Handle<CwCheatScreen>(this, &CwCheatScreen::OnEnableAll);
|
||||
leftColumn->Add(new Choice(d->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
//leftColumn->Add(new Choice(k->T("Add Cheat")))->OnClick.Handle(this, &CwCheatScreen::OnAddCheat);
|
||||
leftColumn->Add(new Choice(k->T("Import Cheats")))->OnClick.Handle(this, &CwCheatScreen::OnImportCheat);
|
||||
leftColumn->Add(new Choice(k->T("Enable/Disable All")))->OnClick.Handle(this, &CwCheatScreen::OnEnableAll);
|
||||
|
||||
ScrollView *rightScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(0.5f));
|
||||
rightScroll->SetScrollToTop(false);
|
||||
@ -91,8 +91,7 @@ void CwCheatScreen::CreateViews() {
|
||||
}
|
||||
}
|
||||
|
||||
UI::EventReturn CwCheatScreen::OnBack(UI::EventParams ¶ms) {
|
||||
screenManager()->finishDialog(this, DR_OK);
|
||||
void CwCheatScreen::onFinish(DialogResult result) {
|
||||
os.open(activeCheatFile.c_str());
|
||||
for (int j = 0; j < (int)cheatList.size(); j++) {
|
||||
os << cheatList[j];
|
||||
@ -103,10 +102,8 @@ UI::EventReturn CwCheatScreen::OnBack(UI::EventParams ¶ms) {
|
||||
os.close();
|
||||
g_Config.bReloadCheats = true;
|
||||
if (MIPSComp::jit) {
|
||||
auto blocks = MIPSComp::jit->GetBlockCache();
|
||||
blocks->Clear();
|
||||
MIPSComp::jit->ClearCache();
|
||||
}
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn CwCheatScreen::OnEnableAll(UI::EventParams ¶ms) {
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
UI::EventReturn OnImportCheat(UI::EventParams ¶ms);
|
||||
UI::EventReturn OnEnableAll(UI::EventParams ¶ms);
|
||||
|
||||
virtual void onFinish(DialogResult result);
|
||||
protected:
|
||||
virtual void CreateViews();
|
||||
|
||||
|
@ -132,9 +132,8 @@ EmuScreen::~EmuScreen() {
|
||||
}
|
||||
|
||||
void EmuScreen::dialogFinished(const Screen *dialog, DialogResult result) {
|
||||
|
||||
// TODO: improve the way with which we got commands from PauseMenu.
|
||||
// DR_CANCEL means clicked on "continue", DR_OK means clicked on "back to menu",
|
||||
// DR_CANCEL/DR_BACK means clicked on "continue", DR_OK means clicked on "back to menu",
|
||||
// DR_YES means a message sent to PauseMenu by NativeMessageReceived.
|
||||
if (result == DR_OK) {
|
||||
screenManager()->switchScreen(new MainScreen());
|
||||
|
@ -84,7 +84,7 @@ void GameSettingsScreen::CreateViews() {
|
||||
ViewGroup *leftColumn = new AnchorLayout(new LinearLayoutParams(1.0f));
|
||||
root_->Add(leftColumn);
|
||||
|
||||
root_->Add(new Choice(d->T("Back"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &GameSettingsScreen::OnBack);
|
||||
root_->Add(new Choice(d->T("Back"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
|
||||
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, 200, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
|
||||
@ -371,15 +371,7 @@ void GameSettingsScreen::sendMessage(const char *message, const char *value) {
|
||||
}
|
||||
}
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnBack(UI::EventParams &e) {
|
||||
// If we're in-game, return to the game via DR_CANCEL.
|
||||
if (PSP_IsInited()) {
|
||||
screenManager()->finishDialog(this, DR_CANCEL);
|
||||
host->UpdateScreen();
|
||||
} else {
|
||||
screenManager()->finishDialog(this, DR_OK);
|
||||
}
|
||||
|
||||
void GameSettingsScreen::onFinish(DialogResult result) {
|
||||
if (g_Config.bEnableSound) {
|
||||
if (PSP_IsInited() && !IsAudioInitialised())
|
||||
Audio_Init();
|
||||
@ -391,6 +383,16 @@ UI::EventReturn GameSettingsScreen::OnBack(UI::EventParams &e) {
|
||||
host->UpdateUI();
|
||||
|
||||
KeyMap::UpdateConfirmCancelKeys();
|
||||
}
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnBack(UI::EventParams &e) {
|
||||
// If we're in-game, return to the game via DR_CANCEL.
|
||||
if (PSP_IsInited()) {
|
||||
screenManager()->finishDialog(this, DR_CANCEL);
|
||||
host->UpdateScreen();
|
||||
} else {
|
||||
screenManager()->finishDialog(this, DR_OK);
|
||||
}
|
||||
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
@ -508,21 +510,16 @@ void DeveloperToolsScreen::CreateViews() {
|
||||
list->Add(new ItemHeader(de->T("Language")));
|
||||
list->Add(new Choice(de->T("Load language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoadLanguageIni);
|
||||
list->Add(new Choice(de->T("Save language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnSaveLanguageIni);
|
||||
list->Add(new Choice(d->T("Back")))->OnClick.Handle(this, &DeveloperToolsScreen::OnBack);
|
||||
list->Add(new Choice(d->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
}
|
||||
|
||||
UI::EventReturn DeveloperToolsScreen::OnBack(UI::EventParams &e) {
|
||||
screenManager()->finishDialog(this, DR_OK);
|
||||
|
||||
void DeveloperToolsScreen::onFinish(DialogResult result) {
|
||||
g_Config.Save();
|
||||
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
void GameSettingsScreen::CallbackRestoreDefaults(bool yes) {
|
||||
if(yes)
|
||||
if (yes)
|
||||
g_Config.RestoreDefaults();
|
||||
|
||||
host->UpdateUI();
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ public:
|
||||
: gamePath_(gamePath), gameID_(gameID), iAlternateSpeedPercent_(3), enableReports_(false) {}
|
||||
|
||||
virtual void update(InputState &input);
|
||||
virtual void onFinish(DialogResult result);
|
||||
|
||||
UI::Event OnLanguageChanged;
|
||||
UI::Event OnRecentChanged;
|
||||
@ -91,6 +92,7 @@ private:
|
||||
class DeveloperToolsScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
DeveloperToolsScreen() {}
|
||||
virtual void onFinish(DialogResult result);
|
||||
|
||||
protected:
|
||||
virtual void CreateViews();
|
||||
|
@ -704,14 +704,6 @@ void GamePauseScreen::update(InputState &input) {
|
||||
UIScreen::update(input);
|
||||
}
|
||||
|
||||
void GamePauseScreen::key(const KeyInput &key) {
|
||||
if ((key.flags & KEY_DOWN) && UI::IsEscapeKeyCode(key.keyCode)) {
|
||||
screenManager()->finishDialog(this, DR_CANCEL);
|
||||
} else {
|
||||
UIScreen::key(key);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawBackground(float alpha);
|
||||
|
||||
void GamePauseScreen::DrawBackground(UIContext &dc) {
|
||||
|
@ -56,7 +56,6 @@ class GamePauseScreen : public UIScreen {
|
||||
public:
|
||||
GamePauseScreen(const std::string &filename) : UIScreen(), gamePath_(filename), saveSlots_(NULL) {}
|
||||
~GamePauseScreen();
|
||||
virtual void key(const KeyInput &key);
|
||||
|
||||
protected:
|
||||
virtual void DrawBackground(UIContext &dc);
|
||||
@ -81,4 +80,4 @@ private:
|
||||
UI::ChoiceStrip *saveSlots_;
|
||||
UI::Choice *saveStateButton_;
|
||||
UI::Choice *loadStateButton_;
|
||||
};
|
||||
};
|
||||
|
@ -569,8 +569,6 @@ void TakeScreenshot() {
|
||||
}
|
||||
|
||||
void NativeRender() {
|
||||
EnableFZ();
|
||||
|
||||
glstate.depthWrite.set(GL_TRUE);
|
||||
glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
|
||||
|
@ -225,9 +225,11 @@ void TouchControlLayoutScreen::touch(const TouchInput &touch) {
|
||||
}
|
||||
};
|
||||
|
||||
UI::EventReturn TouchControlLayoutScreen::OnBack(UI::EventParams &e) {
|
||||
g_Config.Save();
|
||||
|
||||
|
||||
UI::EventReturn TouchControlLayoutScreen::OnBack(UI::EventParams &e) {
|
||||
|
||||
// Hm, wtf?
|
||||
if (PSP_IsInited()) {
|
||||
screenManager()->finishDialog(this, DR_CANCEL);
|
||||
} else {
|
||||
@ -237,6 +239,10 @@ UI::EventReturn TouchControlLayoutScreen::OnBack(UI::EventParams &e) {
|
||||
return UI::EVENT_DONE;
|
||||
};
|
||||
|
||||
void TouchControlLayoutScreen::onFinish(DialogResult reason) {
|
||||
g_Config.Save();
|
||||
}
|
||||
|
||||
UI::EventReturn TouchControlLayoutScreen::OnVisibility(UI::EventParams &e) {
|
||||
screenManager()->push(new TouchControlVisibilityScreen());
|
||||
return UI::EVENT_DONE;
|
||||
|
@ -24,13 +24,14 @@
|
||||
|
||||
class DragDropButton;
|
||||
|
||||
class TouchControlLayoutScreen : public UIDialogScreenWithBackground{
|
||||
class TouchControlLayoutScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
TouchControlLayoutScreen();
|
||||
|
||||
virtual void CreateViews();
|
||||
virtual void touch(const TouchInput &touch);
|
||||
virtual void dialogFinished(const Screen *dialog, DialogResult result);
|
||||
virtual void onFinish(DialogResult reason);
|
||||
|
||||
protected:
|
||||
virtual UI::EventReturn OnBack(UI::EventParams &e);
|
||||
|
@ -29,7 +29,7 @@ void TouchControlVisibilityScreen::CreateViews() {
|
||||
|
||||
LinearLayout *topBar = new LinearLayout(ORIENT_HORIZONTAL);
|
||||
I18NCategory *di = GetI18NCategory("Dialog");
|
||||
topBar->Add(new Choice(di->T("Back")))->OnClick.Handle<TouchControlVisibilityScreen>(this, &TouchControlVisibilityScreen::OnBack);
|
||||
topBar->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
topBar->Add(new Choice(di->T("Toggle All")))->OnClick.Handle(this, &TouchControlVisibilityScreen::OnToggleAll);
|
||||
|
||||
vert->Add(topBar);
|
||||
@ -94,12 +94,8 @@ void TouchControlVisibilityScreen::CreateViews() {
|
||||
}
|
||||
}
|
||||
|
||||
UI::EventReturn TouchControlVisibilityScreen::OnBack(UI::EventParams &e) {
|
||||
screenManager()->finishDialog(this, DR_OK);
|
||||
|
||||
void TouchControlVisibilityScreen::onFinish(DialogResult result) {
|
||||
g_Config.Save();
|
||||
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn TouchControlVisibilityScreen::OnToggleAll(UI::EventParams &e) {
|
||||
|
@ -25,11 +25,12 @@ namespace UI {
|
||||
class CheckBox;
|
||||
}
|
||||
|
||||
class TouchControlVisibilityScreen : public UIScreenWithBackground {
|
||||
class TouchControlVisibilityScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
TouchControlVisibilityScreen() { }
|
||||
|
||||
virtual void CreateViews();
|
||||
virtual void onFinish(DialogResult result);
|
||||
|
||||
protected:
|
||||
virtual UI::EventReturn OnToggleAll(UI::EventParams &e);
|
||||
|
@ -127,7 +127,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avdevice.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;xinput.lib;d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
@ -160,7 +160,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avdevice.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -194,7 +194,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avdevice.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -235,7 +235,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avdevice.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -16,11 +16,16 @@ public:
|
||||
void ShowTab(HWND pageHandle);
|
||||
void NextTab(bool cycle);
|
||||
void PreviousTab(bool cycle);
|
||||
int CurrentTabIndex() { return currentTab; };
|
||||
HWND CurrentTabHandle() { return tabs[currentTab].pageHandle; };
|
||||
int CurrentTabIndex() { return currentTab; }
|
||||
HWND CurrentTabHandle() {
|
||||
if (currentTab < 0 || currentTab >= (int)tabs.size()) {
|
||||
return NULL;
|
||||
}
|
||||
return tabs[currentTab].pageHandle;
|
||||
}
|
||||
void SetShowTabTitles(bool enabled);
|
||||
void SetIgnoreBottomMargin(bool enabled) { ignoreBottomMargin = enabled; };
|
||||
bool GetShowTabTitles() { return showTabTitles; };
|
||||
void SetIgnoreBottomMargin(bool enabled) { ignoreBottomMargin = enabled; }
|
||||
bool GetShowTabTitles() { return showTabTitles; }
|
||||
void SetMinTabWidth(int w);
|
||||
|
||||
private:
|
||||
|
@ -45,3 +45,4 @@ Name=Spline36 Upscaler
|
||||
Fragment=upscale_spline36.fsh
|
||||
Vertex=upscale_spline36.vsh
|
||||
OutputResolution=True
|
||||
RequiresIntSupport=True
|
2
ffmpeg
2
ffmpeg
@ -1 +1 @@
|
||||
Subproject commit 338c515b93735f48c7696259cc7fb3bb04403571
|
||||
Subproject commit 657ba596a6f0592ace6164445d163d7f67e5df25
|
@ -326,6 +326,10 @@ int main(int argc, const char* argv[])
|
||||
g_Config.iInternalResolution = 1;
|
||||
g_Config.bFrameSkipUnthrottle = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
InitSysDirectories();
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID)
|
||||
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__)
|
||||
#elif !defined(_WIN32)
|
||||
|
@ -100,7 +100,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avdevice.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;xinput.lib;d3d9.lib;d3dx9d.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;xinput.lib;d3d9.lib;d3dx9d.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
@ -123,7 +123,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avdevice.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9d.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9d.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
@ -150,7 +150,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avdevice.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
@ -178,7 +178,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avdevice.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
|
2
native
2
native
@ -1 +1 @@
|
||||
Subproject commit 4c8157694a60e4922818431d73da9a3f983b343e
|
||||
Subproject commit 55810809b0a0d4153bdeafd41c737ca48f2f6926
|
@ -1 +1 @@
|
||||
Subproject commit 268575b6331558e0a2f09a5c640cbb10777b5ec9
|
||||
Subproject commit bf68a5fefcd951b5c62d69f41474650586bafcf9
|
15
test.py
15
test.py
@ -178,6 +178,7 @@ tests_good = [
|
||||
"threads/threads/release",
|
||||
"threads/threads/rotate",
|
||||
"threads/threads/stackfree",
|
||||
"threads/threads/start",
|
||||
"threads/threads/suspend",
|
||||
"threads/threads/threadend",
|
||||
"threads/threads/threads",
|
||||
@ -190,6 +191,17 @@ tests_good = [
|
||||
"threads/vpl/refer",
|
||||
"threads/vpl/try",
|
||||
"threads/vpl/vpl",
|
||||
"threads/vtimers/vtimer",
|
||||
"threads/vtimers/cancelhandler",
|
||||
"threads/vtimers/create",
|
||||
"threads/vtimers/delete",
|
||||
"threads/vtimers/getbase",
|
||||
"threads/vtimers/gettime",
|
||||
"threads/vtimers/interrupt",
|
||||
"threads/vtimers/refer",
|
||||
"threads/vtimers/settime",
|
||||
"threads/vtimers/start",
|
||||
"threads/vtimers/stop",
|
||||
"utility/savedata/autosave",
|
||||
"utility/savedata/filelist",
|
||||
"utility/savedata/makedata",
|
||||
@ -218,9 +230,8 @@ tests_next = [
|
||||
"threads/scheduling/dispatch",
|
||||
"threads/scheduling/scheduling",
|
||||
"threads/threads/create",
|
||||
"threads/threads/start",
|
||||
"threads/threads/terminate",
|
||||
"threads/vtimers/vtimer",
|
||||
"threads/vtimers/sethandler",
|
||||
"threads/vpl/create",
|
||||
"utility/savedata/getsize",
|
||||
"utility/savedata/idlist",
|
||||
|
Loading…
x
Reference in New Issue
Block a user