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.
This commit is contained in:
Tamás Bálint Misius
2025-01-22 15:04:20 +01:00
parent 6576872074
commit c32166efdc
14 changed files with 152 additions and 63 deletions

View File

@@ -8,7 +8,11 @@ struct FpsLimitExplicit
{ {
float value; float value;
}; };
using FpsLimit = std::variant<FpsLimitNone, FpsLimitExplicit>; using SimFpsLimit = std::variant<FpsLimitNone, FpsLimitExplicit>;
struct FpsLimitFollowDraw
{
};
using FpsLimit = std::variant<FpsLimitNone, FpsLimitExplicit, FpsLimitFollowDraw>;
struct DrawLimitDisplay struct DrawLimitDisplay
{ {

View File

@@ -477,6 +477,7 @@ void EngineProcess()
EventProcess(event); EventProcess(event);
} }
std::optional<uint64_t> delay;
{ {
auto nowNs = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000); auto nowNs = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000);
auto effectiveDrawLimit = engine.GetEffectiveDrawCap(); auto effectiveDrawLimit = engine.GetEffectiveDrawCap();
@@ -485,10 +486,6 @@ void EngineProcess()
engine.Tick(); engine.Tick();
engine.Draw(); engine.Draw();
drawSchedule.SetNow(nowNs); drawSchedule.SetNow(nowNs);
if (effectiveDrawLimit)
{
drawSchedule.Arm(float(*effectiveDrawLimit));
}
SDLSetScreen(); SDLSetScreen();
blit(engine.g->Data()); blit(engine.g->Data());
} }
@@ -496,14 +493,24 @@ void EngineProcess()
{ {
engine.SimTick(); engine.SimTick();
} }
if (effectiveDrawLimit)
{
delay = drawSchedule.Arm(float(*effectiveDrawLimit)) / UINT64_C(1'000'000);
}
} }
auto fpsLimit = ui::Engine::Ref().GetFpsLimit();
if (!std::holds_alternative<FpsLimitFollowDraw>(fpsLimit))
{ {
auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); delay.reset();
auto nowNs = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000); auto nowNs = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000);
tickSchedule.SetNow(nowNs); tickSchedule.SetNow(nowNs);
if (auto *fpsLimitExplicit = std::get_if<FpsLimitExplicit>(&fpsLimit)) if (auto *fpsLimitExplicit = std::get_if<FpsLimitExplicit>(&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)));
}
} }

View File

@@ -970,6 +970,11 @@ void GameController::SetZoomPosition(ui::Point position)
gameModel->SetZoomWindowPosition(zoomWindowPosition); gameModel->SetZoomWindowPosition(zoomWindowPosition);
} }
bool GameController::GetPaused() const
{
return gameModel->GetPaused();
}
void GameController::SetPaused(bool pauseState) void GameController::SetPaused(bool pauseState)
{ {
gameModel->SetPaused(pauseState); gameModel->SetPaused(pauseState);
@@ -1730,7 +1735,7 @@ void GameController::AfterSimDraw()
bool GameController::ThreadedRenderingAllowed() bool GameController::ThreadedRenderingAllowed()
{ {
return gameModel->GetThreadedRendering() && !commandInterface->HaveSimGraphicsEventHandlers(); return gameModel->GetThreadedRendering() && !GetPaused() && !commandInterface->HaveSimGraphicsEventHandlers();
} }
void GameController::SetToolIndex(ByteString identifier, std::optional<int> index) void GameController::SetToolIndex(ByteString identifier, std::optional<int> index)

View File

@@ -117,6 +117,7 @@ public:
void CopyRegion(ui::Point point1, ui::Point point2); void CopyRegion(ui::Point point1, ui::Point point2);
void CutRegion(ui::Point point1, ui::Point point2); void CutRegion(ui::Point point1, ui::Point point2);
void Update(); void Update();
bool GetPaused() const;
void SetPaused(bool pauseState); void SetPaused(bool pauseState);
void SetPaused(); void SetPaused();
void SetDecoration(bool decorationState); void SetDecoration(bool decorationState);

View File

@@ -1018,7 +1018,7 @@ void GameModel::SetPaused(bool pauseState)
notifyPausedChanged(); notifyPausedChanged();
} }
bool GameModel::GetPaused() bool GameModel::GetPaused() const
{ {
return sim->sys_pause?true:false; return sim->sys_pause?true:false;
} }

