Throttle by coretiming event instead of VI

VI isn't called as regular as we want to, so we have to create a new throttling event called regularly by coretiming.

Atm we throttle every 1 ms when we are too fast and skip throttling when we lack 40ms (to avoid fast boosts after slowdowns)
This commit is contained in:
degasus 2014-02-06 18:17:03 +01:00
parent fa038af0c1
commit f7dc918057
2 changed files with 27 additions and 24 deletions

View file

@ -613,30 +613,6 @@ bool PauseAndLock(bool doLock, bool unpauseOnUnlock)
// This should only be called from VI
void VideoThrottle()
{
u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 2) ?
(SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate;
if (Host_GetKeyState('\t'))
isTabPressed = true;
else
isTabPressed = false;
// Disable the frame-limiter when the throttle (Tab) key is held down. Audio throttle: m_Framelimit = 2
if (SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t'))
{
u32 frametime = ((SConfig::GetInstance().b_UseFPS)? Common::AtomicLoad(DrawnFrame) : DrawnVideo) * 1000 / TargetVPS;
u32 timeDifference = (u32)Timer.GetTimeDifference();
if (timeDifference < frametime)
{
Common::SleepCurrentThread(frametime - timeDifference - 1);
}
while ((u32)Timer.GetTimeDifference() < frametime)
Common::YieldCPU();
//Common::SleepCurrentThread(1);
}
// Update info per second
u32 ElapseTime = (u32)Timer.GetTimeDifference();
if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo)

View file

@ -75,6 +75,7 @@ IPC_HLE_PERIOD: For the Wiimote this is the call schedule:
#include "Timer.h"
#include "VideoBackendBase.h"
#include "CommandProcessor.h"
#include "Host.h"
namespace SystemTimers
@ -115,6 +116,7 @@ int et_AudioDMA;
int et_DSP;
int et_IPC_HLE;
int et_PatchEngine; // PatchEngine updates every 1/60th of a second by default
int et_Throttle;
// These are badly educated guesses
// Feel free to experiment. Set these in Init below.
@ -229,6 +231,29 @@ void PatchEngineCallback(u64 userdata, int cyclesLate)
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame() - cyclesLate, et_PatchEngine);
}
void ThrottleCallback(u64 last_time, int cyclesLate)
{
u32 time = Common::Timer::GetTimeMs();
int diff = (u32)last_time - time;
bool frame_limiter = SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t');
u32 next_event = GetTicksPerSecond()/1000;
if (SConfig::GetInstance().m_Framelimit > 2)
{
next_event = next_event * (SConfig::GetInstance().m_Framelimit - 1) * 5 / VideoInterface::TargetRefreshRate;
}
const int max_fallback = 40; // 40 ms for one frame on 25 fps games
if (frame_limiter && abs(diff) > max_fallback)
{
WARN_LOG(COMMON, "system too %s, %d ms skipped", diff<0 ? "slow" : "fast", abs(diff) - max_fallback);
last_time = time - max_fallback;
}
else if (frame_limiter && diff > 0)
Common::SleepCurrentThread(diff);
CoreTiming::ScheduleEvent(next_event - cyclesLate, et_Throttle, last_time + 1);
}
// split from Init to break a circular dependency between VideoInterface::Init and SystemTimers::Init
void PreInit()
{
@ -274,11 +299,13 @@ void Init()
et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback);
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback);
et_Throttle = CoreTiming::RegisterEvent("Throttle", ThrottleCallback);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine(), et_VI);
CoreTiming::ScheduleEvent(0, et_DSP);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI);
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD, et_AudioDMA);
CoreTiming::ScheduleEvent(0, et_Throttle, Common::Timer::GetTimeMs());
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU)
CoreTiming::ScheduleEvent(CP_PERIOD, et_CP);