Revision: 217 http://skycastle.svn.sourceforge.net/skycastle/?rev=217&view=rev Author: zzorn Date: 2007-10-04 16:27:33 -0700 (Thu, 04 Oct 2007) Log Message: ----------- Some improvements to the FPS counter code Modified Paths: -------------- trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/fpscounter/FpsCounter.java Modified: trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/fpscounter/FpsCounter.java =================================================================== --- trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/fpscounter/FpsCounter.java 2007-10-04 23:26:45 UTC (rev 216) +++ trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/fpscounter/FpsCounter.java 2007-10-04 23:27:33 UTC (rev 217) @@ -1,35 +1,27 @@ -/** - * Copyright Hans H\xE4ggstr\xF6m 2004 - * hans.haggstrom at iki dot fi - */ - package org.skycastle.util.fpscounter; /** - * A class used to count frames per second. + * An utlity class for counting number of frames per second. * <p/> * Usage: Create an instance, then every frame call onFrame(). * The frames per second value can be read at any time using getFps(). * <p/> - * IDEA: The implementation could use a longer time sampling span than a single frame to get - * around the imprecision of the standard Java timer. - * <p/> - * IDEA: Smoothness feature, averaging the FPS value a bit with the previous value - this produces smoother changes, - * IDEA which is better looking for some kinds of FPS gauges. - * <p/> - * IDEA: Make NUMBER_OF_FPS_SAMPLE_FRAMES a caller adjustable property? + * Thread safe, as long as onFrame is only called from a single thread. * * @author Hans H\xE4ggstr\xF6m */ -public class FpsCounter +public final class FpsCounter { //====================================================================== // Private Fields - private double myFramesPerSecond = 0; + private final Object mySyncLock = new Object(); + + // IDEA: Also calculate average over a number of frames, if a smoother value is needed, or if trend information is needed. + private double myFramesPerSecond = -1; + private double mySecondsBetweenFrames = -1; private long myFrameStartTime_ns = -1; - private double mySecondsSinceLastFrame = 0; private boolean myHasPreviousSample = false; //====================================================================== @@ -45,7 +37,7 @@ /** * Creates a new FpsCounter. - * Initially the frames per second property will be 0, until onFrame() is called. + * Initially the frames per second property will be a negative value, until onFrame() is called (twice). */ public FpsCounter() { @@ -55,68 +47,85 @@ // Other Public Methods /** - * @return the number of frames rendered per second, or 0 if the counter has not yet been started or has been stopped. + * @return the number of frames rendered per second, or a negative value if the counter has not yet been started or has been stopped. */ public double getFramesPerSecond() { - return myFramesPerSecond; + synchronized ( mySyncLock ) + { + return myFramesPerSecond; + } } /** - * @return number of seconds since the last frame, or a negative value if there were no earlier frames. + * @return number of seconds between the most recent frame and the frame before that, + * or a negative value if there were no earlier frames. * Uses the averaged frames per second instead of the latest measurement. */ - public double getSecondsSinceLastFrame() + public double getSecondsBetweenFrames() { - return mySecondsSinceLastFrame; + synchronized ( mySyncLock ) + { + return mySecondsBetweenFrames; + } } /** * Call this method once each frame, to allow the counter to compute the frames per second property. + * <p/> + * NOTE: Should be called from a single thread, or wrapped in a syncronized object. If called from two different + * threads, there could be frames with negative fps or secondsBetweenFrames. */ public void onFrame() { // Get start time of current frame - long now_ns = System.nanoTime(); + final long now_ns = System.nanoTime(); - // Only update the fps property if we have two values already, so the duration is valid. - if ( myHasPreviousSample ) + synchronized ( mySyncLock ) { - // Calculate the duration since the last frame - long duration_ns = now_ns - myFrameStartTime_ns; + // Only update the fps property if we have two values already, so the duration is valid. + if ( myHasPreviousSample ) + { + // Calculate the duration since the last frame + long duration_ns = now_ns - myFrameStartTime_ns; - // Avoid division by zero if the frame rate is very high - if ( duration_ns == 0 ) + // Avoid division by zero if the frame rate is very high + if ( duration_ns == 0 ) + { + duration_ns = 1; + } + + // Update the frames per second and time since last frame property + mySecondsBetweenFrames = ( 1.0 * duration_ns ) / TICKS_PER_SECOND; + myFramesPerSecond = TICKS_PER_SECOND / duration_ns; + } + else { - duration_ns = 1; + // Now we have one sample already, so next time we can update the property + myHasPreviousSample = true; } - // Update the frames per second and time since last frame property - mySecondsSinceLastFrame = ( 1.0 * duration_ns ) / TICKS_PER_SECOND; - myFramesPerSecond = TICKS_PER_SECOND / duration_ns; + // Remember current frame start time + myFrameStartTime_ns = now_ns; } - else - { - // Now we have one sample already, so next time we can update the property - myHasPreviousSample = true; - } - - // Remember current frame start time - myFrameStartTime_ns = now_ns; } /** - * Sets the frames per second value to 0, until onFrame() is called again. + * Sets the frames per second and seconds since last frame value to negative values, until onFrame() is called again. */ public void stopCounting() { - myFramesPerSecond = 0; - myHasPreviousSample = false; + synchronized ( mySyncLock ) + { + myFramesPerSecond = -1; + mySecondsBetweenFrames = -1; + myHasPreviousSample = false; + } } - } + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.