From b237961450e06765f142517e73f22c3bfa545b98 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Wed, 7 Nov 2018 22:24:45 +0100 Subject: [PATCH] Stop frame rate counter from exaggerating Frame rate counter finally gets its ticket for speeding. Frame rate is now calculated by averaging frame times instead of averaging frame rates. Rationale is explained in the comment. --- core/src/processing/core/PApplet.java | 33 +++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 457b50ea4..7a4adf910 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -705,7 +705,7 @@ public class PApplet implements PConstants { * @see PApplet#frameRate(float) * @see PApplet#frameCount */ - public float frameRate = 10; + public float frameRate = 60; protected boolean looping = true; @@ -2426,9 +2426,34 @@ public class PApplet implements PConstants { } else { // frameCount > 0, meaning an actual draw() // update the current frameRate - double rate = 1000000.0 / ((now - frameRateLastNanos) / 1000000.0); - float instantaneousRate = (float) (rate / 1000.0); - frameRate = (frameRate * 0.9f) + (instantaneousRate * 0.1f); + + // Calculate frameRate through average frame times, not average fps, e.g.: + // + // Alternating 2 ms and 20 ms frames (JavaFX or JOGL sometimes does this) + // is around 90.91 fps (two frames in 22 ms, one frame 11 ms). + // + // However, averaging fps gives us: (500 fps + 50 fps) / 2 = 275 fps. + // This is because we had 500 fps for 2 ms and 50 fps for 20 ms, but we + // counted them with equal weight. + // + // If we average frame times instead, we get the right result: + // (2 ms + 20 ms) / 2 = 11 ms per frame, which is 1000/11 = 90.91 fps. + // + // The counter below uses exponential moving average. To do the + // calculation, we first convert the accumulated frame rate to average + // frame time, then calculate the exponential moving average, and then + // convert the average frame time back to frame rate. + { + // Get the frame time of the last frame + double frameTimeSecs = (now - frameRateLastNanos) / 1e9; + // Convert average frames per second to average frame time + double avgFrameTimeSecs = 1.0 / (double) frameRate; + // Calculate exponential moving average of frame time + final double alpha = 0.05; + avgFrameTimeSecs = (1.0 - alpha) * avgFrameTimeSecs + alpha * frameTimeSecs; + // Convert frame time back to frames per second + frameRate = (float) (1.0 / avgFrameTimeSecs); + } if (frameCount != 0) { handleMethods("pre");