winit: Fix occasional hang on Windows when quitting python app that uses skia opengl renderer and certain renderer features
Some checks are pending
autofix.ci / format_fix (push) Waiting to run
autofix.ci / lint_typecheck (push) Waiting to run
CI / python_test (windows-2022) (push) Blocked by required conditions
CI / mcu (pico2-st7789, thumbv8m.main-none-eabihf) (push) Blocked by required conditions
CI / files-changed (push) Waiting to run
CI / build_and_test (--exclude bevy-example, ubuntu-22.04, 1.85) (push) Blocked by required conditions
CI / cpp_cmake (ubuntu-22.04, stable) (push) Blocked by required conditions
CI / build_and_test (--exclude ffmpeg --exclude gstreamer-player, --exclude bevy-example, windows-2022, 1.85) (push) Blocked by required conditions
CI / build_and_test (--exclude ffmpeg --exclude gstreamer-player, macos-14, stable) (push) Blocked by required conditions
CI / build_and_test (--exclude ffmpeg --exclude gstreamer-player, windows-2022, beta) (push) Blocked by required conditions
CI / build_and_test (--exclude ffmpeg --exclude gstreamer-player, windows-2022, stable) (push) Blocked by required conditions
CI / build_and_test (ubuntu-22.04, nightly) (push) Blocked by required conditions
CI / node_test (macos-14) (push) Blocked by required conditions
CI / node_test (ubuntu-22.04) (push) Blocked by required conditions
CI / node_test (windows-2022) (push) Blocked by required conditions
CI / python_test (macos-14) (push) Blocked by required conditions
CI / python_test (ubuntu-22.04) (push) Blocked by required conditions
CI / cpp_test_driver (macos-13) (push) Blocked by required conditions
CI / cpp_test_driver (ubuntu-22.04) (push) Blocked by required conditions
CI / cpp_test_driver (windows-2022) (push) Blocked by required conditions
CI / cpp_cmake (macos-14, 1.85) (push) Blocked by required conditions
CI / cpp_cmake (windows-2022, nightly) (push) Blocked by required conditions
CI / cpp_package_test (push) Blocked by required conditions
CI / vsce_build_test (push) Blocked by required conditions
CI / mcu (pico-st7789, thumbv6m-none-eabi) (push) Blocked by required conditions
CI / mcu (stm32h735g, thumbv7em-none-eabihf) (push) Blocked by required conditions
CI / mcu-embassy (push) Blocked by required conditions
CI / ffi_32bit_build (push) Blocked by required conditions
CI / docs (push) Blocked by required conditions
CI / wasm (push) Blocked by required conditions
CI / wasm_demo (push) Blocked by required conditions
CI / tree-sitter (push) Blocked by required conditions
CI / updater_test (0.3.0) (push) Blocked by required conditions
CI / fmt_test (push) Blocked by required conditions
CI / esp-idf-quick (push) Blocked by required conditions
CI / android (push) Blocked by required conditions
CI / miri (push) Blocked by required conditions
CI / test-figma-inspector (push) Blocked by required conditions

The backtrace indicates a very late shutdown causing an infinite loop deep inside skia.

To work around this, gracefully release any rendering resources for any hidden windows when quitting the event loop, thus earlier and ordered.

Fixes #8795
This commit is contained in:
Simon Hausmann 2025-07-29 08:45:12 +02:00 committed by Simon Hausmann
parent b37c956911
commit 9d87f6bf8e
2 changed files with 27 additions and 3 deletions

View file

@ -8,6 +8,7 @@
aspects of windows on the screen.
*/
use crate::drag_resize_window::{handle_cursor_move_for_resize, handle_resize};
use crate::winitwindowadapter::WindowVisibility;
use crate::WinitWindowEventResult;
use crate::{SharedBackendData, SlintEvent};
use corelib::graphics::euclid;
@ -89,6 +90,22 @@ impl EventLoopState {
custom_application_handler,
}
}
/// Free graphics resources for any hidden windows. Called when quitting the event loop, to work
/// around #8795.
fn suspend_all_hidden_windows(&self) {
let windows_to_suspend = self
.shared_backend_data
.active_windows
.borrow()
.values()
.filter_map(|w| w.upgrade())
.filter(|w| matches!(w.visibility(), WindowVisibility::Hidden))
.collect::<Vec<_>>();
for window in windows_to_suspend.into_iter() {
let _ = window.suspend();
}
}
}
impl winit::application::ApplicationHandler<SlintEvent> for EventLoopState {
@ -407,7 +424,10 @@ impl winit::application::ApplicationHandler<SlintEvent> for EventLoopState {
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: SlintEvent) {
match event.0 {
CustomEvent::UserEvent(user_callback) => user_callback(),
CustomEvent::Exit => event_loop.exit(),
CustomEvent::Exit => {
self.suspend_all_hidden_windows();
event_loop.exit()
}
#[cfg(enable_accesskit)]
CustomEvent::Accesskit(accesskit_winit::Event { window_id, window_event }) => {
if let Some(window) = self.shared_backend_data.window_by_id(window_id) {

View file

@ -276,7 +276,7 @@ impl WinitWindowOrNone {
}
#[derive(Default, PartialEq, Clone, Copy)]
enum WindowVisibility {
pub(crate) enum WindowVisibility {
#[default]
Hidden,
/// This implies that we might resize the window the first time it's shown.
@ -513,7 +513,7 @@ impl WinitWindowAdapter {
Ok(winit_window)
}
fn suspend(&self) -> Result<(), PlatformError> {
pub(crate) fn suspend(&self) -> Result<(), PlatformError> {
let mut winit_window_or_none = self.winit_window_or_none.borrow_mut();
match *winit_window_or_none {
WinitWindowOrNone::HasWindow { ref window, .. } => {
@ -938,6 +938,10 @@ impl WinitWindowAdapter {
}
}
pub(crate) fn visibility(&self) -> WindowVisibility {
self.shown.get()
}
pub(crate) fn pending_redraw(&self) -> bool {
self.pending_redraw.get()
}