diff --git a/src/i_timer.c b/src/i_timer.c index b4d5880e..96c68d48 100644 --- a/src/i_timer.c +++ b/src/i_timer.c @@ -24,49 +24,63 @@ #include "doomstat.h" #include "m_argv.h" -static int MSToTic(Uint32 time) +static uint64_t basecounter = 0; +static uint64_t basefreq = 0; + +static int MSToTic(uint32_t time) { return time * TICRATE / 1000; } -static Uint32 TicToMS(int tic) +static uint64_t TicToCounter(int tic) { - return (Uint32)tic * 1000 / TICRATE; + return (uint64_t)tic * basefreq / TICRATE; } -static Uint32 basetime = 0; - int I_GetTimeMS(void) { - Uint32 time; + uint64_t counter = SDL_GetPerformanceCounter(); - time = SDL_GetTicks(); + if (basecounter == 0) + basecounter = counter; - if (basetime == 0) - basetime = time; + return ((counter - basecounter) * 1000ull) / basefreq; +} - return time - basetime; +uint64_t I_GetTimeUS(void) +{ + uint64_t counter = SDL_GetPerformanceCounter(); + + if (basecounter == 0) + basecounter = counter; + + return ((counter - basecounter) * 1000000ull) / basefreq; } int time_scale = 100; -static Uint32 GetTimeMS_Scaled(void) +static uint64_t GetPerfCounter_Scaled(void) { - Uint32 time; + uint64_t counter; - if (time_scale == 100) - { - time = SDL_GetTicks(); - } - else - { - time = SDL_GetTicks() * time_scale / 100; - } + counter = SDL_GetPerformanceCounter() * time_scale / 100; - if (basetime == 0) - basetime = time; + if (basecounter == 0) + basecounter = counter; - return time - basetime; + return counter - basecounter; +} + +static uint32_t GetTimeMS_Scaled(void) +{ + uint64_t counter; + + counter = SDL_GetPerformanceCounter() * time_scale / 100; + + if (basecounter == 0) + basecounter = counter; + + return ((counter - basecounter) * 1000ull) / basefreq; } int I_GetTime_RealTime(void) @@ -104,19 +118,21 @@ int (*I_GetFracTime)(void) = I_GetFracTime_Scaled; void I_InitTimer(void) { + basefreq = SDL_GetPerformanceFrequency(); + I_GetTime = I_GetTime_Scaled; I_GetFracTime = I_GetFracTime_Scaled; } void I_SetTimeScale(int scale) { - Uint32 time; + uint64_t counter; - time = GetTimeMS_Scaled(); + counter = GetPerfCounter_Scaled(); time_scale = scale; - basetime += (GetTimeMS_Scaled() - time); + basecounter += (GetPerfCounter_Scaled() - counter); } void I_SetFastdemoTimer(boolean on) @@ -130,11 +146,11 @@ void I_SetFastdemoTimer(boolean on) } else if (I_GetTime == I_GetTime_FastDemo) { - Uint32 time; + uint64_t counter; - time = TicToMS(I_GetTime_FastDemo()); + counter = TicToCounter(I_GetTime_FastDemo()); - basetime += (GetTimeMS_Scaled() - time); + basecounter += (GetPerfCounter_Scaled() - counter); I_GetTime = I_GetTime_Scaled; I_GetFracTime = I_GetFracTime_Scaled; diff --git a/src/i_timer.h b/src/i_timer.h index b2d83cdf..15407863 100644 --- a/src/i_timer.h +++ b/src/i_timer.h @@ -30,7 +30,9 @@ int I_GetTime_RealTime(void); // killough extern int (*I_GetFracTime)(void); // [FG] Same as I_GetTime, but returns time in milliseconds -int I_GetTimeMS(); +int I_GetTimeMS(void); + +uint64_t I_GetTimeUS(void); void I_SetTimeScale(int scale); diff --git a/src/i_video.c b/src/i_video.c index 4d850fb4..8aacc637 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -970,21 +970,29 @@ void I_FinishUpdate(void) if (uncapped) { - if (fpslimit >= TICRATE) - { - static uint64_t last_frame; - uint64_t current_frame; + if (fpslimit >= TICRATE) + { + uint64_t target_time = 1000000ull / fpslimit; + static uint64_t start_time; - current_frame = (I_GetTimeMS() * fpslimit) / 1000; + while (1) + { + uint64_t current_time = I_GetTimeUS(); + uint64_t elapsed_time = current_time - start_time; + uint64_t remaining_time = 0; - while (current_frame == last_frame) - { - I_Sleep(1); - current_frame = (I_GetTimeMS() * fpslimit) / 1000; - } + if (elapsed_time >= target_time) + { + start_time = current_time; + break; + } - last_frame = current_frame; - } + remaining_time = target_time - elapsed_time; + + if (remaining_time > 1000) + I_Sleep((remaining_time - 1000) / 1000); + } + } // [AM] Figure out how far into the current tic we're in as a fixed_t. fractionaltic = I_GetFracTime();