2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-05-13 17:11:22 +00:00

Improve frame limiter on Windows

This commit is contained in:
Luke Street 2025-04-06 20:25:58 -06:00
parent eae0696bea
commit 8a046832eb

View File

@ -81,29 +81,35 @@ private:
}
#if _WIN32
bool m_initialized;
double m_countPerNs;
void NanoSleep(const duration_t duration) {
if (!m_initialized) {
static bool initialized = false;
static double countPerNs;
static size_t numSleeps = 0;
// QueryPerformanceFrequency's result is constant, but calling it occasionally
// appears to stabilize QueryPerformanceCounter. Without it, the game drifts
// from 60hz to 144hz. (Cursed, but I suspect it's NVIDIA/G-SYNC related)
if (!initialized || numSleeps++ % 1000 == 0) {
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
m_countPerNs = static_cast<double>(freq.QuadPart) / 1000000000.0;
m_initialized = true;
if (QueryPerformanceFrequency(&freq) == 0) {
spdlog::warn("QueryPerformanceFrequency failed: {}", GetLastError());
return;
}
countPerNs = static_cast<double>(freq.QuadPart) / 1e9;
initialized = true;
numSleeps = 0;
}
DWORD ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
auto tickCount = static_cast<LONGLONG>(static_cast<double>(duration.count()) * m_countPerNs);
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
if (ms > 10) {
// Adjust for Sleep overhead
::Sleep(ms - 10);
LARGE_INTEGER start, current;
QueryPerformanceCounter(&start);
LONGLONG ticksToWait = static_cast<LONGLONG>(duration.count() * countPerNs);
if (DWORD ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); ms > 1) {
::Sleep(ms - 1);
}
auto end = count.QuadPart + tickCount;
do {
QueryPerformanceCounter(&count);
} while (count.QuadPart < end);
QueryPerformanceCounter(&current);
_mm_pause(); // Yield CPU
} while (current.QuadPart - start.QuadPart < ticksToWait);
}
#else
void NanoSleep(const duration_t duration) { std::this_thread::sleep_for(duration); }