test(vulkan-smoke): cover explicit teardown order
This commit is contained in:
@@ -15,6 +15,20 @@ use super::{
|
||||
};
|
||||
use crate::shader_manifest::{triangle_shader_manifest, validate_shader_manifest};
|
||||
|
||||
fn take_runtime_owners_in_dependency_order<Instance, Validation, Surface, Device, Swapchain>(
|
||||
instance: &mut Option<Instance>,
|
||||
validation: &mut Option<Validation>,
|
||||
surface: &mut Option<Surface>,
|
||||
device: &mut Option<Device>,
|
||||
swapchain: &mut Option<Swapchain>,
|
||||
) {
|
||||
swapchain.take();
|
||||
device.take();
|
||||
surface.take();
|
||||
validation.take();
|
||||
instance.take();
|
||||
}
|
||||
|
||||
impl VulkanSmokeRenderer {
|
||||
/// Creates a live Vulkan smoke renderer bound to a live native window.
|
||||
///
|
||||
@@ -546,11 +560,13 @@ impl VulkanSmokeRenderer {
|
||||
};
|
||||
}
|
||||
// Drop child Vulkan owners explicitly before their parents instead of relying on field order.
|
||||
self.swapchain.take();
|
||||
self.device.take();
|
||||
self.surface.take();
|
||||
self.validation.take();
|
||||
self.instance.take();
|
||||
take_runtime_owners_in_dependency_order(
|
||||
&mut self.instance,
|
||||
&mut self.validation,
|
||||
&mut self.surface,
|
||||
&mut self.device,
|
||||
&mut self.swapchain,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,3 +575,142 @@ impl Drop for VulkanSmokeRenderer {
|
||||
self.teardown();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::take_runtime_owners_in_dependency_order;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum TeardownStep {
|
||||
Instance,
|
||||
Validation,
|
||||
Surface,
|
||||
Device,
|
||||
Swapchain,
|
||||
}
|
||||
|
||||
struct DropTracker {
|
||||
step: TeardownStep,
|
||||
log: Rc<RefCell<Vec<TeardownStep>>>,
|
||||
}
|
||||
|
||||
impl Drop for DropTracker {
|
||||
fn drop(&mut self) {
|
||||
self.log.borrow_mut().push(self.step);
|
||||
}
|
||||
}
|
||||
|
||||
fn tracker(step: TeardownStep, log: &Rc<RefCell<Vec<TeardownStep>>>) -> DropTracker {
|
||||
DropTracker {
|
||||
step,
|
||||
log: Rc::clone(log),
|
||||
}
|
||||
}
|
||||
|
||||
fn record_teardown_steps(present_steps: &[TeardownStep]) -> Vec<TeardownStep> {
|
||||
let log = Rc::new(RefCell::new(Vec::new()));
|
||||
let mut instance = present_steps
|
||||
.contains(&TeardownStep::Instance)
|
||||
.then(|| tracker(TeardownStep::Instance, &log));
|
||||
let mut validation = present_steps
|
||||
.contains(&TeardownStep::Validation)
|
||||
.then(|| tracker(TeardownStep::Validation, &log));
|
||||
let mut surface = present_steps
|
||||
.contains(&TeardownStep::Surface)
|
||||
.then(|| tracker(TeardownStep::Surface, &log));
|
||||
let mut device = present_steps
|
||||
.contains(&TeardownStep::Device)
|
||||
.then(|| tracker(TeardownStep::Device, &log));
|
||||
let mut swapchain = present_steps
|
||||
.contains(&TeardownStep::Swapchain)
|
||||
.then(|| tracker(TeardownStep::Swapchain, &log));
|
||||
|
||||
take_runtime_owners_in_dependency_order(
|
||||
&mut instance,
|
||||
&mut validation,
|
||||
&mut surface,
|
||||
&mut device,
|
||||
&mut swapchain,
|
||||
);
|
||||
Rc::into_inner(log)
|
||||
.expect("all drop trackers released")
|
||||
.into_inner()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_owners_drop_in_explicit_dependency_order() {
|
||||
assert_eq!(
|
||||
record_teardown_steps(&[
|
||||
TeardownStep::Instance,
|
||||
TeardownStep::Validation,
|
||||
TeardownStep::Surface,
|
||||
TeardownStep::Device,
|
||||
TeardownStep::Swapchain,
|
||||
]),
|
||||
vec![
|
||||
TeardownStep::Swapchain,
|
||||
TeardownStep::Device,
|
||||
TeardownStep::Surface,
|
||||
TeardownStep::Validation,
|
||||
TeardownStep::Instance,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_owners_drop_remaining_children_after_partial_init_failures() {
|
||||
let cases = [
|
||||
(vec![TeardownStep::Instance], vec![TeardownStep::Instance]),
|
||||
(
|
||||
vec![TeardownStep::Instance, TeardownStep::Validation],
|
||||
vec![TeardownStep::Validation, TeardownStep::Instance],
|
||||
),
|
||||
(
|
||||
vec![
|
||||
TeardownStep::Instance,
|
||||
TeardownStep::Validation,
|
||||
TeardownStep::Surface,
|
||||
],
|
||||
vec![
|
||||
TeardownStep::Surface,
|
||||
TeardownStep::Validation,
|
||||
TeardownStep::Instance,
|
||||
],
|
||||
),
|
||||
(
|
||||
vec![
|
||||
TeardownStep::Instance,
|
||||
TeardownStep::Validation,
|
||||
TeardownStep::Surface,
|
||||
TeardownStep::Device,
|
||||
],
|
||||
vec![
|
||||
TeardownStep::Device,
|
||||
TeardownStep::Surface,
|
||||
TeardownStep::Validation,
|
||||
TeardownStep::Instance,
|
||||
],
|
||||
),
|
||||
(
|
||||
vec![
|
||||
TeardownStep::Instance,
|
||||
TeardownStep::Surface,
|
||||
TeardownStep::Device,
|
||||
TeardownStep::Swapchain,
|
||||
],
|
||||
vec![
|
||||
TeardownStep::Swapchain,
|
||||
TeardownStep::Device,
|
||||
TeardownStep::Surface,
|
||||
TeardownStep::Instance,
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
for (present_steps, expected) in cases {
|
||||
assert_eq!(record_teardown_steps(&present_steps), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user