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