Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions crates/gpui/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,19 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
#[doc(hidden)]
pub type RunnableVariant = Runnable<RunnableMeta>;

#[doc(hidden)]
pub struct TimerResolutionGuard {
cleanup: Option<Box<dyn FnOnce() + Send>>,
}

impl Drop for TimerResolutionGuard {
fn drop(&mut self) {
if let Some(cleanup) = self.cleanup.take() {
cleanup();
}
}
}

/// This type is public so that our test macro can generate and use it, but it should not
/// be considered part of our public API.
#[doc(hidden)]
Expand All @@ -611,6 +624,10 @@ pub trait PlatformDispatcher: Send + Sync {
Instant::now()
}

fn increase_timer_resolution(&self) -> TimerResolutionGuard {
TimerResolutionGuard { cleanup: None }
}

#[cfg(any(test, feature = "test-support"))]
fn as_test(&self) -> Option<&TestDispatcher> {
None
Expand Down
14 changes: 13 additions & 1 deletion crates/gpui/src/platform/windows/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use windows::{
},
Win32::{
Foundation::{LPARAM, WPARAM},
Media::{timeBeginPeriod, timeEndPeriod},
System::Threading::{
GetCurrentThread, HIGH_PRIORITY_CLASS, SetPriorityClass, SetThreadPriority,
THREAD_PRIORITY_TIME_CRITICAL,
Expand All @@ -22,7 +23,7 @@ use windows::{

use crate::{
GLOBAL_THREAD_TIMINGS, HWND, PlatformDispatcher, Priority, PriorityQueueSender,
RunnableVariant, SafeHwnd, THREAD_TIMINGS, TaskTiming, ThreadTaskTimings,
RunnableVariant, SafeHwnd, THREAD_TIMINGS, TaskTiming, ThreadTaskTimings, TimerResolutionGuard,
WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD, profiler,
};

Expand Down Expand Up @@ -193,4 +194,15 @@ impl PlatformDispatcher for WindowsDispatcher {
f();
});
}

fn increase_timer_resolution(&self) -> TimerResolutionGuard {
unsafe {
timeBeginPeriod(1);
}
TimerResolutionGuard {
cleanup: Some(Box::new(|| unsafe {
timeEndPeriod(1);
})),
}
}
}
6 changes: 0 additions & 6 deletions crates/gpui/src/platform/windows/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use windows::{
Win32::{
Foundation::*,
Graphics::{Direct3D11::ID3D11Device, Gdi::*},
Media::{timeBeginPeriod, timeEndPeriod},
Security::Credentials::*,
System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*},
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
Expand Down Expand Up @@ -98,10 +97,6 @@ impl WindowsPlatform {
pub(crate) fn new(headless: bool) -> Result<Self> {
unsafe {
OleInitialize(None).context("unable to initialize Windows OLE")?;
// Set the system timer resolution to 1ms so that short timeouts
// (e.g. in Scheduler::block) are not rounded up to the default
// ~15.6ms tick interval.
timeBeginPeriod(1);
}
let (directx_devices, text_system, direct_write_text_system) = if !headless {
let devices = DirectXDevices::new().context("Creating DirectX devices")?;
Expand Down Expand Up @@ -985,7 +980,6 @@ impl WindowsPlatformInner {
impl Drop for WindowsPlatform {
fn drop(&mut self) {
unsafe {
timeEndPeriod(1);
DestroyWindow(self.handle)
.context("Destroying platform window")
.log_err();
Expand Down
10 changes: 9 additions & 1 deletion crates/gpui/src/platform_scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,17 @@ impl Scheduler for PlatformScheduler {
if let Poll::Ready(()) = future.as_mut().poll(&mut cx) {
return true;
}

let park_deadline = |deadline: Instant| {
// Timer expirations are only delivered every ~15.6 milliseconds by default on Windows.
// We increase the resolution during this wait so that short timeouts stay reasonably short.
let _timer_guard = self.dispatcher.increase_timer_resolution();
parker.park_deadline(deadline)
};

loop {
match deadline {
Some(deadline) if !parker.park_deadline(deadline) && deadline <= Instant::now() => {
Some(deadline) if !park_deadline(deadline) && deadline <= Instant::now() => {
return false;
}
Some(_) => (),
Expand Down