Game timing in XNA Game Studio 2.0

Game timing in XNA Game Studio 2.0

  • Comments 7

In a previous post I explained how the game timing system works when Game.IsFixedTimeStep is set to true:

  • We will call your Update method exactly 60 times per second
  • We will call your Draw method whenever we feel like it

This is still true in the 2.0 framework, but we changed our implementation of "whenever we feel like it".

In 1.0, things worked like this:

  • Call Update as many times as needed to catch up to the current time
  • Call Draw repeatedly until it is time for the next Update

In 2.0, the Draw behavior has changed:

  • Call Update as many times as needed to catch up to the current time
  • Call Draw once
  • Wait until it is time for the next Update

In other words, we no longer call Draw more than once without an Update in between. That was a pointless thing to do, as it would just render the exact same image a second time!

Here's why the new behavior is an improvement:

  • Consider a fixed timestep game running at 60 fps, with vsync enabled on a 75 hz monitor
  • Update completes in, let's say, 3 milliseconds
  • Draw completes in, let's say, 5 milliseconds
  • This has taken 8 milliseconds total
  • 60 fps is 16.7 milliseconds, so it is not yet time for another Update
  • We call Draw again
  • Because vsync is enabled, the graphics driver waits 13 milliseconds for the next 75 hz retrace
  • Yikes! By the time this returns, we have taken 21 milliseconds in total, so we are late for the next Update

In practice the effects of this were very minor, because the next Update would quickly catch up to the correct time, but it caused some unnecessary jitter in the rate of calls to Update.

In 2.0, we call Update at more precisely controlled times:

  • Update completes in 3 milliseconds
  • Draw completes in 5 milliseconds
  • There are 8.7 milliseconds left over, so we wait exactly that long
  • Rinse, lather, repeat

Apart from noticing how things now run slightly smoother, how might your game be affected by this change?

The main impact is on games that measure their framerate, for instance using the technique I described here. To take accurate framerate measurements, you should disable vsync and select variable timestep mode. But with the 1.0 fixed timestep behavior, you could still get kind-of-almost-right framerate measurements just by counting the number of Draw calls. With the 2.0 behavior that will just return a steady 60 fps, even if your game is actually capable of running much faster.

Seems like a step backward, huh?

Not really. The thing is, trying to measure the framerate of a fixed timestep update is fundamentally bogus. We want to measure the framerate in order to know how much performance headroom is available. But consider a game where Update takes 15 milliseconds, and Draw 0.5 milliseconds. With the 1.0 behavior we would call Update once, then Draw 4 times, before our 16.7 millisecond timestep was used up. The game thus appears to be running at 240 frames per second. Awesome! That means you have lots of headroom to add new functionality, neh? Not so: your Update method is right on the verge of fitting, and everything will collapse if you make this even slightly slower.

In 2.0, you can't use fixed timestep mode to measure framerate. But you never really could in the first place! It sometimes seemed like this worked using the 1.0 behavior, but would return misleading information.

So how should you measure the framerate of a 2.0 game?

I recommend doing this exactly as before, but also adding a special configuration that will run in variable timestep mode for taking more precise measurements. Here's how you do that:

  • Pull down the project configuration combo from the toolbar (the one where you select Debug or Release), and click "Configuration Manager"
  • In the project list, click the Configuration column and choose "<New...>"
  • Name the configuration "Profile", and copy settings from the existing Release configuration
  • Close the Configuration Manager
  • Right-click your project in the Solution Explorer, and open Properties
  • Select the Build tab, make sure the new Profile configuration is active, and enter "PROFILE" in the "Conditional compilation symbols" box
  • In your game constructor, add this code:
      #if PROFILE
          this.IsFixedTimeStep=false;
          graphics.SynchronizeWithVerticalRetrace = false;
      #endif

You can now quickly switch between the Debug, Release, and Profile configurations. Debug and Release will run nice and smoothly, with simple fixed timestep update logic. Your framerate counter will show if you are falling behind the desired framerate, but will not be able to detect how much headroom is available if you are running faster than the target speed. The Profile configuration will just run flat out as fast as possible, which isn't so good for actually playing the game, but provides more useful framerate data.

  • No wonder I was "pushed" to measure the update calls instead of the draw ones ... the latter was giving me misleading numbers.

  • Cheers for this info Shawn i had wondered why my FPS timing in XNA 1.0 had never been as accurate as i had wished.

    I have now changed the way i am doing FPS timings in XNA 2.0 and now get accurate FPS data even when running in fixed timestep :)

    If its okay i have a link to my website where i have put up a blank project with the FPS timing code in it here:

    http://www.artificial-studios.co.uk/?p=225

  • Could you should some flow diagram about the 'draw', 'update' and 'retrace of 75Hz'? That's confused. Thanks

  • This is actually quite upsetting to me.  Yes calling Draw multiple times without an update is useless.  However if you are using interpolation in your draw, calling multiple draws in the mean time is extremely meaningful.

    I understand that most beginners and some advanced game developers will opt out of doing this but I prefer having the interpolated draw.  Now you seem to use vSync as a reason for not wanting multiple draws when waiting to update.  However, what if we are not using vSync and wanted the smoothest framerate out there even if tearing happens?

    Now yes that argument may be moot but let me give you a better argument.  What if I want to do my update at 30 fps and my monitor refresh is 60hz.  I could get away with a 30 fps update if I use interpolated draws to smooth the movement of my objects. Now with the new draw only once per update cycle, this is no longer possible.

    The next thing you could say is that if I wanted to do that I could just move to a variable time step and to the timing myself.  But why should I have to do that?  Why could it not be that there could be a flag set that allows me to choose whether or not to have multiple draws per update cycle much like the fixedTimeStep flag can be changed?  I really don't get why such an option would be restricted.

  • > I really don't get why such an option would be restricted.

    Because we don't have time to implement all possible permutations of behavior that anybody might ever want!

    We chose the behavior that we think works the best and is the best default for the most games.

    If you want some different behavior, you are more than welcome to go implement that yourself!

  • I have a question regarding about creating an app on winform but the graphics portion behind is XNA app.

    Is it always in the variable time step?

  • haxpor: the timing system described in this article is part of the Game class, which is not used when you make a WinForms app. In WinForms, depending on the app redraws may be triggered by paint events, or for animating scenes perhaps using a Win32 timer or the Application.Idle event. In any case, you must write your own code to examine the current clock time and decide how far to update your animations, simulation, etc, based on how much time has passed. It is entirely up to you whether you write the code to do this using variable or fixed timestep logic.

Page 1 of 1 (7 items)
Leave a Comment
  • Please add 6 and 8 and type the answer here:
  • Post