Windows Quake - Improved Timer
Posted: Sun May 15, 2011 6:59 pm
Not so much a tutorial as it is an invitation to critique and suggestions for further possible improvements and refinements. If you think it's crap, some words on why you think it's crap would be nice.
The background.
We have two main methods of timing on Windows: QueryPerformanceCounter and timeGetTime. QueryPerformanceCounter sucks because it's unstable on many PCs but it does have high resolution. timeGetTime sucks because it's resolution - while quite high - isn't high enough for Quakes 72 FPS but it is stable on all PCs.
So what I did was use timeGetTime as a solid baseline and QueryPerformanceCounter to fill in the sub-millisecond gaps:
The background.
We have two main methods of timing on Windows: QueryPerformanceCounter and timeGetTime. QueryPerformanceCounter sucks because it's unstable on many PCs but it does have high resolution. timeGetTime sucks because it's resolution - while quite high - isn't high enough for Quakes 72 FPS but it is stable on all PCs.
So what I did was use timeGetTime as a solid baseline and QueryPerformanceCounter to fill in the sub-millisecond gaps:
Code: Select all
double Sys_FloatTime (void)
{
static qboolean firsttime = true;
static __int64 qpcfreq = 0;
static __int64 currqpccount = 0;
static __int64 lastqpccount = 0;
static double qpcfudge = 0;
DWORD currtime = 0;
static DWORD lasttime = 0;
static DWORD starttime = 0;
if (firsttime)
{
timeBeginPeriod (1);
starttime = lasttime = timeGetTime ();
QueryPerformanceFrequency ((LARGE_INTEGER *) &qpcfreq);
QueryPerformanceCounter ((LARGE_INTEGER *) &lastqpccount);
firsttime = false;
return 0;
}
// get the current time from both counters
currtime = timeGetTime ();
QueryPerformanceCounter ((LARGE_INTEGER *) &currqpccount);
if (currtime != lasttime)
{
// requery the frequency in case it changes (which it can on multicore machines)
QueryPerformanceFrequency ((LARGE_INTEGER *) &qpcfreq);
// store back times and calc a fudge factor as timeGetTime can overshoot on a sub-millisecond scale
qpcfudge = ((double) (currqpccount - lastqpccount) / (double) qpcfreq) - ((double) (currtime - lasttime) * 0.001);
lastqpccount = currqpccount;
lasttime = currtime;
}
else qpcfudge = 0;
// the final time is the base from timeGetTime plus an addition from QPC
return ((double) (currtime - starttime) * 0.001) + ((double) (currqpccount - lastqpccount) / (double) qpcfreq) + qpcfudge;
}