Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions Core/GameEngine/Include/Common/FrameRateLimit.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,12 @@ class RenderFpsPreset
class LogicTimeScaleFpsPreset
{
public:
enum CPP_11(: UnsignedInt)
{
#if RTS_DEBUG
MinFpsValue = 5,
#else
MinFpsValue = LOGICFRAMES_PER_SECOND,
#endif
StepFpsValue = 5,
};

static UnsignedInt getNextFpsValue(UnsignedInt value);
static UnsignedInt getPrevFpsValue(UnsignedInt value);
static UnsignedInt changeFpsValue(UnsignedInt value, FpsValueChange change);
static UnsignedInt getNextFpsValue(UnsignedInt value, UnsignedInt snapValue = 0);
static UnsignedInt getPrevFpsValue(UnsignedInt value, UnsignedInt snapValue = 0);
static UnsignedInt changeFpsValue(UnsignedInt value, FpsValueChange change, UnsignedInt snapValue = 0);

private:
static const UnsignedInt s_fpsValues[];
};

64 changes: 51 additions & 13 deletions Core/GameEngine/Source/Common/FrameRateLimit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ Real FrameRateLimit::wait(UnsignedInt maxFps)


const UnsignedInt RenderFpsPreset::s_fpsValues[] = {
30, 50, 56, 60, 65, 70, 72, 75, 80, 85, 90, 100, 110, 120, 144, 240, 480, UncappedFpsValue };
15, 30, 50, 56, 60, 65, 70, 72, 75, 80, 85, 90, 100, 110, 120, 144, 240, 480, UncappedFpsValue };

static_assert(LOGICFRAMES_PER_SECOND <= 30, "Min FPS values need to be revisited!");
// TheSuperHackers @info s_fpsValues MUST be strictly ascending; the search loops break on first match.
const UnsignedInt LogicTimeScaleFpsPreset::s_fpsValues[] = {
1, 5, 15, 30, 45, 60, 75, 90, 105, 120, 240, 480, 960, RenderFpsPreset::UncappedFpsValue };
Comment thread
greptile-apps[bot] marked this conversation as resolved.

UnsignedInt RenderFpsPreset::getNextFpsValue(UnsignedInt value)
{
Expand Down Expand Up @@ -102,30 +104,66 @@ UnsignedInt RenderFpsPreset::changeFpsValue(UnsignedInt value, FpsValueChange ch
}
}


UnsignedInt LogicTimeScaleFpsPreset::getNextFpsValue(UnsignedInt value)
UnsignedInt LogicTimeScaleFpsPreset::getNextFpsValue(UnsignedInt value, UnsignedInt snapValue)
{
return value + StepFpsValue;
UnsignedInt nextValue = s_fpsValues[ARRAY_SIZE(s_fpsValues) - 1]; // Default to Uncapped
Comment thread
githubawn marked this conversation as resolved.
Outdated

// Check if snapValue (e.g. current render FPS) is the next closest candidate
if (snapValue > value && snapValue < nextValue)
{
nextValue = snapValue;
}

// Check predefined steps
for (size_t i = 0; i < ARRAY_SIZE(s_fpsValues); ++i)
{
if (s_fpsValues[i] > value)
Comment thread
githubawn marked this conversation as resolved.
Outdated
{
if (s_fpsValues[i] < nextValue)
{
nextValue = s_fpsValues[i];
}
break;
}
}

return nextValue;
}

UnsignedInt LogicTimeScaleFpsPreset::getPrevFpsValue(UnsignedInt value)
UnsignedInt LogicTimeScaleFpsPreset::getPrevFpsValue(UnsignedInt value, UnsignedInt snapValue)
{
if (value - StepFpsValue < MinFpsValue)
UnsignedInt prevValue = s_fpsValues[0]; // Floor/seed for the search loop

// 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)
Comment thread
githubawn marked this conversation as resolved.
Outdated
{
return MinFpsValue;
prevValue = snapValue;
}
else

// Check predefined steps
for (int i = (int)ARRAY_SIZE(s_fpsValues) - 1; i >= 0; --i)
{
return value - StepFpsValue;
if (s_fpsValues[i] < value)
Comment thread
githubawn marked this conversation as resolved.
Outdated
{
if (s_fpsValues[i] > prevValue)
{
prevValue = s_fpsValues[i];
}
break;
}
}

return prevValue;
}

