mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-23 02:16:33 +11:00
Windows: Increase wait timer resolution (#2007)
Windows: Increase wait timer resolution for more accurate timing when using `WaitUntil`.
This commit is contained in:
parent
5f4df54895
commit
cfbe8462cc
3 changed files with 34 additions and 5 deletions
|
@ -19,6 +19,7 @@
|
||||||
- On X11, if RANDR based scale factor is higher than 20 reset it to 1
|
- On X11, if RANDR based scale factor is higher than 20 reset it to 1
|
||||||
- On Wayland, add an enabled-by-default feature called `wayland-dlopen` so users can opt out of using `dlopen` to load system libraries.
|
- On Wayland, add an enabled-by-default feature called `wayland-dlopen` so users can opt out of using `dlopen` to load system libraries.
|
||||||
- **Breaking:** On Android, bump `ndk` and `ndk-glue` to 0.4.
|
- **Breaking:** On Android, bump `ndk` and `ndk-glue` to 0.4.
|
||||||
|
- On Windows, increase wait timer resolution for more accurate timing when using `WaitUntil`.
|
||||||
|
|
||||||
# 0.25.0 (2021-05-15)
|
# 0.25.0 (2021-05-15)
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,8 @@ features = [
|
||||||
"wingdi",
|
"wingdi",
|
||||||
"winnt",
|
"winnt",
|
||||||
"winuser",
|
"winuser",
|
||||||
|
"mmsystem",
|
||||||
|
"timeapi"
|
||||||
]
|
]
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
|
||||||
|
|
|
@ -25,7 +25,7 @@ use winapi::{
|
||||||
windowsx, winerror,
|
windowsx, winerror,
|
||||||
},
|
},
|
||||||
um::{
|
um::{
|
||||||
libloaderapi, ole2, processthreadsapi, winbase,
|
libloaderapi, mmsystem, ole2, processthreadsapi, timeapi, winbase,
|
||||||
winnt::{HANDLE, LONG, LPCSTR, SHORT},
|
winnt::{HANDLE, LONG, LPCSTR, SHORT},
|
||||||
winuser,
|
winuser,
|
||||||
},
|
},
|
||||||
|
@ -324,6 +324,22 @@ fn get_wait_thread_id() -> DWORD {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref WAIT_PERIOD_MIN: Option<UINT> = unsafe {
|
||||||
|
let mut caps = mmsystem::TIMECAPS {
|
||||||
|
wPeriodMin: 0,
|
||||||
|
wPeriodMax: 0,
|
||||||
|
};
|
||||||
|
if timeapi::timeGetDevCaps(&mut caps, mem::size_of::<mmsystem::TIMECAPS>() as _)
|
||||||
|
== mmsystem::TIMERR_NOERROR
|
||||||
|
{
|
||||||
|
Some(caps.wPeriodMin)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn wait_thread(parent_thread_id: DWORD, msg_window_id: HWND) {
|
fn wait_thread(parent_thread_id: DWORD, msg_window_id: HWND) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut msg: winuser::MSG;
|
let mut msg: winuser::MSG;
|
||||||
|
@ -366,16 +382,26 @@ fn wait_thread(parent_thread_id: DWORD, msg_window_id: HWND) {
|
||||||
if let Some(wait_until) = wait_until_opt {
|
if let Some(wait_until) = wait_until_opt {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now < wait_until {
|
if now < wait_until {
|
||||||
// MsgWaitForMultipleObjects tends to overshoot just a little bit. We subtract
|
// Windows' scheduler has a default accuracy of several ms. This isn't good enough for
|
||||||
// 1 millisecond from the requested time and spinlock for the remainder to
|
// `WaitUntil`, so we request the Windows scheduler to use a higher accuracy if possible.
|
||||||
// compensate for that.
|
// If we couldn't query the timer capabilities, then we use the default resolution.
|
||||||
|
if let Some(period) = *WAIT_PERIOD_MIN {
|
||||||
|
timeapi::timeBeginPeriod(period);
|
||||||
|
}
|
||||||
|
// `MsgWaitForMultipleObjects` is bound by the granularity of the scheduler period.
|
||||||
|
// Because of this, we try to reduce the requested time just enough to undershoot `wait_until`
|
||||||
|
// by the smallest amount possible, and then we busy loop for the remaining time inside the
|
||||||
|
// NewEvents message handler.
|
||||||
let resume_reason = winuser::MsgWaitForMultipleObjectsEx(
|
let resume_reason = winuser::MsgWaitForMultipleObjectsEx(
|
||||||
0,
|
0,
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
dur2timeout(wait_until - now).saturating_sub(1),
|
dur2timeout(wait_until - now).saturating_sub(WAIT_PERIOD_MIN.unwrap_or(1)),
|
||||||
winuser::QS_ALLEVENTS,
|
winuser::QS_ALLEVENTS,
|
||||||
winuser::MWMO_INPUTAVAILABLE,
|
winuser::MWMO_INPUTAVAILABLE,
|
||||||
);
|
);
|
||||||
|
if let Some(period) = *WAIT_PERIOD_MIN {
|
||||||
|
timeapi::timeEndPeriod(period);
|
||||||
|
}
|
||||||
if resume_reason == winerror::WAIT_TIMEOUT {
|
if resume_reason == winerror::WAIT_TIMEOUT {
|
||||||
winuser::PostMessageW(msg_window_id, *PROCESS_NEW_EVENTS_MSG_ID, 0, 0);
|
winuser::PostMessageW(msg_window_id, *PROCESS_NEW_EVENTS_MSG_ID, 0, 0);
|
||||||
wait_until_opt = None;
|
wait_until_opt = None;
|
||||||
|
|
Loading…
Add table
Reference in a new issue