libsdl-org / SDL

Simple Directmedia Layer

Home Page:https://libsdl.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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))