store win32 timer start & frequency in terms of nanoseconds

This commit is contained in:
jacob 2025-01-29 10:56:40 -06:00
parent 4eef91dd63
commit a20e8eced5

View File

@ -98,8 +98,9 @@ struct win32_window {
GLOBAL struct {
SYSTEM_INFO info;
LARGE_INTEGER timer_frequency;
LARGE_INTEGER timer_start;
i64 timer_frequency_s;
i64 timer_frequency_ns;
i64 timer_start_ns;
i32 scheduler_period_ms;
DWORD thread_tls_index;
u32 main_thread_id;
@ -235,21 +236,12 @@ INTERNAL struct sys_datetime win32_time_to_sys_time(SYSTEMTIME st)
};
}
/* prevent 64-bit overflow when computing relative timestamp
* https://github.com/floooh/sokol/blob/d4ac122f36d7659a18b312fd4fa2317fb9e06a63/sokol_time.h#L203
*/
INTERNAL i64 _win32_i64_muldiv(i64 value, i64 numer, i64 denom) {
i64 q = value / denom;
i64 r = value % denom;
return q * numer + r * numer / denom;
}
struct sys_timestamp sys_timestamp_prog(void)
{
struct sys_timestamp ts;
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
ts.v = (u64)_win32_i64_muldiv(time.QuadPart - G.timer_start.QuadPart, 1000000000, G.timer_frequency.QuadPart);
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
ts.v = (qpc.QuadPart * G.timer_frequency_ns) - G.timer_start_ns;
return ts;
}
@ -1951,24 +1943,24 @@ INTERNAL void win32_precise_sleep_timer(f64 seconds, HANDLE timer)
/* TODO: Does the high frequency timer even require setting / scaling of
* timeBeginPeriod/scheduler_period_ms? There isn't much documentation. */
i64 qpc_per_second = G.timer_frequency.QuadPart;
i64 qpc_per_second = G.timer_frequency_s;
i32 scheduler_period_ms = G.scheduler_period_ms;
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
INT64 target_qpc = (INT64)(qpc.QuadPart + seconds * qpc_per_second);
i64 target_qpc = (i64)(qpc.QuadPart + seconds * qpc_per_second);
/* TODO: Maybe increase tolerance for higher precision but more power usage */
//const double tolerance = 0.001200 * scheduler_period_ms;
const double tolerance = 0.000520 * scheduler_period_ms;
//const double tolerance = 1 * scheduler_period_ms;
//const f64 tolerance = 0.001200 * scheduler_period_ms;
const f64 tolerance = 0.000520 * scheduler_period_ms;
//const f64 tolerance = 1 * scheduler_period_ms;
INT64 max_ticks = (INT64)scheduler_period_ms * 9500;
i64 max_ticks = (i64)scheduler_period_ms * 9500;
while (true) {
__profscope(win32_sleep_part);
/* Break sleep up into parts that are lower than scheduler period */
double remaining_seconds = (double)(target_qpc - qpc.QuadPart) / (double)qpc_per_second;
INT64 sleep_ticks = (INT64)((remaining_seconds - tolerance) * 10000000);
f64 remaining_seconds = (f64)(target_qpc - qpc.QuadPart) / (f64)qpc_per_second;
i64 sleep_ticks = (i64)((remaining_seconds - tolerance) * 10000000);
if (sleep_ticks <= 0) {
break;
}
@ -1992,7 +1984,7 @@ INTERNAL void win32_precise_sleep_timer(f64 seconds, HANDLE timer)
INTERNAL void win32_precise_sleep_legacy(f64 seconds)
{
__prof;
i64 qpc_per_second = G.timer_frequency.QuadPart;
i64 qpc_per_second = G.timer_frequency_s;
i32 scheduler_period_ms = G.scheduler_period_ms;
LARGE_INTEGER qpc;
@ -2080,13 +2072,18 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
/* Query system info */
GetSystemInfo(&G.info);
QueryPerformanceFrequency(&G.timer_frequency);
QueryPerformanceCounter(&G.timer_start);
{
LARGE_INTEGER qpf;
QueryPerformanceFrequency(&qpf);
G.timer_frequency_s = qpf.QuadPart;
G.timer_frequency_ns = 1000000000 / qpf.QuadPart;
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
G.timer_start_ns = qpc.QuadPart * G.timer_frequency_ns;
TIMECAPS caps;
timeGetDevCaps(&caps, sizeof caps);
G.scheduler_period_ms = (i32)caps.wPeriodMin;
}
timeGetDevCaps(&caps, sizeof(caps));
/* Set up timing period */
timeBeginPeriod(G.scheduler_period_ms);