Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defaults


// 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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

{
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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

swapping conditions

if (snapValue > prevValue && snapValue < value)

has better readability

{
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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

{
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:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't default and case indented here?

}
}
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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add empty line between const bool declaration and comment for better readability

if (enableTimescale)
{
TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps);
}
TheFramePacer->enableLogicTimeScale(enableTimescale);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add empty line between closing bracket and TheFramePacer->enableLogicTimeScale for better readability.

Optionally: remove whiteline below TheFramePacer->enableLogicTimeScale


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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add empty line between const bool declaration and comment for better readability

if (enableTimescale)
{
TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps);
}
TheFramePacer->enableLogicTimeScale(enableTimescale);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add empty line between closing bracket and TheFramePacer->enableLogicTimeScale for better readability.

Optionally: remove whiteline below TheFramePacer->enableLogicTimeScale


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