aboutsummaryrefslogtreecommitdiff
path: root/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
diff options
context:
space:
mode:
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/ffi/smoke.rs')
-rw-r--r--adapters/fparkan-render-vulkan/src/ffi/smoke.rs165
1 files changed, 160 insertions, 5 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi/smoke.rs b/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
index 0e38b37..1707f2b 100644
--- a/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
+++ b/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
@@ -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);
+ }
+ }
+}