|
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 50fps 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; // this is the current time
LARGE_INTEGER tl; // time of last frame
LARGE_INTEGER tfreq; // performance counter frequency
double tminftime; // 1.0 / max frame rate (in this case,
1.0/60.0=0.016)
// 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 we're throttling frame rate and not enough time
has passed, wait.
if (realdt < tminftime) {
double timeleft = tminftime - realdt;
if (timeleft 0.011) // if there's plenty of time
left...
Sleep(1); // ... be really nice
else if (timeleft 0.001) // if we're getting
closer...
Sleep(0); // ... be kind of nice
// and if < 1 ms remaining then don't
be nice at all.
} else {
break;
}
}
tl = tn;
}
Thanks,
Jason |