Request: SDL_AccurateDelay()
TylerGlaiel opened this issue · comments
sample implementation, requires no platform specific code
SDL_Delay, undershooting by a set amount, then wake up and spin until the accurate amount of time has passed
adjust the undershoot amount if it detects that it overslept
//accurate sleep
void SDL_AccurateDelay(double time_ms) {
static double wait_resolution = 1;
static uint64_t perf_freq = SDL_GetPerformanceFrequency();
int64_t current_ticks = SDL_GetPerformanceCounter();
int64_t wait_until = current_ticks + time_ms * perf_freq/1000.0;
int wait_time_ms = floor(time_ms - wait_resolution);
//sleep for as long is safe without overshooting
if(wait_time_ms >= 1) {
SDL_Delay(wait_time_ms);
}
int64_t sleep_diff = (int64_t)SDL_GetPerformanceCounter() - wait_until;
if(sleep_diff > 0) {
double oversleep_ms = sleep_diff*1000.0/perf_freq;
//we overshot, the wait resolution is probably too low.
//tweak wait_resolution for the next time this is called (slightly)
//if the diff was more than 5ms just assume its a weird OS hiccup and not an issue with resolution
if(oversleep_ms < 5) {
wait_resolution += oversleep_ms+0.1;
//5ms is a lot so lets have that be the max.
if(wait_resolution > 5) wait_resolution = 5;
//todo: should we adjust the resolution back down if we detect that we're consistently undersleeping by a lot?
//since we're just spinning here theres room to do a little extra work
}
}
//spin till the target time
while(SDL_GetPerformanceCounter() < wait_until) {
YieldProcessor(); //expands to _mm_pause; intrinsic on windows, not the same thing as thread yield
}
}
I understand why you want this, but this is loaded with footguns. It makes more sense in the specific context of frame pacing than a general function that people might use everywhere and wonder why their application is using so much CPU time.
@icculus, thoughts?
I mean I also kind of think its a footgun that SDL_Delay is very inaccurate (I've seen a lot of bad sample code out there that uses it incorrectly as a result)
it seems there's some processor intrinsic / asm that can help with the cpu usage here (__mm_pause()) but I dont really know quite how those work (edit, on windows shove YieldProcessor(); in the spin loop))