View File

@@ -237,7 +237,7 @@ public:
void AddObserver(GameView * observer); void AddObserver(GameView * observer);
void SetPaused(bool pauseState); void SetPaused(bool pauseState);
bool GetPaused(); bool GetPaused() const;
void SetDecoration(bool decorationState); void SetDecoration(bool decorationState);
bool GetDecoration(); bool GetDecoration();
void SetAHeatEnable(bool aHeat); void SetAHeatEnable(bool aHeat);

View File

@@ -768,6 +768,7 @@ void GameView::NotifyUserChanged(GameModel * sender)
void GameView::NotifyPausedChanged(GameModel * sender) void GameView::NotifyPausedChanged(GameModel * sender)
{ {
pauseButton->SetToggleState(sender->GetPaused()); pauseButton->SetToggleState(sender->GetPaused());
ApplySimFpsLimit();
} }
void GameView::NotifyToolTipChanged(GameModel * sender) void GameView::NotifyToolTipChanged(GameModel * sender)
@@ -2542,7 +2543,12 @@ void GameView::OnDraw()
{ {
//FPS and some version info //FPS and some version info
StringBuilder fpsInfo; 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) if (showDebug)
{ {
@@ -2563,14 +2569,13 @@ void GameView::OnDraw()
{ {
fpsInfo << "\nSimulation"; fpsInfo << "\nSimulation";
fpsInfo << "\n FPS cap: "; fpsInfo << "\n FPS cap: ";
auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); if (std::holds_alternative<FpsLimitNone>(simFpsLimit))
if (std::holds_alternative<FpsLimitNone>(fpsLimit))
{ {
fpsInfo << "none"; fpsInfo << "none";
} }
else else
{ {
fpsInfo << std::get<FpsLimitExplicit>(fpsLimit).value; fpsInfo << std::get<FpsLimitExplicit>(simFpsLimit).value;
} }
} }
if (c->GetDebugFlags() & DEBUG_RENHUD) if (c->GetDebugFlags() & DEBUG_RENHUD)
@@ -2811,3 +2816,25 @@ void GameView::WaitForRendererThread()
return !rendererThreadOwnsRenderer; return !rendererThreadOwnsRenderer;
}); });
} }
void GameView::ApplySimFpsLimit()
{
if (c->GetPaused())
{
SetFpsLimit(FpsLimitFollowDraw{});
}
else if (std::holds_alternative<FpsLimitNone>(simFpsLimit))
{
SetFpsLimit(FpsLimitNone{});
}
else
{
SetFpsLimit(std::get<FpsLimitExplicit>(simFpsLimit));
}
}
void GameView::SetSimFpsLimit(SimFpsLimit newSimFpsLimit)
{
simFpsLimit = newSimFpsLimit;
ApplySimFpsLimit();
}

View File

@@ -175,6 +175,9 @@ private:
int foundParticles = 0; int foundParticles = 0;
const RendererFrame *rendererFrame = nullptr; const RendererFrame *rendererFrame = nullptr;
SimFpsLimit simFpsLimit = FpsLimitExplicit{ 60.f };
void ApplySimFpsLimit();
public: public:
GameView(); GameView();
~GameView(); ~GameView();
@@ -278,4 +281,10 @@ public:
void RenderSimulation(const RenderableSimulation &sim, bool handleEvents); void RenderSimulation(const RenderableSimulation &sim, bool handleEvents);
void AfterSimDraw(const RenderableSimulation &sim); void AfterSimDraw(const RenderableSimulation &sim);
void SetSimFpsLimit(SimFpsLimit newSimFpsLimit);
SimFpsLimit GetSimFpsLimit() const
{
return simFpsLimit;
}
}; };

