fix(smoke): drop renderer before window teardown

This commit is contained in:
2026-06-25 13:07:40 +04:00
parent 0b8776b850
commit 7c3b3a53f5
+58
View File
@@ -185,6 +185,14 @@ struct SmokeApp {
started_at: Instant, 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 { impl SmokeApp {
fn new( fn new(
options: SmokeOptions, 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( fn render_timeout_failure_report(
options: &SmokeOptions, options: &SmokeOptions,
failure_reason: &str, failure_reason: &str,
@@ -859,6 +875,32 @@ fn parse_bool_env(value: &str) -> Option<bool> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; 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] #[test]
fn parses_required_args() { fn parses_required_args() {
@@ -1058,4 +1100,20 @@ mod tests {
std::fs::remove_file(out).expect("cleanup report"); std::fs::remove_file(out).expect("cleanup report");
std::fs::remove_dir(root).expect("cleanup dir"); 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]
);
}
} }