Games for Windows and the DirectX SDK blog

Technical tips, tricks, and news about game development for Microsoft platforms including desktop, Xbox, and UWP

Project maintained by walbourn Hosted on GitHub Pages — Theme by mattgraham
Home | Posts by Tag | Posts by Month

Understanding Game Time Revisited


Originally posted to Chuck Walbourn's Blog on MSDN,

For as simple a task as it seems, tracking time in Windows games is full of potential pitfalls. There are a number of different ways to do it, and the naive ones seem to work fine initially but then you have all kinds of problems later.

Case in point: the Visual Studio 2012 templates for Windows Store apps for Windows 8.0 and Windows phone 8.0. The initial version of the Direct3D game template included a simple WinRT BasicTimer class. This uses QueryPerformanceCounter to track delta and elapsed time per frame. This variable-length timing approach is very common in games, and is used by the legacy DXUT framework as well. This implementation does suffer from two major problems, however. First, it makes the mistake of using a float rather than a double to track accumulated elapsed time (see Bruce Dawson’s blog for why this is a classic blunder). Second, it does not support fixed-step gaming time which is often easier and can be more robust.

XNA Game Studio demonstrated that fixed-step timing can be a lot more useful, which was the default for the framework. See Shawn Hargreaves posts Understanding GameTime and Game timing in XNA Game Studio 2.0.

For the Visual Studio 2013 templates for Windows Store apps for Windows 8.1 and Windows phone 8.1, they no longer include BasicTimer and instead they have the C++ StepTimer class. This class also uses QueryPerformanceCounter, but supports both variable-length and fixed-step timing. It makes use of 64-bit accumulation for elapsed time, and returns time in units of seconds as a double. The timer also ensures that there’s an upper-bound to the maximum delta since debugging or pausing can otherwise result in huge time jumps that are not well handled by game code. As an added bonus, since it’s no longer a WinRT class you can use it for Win32 desktop C++ programs too (with a minor switch of basic types).

#include <Windows.h>
#include "StepTimer.h"

DX::StepTimer s_timer;

void Update(DX::StepTimer const& timer)
    float delta = float(timer.GetElapsedSeconds());
    // Do your game update here

void Render()
    // Do your frame render here

void Tick()

By default StepTimer uses variable-length timing, but you can easily make it used fixed-step timing instead (for example 60 times a second):

timer.SetTargetElapsedSeconds(1.f / 60.f);

For each frame of your game, you’d call Tick once. This will call Update as many times as needed to ensure you are up-to-date, and then call Render once.

For pause/resume behavior, be sure to make use of ResetElapsedTime.

See this topic page for more details.

Windows Store apps/Windows phone: If your application is still using BasicTimer, you should consider updating your code to use StepTimer instead. It has no dependencies on Windows 8.1 or Windows phone 8.1.

Templates: This class is in use for the stock DirectX app templates in Visual Studio 2013 or later, and in the Xbox One XDK templates. I also make use of it in all the directx-vs-templates.

QueryPerformanceCounter vs. RDTSC

The Intel Pentium rdtsc instruction was introduced as a way to reliably get processor cycle counts for profiling and high-resolution timing. Early games used this instruction extensively to get and compute game time. Compared to older techniques like hooking the timer interrupt, this was much better. Over time, however, problems have cropped up. The transition to multiple-core computing was a problem in the Windows XP era when the AMD Athalon X2 did not synchronize the rdtsc clock between the cores (see KB 909944), breaking a common assumption that time would always be monotonically increasing (i.e. not go backwards!). Aggressive power management schemes like Intel’s SpeedStep also broke another basic assumption that the CPU processor frequency (required to convert a processor cycle count into time units of seconds) was fixed. In fact, this is another version of age-old problem with PC games that first lead to the “Turbo button”.

The work around to all these problems is the Win32 API QueryPerformanceCounter and QueryPerformanceFrequency. See Acquiring high-resolution time stamps on Microsoft Docs for more details and recommendations.

Note that the main issue game developers have hit switching from rdtsc to QPC is that rdtsc was so cheap that they called it tens of thousands of time a frame, where QPC is a system call that can be a bit slower and potentially relies on some other hardware component in the system to get a steady clock result. The best solution here is to try to centralize your delta and elapsed time computation so you don’t feel the need to recompute the delta more than a few times per frame.

Windows RT/Windows phone: The ARM instruction rdpmccntr64 is not guaranteed to be sync’d between cores, and rdtsc is not supported for this platform. Use QueryPerformanceCounter.

C++11 chrono

With C++11’s <chrono> header you may well be tempted to go with the ‘standards-based’ solution and use high_precision_clock. Unfortunately, the VS 2012 and VS 2013 implementations of both high_precision_clock and steady_clock are not based on QueryPerformanceCounter, and instead use GetSystemTimeAsFileTime which is not nearly as high-precision as you’d expect–this is fixed in Visual Studio 2015 or later.


If you don’t really need a high-precision timer and instead can handle a resolution of 10 to 16 milliseconds, then GetTickCount may be a good option which returns the number of milliseconds since the system was started. Note that you should really use GetTickCount64 (requires Windows Vista or later) instead to avoid potential overflow problems. See MSDN.

Xbox One: The Xbox One XDK and Xbox One ADK Direct3D game templates also made use of BasicTimer. As of the September 2014 version, they now use StepTimer instead.

The source file is subject to the MIT license and is available on GitHub