Frame rate control

Started by entis, March 27, 2008, 09:38:55 AM

Previous topic - Next topic

entis

Hi,

I would like to know how can I control rendering frame rate... I want to make it not more than 25 fps. Which is the best way?

The only idea I have is to measure time before and after on rendering cycle and sleep for a time that is greater than 40 (1000/25) but this is not working as I expected (I get more than 25 frames).

Your ideas are welcome. Thanks in advance.

paulscode

I think you should be able to do something like this:

final long granularity = 40;
long frameStartTime, frameTime;
...
// Game loop:
while( running )
{
...
    frameStartTime = System.currentTimeMillis();

    //  Render the frame:
    renderGame();

    frameTime = System.currentTimeMillis() - frameStartTime;
    if (frameTime < granularity)
        sleepTime = granularity - frameTime;
    if (sleepTime > 0)
    {
        try
        {
            Thread.sleep(sleepTime);
        } catch (InterruptedException ie) {}
    }
    else
    {
        Thread.yield();
    }
}


I haven't tested this code, but hopefully it helps :)

EgonOlsen

The granularity of System.currentTimeMillis() isn't the same on all platforms. While it's mostly 1ms on Linux, it's around 10ms on Windows...until you are using a multiprocessor machine (or multi-core cpu), which ups it to 15.
System.nanoTime()/1000000L should provide a better timing, but you'll limit yourself to Java5 or higher with that.

Another thing that might work, is to start a timer thread that uses a fixed sleep time in a loop and put a sleep(<high value>) in your rendering loop. Then let the timer thread interrupt the render thread every time it has finished its own (the timer thread's...) sleep.

paulscode

Quote from: EgonOlsen on March 27, 2008, 01:30:07 PM
start a timer thread that uses a fixed sleep time in a loop and put a sleep(<high value>) in your rendering loop. Then let the timer thread interrupt the render thread every time it has finished its own (the timer thread's...) sleep.

:o That is ingenious!  That's how I'm doin' it from now on...

JavaMan

HI,
I was wondering, what is the reason for limiting the fps rate? I thought the more fps you get in the smoother the image will be, but maybe thats not true, huh?

Jman

paulscode

Quote from: JavaMan on March 28, 2008, 01:17:09 AM
HI,
I was wondering, what is the reason for limiting the fps rate? I thought the more fps you get in the smoother the image will be, but maybe thats not true, huh?

Jman

In most cases that I have limited fps, it was to keep things from moving too fast.  There are of course other ways to do that without limiting the fps, but this is a much simpler way to do it.

The other thing to consider, is that there is an actual maximum fps that the human eye can detect (it is somewhat higher than the 25 fps previously believed, but it is still a proven phenominum.  I kind of remember reading somewhere that the human eye can detect subtle differences up to 70 fps or so).  So as long as you are limiting the fps to a value higher than that, there should not be a noticable impact on smoothness; only on speed (which, as I mentioned, is generally the factor you are trying to limit).

entis

Quote from: JavaMan on March 28, 2008, 01:17:09 AM
HI,
I was wondering, what is the reason for limiting the fps rate? I thought the more fps you get in the smoother the image will be, but maybe thats not true, huh?

Jman

One more reason is to release CPU time for other apps...

EgonOlsen

Quote from: paulscode on March 27, 2008, 08:05:44 PM
:o That is ingenious!  That's how I'm doin' it from now on...
I'm not sure if it is...i've never tried this, at least not for timing things. It's just an idea.

JavaMan

QuoteIn most cases that I have limited fps, it was to keep things from moving too fast.  There are of course other ways to do that without limiting the fps, but this is a much simpler way to do it.

The other thing to consider, is that there is an actual maximum fps that the human eye can detect (it is somewhat higher than the 25 fps previously believed, but it is still a proven phenominum.  I kind of remember reading somewhere that the human eye can detect subtle differences up to 70 fps or so).  So as long as you are limiting the fps to a value higher than that, there should not be a noticable impact on smoothness; only on speed (which, as I mentioned, is generally the factor you are trying to limit).

Quote
One more reason is to release CPU time for other apps...

I see. I never thought of that. Also, I suppose if you got over 70fps that would be overkill and you could spend the cycles doing something else.
Jman

paulscode

Quote from: EgonOlsen on March 28, 2008, 08:55:18 AM
I'm not sure if it is...i've never tried this, at least not for timing things. It's just an idea.

I was actually thinking of altering this a tiny bit (to ensure that both threads start sleeping at the same time):

First Thread:

public void run()
{
    if( timeToSleep )
    {
        try
        {
            Thread.sleep(sleepTime);
        } catch (InterruptedException ie) {}
        timeToSleep = false;
    }
}


Rendering Thread:
timeToSleep = true;       // start the other thread's sleep loop
renderScene();             // render the world
while( timeToSleep ) {}  // First Thread will let us know when to stop


Only thing I was thinking, this would be affected by how long the cpu spends on each thread.  I'm thinking of running some tests to see how well it works.  I think this is really thinking outside the box (which I like).

EgonOlsen

That would cause a busy wait in the rendering loop (if timeToSleep is true) AND in the timerLoop (if it isn't), i.e. no cpu cycles will be saved. I don't think that both threads have to know about the state of each other. The timer loop will just try to wake up the rendering thread every x millis. If there is nothing to wake up, fine. If there is, it'll wake it up and continue sleeping. If the timer thread has a high priority, this should lead to the rendering thread being kicked in the a.. every x ms. A problem occurs, if the rendering thread takes longer than x ms to render. In that case, there will be an additional slow down in the rendering by the amount of time between the rendering thread being finished and the timer threads new "tick", which will take a maximum of x ms.

paulscode

#11
Quote from: EgonOlsen on March 28, 2008, 01:15:08 PM
That would cause a busy wait in the rendering loop (if timeToSleep is true) AND in the timerLoop (if it isn't), i.e. no cpu cycles will be saved. I don't think that both threads have to know about the state of each other. The timer loop will just try to wake up the rendering thread every x millis. If there is nothing to wake up, fine. If there is, it'll wake it up and continue sleeping. If the timer thread has a high priority, this should lead to the rendering thread being kicked in the a.. every x ms. A problem occurs, if the rendering thread takes longer than x ms to render. In that case, there will be an additional slow down in the rendering by the amount of time between the rendering thread being finished and the timer threads new "tick", which will take a maximum of x ms.

After wasting a couple of hours before realizing a stupid mistake in my code, I have re-run the tests with the two threads not knowing about each other, and it works great!  Only has problems, as you predicted, when you try to limit the fps at too high a value (as might happen on a slow machine).

This was a fun puzzle to work on!