From 7c3b3a53f51a87e7d6f28ed26173aa4c8e5b6957 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Thu, 25 Jun 2026 13:07:40 +0400 Subject: fix(smoke): drop renderer before window teardown --- apps/fparkan-vulkan-smoke/src/main.rs | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/apps/fparkan-vulkan-smoke/src/main.rs b/apps/fparkan-vulkan-smoke/src/main.rs index 6339352..8e12ac5 100644 --- a/apps/fparkan-vulkan-smoke/src/main.rs +++ b/apps/fparkan-vulkan-smoke/src/main.rs @@ -185,6 +185,14 @@ struct SmokeApp { started_at: Instant, } +fn drop_renderer_before_window( + renderer: &mut Option, + window: &mut Option, +) { + drop(renderer.take()); + drop(window.take()); +} + impl SmokeApp { fn new( options: SmokeOptions, @@ -408,6 +416,14 @@ impl SmokeApp { } } +impl Drop for SmokeApp { + fn drop(&mut self) { + // Keep the native window alive until the Vulkan renderer finishes + // destroying swapchain and surface state that still references it. + drop_renderer_before_window(&mut self.renderer, &mut self.window); + } +} + fn render_timeout_failure_report( options: &SmokeOptions, failure_reason: &str, @@ -859,6 +875,32 @@ fn parse_bool_env(value: &str) -> Option { #[cfg(test)] mod tests { use super::*; + use std::cell::RefCell; + use std::rc::Rc; + + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + enum DropStep { + Renderer, + Window, + } + + struct DropTracker { + step: DropStep, + log: Rc>>, + } + + impl Drop for DropTracker { + fn drop(&mut self) { + self.log.borrow_mut().push(self.step); + } + } + + fn tracker(step: DropStep, log: &Rc>>) -> DropTracker { + DropTracker { + step, + log: Rc::clone(log), + } + } #[test] fn parses_required_args() { @@ -1058,4 +1100,20 @@ mod tests { std::fs::remove_file(out).expect("cleanup report"); std::fs::remove_dir(root).expect("cleanup dir"); } + + #[test] + fn renderer_is_dropped_before_window() { + let log = Rc::new(RefCell::new(Vec::new())); + let mut renderer = Some(tracker(DropStep::Renderer, &log)); + let mut window = Some(tracker(DropStep::Window, &log)); + + drop_renderer_before_window(&mut renderer, &mut window); + + assert!(renderer.is_none()); + assert!(window.is_none()); + assert_eq!( + Rc::into_inner(log).expect("trackers released").into_inner(), + vec![DropStep::Renderer, DropStep::Window] + ); + } } -- cgit v1.2.3