View File

@@ -24,7 +24,6 @@ Engine::Engine():
mousexp_(0), mousexp_(0),
mouseyp_(0) mouseyp_(0)
{ {
SetFpsLimit(FpsLimitExplicit{ 60.0f });
} }
Engine::~Engine() Engine::~Engine()
@@ -38,19 +37,9 @@ Engine::~Engine()
} }
} }
void Engine::SetFpsLimit(FpsLimit newFpsLimit) void Engine::ApplyFpsLimit()
{ {
fpsLimit = newFpsLimit; ::SetFpsLimit(GetFpsLimit());
::SetFpsLimit(fpsLimit);
// Populate dt with whatever that makes any sort of sense.
if (auto *explicitFpsLimit = std::get_if<FpsLimitExplicit>(&fpsLimit))
{
SetFps(explicitFpsLimit->value);
}
else
{
SetFps(1);
}
} }
void Engine::Begin() void Engine::Begin()
@@ -110,7 +99,7 @@ void Engine::ShowWindow(Window * window)
state_->DoBlur(); state_->DoBlur();
state_ = window; state_ = window;
ApplyFpsLimit();
} }
void Engine::CloseWindowAndEverythingAbove(Window *window) void Engine::CloseWindowAndEverythingAbove(Window *window)
@@ -153,11 +142,13 @@ int Engine::CloseWindow()
mouseyp_ = mousey_; mouseyp_ = mousey_;
} }
ignoreEvents = true; ignoreEvents = true;
ApplyFpsLimit();
return 0; return 0;
} }
else else
{ {
state_ = nullptr; state_ = nullptr;
ApplyFpsLimit();
return 1; return 1;
} }
} }
@@ -179,7 +170,7 @@ void Engine::Tick()
{ {
if(state_ != nullptr) if(state_ != nullptr)
{ {
state_->DoTick(dt); state_->DoTick();
state_->DoSimTick(); state_->DoSimTick();
} }
@@ -241,19 +232,6 @@ void Engine::Draw()
FrameIndex %= 7200; FrameIndex %= 7200;
} }
void Engine::SetFps(float fps)
{
this->fps = fps;
if (std::holds_alternative<FpsLimitExplicit>(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) void Engine::onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
{ {
if (state_ && !ignoreEvents) if (state_ && !ignoreEvents)
@@ -396,3 +374,29 @@ std::optional<int> Engine::GetEffectiveDrawCap() const
} }
return effectiveDrawCap; 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{};
}

View File

@@ -60,8 +60,8 @@ namespace ui
void SimTick(); void SimTick();
void Draw(); void Draw();
void SetFps(float fps); void SetFps(float newFps);
inline float GetFps() { return fps; } float GetFps() const;
inline int GetMouseButton() { return mouseb_; } inline int GetMouseButton() { return mouseb_; }
inline int GetMouseX() { return mousex_; } inline int GetMouseX() { return mousex_; }
@@ -75,11 +75,7 @@ namespace ui
//inline State* GetState() { return state_; } //inline State* GetState() { return state_; }
inline Window* GetWindow() { return state_; } inline Window* GetWindow() { return state_; }
void SetFpsLimit(FpsLimit newFpsLimit); FpsLimit GetFpsLimit() const;
FpsLimit GetFpsLimit() const
{
return fpsLimit;
}
DrawLimit drawingFrequencyLimit; DrawLimit drawingFrequencyLimit;
Graphics * g; Graphics * g;
@@ -89,13 +85,11 @@ namespace ui
unsigned int FrameIndex; unsigned int FrameIndex;
private: private:
FpsLimit fpsLimit;
bool textInput = false; bool textInput = false;
int lastTextEditingStart = INT_MAX; int lastTextEditingStart = INT_MAX;
float dt; void ApplyFpsLimit();
float fps;
std::deque<Window*> windows; std::deque<Window*> windows;
std::stack<Point> mousePositions; std::stack<Point> mousePositions;
//Window* statequeued_; //Window* statequeued_;

View File

@@ -26,6 +26,7 @@ Window::Window(Point _position, Point _size):
destruct(false), destruct(false),
stop(false) stop(false)
{ {
SetFps(1);
} }
Window::~Window() Window::~Window()
@@ -228,7 +229,7 @@ void Window::DoDraw()
} }
} }
void Window::DoTick(float dt) void Window::DoTick()
{ {
if (debugMode) if (debugMode)
return; return;
@@ -610,3 +611,29 @@ void Window::Halt()
halt = true; halt = true;
} }
void Window::SetFps(float newFps)
{
fps = newFps;
if (std::holds_alternative<FpsLimitExplicit>(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<FpsLimitExplicit>(&fpsLimit))
{
SetFps(explicitFpsLimit->value);
}
else
{
SetFps(1);
}
}

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "common/String.h" #include "common/String.h"
#include "gui/interface/Point.h" #include "gui/interface/Point.h"
#include "FpsLimit.h"
#include <vector> #include <vector>
class Graphics; class Graphics;
@@ -54,7 +55,7 @@ namespace ui
virtual void DoInitialized(); virtual void DoInitialized();
virtual void DoExit(); virtual void DoExit();
virtual void DoTick(float dt); virtual void DoTick();
virtual void DoSimTick(); virtual void DoSimTick();
virtual void DoDraw(); virtual void DoDraw();
virtual void DoFocus(); virtual void DoFocus();
@@ -85,6 +86,16 @@ namespace ui
void MakeActiveWindow(); void MakeActiveWindow();
void CloseActiveWindow(); void CloseActiveWindow();
Graphics * GetGraphics(); Graphics * GetGraphics();
void SetFps(float newFps);
float GetFps() const
{
return fps;
}
void SetFpsLimit(FpsLimit newFpsLimit);
FpsLimit GetFpsLimit() const
{
return fpsLimit;
}
protected: protected:
ui::Button * okayButton; ui::Button * okayButton;
@@ -122,5 +133,8 @@ namespace ui
bool destruct; bool destruct;
bool stop; bool stop;
float dt;
float fps;
FpsLimit fpsLimit = FpsLimitFollowDraw{};
}; };
} }

