A simpler FPSAnimator

Hi all, I know this subject has already been discussed often. However I didn’t find a clear argued answer. This post is specially oriented for performance guru like me and people who are looking for an FPSAnimator set in mode ‘schedule at fixed rate’ with a setable FPS value.

What I collected on other forum thread :

  • FPSAnimator is good for almost everybody. I agree.
  • It is not cross-platform and seems to be unstable.
  • Active rendering technique may not be as secure as the listener one.
  • Using nano time may waste CPU cycle and we don’t really need this kind of resolution.
  • Using Thread.sleep() is wasting a lof of CPU cycles.

When looking into FPSAnimator code I’ve seen it is synchronized and based on a java.util.Timer. It actually doesn’t measure the time needed for executing the display and use the timer queue mechanism. I’ve though damn this is pretty complicated for what I want to achieve. Basically I need a timer which doesn’t mind if the task is taking longer than the period. I think we can do this with a simple wait(period).

What do you think about this draft class ?


public class SimpleFPSAnimator extends Thread {

    private GraphDrawable drawable;
    private long delay;
    private AtomicBoolean animating;
    private final Object lock = new Object();

    public SimpleFPSAnimator(GraphDrawable drawble, int fps) {
        super("SimpleFPSAnimator");
        this.drawable = drawble;
        this.animating = new AtomicBoolean();

        setFps(fps);
    }

    @Override
    public void run() {
        animating.set(true);

        try {
            while (animating.get()) {
                long startTime = System.currentTimeMillis();
                drawable.display();
                long timeout;
                while ((timeout = delay - System.currentTimeMillis() + startTime) > 0) {
                    //Wait only if the time spent in display is inferior than delay
                    //Otherwise the render loop acts as a 'as fast as you can' loop
                    synchronized (this.lock) {
                        this.lock.wait(timeout);
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void shutdown() {
        animating.set(false);
    }

    public boolean isAnimating() {
        return animating.get();
    }

    private void setFps(int fps) {
        delay = (long) (1000.0f / (float) fps);
    }
}

I precise I don’t care about thread-safety, I only have one GLAutoDrawable to display and a unique controller manages the Animator. It is better to use this class with a GLCanvas because it doesn’t use special mechanism of Animator to paint GLJPanel (see Animator source).

wait(timeout) and sleep(timeout) should both have similar timing accuracy (and performance). Wait waits on the objects monitor till notify() or timeout, sleep ‘waits’ till timeout.

the best way to render in opengl is still relying on vsync. If you want to render in a lower framerate than your refresh rate and it is not that important for you to to renter in a custom framerate you could use this trick:

What does it do?

  1. it enables sync
  2. renders fast as possible in a while loop
  3. but it calls swapBuffers() more as needed (thats the trick, since this will block when vsync is on)

this is the most accurate way (from a timing point of view) to render with targetFPS = refreshRate/skip. Swapping buffers should be relative inexpensive. In worst case the driver would do active waiting on the CPU - but i don’t believe that someone would implement vsync in this way. (works perfectly on a geforce, haven’t tested it yet on amd hw)

for example with a refresh rate of 60Hz the animator above can easily fix the framerate to 60,30,20,15,12…

possible issues:
-arcane intel chips do not support vsync
-tripple buffers are enabled
-vsynch disabled in driver configuration

This is a nice hack, it works on my hardware but it also have some drawbacks. Because it runs as fast as possible the CPU consuming is high. I’m not sure it really blocks on swapBuffers(), since CPU is almost at 100% (rather than ~40%) with my or FPSAnimator.

the trick won’t work if your hardware does not support vsync in general.