Limiting FPS

Started by
3 comments, last by SillyCow 11 years, 10 months ago
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);
}
}
}

My Oculus Rift Game: RaiderV

My Android VR games: Time-Rider& Dozer Driver

My browser game: Vitrage - A game of stained glass

My android games : Enemies of the Crown & Killer Bees

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?

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.

My Oculus Rift Game: RaiderV

My Android VR games: Time-Rider& Dozer Driver

My browser game: Vitrage - A game of stained glass

My android games : Enemies of the Crown & Killer Bees


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.
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);
}
}
}

My Oculus Rift Game: RaiderV

My Android VR games: Time-Rider& Dozer Driver

My browser game: Vitrage - A game of stained glass

My android games : Enemies of the Crown & Killer Bees

This topic is closed to new replies.

Advertisement