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).
void Update(DX::StepTimer const& timer)
float delta = float(timer.GetElapsedSeconds());
// Do your game update here
// Do your frame render here
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
For pause/resume behavior, be sure to make use of
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.
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
QueryPerformanceFrequency. See Acquiring high-resolution time stamps on MSDN 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
<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
steady_clock are not based on
QueryPerformanceCounter, and instead use
GetSystemTimeAsFileTime which is not nearly as high-precision. This is fixed in Visual Studio 2015.
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
The source file attached to this post is provided subject to the MIT license.