1use crate::{
11 device::{Device, DeviceOwned},
12 instance::InstanceOwnedDebugWrapper,
13 Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError, VulkanObject,
14};
15use std::{mem::MaybeUninit, ptr, sync::Arc};
16
17#[derive(Debug)]
22pub struct DeferredOperation {
23 device: InstanceOwnedDebugWrapper<Arc<Device>>,
24 handle: ash::vk::DeferredOperationKHR,
25}
26
27impl DeferredOperation {
28 #[inline]
34 pub fn new(device: Arc<Device>) -> Result<Arc<Self>, Validated<VulkanError>> {
35 Self::validate_new(&device)?;
36
37 Ok(unsafe { Self::new_unchecked(device) }?)
38 }
39
40 fn validate_new(device: &Device) -> Result<(), Box<ValidationError>> {
41 if !device.enabled_extensions().khr_deferred_host_operations {
42 return Err(Box::new(ValidationError {
43 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
44 "khr_deferred_host_operations",
45 )])]),
46 ..Default::default()
47 }));
48 }
49
50 Ok(())
51 }
52
53 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
54 pub unsafe fn new_unchecked(device: Arc<Device>) -> Result<Arc<Self>, VulkanError> {
55 let handle = {
56 let fns = device.fns();
57 let mut output = MaybeUninit::uninit();
58 unsafe {
59 (fns.khr_deferred_host_operations
60 .create_deferred_operation_khr)(
61 device.handle(),
62 ptr::null(),
63 output.as_mut_ptr(),
64 )
65 }
66 .result()
67 .map_err(VulkanError::from)?;
68 unsafe { output.assume_init() }
69 };
70
71 Ok(unsafe { Self::from_handle(device, handle) })
72 }
73
74 #[inline]
80 pub unsafe fn from_handle(
81 device: Arc<Device>,
82 handle: ash::vk::DeferredOperationKHR,
83 ) -> Arc<Self> {
84 Arc::new(Self {
85 device: InstanceOwnedDebugWrapper(device),
86 handle,
87 })
88 }
89
90 pub fn join(&self) -> Result<DeferredOperationJoinStatus, VulkanError> {
92 let fns = self.device.fns();
93 let result = unsafe {
94 (fns.khr_deferred_host_operations.deferred_operation_join_khr)(
95 self.device.handle(),
96 self.handle,
97 )
98 };
99
100 match result {
101 ash::vk::Result::SUCCESS => Ok(DeferredOperationJoinStatus::Complete),
102 ash::vk::Result::THREAD_DONE_KHR => Ok(DeferredOperationJoinStatus::ThreadDone),
103 ash::vk::Result::THREAD_IDLE_KHR => Ok(DeferredOperationJoinStatus::ThreadIdle),
104 err => Err(VulkanError::from(err)),
105 }
106 }
107
108 pub fn result(&self) -> Option<Result<(), VulkanError>> {
110 let fns = self.device.fns();
111 let result = unsafe {
112 (fns.khr_deferred_host_operations
113 .get_deferred_operation_result_khr)(self.device.handle(), self.handle)
114 };
115
116 match result {
117 ash::vk::Result::NOT_READY => None,
118 ash::vk::Result::SUCCESS => Some(Ok(())),
119 err => Some(Err(VulkanError::from(err))),
120 }
121 }
122
123 pub fn wait(&self) -> Result<Result<(), VulkanError>, VulkanError> {
125 loop {
129 match self.join()? {
130 DeferredOperationJoinStatus::Complete => {
131 break;
132 }
133 DeferredOperationJoinStatus::ThreadDone => {
134 std::thread::yield_now();
135 break;
136 }
137 DeferredOperationJoinStatus::ThreadIdle => {}
138 }
139 }
140
141 loop {
143 if let Some(result) = self.result() {
144 return Ok(result);
145 }
146
147 std::thread::yield_now();
148 }
149 }
150
151 pub fn max_concurrency(&self) -> Option<u32> {
156 let fns = self.device.fns();
157 let result = unsafe {
158 (fns.khr_deferred_host_operations
159 .get_deferred_operation_max_concurrency_khr)(
160 self.device.handle(), self.handle
161 )
162 };
163
164 (result != u32::MAX).then_some(result)
165 }
166}
167
168impl Drop for DeferredOperation {
169 #[inline]
170 fn drop(&mut self) {
171 let _ = self.wait(); let fns = self.device.fns();
174 unsafe {
175 (fns.khr_deferred_host_operations
176 .destroy_deferred_operation_khr)(
177 self.device.handle(), self.handle, ptr::null()
178 )
179 };
180 }
181}
182
183unsafe impl VulkanObject for DeferredOperation {
184 type Handle = ash::vk::DeferredOperationKHR;
185
186 #[inline]
187 fn handle(&self) -> Self::Handle {
188 self.handle
189 }
190}
191
192unsafe impl DeviceOwned for DeferredOperation {
193 #[inline]
194 fn device(&self) -> &Arc<Device> {
195 &self.device
196 }
197}
198
199#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
203pub enum DeferredOperationJoinStatus {
204 Complete,
206
207 ThreadDone,
210
211 ThreadIdle,
214}