Add an experimental sync to keep real time sync.

May help input, audio, and network related lag problems.
This commit is contained in:
Unknown W. Brackets 2014-06-01 00:52:10 -07:00
parent 84ff3d6767
commit 29f2519861
3 changed files with 85 additions and 1 deletions

View file

@ -265,6 +265,7 @@ static ConfigSetting generalSettings[] = {
ConfigSetting("HomebrewStore", &g_Config.bHomebrewStore, false, false),
ConfigSetting("CheckForNewVersion", &g_Config.bCheckForNewVersion, true),
ConfigSetting("Language", &g_Config.sLanguageIni, &DefaultLangRegion),
ConfigSetting("ForceLagSync", &g_Config.bForceLagSync, false),
ReportedConfigSetting("NumWorkerThreads", &g_Config.iNumWorkerThreads, &DefaultNumWorkers),
ConfigSetting("EnableAutoLoad", &g_Config.bEnableAutoLoad, false),

View file

@ -83,6 +83,7 @@ public:
bool bFastMemory;
bool bJit;
bool bCheckForNewVersion;
bool bForceLagSync;
// Definitely cannot be changed while game is running.
bool bSeparateCPUThread;

View file

@ -20,6 +20,22 @@
#include <cmath>
#include <algorithm>
// TODO: Move this somewhere else, cleanup.
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#else
#define NOMINMAX
#include <winsock2.h>
static inline int usleep(long us) {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = us;
return select(0, NULL, NULL, NULL, &tv);
}
#endif
// TODO: Move the relevant parts into common. Don't want the core
// to be dependent on "native", I think. Or maybe should get rid of common
// and move everything into native...
@ -79,6 +95,10 @@ static bool framebufIsLatched;
static int enterVblankEvent = -1;
static int leaveVblankEvent = -1;
static int afterFlipEvent = -1;
static int lagSyncEvent = -1;
static double lastLagSync = 0.0;
static bool lagSyncScheduled = false;
// hCount is computed now.
static int vCount;
@ -140,12 +160,21 @@ static int lastFlipsTooFrequent = 0;
void hleEnterVblank(u64 userdata, int cyclesLate);
void hleLeaveVblank(u64 userdata, int cyclesLate);
void hleAfterFlip(u64 userdata, int cyclesLate);
void hleLagSync(u64 userdata, int cyclesLate);
void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId);
void __DisplayVblankEndCallback(SceUID threadID, SceUID prevCallbackId);
int __DisplayGetFlipCount() { return actualFlips; }
int __DisplayGetVCount() { return vCount; }
static void ScheduleLagSync() {
lagSyncScheduled = g_Config.bForceLagSync;
if (lagSyncScheduled) {
CoreTiming::ScheduleEvent(msToCycles(1), lagSyncEvent, 0);
lastLagSync = real_time_now();
}
}
void __DisplayInit() {
gpuStats.Reset();
hasSetMode = false;
@ -168,6 +197,9 @@ void __DisplayInit() {
leaveVblankEvent = CoreTiming::RegisterEvent("LeaveVBlank", &hleLeaveVblank);
afterFlipEvent = CoreTiming::RegisterEvent("AfterFlip", &hleAfterFlip);
lagSyncEvent = CoreTiming::RegisterEvent("LagSync", &hleLagSync);
ScheduleLagSync();
CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs), enterVblankEvent, 0);
isVblank = 0;
vCount = 0;
@ -189,7 +221,7 @@ void __DisplayInit() {
}
void __DisplayDoState(PointerWrap &p) {
auto s = p.Section("sceDisplay", 1, 4);
auto s = p.Section("sceDisplay", 1, 5);
if (!s)
return;
@ -226,6 +258,19 @@ void __DisplayDoState(PointerWrap &p) {
p.Do(afterFlipEvent);
CoreTiming::RestoreRegisterEvent(afterFlipEvent, "AfterFlip", &hleAfterFlip);
if (s >= 5) {
p.Do(lagSyncEvent);
p.Do(lagSyncScheduled);
CoreTiming::RestoreRegisterEvent(lagSyncEvent, "LagSync", &hleLagSync);
lastLagSync = real_time_now();
if (lagSyncScheduled != g_Config.bForceLagSync) {
ScheduleLagSync();
}
} else {
lagSyncEvent = CoreTiming::RegisterEvent("LagSync", &hleLagSync);
ScheduleLagSync();
}
p.Do(gstate);
gstate_c.DoState(p);
#ifndef _XBOX
@ -621,6 +666,11 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
void hleAfterFlip(u64 userdata, int cyclesLate)
{
gpu->BeginFrame(); // doesn't really matter if begin or end of frame.
// This seems like as good a time as any to check if the config changed.
if (lagSyncScheduled != g_Config.bForceLagSync) {
ScheduleLagSync();
}
}
void hleLeaveVblank(u64 userdata, int cyclesLate) {
@ -632,6 +682,38 @@ void hleLeaveVblank(u64 userdata, int cyclesLate) {
__DisplayFireVblank();
}
void hleLagSync(u64 userdata, int cyclesLate) {
// The goal here is to prevent network, audio, and input lag from the real world.
// Our normal timing is very "stop and go". This is efficient, but causes real world lag.
// This event (optionally) runs every 1ms to sync with the real world.
if (PSP_CoreParameter().unthrottle) {
lagSyncScheduled = false;
return;
}
float scale = 1.0f;
if (PSP_CoreParameter().fpsLimit == FPS_LIMIT_CUSTOM) {
if (g_Config.iFpsLimit == 0) {
lagSyncScheduled = false;
return;
}
scale = g_Config.iFpsLimit / 60.0f;
}
// TODO: Smarter, adaptive? Account for cyclesLate? Let's just try this for now.
const double goal = lastLagSync + (scale / 1000.0f);
time_update();
while (time_now_d() < goal) {
const double left = goal - time_now_d();
usleep((long)(left * 1000000));
time_update();
}
ScheduleLagSync();
}
u32 sceDisplayIsVblank() {
DEBUG_LOG(SCEDISPLAY,"%i=sceDisplayIsVblank()",isVblank);
return isVblank;