From 4002b32ad4504e9100ce51347a3eebd47b655dff Mon Sep 17 00:00:00 2001 From: John Tur Date: Tue, 4 Nov 2025 03:43:06 -0500 Subject: [PATCH] Coalesce dispatcher window messages on Windows (#41861) Take 2 at https://github.com/zed-industries/zed/pull/41595 Release Notes: - N/A --- .../gpui/src/platform/windows/dispatcher.rs | 25 +++++++---- crates/gpui/src/platform/windows/platform.rs | 45 +++++++++++++++---- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/crates/gpui/src/platform/windows/dispatcher.rs b/crates/gpui/src/platform/windows/dispatcher.rs index 8d3e6305f6b4bb60f6c282280bafa7f76f59eecb..f60d6bd884d7bfe6b313a7ca555067991172fe31 100644 --- a/crates/gpui/src/platform/windows/dispatcher.rs +++ b/crates/gpui/src/platform/windows/dispatcher.rs @@ -1,4 +1,5 @@ use std::{ + sync::atomic::{AtomicBool, Ordering}, thread::{ThreadId, current}, time::Duration, }; @@ -21,6 +22,7 @@ use crate::{ }; pub(crate) struct WindowsDispatcher { + pub(crate) wake_posted: AtomicBool, main_sender: Sender, main_thread_id: ThreadId, platform_window_handle: SafeHwnd, @@ -41,6 +43,7 @@ impl WindowsDispatcher { main_thread_id, platform_window_handle, validation_number, + wake_posted: AtomicBool::new(false), } } @@ -81,15 +84,19 @@ impl PlatformDispatcher for WindowsDispatcher { fn dispatch_on_main_thread(&self, runnable: Runnable) { match self.main_sender.send(runnable) { - Ok(_) => unsafe { - PostMessageW( - Some(self.platform_window_handle.as_raw()), - WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD, - WPARAM(self.validation_number), - LPARAM(0), - ) - .log_err(); - }, + Ok(_) => { + if !self.wake_posted.swap(true, Ordering::AcqRel) { + unsafe { + PostMessageW( + Some(self.platform_window_handle.as_raw()), + WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD, + WPARAM(self.validation_number), + LPARAM(0), + ) + .log_err(); + } + } + } Err(runnable) => { // NOTE: Runnable may wrap a Future that is !Send. // diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 361d8e114308323da8629fae93d257cc38147dba..b7f69961c4f0d69d42de1f4f031d8a2a253ac538 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -4,7 +4,7 @@ use std::{ mem::ManuallyDrop, path::{Path, PathBuf}, rc::{Rc, Weak}, - sync::Arc, + sync::{Arc, atomic::Ordering}, }; use ::util::{ResultExt, paths::SanitizedPath}; @@ -48,6 +48,7 @@ struct WindowsPlatformInner { // The below members will never change throughout the entire lifecycle of the app. validation_number: usize, main_receiver: flume::Receiver, + dispatcher: Arc, } pub(crate) struct WindowsPlatformState { @@ -109,8 +110,10 @@ impl WindowsPlatform { inner: None, raw_window_handles: Arc::downgrade(&raw_window_handles), validation_number, + main_sender: Some(main_sender), main_receiver: Some(main_receiver), directx_devices: Some(directx_devices), + dispatcher: None, }; let result = unsafe { CreateWindowExW( @@ -129,12 +132,9 @@ impl WindowsPlatform { ) }; let inner = context.inner.take().unwrap()?; + let dispatcher = context.dispatcher.take().unwrap(); let handle = result?; - let dispatcher = Arc::new(WindowsDispatcher::new( - main_sender, - handle, - validation_number, - )); + let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION) .is_ok_and(|value| value == "true" || value == "1"); let background_executor = BackgroundExecutor::new(dispatcher.clone()); @@ -682,6 +682,7 @@ impl WindowsPlatformInner { Ok(Rc::new(Self { state, raw_window_handles: context.raw_window_handles.clone(), + dispatcher: context.dispatcher.as_ref().unwrap().clone(), validation_number: context.validation_number, main_receiver: context.main_receiver.take().unwrap(), })) @@ -746,9 +747,28 @@ impl WindowsPlatformInner { #[inline] fn run_foreground_task(&self) -> Option { - for runnable in self.main_receiver.drain() { - runnable.run(); + loop { + for runnable in self.main_receiver.drain() { + runnable.run(); + } + + // Someone could enqueue a Runnable here. The flag is still true, so they will not PostMessage. + // We need to check for those Runnables after we clear the flag. + let dispatcher = self.dispatcher.clone(); + + dispatcher.wake_posted.store(false, Ordering::Release); + match self.main_receiver.try_recv() { + Ok(runnable) => { + let _ = dispatcher.wake_posted.swap(true, Ordering::AcqRel); + runnable.run(); + continue; + } + _ => { + break; + } + } } + Some(0) } @@ -832,8 +852,10 @@ struct PlatformWindowCreateContext { inner: Option>>, raw_window_handles: std::sync::Weak>>, validation_number: usize, + main_sender: Option>, main_receiver: Option>, directx_devices: Option, + dispatcher: Option>, } fn open_target(target: impl AsRef) -> Result<()> { @@ -1115,6 +1137,13 @@ unsafe extern "system" fn window_procedure( let params = unsafe { &*params }; let creation_context = params.lpCreateParams as *mut PlatformWindowCreateContext; let creation_context = unsafe { &mut *creation_context }; + + creation_context.dispatcher = Some(Arc::new(WindowsDispatcher::new( + creation_context.main_sender.take().unwrap(), + hwnd, + creation_context.validation_number, + ))); + return match WindowsPlatformInner::new(creation_context) { Ok(inner) => { let weak = Box::new(Rc::downgrade(&inner));