diff options
| -rw-r--r-- | apps/fparkan-vulkan-smoke/src/main.rs | 58 |
1 files changed, 58 insertions, 0 deletions
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, WindowLike>( + renderer: &mut Option<Renderer>, + window: &mut Option<WindowLike>, +) { + 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<bool> { #[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<RefCell<Vec<DropStep>>>, + } + + impl Drop for DropTracker { + fn drop(&mut self) { + self.log.borrow_mut().push(self.step); + } + } + + fn tracker(step: DropStep, log: &Rc<RefCell<Vec<DropStep>>>) -> 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] + ); + } } |
