From c32166efdcb750d7c6c4433e3549386d822747a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Wed, 22 Jan 2025 15:04:20 +0100 Subject: [PATCH] Make the fps cap a per-view property And have ui.fpsCap set only GameView's fps cap. This is the closest we'll be getting to the fps cap being true to its name (i.e. actually controlling frames per second, rather than ticks per second) with this iteration of the user interface. Also disable SRT if the sim is paused. Together, these changes fix some old problems such as non-sim user interfaces burning CPU for no reason when the fps cap is removed. --- src/FpsLimit.h | 6 +++- src/PowderToySDL.cpp | 19 +++++++---- src/gui/game/GameController.cpp | 7 +++- src/gui/game/GameController.h | 1 + src/gui/game/GameModel.cpp | 2 +- src/gui/game/GameModel.h | 2 +- src/gui/game/GameView.cpp | 35 ++++++++++++++++--- src/gui/game/GameView.h | 9 +++++ src/gui/interface/Engine.cpp | 60 ++++++++++++++++++--------------- src/gui/interface/Engine.h | 14 +++----- src/gui/interface/Window.cpp | 29 +++++++++++++++- src/gui/interface/Window.h | 16 ++++++++- src/lua/LuaMisc.cpp | 7 ++-- src/lua/LuaScriptInterface.h | 8 ++--- 14 files changed, 152 insertions(+), 63 deletions(-) diff --git a/src/FpsLimit.h b/src/FpsLimit.h index cd821e3b2..d49c23142 100644 --- a/src/FpsLimit.h +++ b/src/FpsLimit.h @@ -8,7 +8,11 @@ struct FpsLimitExplicit { float value; }; -using FpsLimit = std::variant; +using SimFpsLimit = std::variant; +struct FpsLimitFollowDraw +{ +}; +using FpsLimit = std::variant; struct DrawLimitDisplay { diff --git a/src/PowderToySDL.cpp b/src/PowderToySDL.cpp index c3d4dc750..e455a55dc 100644 --- a/src/PowderToySDL.cpp +++ b/src/PowderToySDL.cpp @@ -477,6 +477,7 @@ void EngineProcess() EventProcess(event); } + std::optional delay; { auto nowNs = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000); auto effectiveDrawLimit = engine.GetEffectiveDrawCap(); @@ -485,10 +486,6 @@ void EngineProcess() engine.Tick(); engine.Draw(); drawSchedule.SetNow(nowNs); - if (effectiveDrawLimit) - { - drawSchedule.Arm(float(*effectiveDrawLimit)); - } SDLSetScreen(); blit(engine.g->Data()); } @@ -496,14 +493,24 @@ void EngineProcess() { engine.SimTick(); } + if (effectiveDrawLimit) + { + delay = drawSchedule.Arm(float(*effectiveDrawLimit)) / UINT64_C(1'000'000); + } } + auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); + if (!std::holds_alternative(fpsLimit)) { - auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); + delay.reset(); auto nowNs = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000); tickSchedule.SetNow(nowNs); if (auto *fpsLimitExplicit = std::get_if(&fpsLimit)) { - SDL_Delay(tickSchedule.Arm(fpsLimitExplicit->value) / UINT64_C(1'000'000)); + delay = tickSchedule.Arm(fpsLimitExplicit->value) / UINT64_C(1'000'000); } } + if (delay.has_value()) + { + SDL_Delay(std::max(*delay, UINT64_C(1))); + } } diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index c8256a651..7ba8adfcc 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -970,6 +970,11 @@ void GameController::SetZoomPosition(ui::Point position) gameModel->SetZoomWindowPosition(zoomWindowPosition); } +bool GameController::GetPaused() const +{ + return gameModel->GetPaused(); +} + void GameController::SetPaused(bool pauseState) { gameModel->SetPaused(pauseState); @@ -1730,7 +1735,7 @@ void GameController::AfterSimDraw() bool GameController::ThreadedRenderingAllowed() { - return gameModel->GetThreadedRendering() && !commandInterface->HaveSimGraphicsEventHandlers(); + return gameModel->GetThreadedRendering() && !GetPaused() && !commandInterface->HaveSimGraphicsEventHandlers(); } void GameController::SetToolIndex(ByteString identifier, std::optional index) diff --git a/src/gui/game/GameController.h b/src/gui/game/GameController.h index fa3531ad8..90ad43a36 100644 --- a/src/gui/game/GameController.h +++ b/src/gui/game/GameController.h @@ -117,6 +117,7 @@ public: void CopyRegion(ui::Point point1, ui::Point point2); void CutRegion(ui::Point point1, ui::Point point2); void Update(); + bool GetPaused() const; void SetPaused(bool pauseState); void SetPaused(); void SetDecoration(bool decorationState); diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 45f12a40a..840170baf 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -1018,7 +1018,7 @@ void GameModel::SetPaused(bool pauseState) notifyPausedChanged(); } -bool GameModel::GetPaused() +bool GameModel::GetPaused() const { return sim->sys_pause?true:false; } diff --git a/src/gui/game/GameModel.h b/src/gui/game/GameModel.h index 9d5edd47e..085e41a4d 100644 --- a/src/gui/game/GameModel.h +++ b/src/gui/game/GameModel.h @@ -237,7 +237,7 @@ public: void AddObserver(GameView * observer); void SetPaused(bool pauseState); - bool GetPaused(); + bool GetPaused() const; void SetDecoration(bool decorationState); bool GetDecoration(); void SetAHeatEnable(bool aHeat); diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index b2c1a9bbf..5e1f83710 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -768,6 +768,7 @@ void GameView::NotifyUserChanged(GameModel * sender) void GameView::NotifyPausedChanged(GameModel * sender) { pauseButton->SetToggleState(sender->GetPaused()); + ApplySimFpsLimit(); } void GameView::NotifyToolTipChanged(GameModel * sender) @@ -2542,7 +2543,12 @@ void GameView::OnDraw() { //FPS and some version info StringBuilder fpsInfo; - fpsInfo << Format::Precision(2) << "FPS: " << ui::Engine::Ref().GetFps(); + auto fps = 0.f; + if (!c->GetPaused()) + { + fps = ui::Engine::Ref().GetFps(); + } + fpsInfo << Format::Precision(2) << "FPS: " << fps; if (showDebug) { @@ -2563,14 +2569,13 @@ void GameView::OnDraw() { fpsInfo << "\nSimulation"; fpsInfo << "\n FPS cap: "; - auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); - if (std::holds_alternative(fpsLimit)) + if (std::holds_alternative(simFpsLimit)) { fpsInfo << "none"; } else { - fpsInfo << std::get(fpsLimit).value; + fpsInfo << std::get(simFpsLimit).value; } } if (c->GetDebugFlags() & DEBUG_RENHUD) @@ -2811,3 +2816,25 @@ void GameView::WaitForRendererThread() return !rendererThreadOwnsRenderer; }); } + +void GameView::ApplySimFpsLimit() +{ + if (c->GetPaused()) + { + SetFpsLimit(FpsLimitFollowDraw{}); + } + else if (std::holds_alternative(simFpsLimit)) + { + SetFpsLimit(FpsLimitNone{}); + } + else + { + SetFpsLimit(std::get(simFpsLimit)); + } +} + +void GameView::SetSimFpsLimit(SimFpsLimit newSimFpsLimit) +{ + simFpsLimit = newSimFpsLimit; + ApplySimFpsLimit(); +} diff --git a/src/gui/game/GameView.h b/src/gui/game/GameView.h index be73ae504..539f455c8 100644 --- a/src/gui/game/GameView.h +++ b/src/gui/game/GameView.h @@ -175,6 +175,9 @@ private: int foundParticles = 0; const RendererFrame *rendererFrame = nullptr; + SimFpsLimit simFpsLimit = FpsLimitExplicit{ 60.f }; + void ApplySimFpsLimit(); + public: GameView(); ~GameView(); @@ -278,4 +281,10 @@ public: void RenderSimulation(const RenderableSimulation &sim, bool handleEvents); void AfterSimDraw(const RenderableSimulation &sim); + + void SetSimFpsLimit(SimFpsLimit newSimFpsLimit); + SimFpsLimit GetSimFpsLimit() const + { + return simFpsLimit; + } }; diff --git a/src/gui/interface/Engine.cpp b/src/gui/interface/Engine.cpp index 95e797eec..e8eb02222 100644 --- a/src/gui/interface/Engine.cpp +++ b/src/gui/interface/Engine.cpp @@ -24,7 +24,6 @@ Engine::Engine(): mousexp_(0), mouseyp_(0) { - SetFpsLimit(FpsLimitExplicit{ 60.0f }); } Engine::~Engine() @@ -38,19 +37,9 @@ Engine::~Engine() } } -void Engine::SetFpsLimit(FpsLimit newFpsLimit) +void Engine::ApplyFpsLimit() { - fpsLimit = newFpsLimit; - ::SetFpsLimit(fpsLimit); - // Populate dt with whatever that makes any sort of sense. - if (auto *explicitFpsLimit = std::get_if(&fpsLimit)) - { - SetFps(explicitFpsLimit->value); - } - else - { - SetFps(1); - } + ::SetFpsLimit(GetFpsLimit()); } void Engine::Begin() @@ -110,7 +99,7 @@ void Engine::ShowWindow(Window * window) state_->DoBlur(); state_ = window; - + ApplyFpsLimit(); } void Engine::CloseWindowAndEverythingAbove(Window *window) @@ -153,11 +142,13 @@ int Engine::CloseWindow() mouseyp_ = mousey_; } ignoreEvents = true; + ApplyFpsLimit(); return 0; } else { state_ = nullptr; + ApplyFpsLimit(); return 1; } } @@ -179,7 +170,7 @@ void Engine::Tick() { if(state_ != nullptr) { - state_->DoTick(dt); + state_->DoTick(); state_->DoSimTick(); } @@ -241,19 +232,6 @@ void Engine::Draw() FrameIndex %= 7200; } -void Engine::SetFps(float fps) -{ - this->fps = fps; - if (std::holds_alternative(fpsLimit)) - { - this->dt = 60/fps; - } - else - { - this->dt = 1.0f; - } -} - void Engine::onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) { if (state_ && !ignoreEvents) @@ -396,3 +374,29 @@ std::optional Engine::GetEffectiveDrawCap() const } return effectiveDrawCap; } + +void Engine::SetFps(float newFps) +{ + if (state_) + { + return state_->SetFps(newFps); + } +} + +float Engine::GetFps() const +{ + if (state_) + { + return state_->GetFps(); + } + return 1; +} + +FpsLimit Engine::GetFpsLimit() const +{ + if (state_) + { + return state_->GetFpsLimit(); + } + return FpsLimitNone{}; +} diff --git a/src/gui/interface/Engine.h b/src/gui/interface/Engine.h index 1de1709d5..84b1f77ac 100644 --- a/src/gui/interface/Engine.h +++ b/src/gui/interface/Engine.h @@ -60,8 +60,8 @@ namespace ui void SimTick(); void Draw(); - void SetFps(float fps); - inline float GetFps() { return fps; } + void SetFps(float newFps); + float GetFps() const; inline int GetMouseButton() { return mouseb_; } inline int GetMouseX() { return mousex_; } @@ -75,11 +75,7 @@ namespace ui //inline State* GetState() { return state_; } inline Window* GetWindow() { return state_; } - void SetFpsLimit(FpsLimit newFpsLimit); - FpsLimit GetFpsLimit() const - { - return fpsLimit; - } + FpsLimit GetFpsLimit() const; DrawLimit drawingFrequencyLimit; Graphics * g; @@ -89,13 +85,11 @@ namespace ui unsigned int FrameIndex; private: - FpsLimit fpsLimit; bool textInput = false; int lastTextEditingStart = INT_MAX; - float dt; - float fps; + void ApplyFpsLimit(); std::deque windows; std::stack mousePositions; //Window* statequeued_; diff --git a/src/gui/interface/Window.cpp b/src/gui/interface/Window.cpp index ed9374683..3d71ade8f 100644 --- a/src/gui/interface/Window.cpp +++ b/src/gui/interface/Window.cpp @@ -26,6 +26,7 @@ Window::Window(Point _position, Point _size): destruct(false), stop(false) { + SetFps(1); } Window::~Window() @@ -228,7 +229,7 @@ void Window::DoDraw() } } -void Window::DoTick(float dt) +void Window::DoTick() { if (debugMode) return; @@ -610,3 +611,29 @@ void Window::Halt() halt = true; } +void Window::SetFps(float newFps) +{ + fps = newFps; + if (std::holds_alternative(fpsLimit)) + { + dt = 60/fps; + } + else + { + dt = 1.0f; + } +} + +void Window::SetFpsLimit(FpsLimit newFpsLimit) +{ + fpsLimit = newFpsLimit; + // Populate dt with whatever that makes any sort of sense. + if (auto *explicitFpsLimit = std::get_if(&fpsLimit)) + { + SetFps(explicitFpsLimit->value); + } + else + { + SetFps(1); + } +} diff --git a/src/gui/interface/Window.h b/src/gui/interface/Window.h index fba72edb8..d5247b3e6 100644 --- a/src/gui/interface/Window.h +++ b/src/gui/interface/Window.h @@ -1,6 +1,7 @@ #pragma once #include "common/String.h" #include "gui/interface/Point.h" +#include "FpsLimit.h" #include class Graphics; @@ -54,7 +55,7 @@ namespace ui virtual void DoInitialized(); virtual void DoExit(); - virtual void DoTick(float dt); + virtual void DoTick(); virtual void DoSimTick(); virtual void DoDraw(); virtual void DoFocus(); @@ -85,6 +86,16 @@ namespace ui void MakeActiveWindow(); void CloseActiveWindow(); Graphics * GetGraphics(); + void SetFps(float newFps); + float GetFps() const + { + return fps; + } + void SetFpsLimit(FpsLimit newFpsLimit); + FpsLimit GetFpsLimit() const + { + return fpsLimit; + } protected: ui::Button * okayButton; @@ -122,5 +133,8 @@ namespace ui bool destruct; bool stop; + float dt; + float fps; + FpsLimit fpsLimit = FpsLimitFollowDraw{}; }; } diff --git a/src/lua/LuaMisc.cpp b/src/lua/LuaMisc.cpp index 1d5126edc..9f9b2b6f1 100644 --- a/src/lua/LuaMisc.cpp +++ b/src/lua/LuaMisc.cpp @@ -197,10 +197,11 @@ static int debug(lua_State *L) static int fpsCap(lua_State *L) { + auto *lsi = GetLSI(); int acount = lua_gettop(L); if (acount == 0) { - auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); + auto fpsLimit = lsi->window->GetSimFpsLimit(); if (std::holds_alternative(fpsLimit)) { lua_pushnumber(L, 2); @@ -218,10 +219,10 @@ static int fpsCap(lua_State *L) } if (fpscap == 2) { - ui::Engine::Ref().SetFpsLimit(FpsLimitNone{}); + lsi->window->SetSimFpsLimit(FpsLimitNone{}); return 0; } - ui::Engine::Ref().SetFpsLimit(FpsLimitExplicit{ fpscap }); + lsi->window->SetSimFpsLimit(FpsLimitExplicit{ fpscap }); return 0; } diff --git a/src/lua/LuaScriptInterface.h b/src/lua/LuaScriptInterface.h index 72a019cac..0ea66c294 100644 --- a/src/lua/LuaScriptInterface.h +++ b/src/lua/LuaScriptInterface.h @@ -14,11 +14,7 @@ namespace http class Request; } -namespace ui -{ - class Window; -} - +class GameView; class Graphics; class Renderer; class Simulation; @@ -82,7 +78,7 @@ public: GameModel *gameModel; GameController *gameController; - ui::Window *window; + GameView *window; Simulation *sim; Graphics *g;