1use {
4 super::{DriverError, device::Device},
5 crate::submission::TimestampQueryPool,
6 ash::vk,
7 log::{error, trace},
8 std::{
9 cell::{Cell, RefCell},
10 fmt::Debug,
11 thread::panicking,
12 },
13};
14
15pub(crate) trait FenceDroppable: Debug + Send {
16 fn fence_signaled(&mut self, _fence: &Fence) {}
17}
18
19#[derive(Debug)]
20struct DeferredDrop<T>(T);
21
22impl<T> FenceDroppable for DeferredDrop<T> where T: Debug + Send {}
23
24#[derive(Debug)]
28#[read_only::cast]
29pub struct Fence {
30 #[readonly]
34 pub device: Device,
35
36 #[readonly]
40 pub handle: vk::Fence,
41
42 pub(crate) queued: Cell<bool>,
43 droppables: RefCell<Vec<Box<dyn FenceDroppable + 'static>>>,
44
45 #[readonly]
49 pub timestamps: TimestampQueryPool,
50}
51
52impl Fence {
53 pub fn create(device: &Device, signaled: bool) -> Result<Self, DriverError> {
57 Ok(Self {
58 device: device.clone(),
59 handle: Device::create_fence(device, signaled)?,
60 queued: Cell::new(signaled),
61 droppables: Default::default(),
62 timestamps: TimestampQueryPool::empty(),
63 })
64 }
65
66 pub(crate) fn drop_when_signaled(&self, x: impl Debug + Send + 'static) {
68 self.droppables.borrow_mut().push(Box::new(DeferredDrop(x)));
69 }
70
71 pub(crate) fn drop_fence_droppable(&self, x: impl FenceDroppable + 'static) {
72 self.droppables.borrow_mut().push(Box::new(x));
73 }
74
75 #[profiling::function]
76 fn drop_signaled(&self) {
77 let mut droppables = self.droppables.borrow_mut();
78
79 if !droppables.is_empty() {
80 trace!("dropping {} shared references", droppables.len());
81 }
82
83 for droppable in droppables.iter_mut() {
84 droppable.fence_signaled(self);
85 }
86
87 droppables.clear();
88 }
89
90 #[deprecated = "use status"]
91 #[doc(hidden)]
92 pub fn is_signaled(&self) -> Result<bool, DriverError> {
93 self.status()
94 }
95
96 pub(crate) fn set_timestamps(&mut self, timestamps: TimestampQueryPool) {
97 self.timestamps = timestamps;
98 }
99
100 #[profiling::function]
106 pub fn status(&self) -> Result<bool, DriverError> {
107 let res = unsafe { self.device.get_fence_status(self.handle) };
108
109 match res {
110 Ok(status) => {
111 if status {
112 self.drop_signaled();
113 }
114
115 Ok(status)
116 }
117 Err(err) if err == vk::Result::ERROR_DEVICE_LOST => {
118 error!("invalid device state: lost");
119
120 Err(DriverError::InvalidData)
121 }
122 Err(err) => {
123 error!("unable to get fence status: {err}");
124
125 Err(DriverError::InvalidData)
126 }
127 }
128 }
129
130 pub fn is_queued(&self) -> bool {
132 self.queued.get()
133 }
134
135 pub(crate) fn mark_queued(&mut self) {
137 self.queued.set(true);
138 }
139
140 pub fn reset(&mut self) -> Result<&mut Self, DriverError> {
147 #[cfg(feature = "checked")]
148 if !self.queued.get() {
149 return Ok(self);
150 }
151
152 if self.status()? {
153 Device::reset_fences(&self.device, std::slice::from_ref(&self.handle))?;
154 }
155
156 self.queued.set(false);
157 self.timestamps = TimestampQueryPool::empty();
158
159 Ok(self)
160 }
161
162 #[deprecated = "use wait"]
163 #[doc(hidden)]
164 pub fn wait_signaled(&mut self) -> Result<&mut Self, DriverError> {
165 self.wait()
166 }
167
168 #[profiling::function]
172 pub fn wait(&mut self) -> Result<&mut Self, DriverError> {
173 #[cfg(feature = "checked")]
174 if !self.queued.get() {
175 return Ok(self);
176 }
177
178 Device::wait_for_fence(&self.device, &self.handle)?;
179 self.drop_signaled();
180
181 Ok(self)
182 }
183}
184
185impl Drop for Fence {
186 #[profiling::function]
187 fn drop(&mut self) {
188 if panicking() {
189 return;
190 }
191
192 if self.queued.get() && self.wait().is_err() {
193 return;
194 }
195
196 unsafe {
197 self.device.destroy_fence(self.handle, None);
198 }
199 }
200}