Skip to content

Commit 8a04683

Browse files
committed
Improve frame limiter on Windows
1 parent eae0696 commit 8a04683

File tree

1 file changed

+23
-17
lines changed

1 file changed

+23
-17
lines changed

Runtime/CMain.cpp

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,29 +81,35 @@ class Limiter {
8181
}
8282

8383
#if _WIN32
84-
bool m_initialized;
85-
double m_countPerNs;
86-
8784
void NanoSleep(const duration_t duration) {
88-
if (!m_initialized) {
85+
static bool initialized = false;
86+
static double countPerNs;
87+
static size_t numSleeps = 0;
88+
89+
// QueryPerformanceFrequency's result is constant, but calling it occasionally
90+
// appears to stabilize QueryPerformanceCounter. Without it, the game drifts
91+
// from 60hz to 144hz. (Cursed, but I suspect it's NVIDIA/G-SYNC related)
92+
if (!initialized || numSleeps++ % 1000 == 0) {
8993
LARGE_INTEGER freq;
90-
QueryPerformanceFrequency(&freq);
91-
m_countPerNs = static_cast<double>(freq.QuadPart) / 1000000000.0;
92-
m_initialized = true;
94+
if (QueryPerformanceFrequency(&freq) == 0) {
95+
spdlog::warn("QueryPerformanceFrequency failed: {}", GetLastError());
96+
return;
97+
}
98+
countPerNs = static_cast<double>(freq.QuadPart) / 1e9;
99+
initialized = true;
100+
numSleeps = 0;
93101
}
94102

95-
DWORD ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
96-
auto tickCount = static_cast<LONGLONG>(static_cast<double>(duration.count()) * m_countPerNs);
97-
LARGE_INTEGER count;
98-
QueryPerformanceCounter(&count);
99-
if (ms > 10) {
100-
// Adjust for Sleep overhead
101-
::Sleep(ms - 10);
103+
LARGE_INTEGER start, current;
104+
QueryPerformanceCounter(&start);
105+
LONGLONG ticksToWait = static_cast<LONGLONG>(duration.count() * countPerNs);
106+
if (DWORD ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); ms > 1) {
107+
::Sleep(ms - 1);
102108
}
103-
auto end = count.QuadPart + tickCount;
104109
do {
105-
QueryPerformanceCounter(&count);
106-
} while (count.QuadPart < end);
110+
QueryPerformanceCounter(&current);
111+
_mm_pause(); // Yield CPU
112+
} while (current.QuadPart - start.QuadPart < ticksToWait);
107113
}
108114
#else
109115
void NanoSleep(const duration_t duration) { std::this_thread::sleep_for(duration); }

0 commit comments

Comments
 (0)