Delta smoothing - fix overflow for long frames

Extremely long frames caused by suspending and resuming the machine could result in an overflow in the delta smoothing because it uses 32 bit math on delta values measured in nanoseconds.

This PR puts a cap of a second as the maximum frame delta that will be processed by the smoothing, otherwise it returns the frame delta 64 bit value unaltered. It also converts internal math to explicitly use 64 bit integers.
This commit is contained in:
lawnjelly
2021-08-11 08:03:45 +01:00
parent 03c41fa34c
commit 3025b6d299
2 changed files with 23 additions and 17 deletions

View File

@ -43,7 +43,7 @@ void MainFrameTime::clamp_idle(float min_idle_step, float max_idle_step) {
/////////////////////////////////
void MainTimerSync::DeltaSmoother::update_refresh_rate_estimator(int p_delta) {
void MainTimerSync::DeltaSmoother::update_refresh_rate_estimator(int64_t p_delta) {
// the calling code should prevent 0 or negative values of delta
// (preventing divide by zero)
@ -195,7 +195,7 @@ void MainTimerSync::DeltaSmoother::update_refresh_rate_estimator(int p_delta) {
}
}
bool MainTimerSync::DeltaSmoother::fps_allows_smoothing(int p_delta) {
bool MainTimerSync::DeltaSmoother::fps_allows_smoothing(int64_t p_delta) {
_measurement_time += p_delta;
_measurement_frame_count++;
@ -209,8 +209,8 @@ bool MainTimerSync::DeltaSmoother::fps_allows_smoothing(int p_delta) {
// estimate fps
if (time_passed) {
float fps = 1000000.0f / time_passed;
float ratio = fps / (float)_estimated_fps;
double fps = 1000000.0 / time_passed;
double ratio = fps / (double)_estimated_fps;
//print_line("ratio : " + String(Variant(ratio)));
@ -230,7 +230,7 @@ bool MainTimerSync::DeltaSmoother::fps_allows_smoothing(int p_delta) {
return _measurement_allows_smoothing;
}
int MainTimerSync::DeltaSmoother::smooth_delta(int p_delta) {
int64_t MainTimerSync::DeltaSmoother::smooth_delta(int64_t p_delta) {
// Conditions to disable smoothing.
// Note that vsync is a request, it cannot be relied on, the OS may override this.
// If the OS turns vsync on without vsync in the app, smoothing will not be enabled.
@ -240,6 +240,12 @@ int MainTimerSync::DeltaSmoother::smooth_delta(int p_delta) {
return p_delta;
}
// Very important, ignore long deltas and pass them back unmodified.
// This is to deal with resuming after suspend for long periods.
if (p_delta > 1000000) {
return p_delta;
}
// keep a running guesstimate of the FPS, and turn off smoothing if
// conditions not close to the estimated FPS
if (!fps_allows_smoothing(p_delta)) {
@ -266,7 +272,7 @@ int MainTimerSync::DeltaSmoother::smooth_delta(int p_delta) {
_leftover_time += p_delta;
// how many vsyncs units can we fit?
int units = _leftover_time / _vsync_delta;
int64_t units = _leftover_time / _vsync_delta;
// a delta must include minimum 1 vsync
// (if it is less than that, it is either random error or we are no longer running at the vsync rate,