summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornanahi <130121847+na-na-hi@users.noreply.github.com>2023-10-26 15:13:12 -0400
committerKacper Michajłow <kasper93@gmail.com>2024-03-19 20:23:25 +0100
commitaff376e066359afbb78fca1c53355104281d9712 (patch)
treec95950a0a4dcb325c424c95c0712fdfb64a4297d
parentbfd016d1013ad6cac9a190ec109e814744055d8c (diff)
downloadmpv-aff376e066359afbb78fca1c53355104281d9712.tar.bz2
mpv-aff376e066359afbb78fca1c53355104281d9712.tar.xz
win32: increase hires timer resolution
timeBeginPeriod() only allows setting minimum timer resolution to 1 ms. However, modern x86 platforms support a minimum timer resolution of 0.5 ms. Use NtSetTimerResolution() instead for the increased resolution, which can be set with MPV_HRT_RES. Additionally, change the units of mp_start_hires_timers(), mp_end_hires_timer(), MPV_HRT_RES, and MPV_HRT_MAX to nanoseconds, in accordance with other functions used in timer.h.
-rw-r--r--meson.build1
-rw-r--r--osdep/threads-win32.h2
-rw-r--r--osdep/timer-win32.c51
-rw-r--r--osdep/timer.h6
-rw-r--r--test/meson.build1
5 files changed, 40 insertions, 21 deletions
diff --git a/meson.build b/meson.build
index 6ccc8bbfb8..d31ec88eb0 100644
--- a/meson.build
+++ b/meson.build
@@ -497,6 +497,7 @@ if features['win32-desktop']
cc.find_library('dwmapi'),
cc.find_library('gdi32'),
cc.find_library('imm32'),
+ cc.find_library('ntdll'),
cc.find_library('ole32'),
cc.find_library('uuid'),
cc.find_library('uxtheme'),
diff --git a/osdep/threads-win32.h b/osdep/threads-win32.h
index f1c654a5cb..ec90fe9387 100644
--- a/osdep/threads-win32.h
+++ b/osdep/threads-win32.h
@@ -115,7 +115,7 @@ static inline int mp_cond_timedwait(mp_cond *cond, mp_mutex *mutex, int64_t time
timeout = MPCLAMP(timeout, 0, MP_TIME_MS_TO_NS(INFINITE)) / MP_TIME_MS_TO_NS(1);
int ret = 0;
- int hrt = mp_start_hires_timers(timeout);
+ int64_t hrt = mp_start_hires_timers(MP_TIME_MS_TO_NS(timeout));
BOOL bRet;
if (mutex->use_cs) {
diff --git a/osdep/timer-win32.c b/osdep/timer-win32.c
index 7867b5a525..a2815cae0f 100644
--- a/osdep/timer-win32.c
+++ b/osdep/timer-win32.c
@@ -16,6 +16,8 @@
*/
#include <windows.h>
+#include <winternl.h>
+#include <ntstatus.h>
#include <sys/time.h>
#include <mmsystem.h>
#include <stdlib.h>
@@ -27,16 +29,23 @@
static LARGE_INTEGER perf_freq;
-// ms values
-static int hires_max = 50;
-static int hires_res = 1;
+static int64_t hires_max = MP_TIME_MS_TO_NS(50);
+static int64_t hires_res = MP_TIME_MS_TO_NS(1);
-int mp_start_hires_timers(int wait_ms)
+// NtSetTimerResolution allows setting the timer resolution to less than 1 ms.
+// Resolutions are specified in 100-ns units.
+// If Set is TRUE, set the RequestedResolution. Otherwise, return to the previous resolution.
+NTSTATUS NTAPI NtSetTimerResolution(ULONG RequestedResolution, BOOLEAN Set, PULONG ActualResolution);
+// Acquire the valid timer resolution range.
+NTSTATUS NTAPI NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution, PULONG ActualResolution);
+
+int64_t mp_start_hires_timers(int64_t wait_ns)
{
#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)
+ ULONG actual_res = 0;
+ // policy: request hires_res resolution if wait < hires_max ns
+ if (wait_ns > 0 && wait_ns <= hires_max &&
+ NtSetTimerResolution(hires_res / 100, TRUE, &actual_res) == STATUS_SUCCESS)
{
return hires_res;
}
@@ -44,11 +53,12 @@ int mp_start_hires_timers(int wait_ms)
return 0;
}
-void mp_end_hires_timers(int res_ms)
+void mp_end_hires_timers(int64_t res_ns)
{
#if !HAVE_UWP
- if (res_ms > 0)
- timeEndPeriod(res_ms);
+ ULONG actual_res = 0;
+ if (res_ns > 0)
+ NtSetTimerResolution(res_ns / 100, FALSE, &actual_res);
#endif
}
@@ -57,7 +67,7 @@ void mp_sleep_ns(int64_t ns)
if (ns < 0)
return;
- int hrt = mp_start_hires_timers(ns < 1e6 ? 1 : ns / 1e6);
+ int64_t hrt = mp_start_hires_timers(ns);
#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x2
@@ -107,21 +117,28 @@ void mp_raw_time_init(void)
QueryPerformanceFrequency(&perf_freq);
#if !HAVE_UWP
+ ULONG min_res, max_res, actual_res;
+ if (NtQueryTimerResolution(&min_res, &max_res, &actual_res) != STATUS_SUCCESS) {
+ min_res = 156250;
+ max_res = 10000;
+ }
+
// allow (undocumented) control of all the High Res Timers parameters,
// for easier experimentation and diagnostic of bug reports.
const char *v;
+ char *end;
// 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)
+ int64_t hmax = strtoll(v, &end, 10);
+ if (*end == '\0' && hmax >= MP_TIME_MS_TO_NS(1) && hmax <= MP_TIME_MS_TO_NS(1000))
hires_max = hmax;
}
- // 1..15 ms hires resolution (not used in "never" mode)
+ // hires resolution clamped by the available resolution range (not used in "never" mode)
if ((v = getenv("MPV_HRT_RES"))) {
- int res = atoi(v);
- if (res >= 1 && res <= 15)
+ int64_t res = strtoll(v, &end, 10);
+ if (*end == '\0' && res >= max_res * INT64_C(100) && res <= min_res * INT64_C(100))
hires_res = res;
}
@@ -134,8 +151,8 @@ void mp_raw_time_init(void)
} else if (!strcmp(v, "never")) {
hires_max = 0;
} else { // "always" or unknown value
+ mp_start_hires_timers(hires_res);
hires_max = 0;
- timeBeginPeriod(hires_res);
}
#endif
}
diff --git a/osdep/timer.h b/osdep/timer.h
index 3eab817626..d8ec185bfe 100644
--- a/osdep/timer.h
+++ b/osdep/timer.h
@@ -39,11 +39,11 @@ uint64_t mp_raw_time_ns(void);
void mp_sleep_ns(int64_t ns);
#ifdef _WIN32
-// returns: timer resolution in ms if needed and started successfully, else 0
-int mp_start_hires_timers(int wait_ms);
+// returns: timer resolution in ns if needed and started successfully, else 0
+int64_t mp_start_hires_timers(int64_t wait_ns);
// call unconditionally with the return value of mp_start_hires_timers
-void mp_end_hires_timers(int resolution_ms);
+void mp_end_hires_timers(int64_t resolution_ns);
#endif /* _WIN32 */
// Converts time units to nanoseconds (int64_t)
diff --git a/test/meson.build b/test/meson.build
index b45f672c7a..7be1db4777 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -52,6 +52,7 @@ endif
if features['win32-desktop']
test_utils_deps += cc.find_library('imm32')
+ test_utils_deps += cc.find_library('ntdll')
test_utils_deps += cc.find_library('winmm')
endif
test_utils_objects = libmpv.extract_objects(test_utils_files)