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:
parent
03c41fa34c
commit
3025b6d299
2 changed files with 23 additions and 17 deletions
|
@ -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,
|
||||
|
|
|
@ -48,11 +48,11 @@ class MainTimerSync {
|
|||
class DeltaSmoother {
|
||||
public:
|
||||
// pass the recorded delta, returns a smoothed delta
|
||||
int smooth_delta(int p_delta);
|
||||
int64_t smooth_delta(int64_t p_delta);
|
||||
|
||||
private:
|
||||
void update_refresh_rate_estimator(int p_delta);
|
||||
bool fps_allows_smoothing(int p_delta);
|
||||
void update_refresh_rate_estimator(int64_t p_delta);
|
||||
bool fps_allows_smoothing(int64_t p_delta);
|
||||
|
||||
// estimated vsync delta (monitor refresh rate)
|
||||
int64_t _vsync_delta = 16666;
|
||||
|
@ -75,19 +75,19 @@ class MainTimerSync {
|
|||
|
||||
// we can estimate the fps by growing it on condition
|
||||
// that a large proportion of frames are higher than the current estimate.
|
||||
int _estimated_fps = 0;
|
||||
int _hits_at_estimated = 0;
|
||||
int _hits_above_estimated = 0;
|
||||
int _hits_below_estimated = 0;
|
||||
int _hits_one_above_estimated = 0;
|
||||
int _hits_one_below_estimated = 0;
|
||||
int32_t _estimated_fps = 0;
|
||||
int32_t _hits_at_estimated = 0;
|
||||
int32_t _hits_above_estimated = 0;
|
||||
int32_t _hits_below_estimated = 0;
|
||||
int32_t _hits_one_above_estimated = 0;
|
||||
int32_t _hits_one_below_estimated = 0;
|
||||
bool _estimate_complete = false;
|
||||
bool _estimate_locked = false;
|
||||
|
||||
// data for averaging the delta over a second or so
|
||||
// to prevent spurious values
|
||||
int _estimator_total_delta = 0;
|
||||
int _estimator_delta_readings = 0;
|
||||
int64_t _estimator_total_delta = 0;
|
||||
int32_t _estimator_delta_readings = 0;
|
||||
|
||||
void made_new_estimate() {
|
||||
_hits_above_estimated = 0;
|
||||
|
|
Loading…
Reference in a new issue