SDL icon indicating copy to clipboard operation
SDL copied to clipboard

SDL3 Proposal: Add new "precise timers"

Open nightmareci opened this issue 1 year ago • 3 comments

In my own code, I took inspiration from the snake game example, and set up an SDL timer that generates events at a desired pace for running the logic in my code, which worked acceptably. But I've since refactored it into my own timer-esque thread, that internally uses a combination of the fixed timestep algorithm and the new SDL_DelayPrecise() function, resulting in much more consistent update timing. I'm proposing adding new timer types that internally use SDL_DelayPrecise() rather than refactoring the existing timers to delay-precise, because delay-precise uses more CPU/power; in many cases, it's entirely fine to have sloppier timing with the current timers' behavior, in exchange for the lower CPU/power usage of their ordinary delays.

nightmareci avatar Oct 12 '24 19:10 nightmareci

SDL_AddTimerPrecise()? Seems good to me, do you want to whip up a PR?

slouken avatar Oct 12 '24 20:10 slouken

I took a stab at it. Let me know if there's something off about it.

nightmareci avatar Oct 13 '24 20:10 nightmareci

@slouken Well, I've decided that no change should be made to timers. I did some heavy A/B testing of using SDL_DelayNS() and SDL_DelayPrecise() in the snake game example, and there's not really any major difference, due to threading stuff, as you said. And, users can implement fixed timestepping with the current timer APIs if desired, leaving the option for the old timer behavior when no fixed timestepping logic is in effect. Changing the snake game example to using a nanosecond timer, this produces better timing than without the new logic:

#define STEP_RATE_IN_NANOSECONDS (STEP_RATE_IN_MILLISECONDS * SDL_NS_PER_MS)
static Uint64 sdl_timer_callback_(void *payload, SDL_TimerID timer_id, Uint64 interval)
{
    static bool first = true;
    static Uint64 last;
    static Uint64 start;
    static Sint64 accumulated;

    if (first) {
        first = false;
        start = SDL_GetTicksNS();
        accumulated = 0;
    } else {
	last = start;
	start = SDL_GetTicksNS();
	const Sint64 next_accumulated = accumulated + (start - last) - STEP_RATE_IN_NANOSECONDS;
        if (next_accumulated >= STEP_RATE_IN_NANOSECONDS || (next_accumulated < 0 && -next_accumulated >= STEP_RATE_IN_NANOSECONDS)) {
            accumulated = 0;
        } else {
            accumulated = next_accumulated;
        }
    }

    SDL_Event event;
    SDL_zero(event);
    event.type = SDL_EVENT_USER;
    SDL_PushEvent(&event);
    return STEP_RATE_IN_NANOSECONDS - accumulated;
}

nightmareci avatar Oct 14 '24 20:10 nightmareci

Okay, sounds good.

slouken avatar Oct 21 '24 15:10 slouken