Custom vsync Algorithm
Asked Answered
B

1

1

When creating a game with any programming language (that can), it is important to have a fixed target frame rate the game will redraw the screen at, however some languages either do not have a sync function or timers are unreliable so is there any method of keeping the frame rate steady manually with only math and/or by sleeping the thread? Maybe using a frame delta?
So far I have only tried 'sleep(targetframerate - (targetframerate-delta))' This is supposed to realise that the previous frame took longer than the target so then compensates by making the next frame sooner, however it effects itself and simply kills the frame rate reverse exponentially.
These built-in sync functions must be using some sort of math in a method like this to steady the frame rate. How is it done in high-end APIs such as OpenGL?

Busywork answered 25/7, 2013 at 2:17 Comment(0)
B
2

Create a timer that runs very quickly such as every millisecond (explained why later) and declare these three variables:

private int targetMillis = 1000/60,
            lastTime = (int)System.currentTimeMillis(), 
            targetTime = lastTime+targetMillis;

targetMilis is the desired amount of milliseconds between each frame. Change 60 to desired frame rate.
lastTime is simply when the last frame was, to compare how long its been. Set to now.
targetTime is what time the next frame is due. Now + targetMillis.
An optional timerScaler can be added also, to scale any movements so they don't slow down because the frame rate has with:
public static float timeScaler = 1;
Then on each tick of the timer, run this code that will check if it's time for the next frame and to set up the next - taking into account if the frame is late and making the next one sooner appropriately.

int current = (int)System.currentTimeMillis(); // Now time
if (current < targetTime) return; // Stop here if its not time for the next frame
timeScaler = (float)targetMillis/(current-lastTime);
//Scale game on how late frame is.
lastTime = current;
targetTime = (current+targetMillis)-(current-targetTime);
// Create next frame where it should be (in targetMillis) and subtract if frame was late.
[Game code here.]

One would assume if we needed a frame every targetMillis we can just create a timer for that time, however as you said they can be a few milliseconds out therefore if we still used this method and did offset the targetTime a few back it wouldn't matter as it would always overshoot, therefore the speed of the timer is more of a resolution of accuracy.

Busywork answered 6/8, 2013 at 0:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.