store win32 timer start & frequency in terms of nanoseconds
This commit is contained in:
parent
4eef91dd63
commit
a20e8eced5
@ -98,8 +98,9 @@ struct win32_window {
|
|||||||
|
|
||||||
GLOBAL struct {
|
GLOBAL struct {
|
||||||
SYSTEM_INFO info;
|
SYSTEM_INFO info;
|
||||||
LARGE_INTEGER timer_frequency;
|
i64 timer_frequency_s;
|
||||||
LARGE_INTEGER timer_start;
|
i64 timer_frequency_ns;
|
||||||
|
i64 timer_start_ns;
|
||||||
i32 scheduler_period_ms;
|
i32 scheduler_period_ms;
|
||||||
DWORD thread_tls_index;
|
DWORD thread_tls_index;
|
||||||
u32 main_thread_id;
|
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 sys_timestamp_prog(void)
|
||||||
{
|
{
|
||||||
struct sys_timestamp ts;
|
struct sys_timestamp ts;
|
||||||
LARGE_INTEGER time;
|
LARGE_INTEGER qpc;
|
||||||
QueryPerformanceCounter(&time);
|
QueryPerformanceCounter(&qpc);
|
||||||
ts.v = (u64)_win32_i64_muldiv(time.QuadPart - G.timer_start.QuadPart, 1000000000, G.timer_frequency.QuadPart);
|
ts.v = (qpc.QuadPart * G.timer_frequency_ns) - G.timer_start_ns;
|
||||||
return ts;
|
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
|
/* TODO: Does the high frequency timer even require setting / scaling of
|
||||||
* timeBeginPeriod/scheduler_period_ms? There isn't much documentation. */
|
* 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;
|
i32 scheduler_period_ms = G.scheduler_period_ms;
|
||||||
|
|
||||||
LARGE_INTEGER qpc;
|
LARGE_INTEGER qpc;
|
||||||
QueryPerformanceCounter(&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 */
|
/* TODO: Maybe increase tolerance for higher precision but more power usage */
|
||||||
//const double tolerance = 0.001200 * scheduler_period_ms;
|
//const f64 tolerance = 0.001200 * scheduler_period_ms;
|
||||||
const double tolerance = 0.000520 * scheduler_period_ms;
|
const f64 tolerance = 0.000520 * scheduler_period_ms;
|
||||||
//const double tolerance = 1 * 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) {
|
while (true) {
|
||||||
__profscope(win32_sleep_part);
|
__profscope(win32_sleep_part);
|
||||||
/* Break sleep up into parts that are lower than scheduler period */
|
/* Break sleep up into parts that are lower than scheduler period */
|
||||||
double remaining_seconds = (double)(target_qpc - qpc.QuadPart) / (double)qpc_per_second;
|
f64 remaining_seconds = (f64)(target_qpc - qpc.QuadPart) / (f64)qpc_per_second;
|
||||||
INT64 sleep_ticks = (INT64)((remaining_seconds - tolerance) * 10000000);
|
i64 sleep_ticks = (i64)((remaining_seconds - tolerance) * 10000000);
|
||||||
if (sleep_ticks <= 0) {
|
if (sleep_ticks <= 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1992,7 +1984,7 @@ INTERNAL void win32_precise_sleep_timer(f64 seconds, HANDLE timer)
|
|||||||
INTERNAL void win32_precise_sleep_legacy(f64 seconds)
|
INTERNAL void win32_precise_sleep_legacy(f64 seconds)
|
||||||
{
|
{
|
||||||
__prof;
|
__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;
|
i32 scheduler_period_ms = G.scheduler_period_ms;
|
||||||
|
|
||||||
LARGE_INTEGER qpc;
|
LARGE_INTEGER qpc;
|
||||||
@ -2080,13 +2072,18 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
|||||||
|
|
||||||
/* Query system info */
|
/* Query system info */
|
||||||
GetSystemInfo(&G.info);
|
GetSystemInfo(&G.info);
|
||||||
QueryPerformanceFrequency(&G.timer_frequency);
|
|
||||||
QueryPerformanceCounter(&G.timer_start);
|
LARGE_INTEGER qpf;
|
||||||
{
|
QueryPerformanceFrequency(&qpf);
|
||||||
TIMECAPS caps;
|
G.timer_frequency_s = qpf.QuadPart;
|
||||||
timeGetDevCaps(&caps, sizeof caps);
|
G.timer_frequency_ns = 1000000000 / qpf.QuadPart;
|
||||||
G.scheduler_period_ms = (i32)caps.wPeriodMin;
|
|
||||||
}
|
LARGE_INTEGER qpc;
|
||||||
|
QueryPerformanceCounter(&qpc);
|
||||||
|
G.timer_start_ns = qpc.QuadPart * G.timer_frequency_ns;
|
||||||
|
|
||||||
|
TIMECAPS caps;
|
||||||
|
timeGetDevCaps(&caps, sizeof(caps));
|
||||||
|
|
||||||
/* Set up timing period */
|
/* Set up timing period */
|
||||||
timeBeginPeriod(G.scheduler_period_ms);
|
timeBeginPeriod(G.scheduler_period_ms);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user