Back QueryPerformanceCounter with a monotonic clock

The linux shim sampled gettimeofday(), which reports CLOCK_REALTIME and can
be slewed or stepped backwards by time synchronisation. Clock::update()
subtracts successive samples to derive frame time, so a backwards step
produced a negative elapsed time, which AlterScheduler then reported as
"no forward time movement" once per affected frame.

Use clock_gettime(CLOCK_MONOTONIC) and keep microsecond units so the value
still matches QueryPerformanceFrequency(). Falls back to gettimeofday() if
the call fails. All getFrameStartTimeMs() consumers compare values
relatively, so nothing depends on the previous epoch-based origin.
This commit is contained in:
Sais
2026-07-25 03:52:43 -04:00
parent ec3419dbb0
commit 4fac50d2e5
@@ -27,10 +27,23 @@ char* _itoa(int value, char* stringOut, int radix)
bool QueryPerformanceCounter(__int64* time)
{
struct timeval tv;
gettimeofday(&tv, nullptr);
*time = static_cast<LARGE_INTEGER>(tv.tv_sec);
*time = (*time * 1000000) + static_cast<LARGE_INTEGER>(tv.tv_usec);
// Must be monotonic. gettimeofday() reports CLOCK_REALTIME, which NTP can
// slew or step backwards; callers subtract successive samples to derive
// frame time, so a backwards step produced negative elapsed times (see
// AlterScheduler "no forward time movement"). CLOCK_MONOTONIC never goes
// backwards. Units stay microseconds to match QueryPerformanceFrequency().
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
{
struct timeval tv;
gettimeofday(&tv, nullptr);
*time = static_cast<LARGE_INTEGER>(tv.tv_sec);
*time = (*time * 1000000) + static_cast<LARGE_INTEGER>(tv.tv_usec);
return TRUE;
}
*time = static_cast<LARGE_INTEGER>(ts.tv_sec);
*time = (*time * 1000000) + static_cast<LARGE_INTEGER>(ts.tv_nsec / 1000);
return TRUE;
}