Updating and Drawing at Different Framerates (CPU Issues)

Started by
11 comments, last by nife87 12 years, 10 months ago
Since I've read that in a game loop updates generally don't become noticeable as frequently as the screen is rendered, I've separated updating from rendering by using two different timers. I have a couple questions regarding this.

1.) Is my method a decent/efficient way of handling this?
2.) This bad boy takes 100% CPU since I'm not sleeping. How can I fix this easily without hindering performance?


#define UPDATE_FPS 60 // update twice as fast as we draw
#define DRAW_FPS 30

void Window::CallbackDrawScene(void)
{
// update
if (mUpdateTimer.TimeElapsed() >= 1000 / UPDATE_FPS)
{
// all updating here, passing the elapsed time as the delta time to calculate physics changes
mUpdateTimer.Reset();
}

// draw
if (mDrawTimer.TimeElapsed() >= 1000 / DRAW_FPS)
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glClear(GL_COLOR_BUFFER_BIT);

// all drawing here

glutSwapBuffers();

mDrawTimer.Reset();
}

glutPostRedisplay(); // essentially recalls this function (The Draw Scene function)
}
Advertisement
The goal of separating physics and rendering framerates is often to have fixed timesteps (as you do) so that it don't handle differently on faster/slower computer. The rendering don't needs to be fixed though. You can skip rendering frames if it slow down the physics calculations under your wanted rate, or you can render multiple times between physics frame, using interpolation for the position/rotation of objects (players usually love high rendering framerates). A certain algorithm using an accumulator do this, but might be hard to implement. As for using 100% of the cpu, I'm wondering why but I don't have this problem. Maybe because I use Windows's PeekMessage/TranslateMessage/DispatchMessage commands instead of glut, or maybe the physics library handle this. I guess a simple sleep(1) wouldn't hurt and fix it.
You shouldn't tell your program to re-enter the function at the end of the function, and that's why you're hitting 100% CPU usage. You'll taking away the systems ability to delegate CPU usage as necessary by essentially locking the game into a tight loop. It's about as bad as putting your rendering function in a for(;;) loop.
Is it a problem that your program takes 100% of CPU time? Enable "wait vertical refresh" should cap your FPS in full screen mode to your screen refresh frequency. Practically, if your program runs on multicore system and doesn't use much of threads, your CPU isn't actually under 100% utilization (25% on 4-core system, 50% on dual-core).

Adding sleep(0) to the program loop should yield the rest of the time slice for other processes. Otherwise, as far as I know, sleep is rather inaccurate way to cap your fps.

Is your program supposed to run in window with other heavy weight programs running concurrently?

Cheers!

[corrected terminology]

Is it a problem that your program takes 100% of CPU time? Enable "wait vertical refresh" should cap your FPS in full screen mode to your screen update frequency. Practically, if your program runs on multicore system and doesn't use much of threads, your CPU isn't actually under 100% utilization (25% on 4-core system, 50% on dual-core).

Adding sleep(0) to the program loop should yield the rest of the time step for other processes. Otherwise, as far as I know, sleep is rather inaccurate way to cap your fps.

Is your program supposed to run in window with other heavy weight programs running concurrently?

Cheers!

Running at 100% CPU like this can be a problem. Causing overheating is easy on laptops and if the game is windowed and/or the user alt+tabs out, the rest of the OS can be noticeably slowed. Trying to load a browser for instance can become a lesson in frustration.

When you plan to actually have others run the program, it's usually just better to avoid the issue since it's not hard.

Running at 100% CPU like this can be a problem. Causing overheating is easy on laptops and if the game is windowed and/or the user alt+tabs out, the rest of the OS can be noticeably slowed. Trying to load a browser for instance can become a lesson in frustration.

When you plan to actually have others run the program, it's usually just better to avoid the issue since it's not hard.
[/quote]


I do agree that pushing hundreds of FPS is useless and may cause over heating or break your CPU/GPU if your drivers are faulty.
As a safety method it would be great if the user could cap the frame rate to something that doesn't burn the computer.

However, even if you cap your fps, your GPU may still work under 100% load.

Alt-tab case, especially full screen, can be handled in the way that program pauses or just stop rendering. Just need to keep in mind that several things such as networking must be handled when the program is out of focus.
Detect when the user has Alt-Tabbed out and start Sleeping then, eh? It's not too difficult.

Regarding Sleeping in your main game loop, yes there are times when it's a valid choice (provided you know that the timer your Sleep function is based on is accurate) but there are also times when it's not. And what is a valid choice in one situation shouldn't enforce that same choice in all situations, so the argument becomes bogus. Either give the user a "low power mode" option or try to detect it yourself in code. Because if you think the fact that Sleeping is good for mobile devices means that you should always Sleep under every circumstance, you're quite firmly in cargo cult territory.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Also, if your updates are fast enough for 60 fps, why would you draw at 30?

Also, if your updates are fast enough for 60 fps, why would you draw at 30?


That was my first point. Capping the rendering FPS is often frowned upon, why would you do that? As for using Sleep(), of course DON'T USE IT TO COMPUTE TIMING ACCURACY! Just pass 0 or 1milliseconds and use it to let the cpu breath a little (hence removing the 100% usage).
Hi,
I think that the discussion here got a bit side tracked.

I haven't seen in this thread any actual referenced how frame rate capping can be done accurately in the case where vertical sync isn't enabled.

Actually one could argue that if "wait vertical refresh" is enabled, you shouldn't try to cap your frame rate. Consider case where your monitor frequency is 60hz and you try to cap to 45fps. Every 4th frame on screen would be the same as the frame before which in my opinion could look like stuttering. Or your cap is at 30fps and your monitor works at 75hz.

However, for the original question:

[color="#1C2837"][color="#000000"]mUpdateTimer[color="#666600"].[color="#660066"]TimeElapsed[color="#666600"]()

Does the above function return floats or integer numbers. In case of integers, the integer rounding will make your program run slightly faster than you think. It may or may not be a problem. However, if vertical sync is enabled, your calculations may interfere and possibly cause stuttering.

Usually the update frequency is less than the drawing frequency (ie. drawing at 60fps and updating at 30fps).
In this case, for the frames between updates you'll need to interpolate positions and rotations etc.


In my current project I haven't implemented explicit frame rate capping, but logic updates are running at 30fps, which saves a huge deal of calculations and actually increases the drawn frames. Even if I don't cap anything, my processor is running at ~10% load (4 cores with HT) since my GPU is the bottleneck.

Cheers!

This topic is closed to new replies.

Advertisement