feat(frame-pacer): overhaul logic and render FPS limits and presets#2699
feat(frame-pacer): overhaul logic and render FPS limits and presets#2699githubawn wants to merge 2 commits into
Conversation
- Added 15 FPS to render presets and expanded logic presets (1 to 960 FPS). - Implemented array-based preset snapping for logic FPS. - Renamed extraStep to snapValue for clarity. - Removed redundant logic speed scaling guards and safety asserts. - Cleaned up stale comments and dead code in CommandXlat.
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Include/Common/FrameRateLimit.h | Removed the enum-based step/min constants from LogicTimeScaleFpsPreset, replaced with a private array declaration and updated public API to accept an optional snapValue parameter. |
| Core/GameEngine/Source/Common/FrameRateLimit.cpp | Defines the new logic-preset array (1–960 + Uncapped), adds 15 to render presets, and replaces fixed-step math with array-based search that incorporates an optional snap candidate (render FPS). |
| Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp | Simplifies changeLogicTimeScale: removes the old step-based ceiling/remainder math, passes maxRenderFps as snap hint, and only calls setLogicTimeScaleFps when timescale is being enabled. |
| GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp | Identical simplification to the Generals variant — mirrors the same changeLogicTimeScale overhaul for the Zero Hour expansion. |
Reviews (2): Last reviewed commit: "greptile fixes" | Re-trigger Greptile
| // Set value after potentially enabling it. | ||
| if (TheFramePacer->isLogicTimeScaleEnabled()) | ||
| const bool enableTimescale = (logicTimeScaleFps < maxRenderFps); | ||
| // TheSuperHackers @info Preserve the last real FPS in m_logicTimeScaleFPS so re-enabling timescale resumes from a sane value. |
There was a problem hiding this comment.
Add empty line between const bool declaration and comment for better readability
| { | ||
| TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps); | ||
| } | ||
| TheFramePacer->enableLogicTimeScale(enableTimescale); |
There was a problem hiding this comment.
Add empty line between closing bracket and TheFramePacer->enableLogicTimeScale for better readability.
Optionally: remove whiteline below TheFramePacer->enableLogicTimeScale
| { | ||
| TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps); | ||
| } | ||
| TheFramePacer->enableLogicTimeScale(enableTimescale); |
There was a problem hiding this comment.
Add empty line between closing bracket and TheFramePacer->enableLogicTimeScale for better readability.
Optionally: remove whiteline below TheFramePacer->enableLogicTimeScale
| // Set value after potentially enabling it. | ||
| if (TheFramePacer->isLogicTimeScaleEnabled()) | ||
| const bool enableTimescale = (logicTimeScaleFps < maxRenderFps); | ||
| // TheSuperHackers @info Preserve the last real FPS in m_logicTimeScaleFPS so re-enabling timescale resumes from a sane value. |
There was a problem hiding this comment.
Add empty line between const bool declaration and comment for better readability
| case FpsValueChange_Increase: return getNextFpsValue(value); | ||
| case FpsValueChange_Decrease: return getPrevFpsValue(value); | ||
| case FpsValueChange_Increase: return getNextFpsValue(value, snapValue); | ||
| case FpsValueChange_Decrease: return getPrevFpsValue(value, snapValue); |
There was a problem hiding this comment.
Shouldn't default and case indented here?
| { | ||
| switch (change) | ||
| { | ||
| default: |
There was a problem hiding this comment.
The default falls through to case FpsValueChange_Increase which is quite the curious (and maybe unexpected behaviour. I think it warrants a comment.
Better (if possible): change should only have value FpsValueChange_Increase or FpsValueChange_Decrease, so default should never be called. Maybe put it at the end and add an assert instead.
| for (int i = (int)ARRAY_SIZE(s_fpsValues) - 1; i >= 0; --i) | ||
| { | ||
| return value - StepFpsValue; | ||
| if (s_fpsValues[i] < value) |
There was a problem hiding this comment.
I could be wrong, but wouldn't
int fpsValue = s_fpsValues[i];
add a slight performance increase, as otherwise the array value needs to be looked up three times?
| // Check if snapValue (e.g. current render FPS) is the previous closest candidate. | ||
| // Note: if snapValue == value, neither branch below fires and the snap point is | ||
| // intentionally skipped — the caller must step to a different preset. | ||
| if (snapValue < value && snapValue > prevValue) |
There was a problem hiding this comment.
swapping conditions
if (snapValue > prevValue && snapValue < value)
has better readability
| // Check predefined steps | ||
| for (size_t i = 0; i < ARRAY_SIZE(s_fpsValues); ++i) | ||
| { | ||
| if (s_fpsValues[i] > value) |
There was a problem hiding this comment.
I could be wrong, but wouldn't
int fpsValue = s_fpsValues[i];
add a slight performance increase, as otherwise the array value needs to be looked up three times?
| UnsignedInt LogicTimeScaleFpsPreset::getNextFpsValue(UnsignedInt value, UnsignedInt snapValue) | ||
| { | ||
| return value + StepFpsValue; | ||
| UnsignedInt nextValue = s_fpsValues[ARRAY_SIZE(s_fpsValues) - 1]; // Default to Uncapped |
This change was generated with AI assistance. All generated code has been reviewed, tested, and verified for functionality.