Jump to content

  • Log In with Google      Sign In   
  • Create Account


Updating and Drawing at Different Framerates (CPU Issues)


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 Master Jake   Members   -  Reputation: 100

Like
0Likes
Like

Posted 08 June 2011 - 04:05 PM

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


Sponsor:

#2 Dunge   Members   -  Reputation: 405

Like
0Likes
Like

Posted 08 June 2011 - 05:59 PM

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.

#3 Flimflam   Members   -  Reputation: 657

Like
-2Likes
Like

Posted 08 June 2011 - 11:32 PM

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.

#4 kauna   Crossbones+   -  Reputation: 2337

Like
1Likes
Like

Posted 09 June 2011 - 01:41 AM

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]

#5 Flimflam   Members   -  Reputation: 657

Like
0Likes
Like

Posted 09 June 2011 - 03:38 AM

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.

#6 kauna   Crossbones+   -  Reputation: 2337

Like
0Likes
Like

Posted 09 June 2011 - 04:37 AM

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.



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.

#7 mhagain   Crossbones+   -  Reputation: 7803

Like
0Likes
Like

Posted 09 June 2011 - 07:12 AM

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.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#8 EJH   Members   -  Reputation: 314

Like
0Likes
Like

Posted 09 June 2011 - 02:49 PM

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

#9 Dunge   Members   -  Reputation: 405

Like
0Likes
Like

Posted 09 June 2011 - 03:52 PM

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

#10 kauna   Crossbones+   -  Reputation: 2337

Like
0Likes
Like

Posted 10 June 2011 - 12:10 AM

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:

mUpdateTimer.TimeElapsed()

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!

#11 Master Jake   Members   -  Reputation: 100

Like
0Likes
Like

Posted 10 June 2011 - 02:57 PM

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:

mUpdateTimer.TimeElapsed()

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!


Thank you. It actually does return integers, but it wouldn't be a problem to make it return floats. The reason I was minimizing the rendering is because I've read that rendering takes much more time and processing power than updating does. I'm just trying to get on the right track to making a game that runs equally well on all pc's so that I can stop worrying about the boring engine stuff and start doing the fun logic stuff.

P.S. can you post an article link on interpolation or a tutorial or something to help me with it?

#12 Zoner   Members   -  Reputation: 232

Like
0Likes
Like

Posted 12 June 2011 - 09:57 PM

On windows? use MsgWaitForMultipleObjects with a timeout, when enough time has elapsed run whichever of two major update functions you need to process.

If you get a timeout, do your update or render.
If you got a message, process the message, then re-run MsgWaitForMultipleObjects with an updated timeout (based on how much time has elapsed).

This has a bonus of not using 100% cpu unless its falling behind (at which point you need probably need to run some ratio of updates vs rendering (2:1 3:2 etc).

The only real trick is to also track how much time was spent in the update or rendering phase, and reduce the timeout for the next iteration by that amount.


stay away from timeGetTime as the granularity will not be good enough for this (and calling timeBeginPeriod(1) at startup is pretty much essential for a game)


Bonus: if you thread the renderer, then you can still use MsgWaitForMultipleObjects, and have it process 'rendering completed' events from the rendering thread, so you can figure out when the next time a good time to wake up the rendering thread will be.

#13 nife87   Members   -  Reputation: 516

Like
0Likes
Like

Posted 13 June 2011 - 02:57 AM

Is it just me, or does a certain cvar named fps_max come to mind? fps_max is often limited to range from like 10 to 1000 fps.

while (!TimeForShutdown())
{
	Input(); // Process input (however you choose do it)

	while (NeedsUpdate())
 	   Update(); // As many times as needed for the sim. to be in sync.

	if (!AltTabActive() && !NeedsUpdate() && frames_this_second < fps_max)
		Render(); // As many times per second as fps_max allows, whilst not exceeding the next update time.

	if (!NeedsUpdate())
		Sleep(0); // If sim. is still in sync. and rendering is complete.
}

Perhaps, you could measure the use of Sleep(0) the first couple of seconds, and if it continuously slows down the message loop (you have to run Update() multiple times each iteration), just abandon it entirely for that run/match.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS