1use {
4 super::{DriverError, device::Device},
5 ash::vk,
6 log::{error, trace},
7 std::{fmt::Debug, thread::panicking},
8};
9
10#[derive(Debug)]
14#[read_only::cast]
15pub struct Fence {
16 #[readonly]
20 pub device: Device,
21
22 #[readonly]
26 pub handle: vk::Fence,
27
28 pub(crate) queued: bool,
29 droppables: Vec<Box<dyn Debug + Send + 'static>>,
30}
31
32impl Fence {
33 pub fn create(device: &Device, signaled: bool) -> Result<Self, DriverError> {
37 Ok(Self {
38 device: device.clone(),
39 handle: Device::create_fence(device, signaled)?,
40 queued: signaled,
41 droppables: Vec::new(),
42 })
43 }
44
45 pub(crate) fn drop_when_signaled(&mut self, x: impl Debug + Send + 'static) {
47 self.droppables.push(Box::new(x));
48 }
49
50 #[profiling::function]
51 fn drop_signaled(&mut self) {
52 if !self.droppables.is_empty() {
53 trace!("dropping {} shared references", self.droppables.len());
54 }
55
56 self.droppables.clear();
57 }
58
59 #[profiling::function]
63 pub fn is_signaled(&self) -> Result<bool, DriverError> {
64 let res = unsafe { self.device.get_fence_status(self.handle) };
65
66 match res {
67 Ok(status) => Ok(status),
68 Err(err) if err == vk::Result::ERROR_DEVICE_LOST => {
69 error!("invalid device state: lost");
70
71 Err(DriverError::InvalidData)
72 }
73 Err(err) => {
74 error!("unable to get fence status: {err}");
75
76 Err(DriverError::InvalidData)
77 }
78 }
79 }
80
81 pub fn is_queued(&self) -> bool {
83 self.queued
84 }
85
86 pub(crate) fn mark_queued(&mut self) {
88 self.queued = true;
89 }
90
91 pub fn reset(&mut self) -> Result<&mut Self, DriverError> {
95 #[cfg(feature = "checked")]
96 if !self.queued {
97 return Ok(self);
98 }
99
100 Device::reset_fences(&self.device, std::slice::from_ref(&self.handle))?;
101 self.queued = false;
102
103 Ok(self)
104 }
105
106 #[profiling::function]
110 pub fn wait_signaled(&mut self) -> Result<&mut Self, DriverError> {
111 #[cfg(feature = "checked")]
112 if !self.queued {
113 return Ok(self);
114 }
115
116 Device::wait_for_fence(&self.device, &self.handle)?;
117 self.drop_signaled();
118
119 Ok(self)
120 }
121}
122
123impl Drop for Fence {
124 #[profiling::function]
125 fn drop(&mut self) {
126 if panicking() {
127 return;
128 }
129
130 if self.queued && self.wait_signaled().is_err() {
131 return;
132 }
133
134 unsafe {
135 self.device.destroy_fence(self.handle, None);
136 }
137 }
138}