1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! An event provides fine-grained synchronization within a single queue, or from the host to a
11 //! queue.
12 //!
13 //! When an event is signaled from a queue using the [`set_event`] command buffer command,
14 //! an event acts similar to a [pipeline barrier], but the synchronization scopes are split:
15 //! the source synchronization scope includes only commands before the `set_event` command,
16 //! while the destination synchronization scope includes only commands after the
17 //! [`wait_events`] command. Commands in between the two are not included.
18 //!
19 //! An event can also be signaled from the host, by calling the [`set`] method directly on the
20 //! [`Event`].
21 //!
22 //! [`set_event`]: crate::command_buffer::CommandBufferBuilder::set_event
23 //! [pipeline barrier]: crate::command_buffer::CommandBufferBuilder::pipeline_barrier
24 //! [`wait_events`]: crate::command_buffer::CommandBufferBuilder::wait_events
25 //! [`set`]: Event::set
26 
27 use crate::{
28     device::{Device, DeviceOwned},
29     macros::impl_id_counter,
30     OomError, RequiresOneOf, VulkanError, VulkanObject,
31 };
32 use std::{
33     error::Error,
34     fmt::{Display, Error as FmtError, Formatter},
35     mem::MaybeUninit,
36     num::NonZeroU64,
37     ptr,
38     sync::Arc,
39 };
40 
41 /// Used to block the GPU execution until an event on the CPU occurs.
42 ///
43 /// Note that Vulkan implementations may have limits on how long a command buffer will wait for an
44 /// event to be signaled, in order to avoid interfering with progress of other clients of the GPU.
45 /// If the event isn't signaled within these limits, results are undefined and may include
46 /// device loss.
47 #[derive(Debug)]
48 pub struct Event {
49     handle: ash::vk::Event,
50     device: Arc<Device>,
51     id: NonZeroU64,
52     must_put_in_pool: bool,
53 }
54 
55 impl Event {
56     /// Creates a new `Event`.
57     ///
58     /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
59     /// devices, the
60     /// [`events`](crate::device::Features::events)
61     /// feature must be enabled on the device.
62     #[inline]
new(device: Arc<Device>, _create_info: EventCreateInfo) -> Result<Event, EventError>63     pub fn new(device: Arc<Device>, _create_info: EventCreateInfo) -> Result<Event, EventError> {
64         // VUID-vkCreateEvent-events-04468
65         if device.enabled_extensions().khr_portability_subset && !device.enabled_features().events {
66             return Err(EventError::RequirementNotMet {
67                 required_for: "this device is a portability subset device, and `Event::new` was \
68                     called",
69                 requires_one_of: RequiresOneOf {
70                     features: &["events"],
71                     ..Default::default()
72                 },
73             });
74         }
75 
76         let create_info = ash::vk::EventCreateInfo {
77             flags: ash::vk::EventCreateFlags::empty(),
78             ..Default::default()
79         };
80 
81         let handle = unsafe {
82             let mut output = MaybeUninit::uninit();
83             let fns = device.fns();
84             (fns.v1_0.create_event)(
85                 device.handle(),
86                 &create_info,
87                 ptr::null(),
88                 output.as_mut_ptr(),
89             )
90             .result()
91             .map_err(VulkanError::from)?;
92             output.assume_init()
93         };
94 
95         Ok(Event {
96             handle,
97             device,
98             id: Self::next_id(),
99             must_put_in_pool: false,
100         })
101     }
102 
103     /// Takes an event from the vulkano-provided event pool.
104     /// If the pool is empty, a new event will be allocated.
105     /// Upon `drop`, the event is put back into the pool.
106     ///
107     /// For most applications, using the event pool should be preferred,
108     /// in order to avoid creating new events every frame.
109     #[inline]
from_pool(device: Arc<Device>) -> Result<Event, EventError>110     pub fn from_pool(device: Arc<Device>) -> Result<Event, EventError> {
111         let handle = device.event_pool().lock().pop();
112         let event = match handle {
113             Some(handle) => {
114                 unsafe {
115                     // Make sure the event isn't signaled
116                     let fns = device.fns();
117                     (fns.v1_0.reset_event)(device.handle(), handle)
118                         .result()
119                         .map_err(VulkanError::from)?;
120                 }
121                 Event {
122                     handle,
123                     device,
124                     id: Self::next_id(),
125                     must_put_in_pool: true,
126                 }
127             }
128             None => {
129                 // Pool is empty, alloc new event
130                 let mut event = Event::new(device, Default::default())?;
131                 event.must_put_in_pool = true;
132                 event
133             }
134         };
135 
136         Ok(event)
137     }
138 
139     /// Creates a new `Event` from a raw object handle.
140     ///
141     /// # Safety
142     ///
143     /// - `handle` must be a valid Vulkan object handle created from `device`.
144     /// - `create_info` must match the info used to create the object.
145     #[inline]
from_handle( device: Arc<Device>, handle: ash::vk::Event, _create_info: EventCreateInfo, ) -> Event146     pub unsafe fn from_handle(
147         device: Arc<Device>,
148         handle: ash::vk::Event,
149         _create_info: EventCreateInfo,
150     ) -> Event {
151         Event {
152             handle,
153             device,
154             id: Self::next_id(),
155             must_put_in_pool: false,
156         }
157     }
158 
159     /// Returns true if the event is signaled.
160     #[inline]
signaled(&self) -> Result<bool, OomError>161     pub fn signaled(&self) -> Result<bool, OomError> {
162         unsafe {
163             let fns = self.device.fns();
164             let result = (fns.v1_0.get_event_status)(self.device.handle(), self.handle);
165             match result {
166                 ash::vk::Result::EVENT_SET => Ok(true),
167                 ash::vk::Result::EVENT_RESET => Ok(false),
168                 err => Err(VulkanError::from(err).into()),
169             }
170         }
171     }
172 
173     /// See the docs of set().
174     #[inline]
set_raw(&mut self) -> Result<(), OomError>175     pub fn set_raw(&mut self) -> Result<(), OomError> {
176         unsafe {
177             let fns = self.device.fns();
178             (fns.v1_0.set_event)(self.device.handle(), self.handle)
179                 .result()
180                 .map_err(VulkanError::from)?;
181             Ok(())
182         }
183     }
184 
185     /// Changes the `Event` to the signaled state.
186     ///
187     /// If a command buffer is waiting on this event, it is then unblocked.
188     ///
189     /// # Panics
190     ///
191     /// - Panics if the device or host ran out of memory.
192     #[inline]
set(&mut self)193     pub fn set(&mut self) {
194         self.set_raw().unwrap();
195     }
196 
197     /// See the docs of reset().
198     #[inline]
reset_raw(&mut self) -> Result<(), OomError>199     pub fn reset_raw(&mut self) -> Result<(), OomError> {
200         unsafe {
201             let fns = self.device.fns();
202             (fns.v1_0.reset_event)(self.device.handle(), self.handle)
203                 .result()
204                 .map_err(VulkanError::from)?;
205             Ok(())
206         }
207     }
208 
209     /// Changes the `Event` to the unsignaled state.
210     ///
211     /// # Panics
212     ///
213     /// - Panics if the device or host ran out of memory.
214     #[inline]
reset(&mut self)215     pub fn reset(&mut self) {
216         self.reset_raw().unwrap();
217     }
218 }
219 
220 impl Drop for Event {
221     #[inline]
drop(&mut self)222     fn drop(&mut self) {
223         unsafe {
224             if self.must_put_in_pool {
225                 let raw_event = self.handle;
226                 self.device.event_pool().lock().push(raw_event);
227             } else {
228                 let fns = self.device.fns();
229                 (fns.v1_0.destroy_event)(self.device.handle(), self.handle, ptr::null());
230             }
231         }
232     }
233 }
234 
235 unsafe impl VulkanObject for Event {
236     type Handle = ash::vk::Event;
237 
238     #[inline]
handle(&self) -> Self::Handle239     fn handle(&self) -> Self::Handle {
240         self.handle
241     }
242 }
243 
244 unsafe impl DeviceOwned for Event {
245     #[inline]
device(&self) -> &Arc<Device>246     fn device(&self) -> &Arc<Device> {
247         &self.device
248     }
249 }
250 
251 impl_id_counter!(Event);
252 
253 /// Parameters to create a new `Event`.
254 #[derive(Clone, Debug)]
255 pub struct EventCreateInfo {
256     pub _ne: crate::NonExhaustive,
257 }
258 
259 impl Default for EventCreateInfo {
260     #[inline]
default() -> Self261     fn default() -> Self {
262         Self {
263             _ne: crate::NonExhaustive(()),
264         }
265     }
266 }
267 
268 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
269 pub enum EventError {
270     /// Not enough memory available.
271     OomError(OomError),
272 
273     RequirementNotMet {
274         required_for: &'static str,
275         requires_one_of: RequiresOneOf,
276     },
277 }
278 
279 impl Error for EventError {
source(&self) -> Option<&(dyn Error + 'static)>280     fn source(&self) -> Option<&(dyn Error + 'static)> {
281         match self {
282             Self::OomError(err) => Some(err),
283             _ => None,
284         }
285     }
286 }
287 
288 impl Display for EventError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>289     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
290         match self {
291             Self::OomError(_) => write!(f, "not enough memory available"),
292             Self::RequirementNotMet {
293                 required_for,
294                 requires_one_of,
295             } => write!(
296                 f,
297                 "a requirement was not met for: {}; requires one of: {}",
298                 required_for, requires_one_of,
299             ),
300         }
301     }
302 }
303 
304 impl From<VulkanError> for EventError {
from(err: VulkanError) -> Self305     fn from(err: VulkanError) -> Self {
306         match err {
307             e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
308                 Self::OomError(e.into())
309             }
310             _ => panic!("unexpected error: {:?}", err),
311         }
312     }
313 }
314 
315 #[cfg(test)]
316 mod tests {
317     use crate::{sync::event::Event, VulkanObject};
318 
319     #[test]
event_create()320     fn event_create() {
321         let (device, _) = gfx_dev_and_queue!();
322         let event = Event::new(device, Default::default()).unwrap();
323         assert!(!event.signaled().unwrap());
324     }
325 
326     #[test]
event_set()327     fn event_set() {
328         let (device, _) = gfx_dev_and_queue!();
329         let mut event = Event::new(device, Default::default()).unwrap();
330         assert!(!event.signaled().unwrap());
331 
332         event.set();
333         assert!(event.signaled().unwrap());
334     }
335 
336     #[test]
event_reset()337     fn event_reset() {
338         let (device, _) = gfx_dev_and_queue!();
339 
340         let mut event = Event::new(device, Default::default()).unwrap();
341         event.set();
342         assert!(event.signaled().unwrap());
343 
344         event.reset();
345         assert!(!event.signaled().unwrap());
346     }
347 
348     #[test]
event_pool()349     fn event_pool() {
350         let (device, _) = gfx_dev_and_queue!();
351 
352         assert_eq!(device.event_pool().lock().len(), 0);
353         let event1_internal_obj = {
354             let event = Event::from_pool(device.clone()).unwrap();
355             assert_eq!(device.event_pool().lock().len(), 0);
356             event.handle()
357         };
358 
359         assert_eq!(device.event_pool().lock().len(), 1);
360         let event2 = Event::from_pool(device.clone()).unwrap();
361         assert_eq!(device.event_pool().lock().len(), 0);
362         assert_eq!(event2.handle(), event1_internal_obj);
363     }
364 }
365