Jump to content
  • Advertisement
Sign in to follow this  
SillyCow

Limiting FPS

This topic is 2326 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am trying to limit the FPS rate of my logic frames. (The state updates).
My requirements:
1. Generally smooth flow.
2. Try to smooth out bad frames ( bad frames == frames who have a long running time compared to other frames [ex: calculate big AI decision] ).

I find that most frames run in under a millisecond, but some frames take as much as 70ms.

Currently I am using a sliding window (Code below).
I wait until 2 seconds have elapsed since the last 60 frames have been calculated (I am using 30FPS).

Problems is, this algorithm is not as stable as I hoped. Every once in a while I have a long running logic frame, and it throws off the next frames. When it disappears from the sliding window, it causes another timing artefact.

Does anyone have a suggestion for a better FPS limiter? (not limiting graphics FPS, just the logic frames...)
Thinking of trying a simple low-pass filter of some-sort.
Solution does not have to be high-performance (this code only gets called when the CPU has time to rest)



public class FrequencyConstrainer {
double m_FPS;
Queue<Long> m_Ticks = new LinkedList<Long>();

public FrequencyConstrainer(double FPS) {
m_FPS = FPS;
}
public void setFPS(double FPS) {
m_FPS = FPS;
}
public void clear() {
m_Ticks.clear();
}
public void Tick() {
m_Ticks.add(System.currentTimeMillis());
while (m_Ticks.size() > m_FPS*2) {
m_Ticks.poll();
}
}
public long getNextExecutionTime() {
if (m_Ticks.isEmpty()) {
return System.currentTimeMillis();
} else {
return m_Ticks.peek() + (long) ((m_Ticks.size() * 1000) / m_FPS);
}
}
public void ConstrainExecutionSpeed() throws InterruptedException {
long targetTime = getNextExecutionTime();
while (System.currentTimeMillis() < targetTime) {
Thread.sleep(10);
}
}
}
Edited by SillyCow

Share this post


Link to post
Share on other sites
Advertisement
Not sure if this is helpful, If any frame takes more than a fixed amount of time (usually 30ms) to calculate, it will cause stuttering. You can identify the bottleneck and optimize your code so that it will not take that long, or try to run the offending calculation in a separate thread, or distribute it over a few frames. Or am I talking about something else here?

Share this post


Link to post
Share on other sites

Not sure if this is helpful, If any frame takes more than a fixed amount of time (usually 30ms) to calculate, it will cause stuttering. You can identify the bottleneck and optimize your code so that it will not take that long, or try to run the offending calculation in a separate thread, or distribute it over a few frames. Or am I talking about something else here?


I acknowledge that a 70 ms frame causes momentary stuttering, but the limiter I have implemented causes that stuttering to happen twice (It overcompensates for said frame). I see this especially on debug breakpoints (very long frames....). The frame limiter starts stuttering, and never stops, even if all subsequent frames are short. Incidentally these stutters re-occur every 2 seconds (just like my window length) .

The behaviour I am looking for in this case:
1) Compensate for stutter.
2) Over a period of 2 seconds calculate (2 * FPS) +/- 1

I am not necessarily looking to improve my specific solution, I would prefer a generic solution if one exists. Edited by SillyCow

Share this post


Link to post
Share on other sites

long running logic frame

You need to get rid of them.

Either use an other thread to do the calculation (can be really tricky) or you build your algorithm to be yielded and continued in the next frame. I.e. my A* algorithm only calculates a fixed amount of nodes each frame, so it is very time stable. The worst what happens is, that a path calculation needed more than 1 frame. In this case you need to make this kind of calls asynchrously.

Best to use a request queue for heavy logic calculations and use a dispatcher/worker combo in either a yieldable way or in a multithreaded environment.

Share this post


Link to post
Share on other sites
Finally figured it out.
I should be using a sliding window of time, instead of a sliding window of frames.


public class FrequencyConstrainer {
double m_FPS;
LinkedList<Long> m_Ticks = new LinkedList<Long>();
public FrequencyConstrainer(double FPS) {
m_FPS = FPS;
}
public void setFPS(double FPS) {
m_FPS = FPS;
}
public void clear() {
m_Ticks.clear();
}
public void Tick() {
m_Ticks.add(System.currentTimeMillis());
while (m_Ticks.getLast() - m_Ticks.getFirst() > 2 * 1000) {
m_Ticks.poll();
}
//Saftey:
while (m_Ticks.size() > m_FPS * 2 * 2) {
m_Ticks.poll();
}
}
public long getNextExecutionTime() {
if (m_Ticks.isEmpty()) {
return System.currentTimeMillis();
} else {
long startedExecution= m_Ticks.getFirst();
long expectedTime=(long) (1000*m_Ticks.size()/m_FPS);
return startedExecution + expectedTime;
}
}
public void ConstrainExecutionSpeed() throws InterruptedException {
long targetTime = getNextExecutionTime();
while (System.currentTimeMillis() < targetTime) {
Thread.sleep(10);
}
}
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!