I’ve written my 3D engine in OpenGL and I’ve got to the stage where I’ve added support for the windows performance timer. I can now count the seconds passed and lock my animation to this value. I use the timer to read the fps. On my machine I achieve 75 fps (same as my monitors Hz) however on my friends monster machine he achieves over 700 fps!! I want my code to limit the number of frames displayed to 60 so CPU time is not wasted on redundant frames. How do I implement this??
The easiest way is to get your app to sync to the monitor refresh rate using the GL_EXT_swap_control extension. Note that this will limit the framerate to the vertical sync of the monitor (i.e. not necessarily 60 fps). However it is usually overrideable in the control panel which means vsync could be forcibly disabled.
If you are using windows you could look into using waitable timers (CreateWaitableTimer).
Use QueryPerformanceCounter to get how much time your drawing loop takes & do a swap as soon as 1/75 of second has elapsed, else wait a bit. Or even better, just make your movement time based instead of frame based.
I would avoid syncing the GL with the monitor.
I always prefer to have things done by the code…
I code only on Linux, but you should be able to do
similar things on Windows, etc.
There is usually a loop that keeps rendering and
swaps the buffer. You will need to have some “wait”
statement in that loop. Find the function of the
kernel that will first pick the current time and
store it. Now render, trap events, etc.
Then, use the kernel function that waits
no more than a certain amount of time, given the
time interval and the previous time you had stored.
The time interval is pre-specified such
that it corresponds to the equivalent framerate
you want. The results should be having a framerate
that is less or equal to what you want, but not
I hope this makes sense.
At the end of the loop:
If you want your app to perform equally on each computer, you don´t clamp the frames, but you do all your stuff (eg. animations) time based.
This is very easy AND always correct. Clamping the framerate will disappoint people with good hardware, because they expect more and, if your app actually runs SLOWER than your desired 60 fps, you don´t get into trouble.
But maybe you knew that already…
I think there are perfectly legitimate reasons for wanting to clamp frame rate. You may want your app to run alongside other applications for example without hogging the CPU.
If the post is asking: How do I get my animations to move at the same rate on any computer? then yes, absolutely, use time to do your animations.
However IMHO the post was asking about clamping frame rate and not wasting CPU time, for which you would need some kind of wait or timing event mechanism. WaitForSingleObject would be one way of doing as iznogoud suggested under windows.
Sometimes fps higher than 60 might help, but that’s usually the case only in racing simulators. All other apps are less picky about framerate from my point of view.
Still Doom3 stuck with fixed framerate, because of the jump issues Quake 3 had in multiplayer. But I think that’s only because of small ‘bug’ in physics implementation rather than limitation of rendering method. Allways check what happens if frame rate is low (walking through walls) & what if high (insanely small state values, precision issues).
What I did to solve the fps+time issue is as follows:
calculate the fps based on the number of frame rendered per 0.1 sec. (this way, I get a new fps per 1/10 sec)
all movements are numtiplied by (1/fps). It’s a pseudo-fixed time engine. And it’s working well so far.
That’s the problem, because it is easy to find the case when you are turning, and there is a moment you are facing one unshaded quad, the next you see, bunch of detail. Portals & doors could do that as well. Take a look at aquamark tests, they’re frame based. As soon as ship rises up in the first scene, fps drop down dramaticaly & you see jerkiness very well, even on high end HW. Allways rely on time in every frame, though grpx calculation is asynchronous, so it might break too.
Ok well I guess clamping the framerate has it’s good points and bad points. My initial thought for this was so that the engine could spend more time on physics and AI instead of throwing more frames at the screen. But I think if a computer is fast enough to display 700 fps then it’s fast enough to process all the extra work involved in a game. Also if you spend your time waiting in the main loop this probably isn’t too friendly on your computers multitasking as your computer isn’t actually sleeping it’s just running in a loop.
if you spend your time waiting in the main loop this probably isn’t too friendly on your computers multitasking as your computer isn’t actually sleeping it’s just running in a loop.
If you use proper system wait(), it will let multitasking work.
As a random rant, I would personnaly love a modified SwapInterval working that way :
- if a screen refresh has already occured since previous swap, swap now.
- else, swap right after the screen refresh.
That would mean :
- no fps decrease if FPS < display refresh rate
- vsync visual stability + frame rate clamping at display refresh rate if FPS > display refresh rate
… the best of both worlds …