From 6fa21128ab3c624aaa1cdb73076101b75021832a Mon Sep 17 00:00:00 2001 From: William JCM Date: Wed, 30 Nov 2022 10:03:45 +0100 Subject: [PATCH] SaveTool: improve FPS capping mechanism. --- src/SaveTool/SaveTool.cpp | 31 ++++++--------- src/SaveTool/SaveTool.h | 16 ++++---- src/SaveTool/SaveTool_Initialisation.cpp | 26 +++++++++--- src/SaveTool/SaveTool_drawMainMenu.cpp | 50 ++++++++++++++++-------- 4 files changed, 74 insertions(+), 49 deletions(-) diff --git a/src/SaveTool/SaveTool.cpp b/src/SaveTool/SaveTool.cpp index 23e61bb..717b1d0 100644 --- a/src/SaveTool/SaveTool.cpp +++ b/src/SaveTool/SaveTool.cpp @@ -128,15 +128,6 @@ SaveTool::SaveTool(const Arguments& arguments): initialiseConfiguration(); - switch(_framelimit) { - case Framelimit::Vsync: - setSwapInterval(1); - break; - case Framelimit::HalfVsync: - setSwapInterval(2); - break; - } - LOG_INFO("Initialising update checker."); curl_global_init(CURL_GLOBAL_DEFAULT); if(_checkUpdatesOnStartup) { @@ -154,6 +145,8 @@ SaveTool::SaveTool(const Arguments& arguments): _uiState = UiState::Initialising; _initThread = std::thread{[this]{ initialiseManager(); }}; } + + _timeline.start(); } SaveTool::~SaveTool() { @@ -170,17 +163,8 @@ SaveTool::~SaveTool() { _conf.setValue("advanced_mode"_s, _advancedMode); _conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup); _conf.setValue("skip_disclaimer"_s, _skipDisclaimer); - - switch(_framelimit) { - case Framelimit::Vsync: - _conf.setValue("frame_limit"_s, "vsync"_s); - break; - case Framelimit::HalfVsync: - _conf.setValue("frame_limit"_s, "half_vsync"_s); - break; - default: - _conf.setValue("frame_limit"_s, "vsync"_s); - } + _conf.setValue("swap_interval"_s, _swapInterval); + _conf.setValue("fps_cap"_s, _fpsCap); _conf.save(); @@ -197,7 +181,14 @@ void SaveTool::drawEvent() { drawImGui(); swapBuffers(); + + if(_swapInterval == 0 && _fpsCap < 301.0f) { + while(_timeline.currentFrameDuration() < (1.0f / _fpsCap)); + } + redraw(); + + _timeline.nextFrame(); } void SaveTool::viewportEvent(ViewportEvent& event) { diff --git a/src/SaveTool/SaveTool.h b/src/SaveTool/SaveTool.h index 19b1070..c662203 100644 --- a/src/SaveTool/SaveTool.h +++ b/src/SaveTool/SaveTool.h @@ -23,7 +23,11 @@ #include #include #include +#ifdef SAVETOOL_DEBUG_BUILD +#include +#endif +#include #include #include @@ -39,8 +43,6 @@ #include "../ToastQueue/ToastQueue.h" #ifdef SAVETOOL_DEBUG_BUILD -#include - #define tw CORRADE_TWEAKABLE #endif @@ -174,7 +176,7 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener // Also, func should be a lambda if there are any default arguments, like ImGui::Button(), etc... template - void drawUnsafeText(Containers::StringView text, Args... args) { // Alternative to the above, for ImGui::Text*() variants. + void drawUnsafeText(const char* text, Args... args) { // Alternative to the above, for ImGui::Text*() variants. if(_gameState != GameState::NotRunning) { ImGui::TextDisabled(text, std::forward(args)...); } @@ -260,10 +262,8 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener }; Containers::StaticArray<2, efsw::WatchID> _watchIDs; - enum class Framelimit: UnsignedByte { - Vsync, - HalfVsync - } _framelimit{Framelimit::Vsync}; + int _swapInterval = 1; + float _fpsCap = 60.0f; bool _skipDisclaimer{false}; bool _checkUpdatesOnStartup{true}; @@ -292,4 +292,6 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener bool _cheatMode{false}; bool _advancedMode{false}; + + Timeline _timeline; }; diff --git a/src/SaveTool/SaveTool_Initialisation.cpp b/src/SaveTool/SaveTool_Initialisation.cpp index f0bafcc..5f5ed49 100644 --- a/src/SaveTool/SaveTool_Initialisation.cpp +++ b/src/SaveTool/SaveTool_Initialisation.cpp @@ -79,17 +79,31 @@ void SaveTool::initialiseConfiguration() { _conf.setValue("skip_disclaimer"_s, _skipDisclaimer); } + if(_conf.hasValue("swap_interval"_s)) { + _swapInterval = _conf.value("swap_interval"_s); + } + else { + _conf.setValue("swap_interval"_s, 1); + } + + if(_conf.hasValue("fps_cap"_s)) { + _fpsCap = _conf.value("fps_cap"); + } + else { + _conf.setValue("fps_cap", 60.0f); + } + if(_conf.hasValue("frame_limit"_s)) { std::string frame_limit = _conf.value("frame_limit"_s); if(frame_limit == "half_vsync"_s) { - _framelimit = Framelimit::HalfVsync; - } - else { - _framelimit = Framelimit::Vsync; + _swapInterval = 2; } + _conf.removeValue("frame_limit"_s); } - else { - _conf.setValue("frame_limit"_s, "vsync"_s); + + setSwapInterval(_swapInterval); + if(_swapInterval == 0) { + setMinimalLoopPeriod(0); } _conf.save(); diff --git a/src/SaveTool/SaveTool_drawMainMenu.cpp b/src/SaveTool/SaveTool_drawMainMenu.cpp index 1e3a36a..b588f05 100644 --- a/src/SaveTool/SaveTool_drawMainMenu.cpp +++ b/src/SaveTool/SaveTool_drawMainMenu.cpp @@ -55,31 +55,49 @@ void SaveTool::drawMainMenu() { ImGui::Separator(); if(ImGui::BeginMenu(ICON_FA_COG " Settings")) { - drawAlignedText("Frame limiter:"); + ImGui::BeginGroup(); + drawAlignedText("Vertical sync:"); + if(_swapInterval == 0) { + drawAlignedText("FPS cap:"); + } + ImGui::EndGroup(); + ImGui::SameLine(); - static auto selection = static_cast(_framelimit); - static const char* framelimit_labels[2] = { - "V-sync", - "Half V-sync" + ImGui::BeginGroup(); + + static const char* framelimit_labels[] = { + "Off", + "Every VBLANK", + "Every second VBLANK", + "Every third VBLANK", }; - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if(ImGui::BeginCombo("##FrameLimit", framelimit_labels[selection])) { - if(ImGui::Selectable(framelimit_labels[0], _framelimit == Framelimit::Vsync)) { - selection = 0; - _framelimit = Framelimit::Vsync; - setSwapInterval(1); - } - if(ImGui::Selectable(framelimit_labels[1], _framelimit == Framelimit::HalfVsync)) { - selection = 1; - _framelimit = Framelimit::HalfVsync; - setSwapInterval(2); + ImGui::PushItemWidth(300.0f); + + if(ImGui::BeginCombo("##FrameLimit", framelimit_labels[_swapInterval])) { + for(int i = 0; i <= 3; i++) { + if(ImGui::Selectable(framelimit_labels[i], _swapInterval == i)) { + _swapInterval = i; + setSwapInterval(i); + if(i == 0) { + setMinimalLoopPeriod(0); + } + } } ImGui::EndCombo(); } + if(_swapInterval == 0) { + ImGui::SliderFloat("##FpsCapSlider", &_fpsCap, 15.0f, 301.0f, + _fpsCap != 301.0f ? "%.0f" : "Uncapped", ImGuiSliderFlags_AlwaysClamp); + } + + ImGui::PopItemWidth(); + + ImGui::EndGroup(); + ImGui::Checkbox("Cheat mode", &_cheatMode); ImGui::SameLine(); ImGui::AlignTextToFramePadding();