Merge pull request #44 from degasus/throttling

CPU Throttling by CoreTiming
This commit is contained in:
Pierre Bourdon 2014-02-10 16:30:05 +01:00
commit a0a65a2906
7 changed files with 34 additions and 48 deletions

View File

@ -55,7 +55,7 @@ struct ConfigCache
unsigned int framelimit;
TEXIDevices m_EXIDevice[MAX_EXI_CHANNELS];
std::string strBackend, sBackend;
bool bSetFramelimit, bSetEXIDevice[MAX_EXI_CHANNELS], bSetUseFPS, bSetVolume, bSetPads[MAX_SI_CHANNELS], bSetWiimoteSource[MAX_BBMOTES];
bool bSetFramelimit, bSetEXIDevice[MAX_EXI_CHANNELS], bSetVolume, bSetPads[MAX_SI_CHANNELS], bSetWiimoteSource[MAX_BBMOTES];
};
static ConfigCache config_cache;
@ -114,7 +114,6 @@ bool BootCore(const std::string& _rFilename)
config_cache.Volume = SConfig::GetInstance().m_Volume;
config_cache.sBackend = SConfig::GetInstance().sBackend;
config_cache.framelimit = SConfig::GetInstance().m_Framelimit;
config_cache.bUseFPS = SConfig::GetInstance().b_UseFPS;
for (unsigned int i = 0; i < MAX_BBMOTES; ++i)
{
config_cache.iWiimoteSource[i] = g_wiimote_sources[i];
@ -150,8 +149,6 @@ bool BootCore(const std::string& _rFilename)
game_ini.Get("Core", "HLE_BS2", &StartUp.bHLE_BS2, StartUp.bHLE_BS2);
if (game_ini.Get("Core", "FrameLimit", &SConfig::GetInstance().m_Framelimit, SConfig::GetInstance().m_Framelimit))
config_cache.bSetFramelimit = true;
if (game_ini.Get("Core", "UseFPS", &SConfig::GetInstance().b_UseFPS, SConfig::GetInstance().b_UseFPS))
config_cache.bSetUseFPS = true;
if (game_ini.Get("DSP", "Volume", &SConfig::GetInstance().m_Volume, SConfig::GetInstance().m_Volume))
config_cache.bSetVolume = true;
game_ini.Get("DSP", "EnableJIT", &SConfig::GetInstance().m_EnableJIT, SConfig::GetInstance().m_EnableJIT);
@ -269,8 +266,6 @@ void Stop()
// Only change these back if they were actually set by game ini, since they can be changed while a game is running.
if (config_cache.bSetFramelimit)
SConfig::GetInstance().m_Framelimit = config_cache.framelimit;
if (config_cache.bSetUseFPS)
SConfig::GetInstance().b_UseFPS = config_cache.bUseFPS;
if (config_cache.bSetVolume)
SConfig::GetInstance().m_Volume = config_cache.Volume;

View File

@ -256,7 +256,6 @@ void SConfig::SaveSettings()
ini.Set("Core", "RunCompareServer", m_LocalCoreStartupParameter.bRunCompareServer);
ini.Set("Core", "RunCompareClient", m_LocalCoreStartupParameter.bRunCompareClient);
ini.Set("Core", "FrameLimit", m_Framelimit);
ini.Set("Core", "UseFPS", b_UseFPS);
// GFX Backend
ini.Set("Core", "GFXBackend", m_LocalCoreStartupParameter.m_strVideoBackend);
@ -419,7 +418,6 @@ void SConfig::LoadSettings()
ini.Get("Core", "FastDiscSpeed", &m_LocalCoreStartupParameter.bFastDiscSpeed, false);
ini.Get("Core", "DCBZ", &m_LocalCoreStartupParameter.bDCBZOFF, false);
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default
ini.Get("Core", "UseFPS", &b_UseFPS, false); // use vps as default
// GFX Backend
ini.Get("Core", "GFXBackend", &m_LocalCoreStartupParameter.m_strVideoBackend, "");

View File

@ -51,7 +51,6 @@ struct SConfig : NonCopyable
int m_InterfaceLanguage;
// framelimit choose
unsigned int m_Framelimit;
bool b_UseFPS;
// other interface settings
bool m_InterfaceToolbar;
bool m_InterfaceStatusbar;

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)
@ -697,9 +673,9 @@ void UpdateTitle()
if (ElapseTime == 0)
ElapseTime = 1;
u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime;
u32 VPS = DrawnVideo * 1000 / ElapseTime;
u32 Speed = DrawnVideo * (100 * 1000) / (VideoInterface::TargetRefreshRate * ElapseTime);
float FPS = Common::AtomicLoad(DrawnFrame) * 1000.0 / ElapseTime;
float VPS = DrawnVideo * 1000.0 / ElapseTime;
float Speed = DrawnVideo * (100 * 1000.0) / (VideoInterface::TargetRefreshRate * ElapseTime);
// Settings are shown the same for both extended and summary info
std::string SSettings = StringFromFormat("%s %s | %s | %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC",
@ -735,11 +711,11 @@ void UpdateTitle()
#else // Summary information
std::string SFPS;
if (Movie::IsPlayingInput())
SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
else if (Movie::IsRecordingInput())
SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
else
SFPS = StringFromFormat("FPS: %u - VPS: %u - %u%%", FPS, VPS, Speed);
SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed);
#endif
// This is our final "frame counter" string

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);

