diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 76a5eb4c021e8dbc1cb6dfc1b6d875ab806568fd..b495d70dfdd3594a27ed3c1793e7e0ac4e7e0b4a 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -447,6 +447,8 @@ impl Tiling { #[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] pub(crate) struct RequestFrameOptions { pub(crate) require_presentation: bool, + /// Force refresh of all rendering states when true + pub(crate) force_render: bool, } pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index d49dacea10183e94a1b51c388cda674202403f12..db93116e1d173ccad57650be02a05b8c77f7bf36 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -22,7 +22,7 @@ use crate::{ *, }; -const DISABLE_DIRECT_COMPOSITION: &str = "GPUI_DISABLE_DIRECT_COMPOSITION"; +pub(crate) const DISABLE_DIRECT_COMPOSITION: &str = "GPUI_DISABLE_DIRECT_COMPOSITION"; const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM; // This configuration is used for MSAA rendering on paths only, and it's guaranteed to be supported by DirectX 11. const PATH_MULTISAMPLE_COUNT: u32 = 4; @@ -113,9 +113,7 @@ impl DirectXDevices { } impl DirectXRenderer { - pub(crate) fn new(hwnd: HWND) -> Result { - let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION) - .is_ok_and(|value| value == "true" || value == "1"); + pub(crate) fn new(hwnd: HWND, disable_direct_composition: bool) -> Result { if disable_direct_composition { log::info!("Direct Composition is disabled."); } @@ -198,6 +196,9 @@ impl DirectXRenderer { } fn handle_device_lost(&mut self) -> Result<()> { + // Here we wait a bit to ensure the the system has time to recover from the device lost state. + // If we don't wait, the final drawing result will be blank. + std::thread::sleep(std::time::Duration::from_millis(300)); let disable_direct_composition = self.direct_composition.is_none(); unsafe { @@ -323,6 +324,8 @@ impl DirectXRenderer { "DirectX device removed or reset when resizing. Reason: {:?}", reason ); + self.resources.width = width; + self.resources.height = height; self.handle_device_lost()?; return Ok(()); } diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 4b905302af4714bcccbe732ef4f847af4b3805ee..61f410a8c6f9ebbdf70ce2ba29c18b83229f552f 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -23,6 +23,7 @@ pub(crate) const WM_GPUI_CURSOR_STYLE_CHANGED: u32 = WM_USER + 1; pub(crate) const WM_GPUI_CLOSE_ONE_WINDOW: u32 = WM_USER + 2; pub(crate) const WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD: u32 = WM_USER + 3; pub(crate) const WM_GPUI_DOCK_MENU_ACTION: u32 = WM_USER + 4; +pub(crate) const WM_GPUI_FORCE_UPDATE_WINDOW: u32 = WM_USER + 5; const SIZE_MOVE_LOOP_TIMER_ID: usize = 1; const AUTO_HIDE_TASKBAR_THICKNESS_PX: i32 = 1; @@ -97,6 +98,7 @@ pub(crate) fn handle_msg( WM_SETTINGCHANGE => handle_system_settings_changed(handle, wparam, lparam, state_ptr), WM_INPUTLANGCHANGE => handle_input_language_changed(lparam, state_ptr), WM_GPUI_CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr), + WM_GPUI_FORCE_UPDATE_WINDOW => draw_window(handle, true, state_ptr), _ => None, }; if let Some(n) = handled { @@ -1202,6 +1204,19 @@ fn handle_device_change_msg( state_ptr: Rc, ) -> Option { if wparam.0 == DBT_DEVNODES_CHANGED as usize { + // The reason for sending this message is to actually trigger a redraw of the window. + unsafe { + PostMessageW( + Some(handle), + WM_GPUI_FORCE_UPDATE_WINDOW, + WPARAM(0), + LPARAM(0), + ) + .log_err(); + } + // If the GPU device is lost, this redraw will take care of recreating the device context. + // The WM_GPUI_FORCE_UPDATE_WINDOW message will take care of redrawing the window, after + // the device context has been recreated. draw_window(handle, true, state_ptr) } else { // Other device change messages are not handled. @@ -1212,7 +1227,7 @@ fn handle_device_change_msg( #[inline] fn draw_window( handle: HWND, - force_draw: bool, + force_render: bool, state_ptr: Rc, ) -> Option { let mut request_frame = state_ptr @@ -1222,7 +1237,8 @@ fn draw_window( .request_frame .take()?; request_frame(RequestFrameOptions { - require_presentation: force_draw, + require_presentation: false, + force_render, }); state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame); unsafe { ValidateRect(Some(handle), None).ok().log_err() }; diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 159cb6d95f876da130fec03e6f69e34437c6bab9..9e030ee41b3bb9192b41fe34251de649f4e72c8e 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -84,6 +84,7 @@ impl WindowsWindowState { display: WindowsDisplay, min_size: Option>, appearance: WindowAppearance, + disable_direct_composition: bool, ) -> Result { let scale_factor = { let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32; @@ -100,7 +101,7 @@ impl WindowsWindowState { }; let border_offset = WindowBorderOffset::default(); let restore_from_minimized = None; - let renderer = DirectXRenderer::new(hwnd)?; + let renderer = DirectXRenderer::new(hwnd, disable_direct_composition)?; let callbacks = Callbacks::default(); let input_handler = None; let pending_surrogate = None; @@ -208,6 +209,7 @@ impl WindowsWindowStatePtr { context.display, context.min_size, context.appearance, + context.disable_direct_composition, )?); Ok(Rc::new_cyclic(|this| Self { @@ -339,6 +341,7 @@ struct WindowCreateContext { main_receiver: flume::Receiver, main_thread_id_win32: u32, appearance: WindowAppearance, + disable_direct_composition: bool, } impl WindowsWindow { @@ -371,17 +374,20 @@ impl WindowsWindow { .map(|title| title.as_ref()) .unwrap_or(""), ); - let (dwexstyle, mut dwstyle) = if params.kind == WindowKind::PopUp { - ( - WS_EX_TOOLWINDOW | WS_EX_NOREDIRECTIONBITMAP, - WINDOW_STYLE(0x0), - ) + let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION) + .is_ok_and(|value| value == "true" || value == "1"); + + let (mut dwexstyle, dwstyle) = if params.kind == WindowKind::PopUp { + (WS_EX_TOOLWINDOW, WINDOW_STYLE(0x0)) } else { ( - WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP, + WS_EX_APPWINDOW, WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, ) }; + if !disable_direct_composition { + dwexstyle |= WS_EX_NOREDIRECTIONBITMAP; + } let hinstance = get_module_handle(); let display = if let Some(display_id) = params.display_id { @@ -406,6 +412,7 @@ impl WindowsWindow { main_receiver, main_thread_id_win32, appearance, + disable_direct_composition, }; let lpparam = Some(&context as *const _ as *const _); let creation_result = unsafe { diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 01fbfff1c5485ad0ad0451ef4cf91cbead2eead2..6ebb1cac40c550680b81cbe5b05180b3009b8475 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -1020,7 +1020,7 @@ impl Window { || (active.get() && last_input_timestamp.get().elapsed() < Duration::from_secs(1)); - if invalidator.is_dirty() { + if invalidator.is_dirty() || request_frame_options.force_render { measure("frame duration", || { handle .update(&mut cx, |_, window, cx| {