View File

@@ -197,10 +197,11 @@ static int debug(lua_State *L)
static int fpsCap(lua_State *L) static int fpsCap(lua_State *L)
{ {
auto *lsi = GetLSI();
int acount = lua_gettop(L); int acount = lua_gettop(L);
if (acount == 0) if (acount == 0)
{ {
auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); auto fpsLimit = lsi->window->GetSimFpsLimit();
if (std::holds_alternative<FpsLimitNone>(fpsLimit)) if (std::holds_alternative<FpsLimitNone>(fpsLimit))
{ {
lua_pushnumber(L, 2); lua_pushnumber(L, 2);
@@ -218,10 +219,10 @@ static int fpsCap(lua_State *L)
} }
if (fpscap == 2) if (fpscap == 2)
{ {
ui::Engine::Ref().SetFpsLimit(FpsLimitNone{}); lsi->window->SetSimFpsLimit(FpsLimitNone{});
return 0; return 0;
} }
ui::Engine::Ref().SetFpsLimit(FpsLimitExplicit{ fpscap }); lsi->window->SetSimFpsLimit(FpsLimitExplicit{ fpscap });
return 0; return 0;
} }

View File

@@ -14,11 +14,7 @@ namespace http
class Request; class Request;
} }
namespace ui class GameView;
{
class Window;
}
class Graphics; class Graphics;
class Renderer; class Renderer;
class Simulation; class Simulation;
@@ -82,7 +78,7 @@ public:
GameModel *gameModel; GameModel *gameModel;
GameController *gameController; GameController *gameController;
ui::Window *window; GameView *window;
Simulation *sim; Simulation *sim;
Graphics *g; Graphics *g;