View File

@ -118,7 +118,6 @@ EVT_CHECKBOX(ID_CPUTHREAD, CConfigMain::CoreSettingsChanged)
EVT_CHECKBOX(ID_IDLESKIP, CConfigMain::CoreSettingsChanged)
EVT_CHECKBOX(ID_ENABLECHEATS, CConfigMain::CoreSettingsChanged)
EVT_CHOICE(ID_FRAMELIMIT, CConfigMain::CoreSettingsChanged)
EVT_CHECKBOX(ID_FRAMELIMIT_USEFPSFORLIMITING, CConfigMain::CoreSettingsChanged)
EVT_RADIOBOX(ID_CPUENGINE, CConfigMain::CoreSettingsChanged)
EVT_CHECKBOX(ID_NTSCJ, CConfigMain::CoreSettingsChanged)
@ -324,7 +323,6 @@ void CConfigMain::InitializeGUIValues()
SkipIdle->SetValue(startup_params.bSkipIdle);
EnableCheats->SetValue(startup_params.bEnableCheats);
Framelimit->SetSelection(SConfig::GetInstance().m_Framelimit);
UseFPSForLimiting->SetValue(SConfig::GetInstance().b_UseFPS);
// General - Advanced
for (unsigned int a = 0; a < (sizeof(CPUCores) / sizeof(CPUCore)); ++a)
@ -549,7 +547,6 @@ void CConfigMain::CreateGUIControls()
EnableCheats = new wxCheckBox(GeneralPage, ID_ENABLECHEATS, _("Enable Cheats"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
// Framelimit
Framelimit = new wxChoice(GeneralPage, ID_FRAMELIMIT, wxDefaultPosition, wxDefaultSize, arrayStringFor_Framelimit, 0, wxDefaultValidator);
UseFPSForLimiting = new wxCheckBox(GeneralPage, ID_FRAMELIMIT_USEFPSFORLIMITING, _("Limit by FPS"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
// Core Settings - Advanced
CPUEngine = new wxRadioBox(GeneralPage, ID_CPUENGINE, _("CPU Emulator Engine"), wxDefaultPosition, wxDefaultSize, arrayStringFor_CPUEngine, 0, wxRA_SPECIFY_ROWS);
_NTSCJ = new wxCheckBox(GeneralPage, ID_NTSCJ, _("Force Console as NTSC-J"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
@ -558,7 +555,6 @@ void CConfigMain::CreateGUIControls()
wxBoxSizer* sFramelimit = new wxBoxSizer(wxHORIZONTAL);
sFramelimit->Add(TEXT_BOX(GeneralPage, _("Framelimit:")), 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, 5);
sFramelimit->Add(Framelimit, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
sFramelimit->Add(UseFPSForLimiting, 0, wxALL | wxEXPAND, 5);
wxStaticBoxSizer* const sbBasic = new wxStaticBoxSizer(wxVERTICAL, GeneralPage, _("Basic Settings"));
sbBasic->Add(CPUThread, 0, wxALL, 5);
sbBasic->Add(SkipIdle, 0, wxALL, 5);
@ -890,9 +886,6 @@ void CConfigMain::CoreSettingsChanged(wxCommandEvent& event)
SConfig::GetInstance().m_Framelimit = Framelimit->GetSelection();
AudioCommon::UpdateSoundStream();
break;
case ID_FRAMELIMIT_USEFPSFORLIMITING:
SConfig::GetInstance().b_UseFPS = UseFPSForLimiting->IsChecked();
break;
// Core - Advanced
case ID_CPUENGINE:
SConfig::GetInstance().m_LocalCoreStartupParameter.iCPUCore = CPUCores[CPUEngine->GetSelection()].CPUid;

View File

@ -53,7 +53,6 @@ private:
ID_IDLESKIP,
ID_ENABLECHEATS,
ID_FRAMELIMIT,
ID_FRAMELIMIT_USEFPSFORLIMITING,
ID_CPUENGINE,
ID_DSPTHREAD,
@ -123,7 +122,6 @@ private:
wxCheckBox* SkipIdle;
wxCheckBox* EnableCheats;
wxChoice* Framelimit;
wxCheckBox* UseFPSForLimiting;
// Advanced
wxRadioBox* CPUEngine;