From ea819ff768d507c37a981c1ab0bdc0cad32c6a87 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Sat, 23 Apr 2011 06:20:45 +0200
Subject: New FPSCounter, impl. by GLWindow and GLAnimatorControl (fps perf
 related API change)

- Don't fetch System.currentTimeMillis() by default and for every frame (performance)
- Default behavior is FPSCounter switched off
- Enable by frame interval, ie measure each 60 frames.
- FPSCounterImpl is default impl. used by impl. FPSCounter class (reduce code/redundancy)

- Might be promoted to GLAutoDrawable ?!
---
 .../classes/com/jogamp/opengl/util/Animator.java   |  14 +--
 .../com/jogamp/opengl/util/AnimatorBase.java       |  61 +++++----
 .../com/jogamp/opengl/util/FPSAnimator.java        |   2 +-
 .../classes/javax/media/opengl/FPSCounter.java     | 117 ++++++++++++++++++
 .../javax/media/opengl/GLAnimatorControl.java      |  42 +------
 src/jogl/classes/jogamp/opengl/FPSCounterImpl.java | 137 +++++++++++++++++++++
 6 files changed, 300 insertions(+), 73 deletions(-)
 create mode 100644 src/jogl/classes/javax/media/opengl/FPSCounter.java
 create mode 100644 src/jogl/classes/jogamp/opengl/FPSCounterImpl.java

(limited to 'src/jogl')

diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
index 4fbd0e478..e7fbc4d58 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
@@ -125,7 +125,7 @@ public class Animator extends AnimatorBase {
 
     class MainLoop implements Runnable {
         public String toString() {
-            return "[started "+isStartedImpl()+", animating "+isAnimatingImpl()+", paused "+isPausedImpl()+", frames "+getTotalFrames()+", drawable "+drawables.size()+"]";
+            return "[started "+isStartedImpl()+", animating "+isAnimatingImpl()+", paused "+isPausedImpl()+", drawable "+drawables.size()+"]";
         }
 
         public void run() {
@@ -134,11 +134,7 @@ public class Animator extends AnimatorBase {
                     if(DEBUG) {
                         System.err.println("Animator start:" + Thread.currentThread() + ": " + toString());
                     }
-
-                    startTime = System.currentTimeMillis();
-                    curTime   = startTime;
-                    totalFrames = 0;
-
+                    fpsCounter.resetFPSCounter();
                     animThread = Thread.currentThread();
                     setIsAnimatingSynced(false); // barrier
                     Animator.this.notifyAll();
@@ -161,9 +157,7 @@ public class Animator extends AnimatorBase {
 
                             if (wasPaused) {
                                 // resume from pause -> reset counter
-                                startTime = System.currentTimeMillis();
-                                curTime = startTime;
-                                totalFrames = 0;
+                                fpsCounter.resetFPSCounter();
                                 if (DEBUG) {
                                     System.err.println("Animator resume:" + Thread.currentThread() + ": " + toString());
                                 }
@@ -269,7 +263,7 @@ public class Animator extends AnimatorBase {
         if (runnable == null) {
             runnable = new MainLoop();
         }
-        resetCounter();
+        fpsCounter.resetFPSCounter();
         String threadName = Thread.currentThread().getName()+"-"+baseName;
         Thread thread;
         if(null==threadGroup) {
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
index 01c2ea664..a6ba74665 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
@@ -30,7 +30,12 @@ package com.jogamp.opengl.util;
 
 import com.jogamp.common.util.locks.RecursiveLock;
 import jogamp.opengl.Debug;
+import jogamp.opengl.FPSCounterImpl;
+
+import java.io.PrintStream;
 import java.util.ArrayList;
+
+import javax.media.opengl.FPSCounter;
 import javax.media.opengl.GLAnimatorControl;
 import javax.media.opengl.GLAutoDrawable;
 import javax.media.opengl.GLProfile;
@@ -61,9 +66,7 @@ public abstract class AnimatorBase implements GLAnimatorControl {
     protected Thread animThread;
     protected boolean ignoreExceptions;
     protected boolean printExceptions;
-    protected long startTime;
-    protected long curTime;
-    protected int  totalFrames;
+    protected FPSCounterImpl fpsCounter = new FPSCounterImpl();    
     protected RecursiveLock stateSync = new RecursiveLock();
 
     /** Creates a new, empty Animator. */
@@ -83,7 +86,6 @@ public abstract class AnimatorBase implements GLAnimatorControl {
             baseName = baseName.concat("-"+animatorCount);
             drawablesEmpty = true;
         }
-        resetCounter();
     }
 
     protected abstract String getBaseName(String prefix);
@@ -138,25 +140,48 @@ public abstract class AnimatorBase implements GLAnimatorControl {
         lightweight widgets are continually being redrawn. */
     protected void display() {
         impl.display(drawables, ignoreExceptions, printExceptions);
-        curTime = System.currentTimeMillis();
-        totalFrames++;
+        fpsCounter.tickFPS();
+    }
+
+    public final void setUpdateFPSFrames(int frames, PrintStream out) {
+        fpsCounter.setUpdateFPSFrames(frames, out);
+    }
+    
+    public final void resetFPSCounter() {
+        fpsCounter.resetFPSCounter();
     }
 
-    public long getCurrentTime() {
-        return curTime;
+    public final int getUpdateFPSFrames() {
+        return fpsCounter.getUpdateFPSFrames();
+    }
+    
+    public final long getFPSStartTime()   {
+        return fpsCounter.getFPSStartTime();
     }
 
-    public long getDuration() {
-        return curTime - startTime;
+    public final long getLastFPSUpdateTime() {
+        return fpsCounter.getLastFPSUpdateTime();
     }
 
-    public long getStartTime() {
-        return startTime;
+    public final long getLastFPSPeriod() {
+        return fpsCounter.getLastFPSPeriod();
+    }
+    
+    public final float getLastFPS() {
+        return fpsCounter.getLastFPS();
+    }
+    
+    public final int getTotalFPSFrames() {
+        return fpsCounter.getTotalFPSFrames();
     }
 
-    public int getTotalFrames() {
-        return totalFrames;
+    public final long getTotalFPSDuration() {
+        return fpsCounter.getTotalFPSDuration();
     }
+    
+    public final float getTotalFPS() {
+        return fpsCounter.getTotalFPS();
+    }        
 
     public final Thread getThread() {
         stateSync.lock();
@@ -167,12 +192,6 @@ public abstract class AnimatorBase implements GLAnimatorControl {
         }
     }
 
-    public synchronized void resetCounter() {
-        startTime = System.currentTimeMillis(); // overwrite startTime to real init one
-        curTime   = startTime;
-        totalFrames = 0;
-    }
-
     /** Sets a flag causing this Animator to ignore exceptions produced
     while redrawing the drawables. By default this flag is set to
     false, causing any exception thrown to halt the Animator. */
@@ -189,6 +208,6 @@ public abstract class AnimatorBase implements GLAnimatorControl {
     }
 
     public String toString() {
-        return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", frames "+getTotalFrames()+", drawable "+drawables.size()+"]";
+        return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", drawable "+drawables.size()+"]";
     }
 }
diff --git a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
index f59351ad8..f7fc58160 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
@@ -130,7 +130,7 @@ public class FPSAnimator extends AnimatorBase {
             }
         };
 
-        resetCounter();
+        fpsCounter.resetFPSCounter();
         shouldRun = true;
 
         if (scheduleAtFixedRate) {
diff --git a/src/jogl/classes/javax/media/opengl/FPSCounter.java b/src/jogl/classes/javax/media/opengl/FPSCounter.java
new file mode 100644
index 000000000..aa42ac9e0
--- /dev/null
+++ b/src/jogl/classes/javax/media/opengl/FPSCounter.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package javax.media.opengl;
+
+import java.io.PrintStream;
+
+/**
+ * FPSCounter feature.<br>
+ * An implementation initially has the FPSCounter feature disabled.<br>
+ * Use {@link #setUpdateFPSFrames(int, PrintStream)} to enable and disable the FPSCounter feature.
+ */
+public interface FPSCounter {
+    public static final int DEFAULT_FRAMES_PER_INTERVAL = 60;
+    
+    /**
+     * @param frames Update interval in frames.<br> At every rendered <i>frames</i> interval the currentTime and fps values are updated. 
+     *        If the <i>frames</i> interval is <= 0, no update will be issued, ie the FPSCounter feature is turned off. You may choose {@link #DEFAULT_FRAMES_PER_INTERVAL}.
+     * @param out optional print stream where the fps values gets printed if not null at every <i>frames</i> interval 
+     */
+    void setUpdateFPSFrames(int frames, PrintStream out);
+    
+    /**
+     * Reset all performance counter (startTime, currentTime, frame number)
+     */
+    void resetFPSCounter();
+    
+    /**
+     * @return update interval in frames
+     * 
+     * @see #setUpdateFPSFrames(int, PrintStream)
+     */
+    int getUpdateFPSFrames();
+    
+    /**
+     * Returns the time of the first display call in milliseconds after enabling this feature via {@link #setUpdateFPSFrames(int, PrintStream)}.<br> 
+     * This value is reset via {@link #resetFPSCounter()}.
+     *
+     * @see #setUpdateFPSFrames(int, PrintStream)
+     * @see #resetFPSCounter()
+     */
+    long getFPSStartTime();
+
+    /**
+     * Returns the time of the last update interval in milliseconds, if this feature is enabled via {@link #setUpdateFPSFrames(int, PrintStream)}.<br>
+     * This value is reset via {@link #resetFPSCounter()}.
+     *
+     * @see #setUpdateFPSFrames(int, PrintStream)
+     * @see #resetFPSCounter()
+     */
+    long getLastFPSUpdateTime();
+
+    /**
+     * @return Duration of the last update interval in milliseconds.
+     *
+     * @see #setUpdateFPSFrames(int, PrintStream)
+     * @see #resetFPSCounter()
+     */
+    long getLastFPSPeriod();
+    
+    /**
+     * @return Last update interval's frames per seconds, {@link #getUpdateFPSFrames()} / {@link #getLastFPSPeriod()}
+     * 
+     * @see #setUpdateFPSFrames(int, PrintStream)
+     * @see #resetFPSCounter()
+     */
+    float getLastFPS(); 
+    
+    /**
+     * @return Number of frame rendered since {@link #getFPSStartTime()} up to {@link #getLastFPSUpdateTime()}
+     *  
+     * @see #setUpdateFPSFrames(int, PrintStream)
+     * @see #resetFPSCounter()
+     */
+    int getTotalFPSFrames();
+
+    /**
+     * @return Total duration in milliseconds, {@link #getLastFPSUpdateTime()} - {@link #getFPSStartTime()}
+     *
+     * @see #setUpdateFPSFrames(int, PrintStream)
+     * @see #resetFPSCounter()
+     */
+    long getTotalFPSDuration();
+
+
+    /**
+     * @return Total frames per seconds, {@link #getTotalFPSFrames()} / {@link #getTotalFPSDuration()} 
+     * 
+     * @see #setUpdateFPSFrames(int, PrintStream)
+     * @see #resetFPSCounter()
+     */
+    float getTotalFPS();       
+}
diff --git a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
index 2c8c7cca3..83e9e22c4 100644
--- a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
+++ b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
@@ -32,47 +32,7 @@ package javax.media.opengl;
  * An animator control interface, 
  * which implementation may drive a {@link javax.media.opengl.GLAutoDrawable} animation.
  */
-public interface GLAnimatorControl {
-
-    /**
-     * @return Time of the first display call in milliseconds.
-     *         This value is reset if started or resumed.
-     *
-     * @see #start()
-     * @see #resume()
-     */
-    long getStartTime();
-
-    /**
-     * @return Time of the last display call in milliseconds.
-     *         This value is reset if started or resumed.
-     *
-     * @see #start()
-     * @see #resume()
-     */
-    long getCurrentTime();
-
-    /**
-     * @return Duration <code>getCurrentTime() - getStartTime()</code>.
-     *
-     * @see #getStartTime()
-     * @see #getCurrentTime()
-     */
-    long getDuration();
-
-
-    /**
-     * @return Number of frame cycles displayed
-     *         since the first display call, ie <code>getStartTime()</code>.
-     *         This value is reset if started or resumed.
-     *
-     * @see #start()
-     * @see #resume()
-     */
-    int getTotalFrames();
-
-    /** Reset all performance counter (startTime, currentTime, frame number) */
-    public void resetCounter();
+public interface GLAnimatorControl extends FPSCounter {
 
     /**
      * Indicates whether this animator is running, ie. has been started and not stopped.
diff --git a/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java
new file mode 100644
index 000000000..96d62fbb3
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.opengl;
+
+import java.io.PrintStream;
+import javax.media.opengl.FPSCounter;
+
+/**
+ * Default implementation of FPSCounter to be used for FPSCounter implementing renderer.
+ */
+public class FPSCounterImpl implements FPSCounter {
+    private int fpsUpdateFramesInterval;
+    private PrintStream fpsOutputStream ;
+    private long fpsStartTime, fpsLastUpdateTime, fpsLastPeriod, fpsTotalDuration;
+    private int  fpsTotalFrames;
+    private float fpsLast, fpsTotal;
+    
+    /** Creates a disabled instance */
+    public FPSCounterImpl() {
+        setUpdateFPSFrames(0, null);
+    }
+    
+    /**
+     * Increases total frame count and updates values if feature is enabled and
+     * update interval is reached.<br>
+     * 
+     * Shall be called by actual FPSCounter implementing renderer, after display a new frame.
+     *  
+     */
+    public final synchronized void tickFPS() {
+        fpsTotalFrames++;
+        if(fpsUpdateFramesInterval>0 && fpsTotalFrames%fpsUpdateFramesInterval == 0) {
+            final long now = System.currentTimeMillis();
+            fpsLastPeriod = now - fpsLastUpdateTime;
+            fpsLastPeriod = Math.max(fpsLastPeriod, 1); // div 0 
+            fpsLast = ( (float)fpsUpdateFramesInterval * 1000f ) / ( (float) fpsLastPeriod ) ; 
+            
+            fpsTotalDuration = now - fpsStartTime;
+            fpsTotalDuration = Math.max(fpsTotalDuration, 1); // div 0
+            fpsTotal= ( (float)fpsTotalFrames * 1000f ) / ( (float) fpsTotalDuration ) ;
+            
+            if(null != fpsOutputStream) {
+                fpsOutputStream.println(toString());
+            }
+            
+            fpsLastUpdateTime = now;
+        }
+    }
+    
+    public StringBuilder toString(StringBuilder sb) {
+        if(null==sb) {
+            sb = new StringBuilder();
+        }
+        String fpsLastS = String.valueOf(fpsLast);
+        fpsLastS = fpsLastS.substring(0, fpsLastS.indexOf('.') + 2);
+        String fpsTotalS = String.valueOf(fpsTotal);
+        fpsTotalS = fpsTotalS.substring(0, fpsTotalS.indexOf('.') + 2);                
+        sb.append(fpsTotalDuration/1000 +" s: "+ fpsUpdateFramesInterval+" f / "+ fpsLastPeriod+" ms, " + fpsLastS+" fps, "+ fpsLastPeriod/fpsUpdateFramesInterval+" ms/f; "+
+                  "total: "+ fpsTotalFrames+" f, "+ fpsTotalS+ " fps, "+ fpsTotalDuration/fpsTotalFrames+" ms/f");
+        return sb;
+    }
+    
+    public String toString() {
+        return toString(null).toString();
+    }
+    
+    public final synchronized void setUpdateFPSFrames(int frames, PrintStream out) {
+        fpsUpdateFramesInterval = frames;
+        fpsOutputStream = out;
+        resetFPSCounter();
+    }
+    
+    public final synchronized void resetFPSCounter() {
+        fpsStartTime = System.currentTimeMillis(); // overwrite startTime to real init one
+        fpsLastUpdateTime   = fpsStartTime;
+        fpsLastPeriod = 0;
+        fpsTotalFrames = 0;
+        fpsLast = 0f; fpsTotal = 0f;
+    }
+
+    public final synchronized int getUpdateFPSFrames() {
+        return fpsUpdateFramesInterval;
+    }
+    
+    public final synchronized long getFPSStartTime()   { 
+        return fpsStartTime; 
+    }
+
+    public final synchronized long getLastFPSUpdateTime() {
+        return fpsLastUpdateTime;
+    }
+
+    public final synchronized long getLastFPSPeriod() {
+        return fpsLastPeriod;
+    }
+    
+    public final synchronized float getLastFPS() {
+        return fpsLast;
+    }
+    
+    public final synchronized int getTotalFPSFrames() { 
+        return fpsTotalFrames; 
+    }
+
+    public final synchronized long getTotalFPSDuration() { 
+        return fpsTotalDuration; 
+    }
+    
+    public final synchronized float getTotalFPS() {
+        return fpsTotal;
+    }        
+}
-- 
cgit v1.2.3