diff --git a/Core/Console.cpp b/Core/Console.cpp index e5b0baa..67d57c5 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -13,9 +13,11 @@ #include "VideoDecoder.h" #include "VideoRenderer.h" #include "DebugHud.h" +#include "FrameLimiter.h" #include "MessageManager.h" #include "../Utilities/Timer.h" #include "../Utilities/VirtualFile.h" +#include "../Utilities/PlatformUtilities.h" void Console::Initialize() { @@ -49,11 +51,24 @@ void Console::Run() } _stopFlag = false; + uint32_t previousFrameCount = 0; + + FrameLimiter frameLimiter(16.63926405550947); + + PlatformUtilities::EnableHighResolutionTimer(); auto lock = _runLock.AcquireSafe(); while(!_stopFlag) { _cpu->Exec(); + + if(previousFrameCount != _ppu->GetFrameCount()) { + frameLimiter.ProcessFrame(); + frameLimiter.WaitForNextFrame(); + previousFrameCount = _ppu->GetFrameCount(); + } } + + PlatformUtilities::RestoreTimerResolution(); } void Console::Stop() diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 8bec523..b6b2c63 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -70,6 +70,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index fdc2901..3878ada 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -170,6 +170,9 @@ SNES\Input + + SNES + diff --git a/Core/FrameLimiter.h b/Core/FrameLimiter.h new file mode 100644 index 0000000..0d0bcc9 --- /dev/null +++ b/Core/FrameLimiter.h @@ -0,0 +1,45 @@ +#pragma once +#include "../Utilities/Timer.h" + +class FrameLimiter +{ +private: + Timer _clockTimer; + double _targetTime; + double _delay; + bool _resetRunTimers; + +public: + FrameLimiter(double delay) + { + _delay = delay; + _targetTime = _delay; + } + + void SetDelay(double delay) + { + _delay = delay; + _resetRunTimers = true; + } + + void ProcessFrame() + { + if(_resetRunTimers || (_clockTimer.GetElapsedMS() - _targetTime) > 300) { + //Reset the timers, this can happen in 3 scenarios: + //1) Target frame rate changed + //2) The console was reset/power cycled or the emulation was paused (with or without the debugger) + //3) As a satefy net, if we overshoot our target by over 300 milliseconds, the timer is reset, too. + // This can happen when something slows the emulator down severely (or when breaking execution in VS when debugging Mesen itself, etc.) + _clockTimer.Reset(); + _targetTime = 0; + _resetRunTimers = false; + } + + _targetTime += _delay; + } + + void WaitForNextFrame() + { + _clockTimer.WaitUntil(_targetTime); + } +}; \ No newline at end of file