Merge pull request #6220 from unknownbrackets/lagsync

Add option for less timing lag (spin on Windows)
This commit is contained in:
Henrik Rydgård 2014-06-03 10:53:20 +02:00
commit 318f641c63
4 changed files with 79 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,12 @@
#include <cmath>
#include <algorithm>
// TODO: Move this somewhere else, cleanup.
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#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 +85,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 +150,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(int over = 0) {
lagSyncScheduled = g_Config.bForceLagSync;
if (lagSyncScheduled) {
CoreTiming::ScheduleEvent(msToCycles(1), lagSyncEvent, 0);
lastLagSync = real_time_now() - (over / 1000000.0f);
}
}
void __DisplayInit() {
gpuStats.Reset();
hasSetMode = false;
@ -168,6 +187,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 +211,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 +248,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 +656,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 +672,41 @@ 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 = 60.0f / g_Config.iFpsLimit;
}
const double goal = lastLagSync + (scale / 1000.0f);
time_update();
while (time_now_d() < goal) {
const double left = goal - time_now_d();
#ifndef _WIN32
usleep((long)(left * 1000000));
#endif
time_update();
}
const int emuOver = (int)cyclesToUs(cyclesLate);
const int over = (int)((time_now_d() - goal) * 1000000);
ScheduleLagSync(over - emuOver);
}
u32 sceDisplayIsVblank() {
DEBUG_LOG(SCEDISPLAY,"%i=sceDisplayIsVblank()",isVblank);
return isVblank;

View File

@ -304,6 +304,7 @@ void GameSettingsScreen::CreateViews() {
systemSettings->Add(new CheckBox(&g_Config.bSeparateCPUThread, s->T("Multithreaded (experimental)")))->SetEnabled(!PSP_IsInited());
systemSettings->Add(new CheckBox(&g_Config.bSeparateIOThread, s->T("I/O on thread (experimental)")))->SetEnabled(!PSP_IsInited());
systemSettings->Add(new CheckBox(&g_Config.bForceLagSync, s->T("Force real clock sync (slower, less lag)")));
systemSettings->Add(new PopupSliderChoice(&g_Config.iLockedCPUSpeed, 0, 1000, s->T("Change CPU Clock", "Change CPU Clock (0 = default) (unstable)"), screenManager()));
#ifndef MOBILE_DEVICE
systemSettings->Add(new PopupSliderChoice(&g_Config.iRewindFlipFrequency, 0, 1800, s->T("Rewind Snapshot Frequency", "Rewind Snapshot Frequency (0 = off, mem hog)"), screenManager()));