UnsignedInt LogicTimeScaleFpsPreset::changeFpsValue(UnsignedInt value, FpsValueChange change)
UnsignedInt LogicTimeScaleFpsPreset::changeFpsValue(UnsignedInt value, FpsValueChange change, UnsignedInt snapValue)
{
switch (change)
{
default:
Comment thread
githubawn marked this conversation as resolved.
Outdated
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);
Comment thread
githubawn marked this conversation as resolved.
Outdated
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -211,37 +211,28 @@ bool changeLogicTimeScale(FpsValueChange change)
return false;

const UnsignedInt maxRenderFps = TheFramePacer->getFramesPerSecondLimit();
UnsignedInt maxRenderRemainder = LogicTimeScaleFpsPreset::StepFpsValue;
maxRenderRemainder -= maxRenderFps % LogicTimeScaleFpsPreset::StepFpsValue;
maxRenderRemainder %= LogicTimeScaleFpsPreset::StepFpsValue;

UnsignedInt logicTimeScaleFps = TheFramePacer->getLogicTimeScaleFps();
// Set the value to the max render fps value plus a bit when time scale is
// disabled. This ensures that the time scale does not re-enable with a
// 'surprise' value.

if (!TheFramePacer->isLogicTimeScaleEnabled())
{
logicTimeScaleFps = maxRenderFps + maxRenderRemainder;
logicTimeScaleFps = maxRenderFps;
}
// Ceil the value at the max render fps value plus a bit so that the next fps
// value decrease would undercut the max render fps at the correct step value.
// Example: render fps 72 -> logic value ceiled to 75 -> decreased to 70.
logicTimeScaleFps = min(logicTimeScaleFps, maxRenderFps + maxRenderRemainder);
logicTimeScaleFps = LogicTimeScaleFpsPreset::changeFpsValue(logicTimeScaleFps, change);

// Set value before potentially disabling it.
if (TheFramePacer->isLogicTimeScaleEnabled())
logicTimeScaleFps = LogicTimeScaleFpsPreset::changeFpsValue(logicTimeScaleFps, change, maxRenderFps);

// Ensure logic FPS never exceeds render FPS
if (logicTimeScaleFps > maxRenderFps && logicTimeScaleFps != RenderFpsPreset::UncappedFpsValue)
{
TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps);
logicTimeScaleFps = maxRenderFps;
}

TheFramePacer->enableLogicTimeScale(logicTimeScaleFps < maxRenderFps);

// 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.
Comment thread
githubawn marked this conversation as resolved.
if (enableTimescale)
{
TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps);
}
TheFramePacer->enableLogicTimeScale(enableTimescale);
Comment thread
githubawn marked this conversation as resolved.
Outdated

logicTimeScaleFps = TheFramePacer->getLogicTimeScaleFps();
const UnsignedInt actualLogicTimeScaleFps = TheFramePacer->getActualLogicTimeScaleFps();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,37 +210,28 @@ bool changeLogicTimeScale(FpsValueChange change)
return false;

const UnsignedInt maxRenderFps = TheFramePacer->getFramesPerSecondLimit();
UnsignedInt maxRenderRemainder = LogicTimeScaleFpsPreset::StepFpsValue;
maxRenderRemainder -= maxRenderFps % LogicTimeScaleFpsPreset::StepFpsValue;
maxRenderRemainder %= LogicTimeScaleFpsPreset::StepFpsValue;

UnsignedInt logicTimeScaleFps = TheFramePacer->getLogicTimeScaleFps();
// Set the value to the max render fps value plus a bit when time scale is
// disabled. This ensures that the time scale does not re-enable with a
// 'surprise' value.

if (!TheFramePacer->isLogicTimeScaleEnabled())
{
logicTimeScaleFps = maxRenderFps + maxRenderRemainder;
logicTimeScaleFps = maxRenderFps;
}
// Ceil the value at the max render fps value plus a bit so that the next fps
// value decrease would undercut the max render fps at the correct step value.
// Example: render fps 72 -> logic value ceiled to 75 -> decreased to 70.
logicTimeScaleFps = min(logicTimeScaleFps, maxRenderFps + maxRenderRemainder);
logicTimeScaleFps = LogicTimeScaleFpsPreset::changeFpsValue(logicTimeScaleFps, change);

// Set value before potentially disabling it.
if (TheFramePacer->isLogicTimeScaleEnabled())
logicTimeScaleFps = LogicTimeScaleFpsPreset::changeFpsValue(logicTimeScaleFps, change, maxRenderFps);

// Ensure logic FPS never exceeds render FPS
if (logicTimeScaleFps > maxRenderFps && logicTimeScaleFps != RenderFpsPreset::UncappedFpsValue)
{
TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps);
logicTimeScaleFps = maxRenderFps;
}

TheFramePacer->enableLogicTimeScale(logicTimeScaleFps < maxRenderFps);

// 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.
Comment thread
githubawn marked this conversation as resolved.
if (enableTimescale)
{
TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps);
}
TheFramePacer->enableLogicTimeScale(enableTimescale);
Comment thread
githubawn marked this conversation as resolved.
Outdated

logicTimeScaleFps = TheFramePacer->getLogicTimeScaleFps();
const UnsignedInt actualLogicTimeScaleFps = TheFramePacer->getActualLogicTimeScaleFps();
Expand Down
Loading