diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index dc387c67f39817c51c4b92ba786f5ea6112a25d9..46b1ab64a188ca81fb33c60dd5f9e920be4e7fc1 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -1402,6 +1402,11 @@ impl Window { measure("frame duration", || { handle .update(&mut cx, |_, window, cx| { + if request_frame_options.force_render { + // Bypass cached view reuse so we don't replay stale + // atlas tile references after a GPU device recovery. + window.refresh(); + } let arena_clear_needed = window.draw(cx); window.present(); arena_clear_needed.clear(); diff --git a/crates/gpui_windows/src/events.rs b/crates/gpui_windows/src/events.rs index a4c47789191f9c1fa8a461f4510ce5c66d681fb5..77c4cde9788f7cb62e513fab5485705a7842a770 100644 --- a/crates/gpui_windows/src/events.rs +++ b/crates/gpui_windows/src/events.rs @@ -1174,6 +1174,11 @@ impl WindowsWindowInner { { panic!("Device lost: {err}"); } + // Make sure the first `draw_window` after recovery (whether it comes + // from the forced WM_GPUI_FORCE_UPDATE_WINDOW or a stray WM_PAINT in + // between) is treated as a forced render so it both clears + // `skip_draws` and bypasses the view cache. + self.state.force_render_after_recovery.set(true); Some(0) } @@ -1198,6 +1203,7 @@ impl WindowsWindowInner { } } + let force_render = force_render || self.state.force_render_after_recovery.take(); if force_render { // Re-enable drawing after a device loss recovery. The forced render // will rebuild the scene with fresh atlas textures. diff --git a/crates/gpui_windows/src/window.rs b/crates/gpui_windows/src/window.rs index 130d3dd7214b2cfb939fef01e2698a61519ab3b6..178d750024fdac51e92961522da52162a6947a70 100644 --- a/crates/gpui_windows/src/window.rs +++ b/crates/gpui_windows/src/window.rs @@ -63,6 +63,12 @@ pub struct WindowsWindowState { pub direct_manipulation: DirectManipulationHandler, pub renderer: RefCell, + /// Set after a GPU device-lost recovery so the next `draw_window` call is + /// treated as a forced render. This guarantees the next frame both + /// re-enables drawing (via `mark_drawable`) and bypasses the GPUI view + /// cache, which would otherwise replay stale atlas tile references from + /// the previous frame and panic in `DirectXAtlasState::texture`. + pub force_render_after_recovery: Cell, pub click_state: ClickState, pub current_cursor: Cell>, @@ -159,6 +165,7 @@ impl WindowsWindowState { last_reported_capslock: Cell::new(last_reported_capslock), hovered: Cell::new(hovered), renderer: RefCell::new(renderer), + force_render_after_recovery: Cell::new(false), click_state, current_cursor: Cell::new(current_cursor), cursor_visible,