diff --git a/.vscode/settings.json b/.vscode/settings.json index 0975eeb40..a414c6bf2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -41,6 +41,7 @@ "tuple": "cpp", "type_traits": "cpp", "stdexcept": "cpp", - "fstream": "cpp" + "fstream": "cpp", + "__locale": "cpp" } } diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index ffc714452..7b08d4383 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -987,6 +987,12 @@ void Console::setFramerate(float framerate) // myOSystem.sound().setFrameRate(framerate); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +float Console::getFramerate() const +{ + return myTIA->frameRate(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleTIABit(TIABit bit, const string& bitname, bool show) const { diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 880911e0a..cd6daab86 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -272,7 +272,7 @@ class Console : public Serializable Returns the framerate based on a number of factors (whether 'framerate' is set, what display format is in use, etc) */ - float getFramerate() const { return myFramerate; } + float getFramerate() const; /** Toggles the TIA bit specified in the method name. diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index ab62f93df..1876559a9 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -47,10 +47,7 @@ FrameBuffer::FrameBuffer(OSystem& osystem) myInitializedCount(0), myPausedCount(0), myStatsEnabled(false), - myLastFrameRate(60), - myCurrentModeList(nullptr), - myTotalTime(0), - myTotalFrames(0) + myCurrentModeList(nullptr) { } @@ -290,8 +287,7 @@ Int64 FrameBuffer::update() // Show frame statistics if(myStatsMsg.enabled) drawFrameStats(); - else - myLastFrameRate = myOSystem.console().getFramerate(); + myLastScanlines = myOSystem.console().tia().scanlinesLastFrame(); myPausedCount = 0; break; // EventHandlerState::EMULATION @@ -404,30 +400,7 @@ void FrameBuffer::drawFrameStats() myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); xPos += font().getStringWidth(msg); - // draw framerate - float frameRate; - /*if(myOSystem.settings().getInt("framerate") == 0) - { - // if 'Auto' is selected, draw the calculated framerate - frameRate = myOSystem.console().getFramerate(); - } - else*/ - { - // if 'Auto' is not selected, draw the effective framerate - const TimingInfo& ti = myOSystem.timingInfo(); - if(ti.totalFrames - myTotalFrames >= myLastFrameRate) - { - frameRate = 1000000.0 * (ti.totalFrames - myTotalFrames) / (ti.totalTime - myTotalTime); - if(frameRate > myOSystem.console().getFramerate() + 1) - frameRate = 1; - myTotalFrames = ti.totalFrames; - myTotalTime = ti.totalTime; - } - else - frameRate = myLastFrameRate; - } - myLastFrameRate = frameRate; - std::snprintf(msg, 30, " @ %5.2ffps", frameRate); + std::snprintf(msg, 30, " @ %5.2ffps", myOSystem.console().getFramerate()); myStatsMsg.surface->drawString(font(), msg, xPos, YPOS, myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 7f5a3ce03..a23003fd2 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -517,7 +517,6 @@ class FrameBuffer Message myStatsMsg; bool myStatsEnabled; uInt32 myLastScanlines; - float myLastFrameRate; bool myGrabMouse; @@ -538,9 +537,6 @@ class FrameBuffer // Holds UI palette data (standard and classic colours) static uInt32 ourGUIColors[3][kNumColors-256]; - uInt64 myTotalTime; - uInt64 myTotalFrames; - private: // Following constructors and assignment operators not supported FrameBuffer() = delete; diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 2a5704382..9b9206cff 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -35,6 +35,8 @@ #include "CheatManager.hxx" #endif +#include + #include "FSNode.hxx" #include "MD5.hxx" #include "Cart.hxx" @@ -58,6 +60,8 @@ #include "OSystem.hxx" +using namespace std::chrono; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystem::OSystem() : myLauncherUsed(false), @@ -615,51 +619,35 @@ uInt64 OSystem::getTicks() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::mainLoop() { - if(mySettings->getString("timing") == "sleep") - { - // Sleep-based wait: good for CPU, bad for graphical sync - for(;;) - { - myTimingInfo.start = getTicks(); - myEventHandler->poll(myTimingInfo.start); - if(myQuitLoop) break; // Exit if the user wants to quit - myFrameBuffer->update(); - myTimingInfo.current = getTicks(); - myTimingInfo.virt += myTimePerFrame; + // Sleep-based wait: good for CPU, bad for graphical sync + bool busyWait = mySettings->getString("timing") != "sleep"; + time_point virtualTime = high_resolution_clock::now(); - // Timestamps may periodically go out of sync, particularly on systems - // that can have 'negative time' (ie, when the time seems to go backwards) - // This normally results in having a very large delay time, so we check - // for that and reset the timers when appropriate - if((myTimingInfo.virt - myTimingInfo.current) > (myTimePerFrame << 1)) - { - myTimingInfo.current = myTimingInfo.virt = getTicks(); + for(;;) + { + myEventHandler->poll(myTimingInfo.start); + if(myQuitLoop) break; // Exit if the user wants to quit + + Int64 cycles = myFrameBuffer->update(); + duration timeslice ( + (cycles >= 0) ? + static_cast(cycles) / static_cast(76 * ((myConsole->timing() == ConsoleTiming::ntsc) ? (262 * 60) : (312 * 50))) : + 1. / 30. + ); + + virtualTime += duration_cast(timeslice); + time_point now = high_resolution_clock::now(); + + if (duration_cast>(now - virtualTime).count() > 0.5) + virtualTime = now; + else if (virtualTime > now) { + if (busyWait && cycles >= 0) { + while (high_resolution_clock::now() < virtualTime); } - - if(myTimingInfo.current < myTimingInfo.virt) - SDL_Delay(uInt32(myTimingInfo.virt - myTimingInfo.current) / 1000); - - myTimingInfo.totalTime += (getTicks() - myTimingInfo.start); - myTimingInfo.totalFrames++; + else std::this_thread::sleep_until(virtualTime); } - } - else - { - // Busy-wait: bad for CPU, good for graphical sync - for(;;) - { - myTimingInfo.start = getTicks(); - myEventHandler->poll(myTimingInfo.start); - if(myQuitLoop) break; // Exit if the user wants to quit - myFrameBuffer->update(); - myTimingInfo.virt += myTimePerFrame; - while(getTicks() < myTimingInfo.virt) - ; // busy-wait - - myTimingInfo.totalTime += (getTicks() - myTimingInfo.start); - myTimingInfo.totalFrames++; - } + myTimingInfo.totalFrames++; } // Cleanup time diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index 583087327..7cbf94872 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -237,6 +237,8 @@ class TIA : public Device */ void enableAutoFrame(bool enabled) { myAutoFrameEnabled = enabled; } + float frameRate() const { return myFrameManager ? myFrameManager->frameRate() : 0; } + /** Enables/disables color-loss for PAL modes only.