My first challenge with CanalK: getting the text scrolling smooth. I must warn that I lack of any theoretical training on computer graphics, so some things I say here might be quite basic for experts, but I couldn’t find them explicitly said elsewhere, thus it might be helpful anyway.
All right, back to our scrolling problem. Remember the screen structure?
You’d think that scrolling a text (or a picture) is easy, you just take the time delta since last frame, multiply it by the speed and add that to the text’s position, and you’re done. Unfortunately, this is completely wrong.
Let’s start with the current version. It is plain Qt, and uses the animation framework to move the text. So it’s supposedly well tested, fluid, and everything. And indeed, it is far from using the full CPU, and the FPS looks pretty decent. However, from time to time (around each second) the text jumps.
Later when doing the same thing with OpenGL, I got some similar troubles as well. So what’s happening? Let’s suppose that our rendering process generates 10 frames per second, but that the screen only displays 9 frames per second. When the screen displays a frame, it takes the last generated frame.
What you can see here is that obviously the frame 5 is skipped. That’s only logical because the screen can display less frames than generated. But the text was supposed to go through the position in generated frame 5, and instead jumps from 4 to 6. Culprit is found!
Another thing is: my intuition was to calculate the time delta between to frames with a timer, by watching elapsed time between two calls of the update() function. Very wrong. Indeed, the GPU displays a frame exactly 60 times per second. Which means that whatever I’m doing, the delta will be 1/60s, no more, no less, unless I take too long to render my frame, but in a simple 2D application this should not be the case. The timestamp of the frame generation does not matter in the slightest, what counts is only the time when the frame is displayed.
Now the main problems are identified, what is the solution?
- You must generate the exact same number of frames than your screen. Yup, that’s vsync. There is several ways to do it, and no real standard method. The NVidia driver offers an option, you can also set the environment variable __GL_SYNC_TO_VBLANK to 1. If like me you’re using Qt, just use QGLFormat::setSwapInterva().
- Under normal circumstances, you will set the swap interval to 1 (you swap the buffers every frame), but if you can’t be fast enough for 60FPS, you’ll have to do 30FPS by setting the swap interval to 2.
- If you’re scrolling a text at constant speed, don’t calculate anything and just add a constant to the position, preferably an integer to avoid sub-pixel problems.
By respecting those points I was able to get a perfectly fluid text, so this more or less proves me right. However, this is just a theory I have about a phenomenon I observed, and maybe that I’m wrong… Anyways, scrolling really looks like one of the worst things to do, because the eye won’t be so touchy with other effects, like fade to black.
Once again, this shows that in programming it is very important to be able to know your limits, because there is no secret formula that’s going to help you managing dropped frames (that you can’t predict). Hope my advises here will be useful !