diff --git a/osdep/timer-win2.c b/osdep/timer-win2.c index 63c423560f..72bcca5b4e 100644 --- a/osdep/timer-win2.c +++ b/osdep/timer-win2.c @@ -19,12 +19,39 @@ #include #include #include +#include + #include "timer.h" #include "config.h" static LARGE_INTEGER perf_freq; +// ms values +static int hires_max = 50; +static int hires_res = 1; + +int mp_start_hires_timers(int wait_ms) +{ +#if !HAVE_UWP + // policy: request hires_res ms resolution if wait < hires_max ms + if (wait_ms > 0 && wait_ms <= hires_max && + timeBeginPeriod(hires_res) == TIMERR_NOERROR) + { + return hires_res; + } +#endif + return 0; +} + +void mp_end_hires_timers(int res_ms) +{ +#if !HAVE_UWP + if (res_ms > 0) + timeEndPeriod(res_ms); +#endif +} + void mp_sleep_us(int64_t us) { if (us < 0) @@ -34,7 +61,9 @@ void mp_sleep_us(int64_t us) // it may take some time until it actually starts to run again if (us < 1000) us = 1000; + int hrt = mp_start_hires_timers(us / 1000); Sleep(us / 1000); + mp_end_hires_timers(hrt); } uint64_t mp_raw_time_us(void) @@ -52,7 +81,37 @@ uint64_t mp_raw_time_us(void) void mp_raw_time_init(void) { QueryPerformanceFrequency(&perf_freq); + #if !HAVE_UWP - timeBeginPeriod(1); // request 1ms timer resolution + // allow (undocumented) control of all the High Res Timers parameters, + // for easier experimentation and diagnostic of bug reports. + const char *v; + + // 1..1000 ms max timetout for hires (used in "perwait" mode) + if ((v = getenv("MPV_HRT_MAX"))) { + int hmax = atoi(v); + if (hmax >= 1 && hmax <= 1000) + hires_max = hmax; + } + + // 1..15 ms hires resolution (not used in "never" mode) + if ((v = getenv("MPV_HRT_RES"))) { + int res = atoi(v); + if (res >= 1 && res <= 15) + hires_res = res; + } + + // "always"/"never"/"perwait" (or "auto" - same as unset) + if (!(v = getenv("MPV_HRT")) || !strcmp(v, "auto")) + v = IsWindows10OrGreater() ? "perwait" : "always"; + + if (!strcmp(v, "perwait")) { + // no-op, already per-wait + } else if (!strcmp(v, "never")) { + hires_max = 0; + } else { // "always" or unknown value + hires_max = 0; + timeBeginPeriod(hires_res); + } #endif } diff --git a/osdep/timer.h b/osdep/timer.h index be5e9c0467..8cc1d9dc27 100644 --- a/osdep/timer.h +++ b/osdep/timer.h @@ -37,6 +37,14 @@ uint64_t mp_raw_time_us(void); // Sleep in microseconds. void mp_sleep_us(int64_t us); +#ifdef _WIN32 +// returns: timer resolution in ms if needed and started successfully, else 0 +int mp_start_hires_timers(int wait_ms); + +// call unconditionally with the return value of mp_start_hires_timers +void mp_end_hires_timers(int resolution_ms); +#endif /* _WIN32 */ + #define MP_START_TIME 10000000 // Duration of a second in mpv time. diff --git a/osdep/win32/pthread.c b/osdep/win32/pthread.c index 141ecfc5e0..e892d441cf 100644 --- a/osdep/win32/pthread.c +++ b/osdep/win32/pthread.c @@ -22,6 +22,8 @@ #include #include +#include "osdep/timer.h" // mp_{start,end}_hires_timers + int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { BOOL pending; @@ -78,11 +80,13 @@ static int cond_wait(pthread_cond_t *restrict cond, DWORD ms) { BOOL res; + int hrt = mp_start_hires_timers(ms); if (mutex->use_cs) { res = SleepConditionVariableCS(cond, &mutex->lock.cs, ms); } else { res = SleepConditionVariableSRW(cond, &mutex->lock.srw, ms, 0); } + mp_end_hires_timers(hrt); return res ? 0 : ETIMEDOUT; }