From 7edebd1c2fcbd963e097843a76aff27e3c486b42 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Oct 2013 23:34:02 -0700 Subject: [PATCH 01/56] Put vtimer args on the stack, skip allocation. This is roughly where they are on the PSP based on tests, and it avoids having to manage memory or etc. --- Core/HLE/sceKernelVTimer.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 9438372270..6b5c557e31 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -46,16 +46,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() { @@ -110,6 +112,8 @@ void __rescheduleVTimer(SceUID id, int delay) { class VTimerIntrHandler : public IntrHandler { + static const int HANDLER_STACK_SPACE = 48; + public: VTimerIntrHandler() : IntrHandler(PSP_SYSTIMER1_INTR) {} @@ -122,18 +126,17 @@ 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; return true; @@ -142,6 +145,8 @@ public: virtual void handleResult(PendingInterrupt &pend) { int result = currentMIPS->r[MIPS_REG_V0]; + currentMIPS->r[MIPS_REG_SP] += HANDLER_STACK_SPACE; + int vtimerID = vtimers.front(); vtimers.pop_front(); @@ -193,7 +198,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); @@ -222,9 +226,6 @@ u32 sceKernelDeleteVTimer(u32 uid) { } } - if (vt->memoryPtr != 0) - kernelMemory.Free(vt->memoryPtr); - return kernelObjects.Destroy(uid); } From c9755d7886e17fb0f57cb2dfadb457ef13cd2469 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 17 Oct 2013 00:36:17 -0700 Subject: [PATCH 02/56] Correct errors from sceKernelCancelVTimerHandler(). --- Core/HLE/sceKernelVTimer.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 6b5c557e31..d0e66c3bc6 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -75,17 +75,20 @@ u64 __getVTimerCurrentTime(VTimer* vt) { return vt->nvt.current + __getVTimerRunningTime(vt); } -void __cancelVTimer(SceUID id) { +int __KernelCancelVTimer(SceUID id) { u32 error; VTimer *vt = kernelObjects.Get(id, error); - if (error) - return; + // TODO: 0 returns a different error code, except inside the handler? + // Also, inside the handler returns that same different error code for the timer? + 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) { @@ -151,7 +154,7 @@ public: vtimers.pop_front(); if (result == 0) - __cancelVTimer(vtimerID); + __KernelCancelVTimer(vtimerID); else __rescheduleVTimer(vtimerID, result); } @@ -440,9 +443,7 @@ u32 sceKernelCancelVTimerHandler(u32 uid) { 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) { From 29d7d00b08d0febc53518e641565bef4e6c6c8ff Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 17 Oct 2013 00:36:31 -0700 Subject: [PATCH 03/56] sceKernelCancelVTimerHandler() resets handler only. --- Core/HLE/sceKernelVTimer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index d0e66c3bc6..c02bdf034e 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -85,9 +85,7 @@ int __KernelCancelVTimer(SceUID id) { return error; CoreTiming::UnscheduleEvent(vtimerTimer, id); - vt->nvt.schedule = 0; vt->nvt.handlerAddr = 0; - vt->nvt.commonAddr = 0; return 0; } From 67cd13702e7d2844d13b1a3750022cdb031c51f9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 19 Oct 2013 00:54:59 -0700 Subject: [PATCH 04/56] Correct sceKernelSetVTimerTime*(). --- Core/HLE/FunctionWrappers.h | 8 ++++++++ Core/HLE/sceKernel.cpp | 2 +- Core/HLE/sceKernelVTimer.cpp | 17 ++++++----------- Core/HLE/sceKernelVTimer.h | 2 +- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index b3f362d5ed..f2db68e5d0 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -34,6 +34,14 @@ template void WrapU64_U() { currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF; } +template 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 void WrapI_IU64() { u64 param_one = currentMIPS->r[6]; param_one |= (u64)(currentMIPS->r[7]) << 32; diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index d77bf7aeab..9302746c9e 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -844,7 +844,7 @@ const HLEFunction ThreadManForUser[] = {0xC0B3FFD2,WrapU64_U,"sceKernelGetVTimerTimeWide"}, {0x5F32BEAA,WrapU_UU,"sceKernelReferVTimerStatus"}, {0x542AD630,WrapU_UU,"sceKernelSetVTimerTime"}, - {0xFB6425C3,WrapU_UU64,"sceKernelSetVTimerTimeWide"}, + {0xFB6425C3,WrapU64_UU64,"sceKernelSetVTimerTimeWide"}, {0xd8b299ae,WrapU_UUUU,"sceKernelSetVTimerHandler"}, {0x53B00E9A,WrapU_UU64UU,"sceKernelSetVTimerHandlerWide"}, diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index c02bdf034e..44b0055b4a 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -294,10 +294,9 @@ u64 sceKernelGetVTimerTimeWide(u32 uid) { 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; return current; } @@ -315,27 +314,23 @@ 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) { +u64 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock) { DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu", uid, timeClock); u32 error; VTimer *vt = kernelObjects.Get(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) { diff --git a/Core/HLE/sceKernelVTimer.h b/Core/HLE/sceKernelVTimer.h index 9153af3c06..17597c987e 100644 --- a/Core/HLE/sceKernelVTimer.h +++ b/Core/HLE/sceKernelVTimer.h @@ -30,7 +30,7 @@ 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); +u64 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock); // TODO void _sceKernelReturnFromTimerHandler(); From 167699ac9ee47cf46900eb1af7dcac5771a21e19 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 20 Oct 2013 14:03:16 -0700 Subject: [PATCH 05/56] Correct sceKernelGetVTimer*Wide() error value. --- Core/HLE/sceKernelVTimer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 44b0055b4a..e8862a1815 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -255,7 +255,7 @@ u64 sceKernelGetVTimerBaseWide(u32 uid) { if (error) { WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerBaseWide(%08x)", error, uid); - return error; + return -1; } return vt->nvt.base; @@ -287,7 +287,7 @@ u64 sceKernelGetVTimerTimeWide(u32 uid) { if (error) { WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerTimeWide(%08x)", error, uid); - return error; + return -1; } u64 time = __getVTimerCurrentTime(vt); From 9bd988e3768fa30cad3fba261f926612cce24dfc Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 20 Oct 2013 14:49:07 -0700 Subject: [PATCH 06/56] Fix doubling of current on vtimer stop. --- Core/HLE/sceKernelVTimer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index e8862a1815..8dd5661af8 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -359,7 +359,8 @@ 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; } From ea507388eaf1ea24f82941c82b2cdcf28c01a868 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 20 Oct 2013 15:25:32 -0700 Subject: [PATCH 07/56] Return a special error for the running vtimer. Also, ues 0 when none is running. This explains the different error code. --- Core/HLE/sceKernelVTimer.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 8dd5661af8..bcca504ae2 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -25,6 +25,7 @@ #include "ChunkFile.h" static int vtimerTimer = -1; +static SceUID runningVTimer = 0; static std::list vtimers; struct NativeVTimer { @@ -140,6 +141,8 @@ public: currentMIPS->r[MIPS_REG_A2] = argArea - 8; currentMIPS->r[MIPS_REG_A3] = vtimer->nvt.commonAddr; + runningVTimer = vtimerID; + return true; } @@ -151,6 +154,8 @@ public: int vtimerID = vtimers.front(); vtimers.pop_front(); + runningVTimer = 0; + if (result == 0) __KernelCancelVTimer(vtimerID); else @@ -170,19 +175,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) { @@ -366,6 +379,10 @@ void __stopVTimer(VTimer *vt) { } u32 sceKernelStopVTimer(u32 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; @@ -383,7 +400,7 @@ u32 sceKernelStopVTimer(u32 uid) { } u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr) { - if (uid == 0) { + if (uid == runningVTimer) { WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x): invalid vtimer", uid, scheduleAddr, handlerFuncAddr, commonAddr); return SCE_KERNEL_ERROR_ILLEGAL_VTID; } @@ -409,7 +426,7 @@ u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u3 } u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr) { - if (uid == 0) { + if (uid == runningVTimer) { WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x): invalid vtimer", uid, schedule, handlerFuncAddr, commonAddr); return SCE_KERNEL_ERROR_ILLEGAL_VTID; } @@ -434,6 +451,11 @@ u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u3 } u32 sceKernelCancelVTimerHandler(u32 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 From 002aed108037c5f8b598277a86fffd6378d379f7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 21 Oct 2013 00:09:11 -0700 Subject: [PATCH 08/56] Update current and limit bytes in vtimer refer. --- Core/HLE/sceKernelVTimer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index bcca504ae2..c1badcda27 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -473,8 +473,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; } From 4a444776abb28d06fd12762797dd6e3211d47e1e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 21 Oct 2013 01:57:00 -0700 Subject: [PATCH 09/56] Sign extend sceKernelUSec2SysClock(). Wow, I guess this has been broken forever. --- Core/HLE/sceKernelTime.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index 28a95502d0..083f2a7769 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -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; } From 856e3b707127bffd1679a8f09ea38dbdd140d0b1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 21 Oct 2013 01:59:14 -0700 Subject: [PATCH 10/56] Fix error code on start vtimer with current. --- Core/HLE/sceKernelVTimer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index c1badcda27..f29b2a2261 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -80,8 +80,6 @@ int __KernelCancelVTimer(SceUID id) { u32 error; VTimer *vt = kernelObjects.Get(id, error); - // TODO: 0 returns a different error code, except inside the handler? - // Also, inside the handler returns that same different error code for the timer? if (!vt) return error; @@ -355,6 +353,11 @@ void __startVTimer(VTimer *vt) { } u32 sceKernelStartVTimer(u32 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; From a47c88d65885bf5f64561bcb7cb331c075ef0e09 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 21 Oct 2013 01:59:38 -0700 Subject: [PATCH 11/56] Run missed handlers when setting vtimer time. --- Core/HLE/sceKernelVTimer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index f29b2a2261..264cdf9287 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -307,7 +307,10 @@ u64 sceKernelGetVTimerTimeWide(u32 uid) { u64 __KernelSetVTimer(VTimer *vt, u64 time) { u64 current = __getVTimerCurrentTime(vt); - vt->nvt.current = time; + vt->nvt.current = time - __getVTimerRunningTime(vt); + + // Run if we're now passed the schedule. + __KernelScheduleVTimer(vt, vt->nvt.schedule); return current; } From b7fd768ecccff962e69ab1c92369eb344d03b98a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 21 Oct 2013 02:00:48 -0700 Subject: [PATCH 12/56] Correct vtimer scheduling. --- Core/HLE/sceKernelVTimer.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 264cdf9287..58135be872 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -93,8 +93,23 @@ 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 goalTicks = usToCycles(vt->nvt.base + schedule - vt->nvt.current); + if (goalTicks < CoreTiming::GetTicks()) + cyclesIntoFuture = usToCycles(200); + else + cyclesIntoFuture = goalTicks - CoreTiming::GetTicks(); + } + + CoreTiming::ScheduleEvent(cyclesIntoFuture, vtimerTimer, vt->GetUID()); + } } void __rescheduleVTimer(SceUID id, int delay) { @@ -104,10 +119,10 @@ void __rescheduleVTimer(SceUID id, int delay) { if (error) return; - if (delay < 0) + if (delay < 100) delay = 100; - __KernelScheduleVTimer(vt, delay); + __KernelScheduleVTimer(vt, vt->nvt.schedule + delay); } class VTimerIntrHandler : public IntrHandler From 0a373b08b7d5c10d02847c4b16eb6469204afb3a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Oct 2013 00:36:51 -0700 Subject: [PATCH 13/56] Return better vtimer errors within interrupts. --- Core/HLE/sceKernel.cpp | 28 ++++++++++++++-------------- Core/HLE/sceKernelVTimer.cpp | 6 +++++- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 9302746c9e..9455d30b63 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -833,20 +833,20 @@ const HLEFunction ThreadManForUser[] = {0xA8AA591F,WrapI_IU, "sceKernelCancelFpl"}, {0xD8199E4C,WrapI_IU, "sceKernelReferFplStatus"}, - {0x20fff560,WrapU_CU,"sceKernelCreateVTimer"}, - {0x328F9E52,WrapU_U,"sceKernelDeleteVTimer"}, - {0xc68d9437,WrapU_U,"sceKernelStartVTimer"}, - {0xD0AEEE87,WrapU_U,"sceKernelStopVTimer"}, - {0xD2D615EF,WrapU_U,"sceKernelCancelVTimerHandler"}, - {0xB3A59970,WrapU_UU,"sceKernelGetVTimerBase"}, - {0xB7C18B77,WrapU64_U,"sceKernelGetVTimerBaseWide"}, - {0x034A921F,WrapU_UU,"sceKernelGetVTimerTime"}, - {0xC0B3FFD2,WrapU64_U,"sceKernelGetVTimerTimeWide"}, - {0x5F32BEAA,WrapU_UU,"sceKernelReferVTimerStatus"}, - {0x542AD630,WrapU_UU,"sceKernelSetVTimerTime"}, - {0xFB6425C3,WrapU64_UU64,"sceKernelSetVTimerTimeWide"}, - {0xd8b299ae,WrapU_UUUU,"sceKernelSetVTimerHandler"}, - {0x53B00E9A,WrapU_UU64UU,"sceKernelSetVTimerHandlerWide"}, + {0x20fff560,WrapU_CU, "sceKernelCreateVTimer", HLE_NOT_IN_INTERRUPT}, + {0x328F9E52,WrapU_U, "sceKernelDeleteVTimer", HLE_NOT_IN_INTERRUPT}, + {0xc68d9437,WrapU_U, "sceKernelStartVTimer"}, + {0xD0AEEE87,WrapU_U, "sceKernelStopVTimer"}, + {0xD2D615EF,WrapU_U, "sceKernelCancelVTimerHandler"}, + {0xB3A59970,WrapU_UU, "sceKernelGetVTimerBase"}, + {0xB7C18B77,WrapU64_U, "sceKernelGetVTimerBaseWide"}, + {0x034A921F,WrapU_UU, "sceKernelGetVTimerTime"}, + {0xC0B3FFD2,WrapU64_U, "sceKernelGetVTimerTimeWide"}, + {0x5F32BEAA,WrapU_UU, "sceKernelReferVTimerStatus"}, + {0x542AD630,WrapU_UU, "sceKernelSetVTimerTime"}, + {0xFB6425C3,WrapU64_UU64, "sceKernelSetVTimerTimeWide"}, + {0xd8b299ae,WrapU_UUUU, "sceKernelSetVTimerHandler"}, + {0x53B00E9A,WrapU_UU64UU, "sceKernelSetVTimerHandlerWide"}, // Names are just guesses, not correct. {0x8daff657,WrapI_CUUUUU, "sceKernelCreateTls"}, diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 58135be872..9704fa00c8 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -349,7 +349,11 @@ u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr) { } u64 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock) { - DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu", uid, 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(uid, error); From 47714d4b8260cc83b8dd9a7ab0fe7761773388d9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Oct 2013 00:47:00 -0700 Subject: [PATCH 14/56] Don't change the vtimer schedule with no handler. --- Core/HLE/sceKernelVTimer.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 9704fa00c8..e509d60337 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -442,10 +442,12 @@ 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; } @@ -467,10 +469,12 @@ 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; } From 580d4436a3fe855fd101c2a52f328aa182580b19 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Oct 2013 02:11:43 -0700 Subject: [PATCH 15/56] Fix vtimer uid param type, add algorithm include. --- Core/HLE/FunctionWrappers.h | 21 +++++++++++++++++++++ Core/HLE/sceDmac.cpp | 1 + Core/HLE/sceKernel.cpp | 26 +++++++++++++------------- Core/HLE/sceKernelVTimer.cpp | 27 ++++++++++++++------------- Core/HLE/sceKernelVTimer.h | 27 +++++++++++++-------------- 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index f2db68e5d0..b80a51b139 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -34,6 +34,12 @@ template void WrapU64_U() { currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF; } +template void WrapU64_I() { + u64 retval = func(PARAM(0)); + currentMIPS->r[2] = retval & 0xFFFFFFFF; + currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF; +} + template void WrapU64_UU64() { u64 param_one = currentMIPS->r[6]; param_one |= (u64)(currentMIPS->r[7]) << 32; @@ -42,6 +48,14 @@ template void WrapU64_UU64() { currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF; } +template 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 void WrapI_IU64() { u64 param_one = currentMIPS->r[6]; param_one |= (u64)(currentMIPS->r[7]) << 32; @@ -84,6 +98,13 @@ template void WrapU_UU64UU() { RETURN(retval); } +template 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 void WrapI_IICU64() { u64 param_three = currentMIPS->r[8]; param_three |= (u64)(currentMIPS->r[9]) << 32; diff --git a/Core/HLE/sceDmac.cpp b/Core/HLE/sceDmac.cpp index 5d9d8d3022..c5e82b72a3 100644 --- a/Core/HLE/sceDmac.cpp +++ b/Core/HLE/sceDmac.cpp @@ -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. diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 9455d30b63..d87480adaa 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -834,19 +834,19 @@ const HLEFunction ThreadManForUser[] = {0xD8199E4C,WrapI_IU, "sceKernelReferFplStatus"}, {0x20fff560,WrapU_CU, "sceKernelCreateVTimer", HLE_NOT_IN_INTERRUPT}, - {0x328F9E52,WrapU_U, "sceKernelDeleteVTimer", HLE_NOT_IN_INTERRUPT}, - {0xc68d9437,WrapU_U, "sceKernelStartVTimer"}, - {0xD0AEEE87,WrapU_U, "sceKernelStopVTimer"}, - {0xD2D615EF,WrapU_U, "sceKernelCancelVTimerHandler"}, - {0xB3A59970,WrapU_UU, "sceKernelGetVTimerBase"}, - {0xB7C18B77,WrapU64_U, "sceKernelGetVTimerBaseWide"}, - {0x034A921F,WrapU_UU, "sceKernelGetVTimerTime"}, - {0xC0B3FFD2,WrapU64_U, "sceKernelGetVTimerTimeWide"}, - {0x5F32BEAA,WrapU_UU, "sceKernelReferVTimerStatus"}, - {0x542AD630,WrapU_UU, "sceKernelSetVTimerTime"}, - {0xFB6425C3,WrapU64_UU64, "sceKernelSetVTimerTimeWide"}, - {0xd8b299ae,WrapU_UUUU, "sceKernelSetVTimerHandler"}, - {0x53B00E9A,WrapU_UU64UU, "sceKernelSetVTimerHandlerWide"}, + {0x328F9E52,WrapU_I, "sceKernelDeleteVTimer", HLE_NOT_IN_INTERRUPT}, + {0xc68d9437,WrapU_I, "sceKernelStartVTimer"}, + {0xD0AEEE87,WrapU_I, "sceKernelStopVTimer"}, + {0xD2D615EF,WrapU_I, "sceKernelCancelVTimerHandler"}, + {0xB3A59970,WrapU_IU, "sceKernelGetVTimerBase"}, + {0xB7C18B77,WrapU64_I, "sceKernelGetVTimerBaseWide"}, + {0x034A921F,WrapU_IU, "sceKernelGetVTimerTime"}, + {0xC0B3FFD2,WrapU64_I, "sceKernelGetVTimerTimeWide"}, + {0x5F32BEAA,WrapU_IU, "sceKernelReferVTimerStatus"}, + {0x542AD630,WrapU_IU, "sceKernelSetVTimerTime"}, + {0xFB6425C3,WrapU64_IU64, "sceKernelSetVTimerTimeWide"}, + {0xd8b299ae,WrapU_IUUU, "sceKernelSetVTimerHandler"}, + {0x53B00E9A,WrapU_IU64UU, "sceKernelSetVTimerHandlerWide"}, // Names are just guesses, not correct. {0x8daff657,WrapI_CUUUUU, "sceKernelCreateTls"}, diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index e509d60337..b200c676b6 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -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 #include "Core/CoreTiming.h" #include "Core/Reporting.h" #include "sceKernel.h" @@ -235,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; @@ -256,7 +257,7 @@ u32 sceKernelDeleteVTimer(u32 uid) { return kernelObjects.Destroy(uid); } -u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr) { +u32 sceKernelGetVTimerBase(SceUID uid, u32 baseClockAddr) { DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerBase(%08x, %08x)", uid, baseClockAddr); u32 error; @@ -273,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; @@ -287,7 +288,7 @@ u64 sceKernelGetVTimerBaseWide(u32 uid) { 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; @@ -305,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; @@ -330,7 +331,7 @@ u64 __KernelSetVTimer(VTimer *vt, u64 time) { return current; } -u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr) { +u32 sceKernelSetVTimerTime(SceUID uid, u32 timeClockAddr) { DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTime(%08x, %08x)", uid, timeClockAddr); u32 error; @@ -348,7 +349,7 @@ u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr) { return 0; } -u64 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock) { +u64 sceKernelSetVTimerTimeWide(SceUID uid, u64 timeClock) { if (__IsInInterrupt()) { WARN_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu): in interrupt", uid, timeClock); return -1; @@ -374,7 +375,7 @@ void __startVTimer(VTimer *vt) { __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; @@ -403,7 +404,7 @@ void __stopVTimer(VTimer *vt) { 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; @@ -424,7 +425,7 @@ u32 sceKernelStopVTimer(u32 uid) { return error; } -u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr) { +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; @@ -452,7 +453,7 @@ u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u3 return 0; } -u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr) { +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; @@ -479,7 +480,7 @@ u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u3 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; @@ -491,7 +492,7 @@ u32 sceKernelCancelVTimerHandler(u32 uid) { 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; diff --git a/Core/HLE/sceKernelVTimer.h b/Core/HLE/sceKernelVTimer.h index 17597c987e..e31ff3f11d 100644 --- a/Core/HLE/sceKernelVTimer.h +++ b/Core/HLE/sceKernelVTimer.h @@ -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); -u64 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(); From 05f2f53358a33e09666317c3aca6f60f792ee794 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Oct 2013 22:50:52 -0700 Subject: [PATCH 16/56] The vtimer return value is treated as u32. --- Core/HLE/sceKernelVTimer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index b200c676b6..aefc83c8a2 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -113,7 +113,7 @@ void __KernelScheduleVTimer(VTimer *vt, u64 schedule) { } } -void __rescheduleVTimer(SceUID id, int delay) { +void __rescheduleVTimer(SceUID id, u32 delay) { u32 error; VTimer *vt = kernelObjects.Get(id, error); @@ -161,7 +161,7 @@ public: } 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; From 2b278d4c13f3222aebf10f93530605bbf4e969cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Oct 2013 17:00:10 +0200 Subject: [PATCH 17/56] Buildfix --- Core/Dialog/SavedataParam.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index 9763605fa6..e45c66fa6e 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -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) From a588b463218efc4c2f75b2189299aa2f836960e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Oct 2013 17:23:05 +0200 Subject: [PATCH 18/56] Clear the JIT cache correctly when exiting the cheat dialog. --- UI/CwCheatScreen.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index ea821d0c34..563dcc8413 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -103,8 +103,7 @@ 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; } From 0a086915f5592c3effca8ab117816a4231bf804d Mon Sep 17 00:00:00 2001 From: adrian17 Date: Wed, 23 Oct 2013 19:05:08 +0200 Subject: [PATCH 19/56] We don't need to reset the counter as it's already done in Reset() --- Core/System.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/System.cpp b/Core/System.cpp index 79d7fc42c2..1adf7089ec 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -171,7 +171,6 @@ void CPU_Init() { Memory::Init(); mipsr4k.Reset(); - mipsr4k.pc = 0; host->AttemptLoadSymbolMap(); From 3a787f46a588e52499fa0bd2ed5c6ffac5f5e30a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 23 Oct 2013 22:58:21 +0200 Subject: [PATCH 20/56] Hide shaders we can't run on GLES2 --- GPU/Common/PostShader.cpp | 8 ++++++++ assets/shaders/defaultshaders.ini | 1 + 2 files changed, 9 insertions(+) diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index dc4ef9264f..2f959b4908 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -83,6 +83,14 @@ void LoadPostShaderInfo(std::vector 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); } diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index 68a3f2c941..1b518b2a8b 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -45,3 +45,4 @@ Name=Spline36 Upscaler Fragment=upscale_spline36.fsh Vertex=upscale_spline36.vsh OutputResolution=True +RequiresIntSupport=True \ No newline at end of file From a790c0a723c300504ccebbb754e11fbd8ac20d3a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 23 Oct 2013 22:59:42 +0200 Subject: [PATCH 21/56] SasAudio: Add some comments about reverb, and add the reverb type list --- Core/HLE/sceSas.cpp | 5 ++--- Core/HW/SasAudio.cpp | 22 +++++++++++++++------- Core/HW/SasAudio.h | 19 +++++++++++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 96193da23b..f1bb204a85 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -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; diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 1cd9c77b77..75318a0f07 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -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; } @@ -340,6 +340,7 @@ static inline s16 clamp_s16(int i) { 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) @@ -434,7 +435,7 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) { // 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; @@ -448,6 +449,7 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) { 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; @@ -461,11 +463,11 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) { } } - //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 +502,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) diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index 0463bc3abf..fcd220ff3e 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -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 @@ -225,6 +236,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; @@ -259,6 +275,9 @@ public: void Mix(u32 outAddr, u32 inAddr = 0, int leftVol = 0, int rightVol = 0); + // Applies reverb to send buffer, according to waveformEffect. + void ApplyReverb(); + void DoState(PointerWrap &p); SasVoice voices[PSP_SAS_VOICES_MAX]; From f0e47838c6722978025d53210e533c8ff5dfedd0 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 24 Oct 2013 01:19:08 +0200 Subject: [PATCH 22/56] Just break out some functions in SasAudio --- Core/HW/SasAudio.cpp | 242 +++++++++++++++++++++++-------------------- Core/HW/SasAudio.h | 3 + 2 files changed, 130 insertions(+), 115 deletions(-) diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 75318a0f07..902e8c06da 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -338,6 +338,132 @@ 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; @@ -346,121 +472,7 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) { 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); } // Okay, apply effects processing to the Send buffer. diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index fcd220ff3e..d4ff3af1c8 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -215,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. @@ -274,6 +276,7 @@ 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(); From 36d433cfc302cbe6ea6b03ef09bb338e14c8c67e Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 24 Oct 2013 01:19:21 +0200 Subject: [PATCH 23/56] Update native with horrifying workaround to let us get a back buffer with destination alpha on all gpus I hope... --- native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native b/native index 4c8157694a..26946b52e7 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 4c8157694a60e4922818431d73da9a3f983b343e +Subproject commit 26946b52e774b0853c10074ed078abf4b11cab36 From e16d1a926b5a1321e99c3f55f37ef9078f9667a9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 00:59:48 -0700 Subject: [PATCH 24/56] Keep more careful track of microsecond time. --- Core/CoreTiming.cpp | 26 +++++++++++++++++++++++++- Core/CoreTiming.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index 6ab5cf2e55..b9867e9908 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -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 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 diff --git a/Core/CoreTiming.h b/Core/CoreTiming.h index 1b72f03eb7..8c53987e3a 100644 --- a/Core/CoreTiming.h +++ b/Core/CoreTiming.h @@ -79,6 +79,7 @@ namespace CoreTiming u64 GetTicks(); u64 GetIdleTicks(); + u64 GetGlobalTimeUs(); // Returns the event_type identifier. int RegisterEvent(const char *name, TimedCallback callback); From 9c874c754e2053cb07dd74f72871e0a00c3208a3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 01:10:09 -0700 Subject: [PATCH 25/56] Use the us based time for rtc/etc. Instead of incorrect conversions from ticks based on current mhz. --- Core/HLE/sceCtrl.cpp | 2 +- Core/HLE/sceKernelAlarm.cpp | 2 +- Core/HLE/sceKernelTime.cpp | 10 +++++----- Core/HLE/sceRtc.cpp | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index cde6f42f7d..27bcfda8ff 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -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)); diff --git a/Core/HLE/sceKernelAlarm.cpp b/Core/HLE/sceKernelAlarm.cpp index 7c0ede0280..02c2b5ff86 100644 --- a/Core/HLE/sceKernelAlarm.cpp +++ b/Core/HLE/sceKernelAlarm.cpp @@ -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()); } diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index 083f2a7769..c57c3c3394 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -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"); @@ -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. diff --git a/Core/HLE/sceRtc.cpp b/Core/HLE/sceRtc.cpp index 940b45aad5..b6013d3eaf 100644 --- a/Core/HLE/sceRtc.cpp +++ b/Core/HLE/sceRtc.cpp @@ -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) @@ -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; From 4803dfdce1fe555c4ee7948af42f5b4014e84b57 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 01:10:46 -0700 Subject: [PATCH 26/56] Use CoreTiming::GetGlobalTimeUs() for vtimers. --- Core/HLE/sceKernelVTimer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index aefc83c8a2..b7db9152f1 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -70,7 +70,7 @@ 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) { @@ -102,11 +102,11 @@ void __KernelScheduleVTimer(VTimer *vt, u64 schedule) { if (schedule < __getVTimerCurrentTime(vt)) cyclesIntoFuture = usToCycles(200); else { - u64 goalTicks = usToCycles(vt->nvt.base + schedule - vt->nvt.current); - if (goalTicks < CoreTiming::GetTicks()) + u64 goalUs = vt->nvt.base + schedule - vt->nvt.current; + if (goalUs < CoreTiming::GetGlobalTimeUs()) cyclesIntoFuture = usToCycles(200); else - cyclesIntoFuture = goalTicks - CoreTiming::GetTicks(); + cyclesIntoFuture = usToCycles(goalUs - CoreTiming::GetGlobalTimeUs()); } CoreTiming::ScheduleEvent(cyclesIntoFuture, vtimerTimer, vt->GetUID()); @@ -369,7 +369,7 @@ u64 sceKernelSetVTimerTimeWide(SceUID uid, u64 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); From 6c5a2ea91af84e5b6d54fcb46a7e83962b274e29 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 24 Oct 2013 12:45:08 +0200 Subject: [PATCH 27/56] Windows: Try to autodetect and adjust for QWERTZ and AZERTY keyboard layouts. Might not have all the layout codes necessary yet. --- Common/KeyMap.cpp | 95 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 4 deletions(-) diff --git a/Common/KeyMap.cpp b/Common/KeyMap.cpp index 7c0772dc46..3583d17d87 100644 --- a/Common/KeyMap.cpp +++ b/Common/KeyMap.cpp @@ -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 +#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 - 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); From e8091dce44bf1487430d1a57990aff64cc22c2f5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 08:23:33 -0700 Subject: [PATCH 28/56] Speed up FPURegCache::Start() on x86. This cuts that func by 97% when running the automated tests, and it was 8% of the total time. Won't really affect games. --- Core/MIPS/x86/RegCacheFPU.cpp | 22 ++++++++++++++++------ Core/MIPS/x86/RegCacheFPU.h | 5 +++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Core/MIPS/x86/RegCacheFPU.cpp b/Core/MIPS/x86/RegCacheFPU.cpp index b8767479d7..35f0d8d6f5 100644 --- a/Core/MIPS/x86/RegCacheFPU.cpp +++ b/Core/MIPS/x86/RegCacheFPU.cpp @@ -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) { diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h index 5f7340f25d..90ebdaa0d9 100644 --- a/Core/MIPS/x86/RegCacheFPU.h +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -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]; From 9eda1fc578f84d99c17747a98ff0b7d84d3b0559 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 19:07:24 -0700 Subject: [PATCH 29/56] Remove code to use last mp3 handle on error. It was copied from mpeg, where it was added for safety, and it shouldn't be hit anyway. --- Core/HLE/sceMp3.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 87eba22da1..22463ca6bb 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -99,14 +99,8 @@ struct Mp3Context { }; static std::map 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]; From 453628946f921d0997a34b0dd750006fe3c6c1e2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 19:12:44 -0700 Subject: [PATCH 30/56] Free mp3 contexts more carefully. --- Core/HLE/sceMp3.cpp | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 22463ca6bb..412c38d659 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -41,10 +41,33 @@ extern "C" { static const int MP3_BITRATES[] = {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}; struct Mp3Context { + Mp3Context() + : +#ifdef USE_FFMPEG + avformat_context(NULL), avio_context(NULL), resampler_context(NULL), +#endif + mediaengine(NULL) { + } + + ~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, 2); + if (!s) + return; p.Do(mp3StreamStart); p.Do(mp3StreamEnd); @@ -294,11 +317,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; } @@ -543,10 +561,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; From 100c188df69306c64cfb6e8e27078d63ebc5926a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 20:00:38 -0700 Subject: [PATCH 31/56] Fix savestate backwards compat. Broken since 80702109f53968b45d947bdd4495585b68e54220. --- Core/HLE/sceDisplay.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 6a5f9720be..8d0b52415d 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -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); From 0b64c5e01490f499898763ceb7938b6a1889e32d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 20:07:07 -0700 Subject: [PATCH 32/56] Savestate and shutdown sceMp3 properly. It wasn't even being saved before. --- Core/HLE/sceKernel.cpp | 3 ++ Core/HLE/sceMp3.cpp | 105 ++++++++++++++++++++++++++--------------- Core/HLE/sceMp3.h | 7 ++- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index d87480adaa..e242f3e72d 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -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); diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 412c38d659..5c9e6ab696 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -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,13 +39,16 @@ 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), + : avformat_context(NULL), avio_context(NULL), resampler_context(NULL) { +#else + { #endif - mediaengine(NULL) { } ~Mp3Context() { @@ -65,7 +67,7 @@ struct Mp3Context { } void DoState(PointerWrap &p) { - auto s = p.Section("Mp3Context", 1, 2); + auto s = p.Section("Mp3Context", 1); if (!s) return; @@ -75,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; @@ -106,7 +110,6 @@ struct Mp3Context { int mp3LoopNum; int mp3MaxSamples; int mp3SumDecodedSamples; - MediaEngine *mediaengine; int mp3Channels; int mp3Bitrate; @@ -129,6 +132,21 @@ Mp3Context *getMp3Ctx(u32 mp3) { 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); @@ -253,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(opaque); int res = 0; @@ -333,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(av_malloc(ctx->mp3BufSize)); + u8 *avio_buffer = static_cast(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; @@ -396,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; @@ -412,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 diff --git a/Core/HLE/sceMp3.h b/Core/HLE/sceMp3.h index f855286ecd..f4ca0b0b5e 100644 --- a/Core/HLE/sceMp3.h +++ b/Core/HLE/sceMp3.h @@ -19,4 +19,9 @@ #include "HLE.h" -void Register_sceMp3(); \ No newline at end of file +class PointerWrap; + +void Register_sceMp3(); + +void __Mp3Shutdown(); +void __Mp3DoState(PointerWrap &p); \ No newline at end of file From 04f1df4415769129b4c0cc6a6fec49309bf0e80f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 21:29:48 -0700 Subject: [PATCH 33/56] Set directories in headless on Windows. Caused some tests to fail. --- headless/Headless.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/headless/Headless.cpp b/headless/Headless.cpp index f5223b0fd7..11d547d0fb 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -326,6 +326,7 @@ int main(int argc, const char* argv[]) g_Config.iInternalResolution = 1; g_Config.bFrameSkipUnthrottle = false; + InitSysDirectories(); #if defined(ANDROID) #elif defined(BLACKBERRY) || defined(__SYMBIAN32__) #elif !defined(_WIN32) From 37c370cec58a6ffca622711996140799379c9a69 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 21:39:52 -0700 Subject: [PATCH 34/56] Update tests. --- pspautotests | 2 +- test.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/pspautotests b/pspautotests index 268575b633..bf68a5fefc 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 268575b6331558e0a2f09a5c640cbb10777b5ec9 +Subproject commit bf68a5fefcd951b5c62d69f41474650586bafcf9 diff --git a/test.py b/test.py index 2003c2a0bf..9ef9c7fd41 100755 --- a/test.py +++ b/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", From ac027fac818394066ac579055a9d7b557cb3aa42 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 21:59:44 -0700 Subject: [PATCH 35/56] Fix missing uniform for GE_TEXMAP_TEXTURE_MATRIX. --- GPU/GLES/VertexShaderGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GLES/VertexShaderGenerator.cpp b/GPU/GLES/VertexShaderGenerator.cpp index e9b4bbfb12..50e95030f4 100644 --- a/GPU/GLES/VertexShaderGenerator.cpp +++ b/GPU/GLES/VertexShaderGenerator.cpp @@ -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++) { From deaaa997636f4878fb2d59a8fff44fbffb391729 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Oct 2013 22:03:10 -0700 Subject: [PATCH 36/56] Exclude 0xFF from logging, happens a lot. --- GPU/GLES/GLES_GPU.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index c26484475c..03d12a2ca8 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -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); From f73aec25707d31be72dc92e79a8fdd24bbbbb461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Oct 2013 11:45:41 +0200 Subject: [PATCH 37/56] Only disable buffered rendering by default on Galaxy Y instead of all Armv6 devices. Would have like to use gpu feature flags but GL isn't necessarily initialized when we load the config. Will need to find a different solution. Also a buildfix for headless non-windows. --- CMakeLists.txt | 2 ++ Core/Config.cpp | 23 +++++++++++------------ headless/Headless.cpp | 3 +++ native | 2 +- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d96a73acb..7ce043f0a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Core/Config.cpp b/Core/Config.cpp index 57f110af6d..d666a32f8b 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -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"); @@ -91,7 +91,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 +119,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 +130,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); diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 11d547d0fb..ab15b27a40 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -326,7 +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) diff --git a/native b/native index 26946b52e7..4c676c3904 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 26946b52e774b0853c10074ed078abf4b11cab36 +Subproject commit 4c676c390448de2236c05df7648e9fc175f18896 From b896a29ec03b5e9f995def3c0d29a1169db62705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Oct 2013 12:40:28 +0200 Subject: [PATCH 38/56] New attempt at solving #4272 by not using alpha in the backbuffer. If some effect ends up requiring destination alpha, just use buffered rendering. --- GPU/GLES/StateMapping.cpp | 11 +++++++++++ native | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 957fe2a855..57134d8b5f 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -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) diff --git a/native b/native index 4c676c3904..0c397c3e68 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 4c676c390448de2236c05df7648e9fc175f18896 +Subproject commit 0c397c3e68dfeac2be8adaf205f483bd6c828466 From 4590e4495496636896b154d697c3f63adf1d4275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Oct 2013 13:19:08 +0200 Subject: [PATCH 39/56] add "onFinish" to screens so that ESC (etc) works the same as the back touch button. --- UI/CwCheatScreen.cpp | 12 +++++------ UI/CwCheatScreen.h | 1 + UI/EmuScreen.cpp | 3 +-- UI/GameSettingsScreen.cpp | 33 +++++++++++++---------------- UI/GameSettingsScreen.h | 2 ++ UI/MainScreen.cpp | 8 ------- UI/MainScreen.h | 3 +-- UI/TouchControlLayoutScreen.cpp | 10 +++++++-- UI/TouchControlLayoutScreen.h | 3 ++- UI/TouchControlVisibilityScreen.cpp | 8 ++----- UI/TouchControlVisibilityScreen.h | 4 ++-- native | 2 +- 12 files changed, 40 insertions(+), 49 deletions(-) diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 563dcc8413..b1f8a9a5fb 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -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(this, &CwCheatScreen::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); + leftColumn->Add(new Choice(d->T("Back")))->OnClick.Handle(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]; @@ -105,7 +104,6 @@ UI::EventReturn CwCheatScreen::OnBack(UI::EventParams ¶ms) { if (MIPSComp::jit) { MIPSComp::jit->ClearCache(); } - return UI::EVENT_DONE; } UI::EventReturn CwCheatScreen::OnEnableAll(UI::EventParams ¶ms) { diff --git a/UI/CwCheatScreen.h b/UI/CwCheatScreen.h index 69829b950d..783bbf7549 100644 --- a/UI/CwCheatScreen.h +++ b/UI/CwCheatScreen.h @@ -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(); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index bf4366fc5f..eb77207076 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -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()); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index a15e19caf0..2574f441ed 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -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(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(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(); } diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 4adf49c050..e4981e297c 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -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(); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index a69f93a119..7da60cbdad 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -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) { diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 6e28b3d175..96590a0e0d 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -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_; -}; \ No newline at end of file +}; diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 7707fc58a9..1a0d839986 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -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; diff --git a/UI/TouchControlLayoutScreen.h b/UI/TouchControlLayoutScreen.h index a35623635e..8db09235b7 100644 --- a/UI/TouchControlLayoutScreen.h +++ b/UI/TouchControlLayoutScreen.h @@ -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); diff --git a/UI/TouchControlVisibilityScreen.cpp b/UI/TouchControlVisibilityScreen.cpp index f58e88c4c5..87f1ef098e 100644 --- a/UI/TouchControlVisibilityScreen.cpp +++ b/UI/TouchControlVisibilityScreen.cpp @@ -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(this, &TouchControlVisibilityScreen::OnBack); + topBar->Add(new Choice(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); topBar->Add(new Choice(di->T("Toggle All")))->OnClick.Handle(this, &TouchControlVisibilityScreen::OnToggleAll); vert->Add(topBar); @@ -89,12 +89,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) { diff --git a/UI/TouchControlVisibilityScreen.h b/UI/TouchControlVisibilityScreen.h index 005071dba5..cda68c0929 100644 --- a/UI/TouchControlVisibilityScreen.h +++ b/UI/TouchControlVisibilityScreen.h @@ -21,14 +21,14 @@ #include -class TouchControlVisibilityScreen : public UIScreenWithBackground { +class TouchControlVisibilityScreen : public UIDialogScreenWithBackground { public: TouchControlVisibilityScreen() { } virtual void CreateViews(); + virtual void onFinish(DialogResult result); protected: - virtual UI::EventReturn OnBack(UI::EventParams &e); virtual UI::EventReturn OnToggleAll(UI::EventParams &e); private: diff --git a/native b/native index 0c397c3e68..c53bf92350 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 0c397c3e68dfeac2be8adaf205f483bd6c828466 +Subproject commit c53bf9235088c922b4a99d546323d2af6fff2c27 From fc37c16aa270b07bbe351df87bd97644f03e9abf Mon Sep 17 00:00:00 2001 From: Sacha Date: Fri, 25 Oct 2013 13:32:57 +1000 Subject: [PATCH 40/56] No need to enable FZ every frame. --- Qt/QtHost.cpp | 3 +-- UI/NativeApp.cpp | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Qt/QtHost.cpp b/Qt/QtHost.cpp index bc03fb1ee2..5146ec6584 100644 --- a/Qt/QtHost.cpp +++ b/Qt/QtHost.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); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 222bf51a0d..4ac617d46d 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -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); From 4c523460630c46c1e49c6976e16e2e1cdbd1a394 Mon Sep 17 00:00:00 2001 From: Sacha Date: Fri, 25 Oct 2013 17:42:27 +1000 Subject: [PATCH 41/56] Use Blackberry/UNIX time functions instead of fallbacks. --- Common/Timer.cpp | 5 +++++ Core/HLE/sceRtc.cpp | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Common/Timer.cpp b/Common/Timer.cpp index 3488c98146..e4bb67d075 100644 --- a/Common/Timer.cpp +++ b/Common/Timer.cpp @@ -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)); diff --git a/Core/HLE/sceRtc.cpp b/Core/HLE/sceRtc.cpp index b6013d3eaf..1703248bb2 100644 --- a/Core/HLE/sceRtc.cpp +++ b/Core/HLE/sceRtc.cpp @@ -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 @@ -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; From cc5934a588d4673a13c889cc6d2bad5b538ef32e Mon Sep 17 00:00:00 2001 From: Sacha Date: Fri, 25 Oct 2013 18:33:42 +1000 Subject: [PATCH 42/56] Blackberry threading optimisations. --- Common/Thread.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Common/Thread.cpp b/Common/Thread.cpp index 8439845be4..38073a030d 100644 --- a/Common/Thread.cpp +++ b/Common/Thread.cpp @@ -24,6 +24,10 @@ #include #endif +#ifdef BLACKBERRY +#include +#endif + #ifdef USE_BEGINTHREADEX #include #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); } From 0282b505b0e03955f8501f0af56b3382f5cc9d8a Mon Sep 17 00:00:00 2001 From: Sacha Date: Sat, 26 Oct 2013 01:18:59 +1000 Subject: [PATCH 43/56] Fix CPUDetect for i386 devices. Thanks @Sonic1. Confirmed by ganoo. --- Common/CPUDetect.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Common/CPUDetect.cpp b/Common/CPUDetect.cpp index 40c82e481d..0aec27a983 100644 --- a/Common/CPUDetect.cpp +++ b/Common/CPUDetect.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) From 6a149200b6cfc75202d7b9414e375e93883340fb Mon Sep 17 00:00:00 2001 From: shenweip Date: Sat, 26 Oct 2013 00:44:19 +0800 Subject: [PATCH 44/56] Fallback to default path if current directory doesn't exist. --- Core/Config.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/Config.cpp b/Core/Config.cpp index 57f110af6d..58d7e18436 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -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); From b06fdfeb02fa37776dd1b1bc324e51d70ad68213 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 25 Oct 2013 23:48:54 -0700 Subject: [PATCH 45/56] Fix crash in wine (it not works.) It was sending the notify early, and we didn't have tabs set up yet. Fixes #4173, at least for the current wine-1.6 Ubuntu packages. --- Windows/W32Util/TabControl.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Windows/W32Util/TabControl.h b/Windows/W32Util/TabControl.h index 489bb55ae9..6dfda63f68 100644 --- a/Windows/W32Util/TabControl.h +++ b/Windows/W32Util/TabControl.h @@ -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: From 7aa70b473b6bb290cdf0822a61923f290c5de035 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Oct 2013 00:32:03 -0700 Subject: [PATCH 46/56] Set the viewport properly on video frame draw. Fixes #3771, video frames being drawn at the wrong size at non-1x. --- GPU/GLES/Framebuffer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 63331c17fc..e70a0e813d 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -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); From f9352ad0b824f8f8d3bc967358fc9045c1348344 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Oct 2013 00:36:37 -0700 Subject: [PATCH 47/56] Update fbos even if they're not the display. But only when coming from a video or other safe source, to ensure we don't hurt speed. Although, might be interesting to do it always? With the previous commit, fixes #4273. --- GPU/GLES/Framebuffer.cpp | 4 ++-- GPU/GLES/Framebuffer.h | 2 +- GPU/GLES/GLES_GPU.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index e70a0e813d..80b60f88ad 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -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; diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index bdefcbba20..bf669f2c47 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -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 diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index 03d12a2ca8..e5b53d18d1 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -1536,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) { From 2c56ccef1818ce06ae330b9aafe6519a409047bd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Oct 2013 02:19:02 -0700 Subject: [PATCH 48/56] Make sure frag shader ID matches generated code. Before, we would use an id with alphatest on, but not actually compile in alphatest. Or, we would use a shader with alphatest, when we actually could compile it out. --- GPU/GLES/FragmentShaderGenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index 94d76e8a9d..1e7c83024d 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -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; From 77333b5cb3f244d910a89a66ace59a29690b7a6a Mon Sep 17 00:00:00 2001 From: Sacha Date: Sat, 26 Oct 2013 21:34:46 +1000 Subject: [PATCH 49/56] Update native and ffmpeg. --- ffmpeg | 2 +- native | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ffmpeg b/ffmpeg index 338c515b93..657ba596a6 160000 --- a/ffmpeg +++ b/ffmpeg @@ -1 +1 @@ -Subproject commit 338c515b93735f48c7696259cc7fb3bb04403571 +Subproject commit 657ba596a6f0592ace6164445d163d7f67e5df25 diff --git a/native b/native index c53bf92350..37cd71b2a4 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit c53bf9235088c922b4a99d546323d2af6fff2c27 +Subproject commit 37cd71b2a4da4b7a15cd67d2d012dc12d4ee5f1a From 4972e7b6803f51d7323a6c6b701a2a880f1a5068 Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 27 Oct 2013 03:38:59 +1000 Subject: [PATCH 50/56] EnqueueList: Relocate code that depends on compatibility check to simplify the code --- GPU/GPUCommon.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 016f26214a..57915863cd 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -206,26 +206,25 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer 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]; From 3ca86d86f9339b9458d8edaa22173214fa7d96ce Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 27 Oct 2013 03:49:12 +1000 Subject: [PATCH 51/56] Symbian: add support for media keys such as volume up and volume down. Mappable in settings. --- Qt/PPSSPP.pro | 6 +++++- native | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Qt/PPSSPP.pro b/Qt/PPSSPP.pro index 35a14c3f1a..00839a8f01 100755 --- a/Qt/PPSSPP.pro +++ b/Qt/PPSSPP.pro @@ -53,13 +53,17 @@ linux { } } qnx: LIBS += -lscreen -symbian: LIBS += -llibglib -lhwrmvibraclient +symbian: LIBS += -llibglib -lhwrmvibraclient -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 \ diff --git a/native b/native index 37cd71b2a4..70968b4a82 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 37cd71b2a4da4b7a15cd67d2d012dc12d4ee5f1a +Subproject commit 70968b4a8209fa86c139b9cd91d73a3275c09f91 From a605c0a8e86d4608cdb2e45515a1c57006fad429 Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 27 Oct 2013 05:34:23 +1000 Subject: [PATCH 52/56] Switch to Qt vibrator instead of Symbian C++ one. --- Qt/PPSSPP.pro | 4 ++-- native | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Qt/PPSSPP.pro b/Qt/PPSSPP.pro index 00839a8f01..96a3918dfd 100755 --- a/Qt/PPSSPP.pro +++ b/Qt/PPSSPP.pro @@ -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,7 +53,7 @@ linux { } } qnx: LIBS += -lscreen -symbian: LIBS += -llibglib -lhwrmvibraclient -lRemConCoreApi -lRemConInterfaceBase +symbian: LIBS += -llibglib -lRemConCoreApi -lRemConInterfaceBase # Avoids problems with some compilers unix:!symbian: LIBS += -lz diff --git a/native b/native index 70968b4a82..7d8beb9449 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 70968b4a8209fa86c139b9cd91d73a3275c09f91 +Subproject commit 7d8beb94490c61c295866dd0324941be34d59357 From 1f1c8e4a4801b1488ab796c43d1107e892fe0c83 Mon Sep 17 00:00:00 2001 From: The Dax Date: Sat, 26 Oct 2013 15:54:17 -0400 Subject: [PATCH 53/56] Remove avdevice.lib linker dependency/input for Headless and PPSSPP. --- Windows/PPSSPP.vcxproj | 8 ++++---- headless/Headless.vcxproj | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 1fc1dd7fd6..428fdedfc1 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -127,7 +127,7 @@ false - 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) + 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;%(AdditionalDependencies) true Windows MachineX86 @@ -160,7 +160,7 @@ false - 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) + 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) true $(OutDir)$(ProjectName).pdb Windows @@ -194,7 +194,7 @@ false - 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) + 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) $(OutDir)$(TargetName)$(TargetExt) %(AdditionalLibraryDirectories) true @@ -235,7 +235,7 @@ false - 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) + 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) %(AdditionalLibraryDirectories) true Windows diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index b0127fc1b8..a198857a0f 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -100,7 +100,7 @@ Console true - 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) + 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) 0x00400000 false true @@ -123,7 +123,7 @@ Console true - 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) + 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) 0x00400000 false true @@ -150,7 +150,7 @@ true true true - 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) + 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) 0x00400000 false true @@ -178,7 +178,7 @@ true true true - 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) + 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) 0x00400000 false true From 105894fdc08753e751b318d73312b7974c030697 Mon Sep 17 00:00:00 2001 From: The Dax Date: Sat, 26 Oct 2013 16:10:58 -0400 Subject: [PATCH 54/56] Remove useless ffmpeg Librarian dependencies from Core. --- Core/Core.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 3ee7695ff4..2d8cdc7d58 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -130,7 +130,7 @@ Updating git-version.cpp - ..\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) @@ -587,4 +587,4 @@ - + \ No newline at end of file From 3a1a72c846047cb083f27437d809c90f76ab5c77 Mon Sep 17 00:00:00 2001 From: The Dax Date: Sat, 26 Oct 2013 16:30:49 -0400 Subject: [PATCH 55/56] Remove stray xinput.lib dependency. --- Windows/PPSSPP.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 428fdedfc1..7a80b84279 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -127,7 +127,7 @@ false - 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;%(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) true Windows MachineX86 From c5532be6af8888299db87697098efeca51dab920 Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 27 Oct 2013 11:12:54 +1000 Subject: [PATCH 56/56] Update readme. --- README.md | 2 ++ native | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7353d6900c..f5fbee62db 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/native b/native index 7d8beb9449..55810809b0 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 7d8beb94490c61c295866dd0324941be34d59357 +Subproject commit 55810809b0a0d4153bdeafd41c737ca48f2f6926