Accurate timer events w/ no window available.

  • Thread starter Thread starter JasonC
  • Start date Start date
J

JasonC

Using C++, platform is Windows XP SP3.

I have a multimedia application that runs a rendering loop that must be throttled to 60 iterations / second max. Currently it is implemented using a dirty and inconsistent wait loop, which I've included below. I am looking for a better way to implement frame rate throttling, and am looking for a timed event that meets the following requirements:

* Does not require a window handle.
* Does not require a message processing loop.
* Minimum CPU usage is very important.
* Consistent, accurate to within 0.1 ms would be ideal.
* If loop time is greater than 1/60th of a second, it must still run the loop as fast as possible rather than skipping timeslices (e.g. run at 55fps instead of halving it to 30 with a lot of idle time).

The SetTimer interface requires a message processing loop, and is not appropriate for this application. It also has dubious accuracy. I have just recently discovered the MSHTML Timer API (http://msdn.microsoft.com/en-us/library/aa741307(VS.85).aspx#The_MSHTML_Timer_API), but have not tried using it yet. However, it appears that that also required a window handle to be available, but maybe I'm wrong?

Current implementation, does not meet accuracy / consistency requirements in certain situations. The idea is to use the performance counter and wait in a loop, but use Sleep() with various parameters to minimize CPU usage (it is expected that Sleep(1) takes significantly longer than 1 ms), depending on the amount of time left to spare:


// vars used below, for context
LARGE_INTEGER tn; // current time
LARGE_INTEGER tl; // last frame
LARGE_INTEGER tfreq; // counter freq
// 1.0 / max frame rate (in this
// case, 1.0/60.0=0.016)
double tminftime;

// initial values of vars
// used below
tminftime = 1.0 / 60.0;
QueryPerformanceFrequency(&tfreq);
QueryPerformanceCounter(&tl);

while (...) {
renderFrame();


// throttle frame rate; pause
// for remainder of 1/60th
// second time slice
while (true) {
QueryPerformanceCounter(&tn);
double realdt = (double)(tn.QuadPart - tl.QuadPart) / (double)tfreq.QuadPart;
// if not enough time passed,
// then wait.
if (realdt < tminftime) {
double timeleft =
tminftime - realdt;
if (timeleft > 0.011)
Sleep(1); // be nicer
else if (timeleft > 0.001)
Sleep(0); // be nice
// if < 1ms then dont be
// nice at all.
} else {
break;
}
}
tl = tn;


}


Thanks,
Jason
 
Back
Top