1 // Copyright (c) 2017 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 use super::{AccessCheckError, FlushError, GpuFuture};
11 use crate::{
12     buffer::Buffer,
13     command_buffer::{SemaphoreSubmitInfo, SubmitInfo},
14     device::{Device, DeviceOwned, Queue, QueueFlags},
15     image::{sys::Image, ImageLayout},
16     swapchain::Swapchain,
17     sync::{
18         fence::Fence,
19         future::{AccessError, SubmitAnyBuilder},
20         PipelineStages,
21     },
22     DeviceSize, OomError,
23 };
24 use parking_lot::{Mutex, MutexGuard};
25 use std::{
26     future::Future,
27     mem::replace,
28     ops::Range,
29     pin::Pin,
30     sync::Arc,
31     task::{Context, Poll},
32     thread,
33     time::Duration,
34 };
35 
36 /// Builds a new fence signal future.
then_signal_fence<F>(future: F, behavior: FenceSignalFutureBehavior) -> FenceSignalFuture<F> where F: GpuFuture,37 pub fn then_signal_fence<F>(future: F, behavior: FenceSignalFutureBehavior) -> FenceSignalFuture<F>
38 where
39     F: GpuFuture,
40 {
41     let device = future.device().clone();
42 
43     assert!(future.queue().is_some()); // TODO: document
44 
45     let fence = Arc::new(Fence::from_pool(device.clone()).unwrap());
46     FenceSignalFuture {
47         device,
48         state: Mutex::new(FenceSignalFutureState::Pending(future, fence)),
49         behavior,
50     }
51 }
52 
53 /// Describes the behavior of the future if you submit something after it.
54 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
55 pub enum FenceSignalFutureBehavior {
56     /// Continue execution on the same queue.
57     Continue,
58     /// Wait for the fence to be signalled before submitting any further operation.
59     #[allow(dead_code)] // TODO: why is this never constructed?
60     Block {
61         /// How long to block the current thread.
62         timeout: Option<Duration>,
63     },
64 }
65 
66 /// Represents a fence being signaled after a previous event.
67 ///
68 /// Contrary to most other future types, it is possible to block the current thread until the event
69 /// happens. This is done by calling the `wait()` function.
70 ///
71 /// This can also be done through Rust's Async system by simply `.await`ing this object. Note though
72 /// that (due to the Vulkan API fence design) this will spin to check the fence, rather than
73 /// blocking in the driver. Therefore if you have a long-running task, blocking may be less
74 /// CPU intense (depending on the driver's implementation).
75 ///
76 /// Also note that the `GpuFuture` trait is implemented on `Arc<FenceSignalFuture<_>>`.
77 /// This means that you can put this future in an `Arc` and keep a copy of it somewhere in order
78 /// to know when the execution reached that point.
79 ///
80 /// ```
81 /// use std::sync::Arc;
82 /// use vulkano::sync::GpuFuture;
83 ///
84 /// # let future: Box<dyn GpuFuture> = return;
85 /// // Assuming you have a chain of operations, like this:
86 /// // let future = ...
87 /// //      .then_execute(foo)
88 /// //      .then_execute(bar)
89 ///
90 /// // You can signal a fence at this point of the chain, and put the future in an `Arc`.
91 /// let fence_signal = Arc::new(future.then_signal_fence());
92 ///
93 /// // And then continue the chain:
94 /// // fence_signal.clone()
95 /// //      .then_execute(baz)
96 /// //      .then_execute(qux)
97 ///
98 /// // Later you can wait until you reach the point of `fence_signal`:
99 /// fence_signal.wait(None).unwrap();
100 /// ```
101 #[must_use = "Dropping this object will immediately block the thread until the GPU has finished \
102               processing the submission"]
103 pub struct FenceSignalFuture<F>
104 where
105     F: GpuFuture,
106 {
107     // Current state. See the docs of `FenceSignalFutureState`.
108     state: Mutex<FenceSignalFutureState<F>>,
109     // The device of the future.
110     device: Arc<Device>,
111     behavior: FenceSignalFutureBehavior,
112 }
113 
114 // This future can be in three different states: pending (ie. newly-created), submitted (ie. the
115 // command that submits the fence has been submitted), or cleaned (ie. the previous future has
116 // been dropped).
117 enum FenceSignalFutureState<F> {
118     // Newly-created. Not submitted yet.
119     Pending(F, Arc<Fence>),
120 
121     // Partially submitted to the queue. Only happens in situations where submitting requires two
122     // steps, and when the first step succeeded while the second step failed.
123     //
124     // Note that if there's ever a submit operation that needs three steps we will need to rework
125     // this code, as it was designed for two-step operations only.
126     PartiallyFlushed(F, Arc<Fence>),
127 
128     // Submitted to the queue.
129     Flushed(F, Arc<Fence>),
130 
131     // The submission is finished. The previous future and the fence have been cleaned.
132     Cleaned,
133 
134     // A function panicked while the state was being modified. Should never happen.
135     Poisoned,
136 }
137 
138 impl<F> FenceSignalFuture<F>
139 where
140     F: GpuFuture,
141 {
142     /// Returns true if the fence is signaled by the GPU.
is_signaled(&self) -> Result<bool, OomError>143     pub fn is_signaled(&self) -> Result<bool, OomError> {
144         let state = self.state.lock();
145 
146         match &*state {
147             FenceSignalFutureState::Pending(_, fence)
148             | FenceSignalFutureState::PartiallyFlushed(_, fence)
149             | FenceSignalFutureState::Flushed(_, fence) => fence.is_signaled(),
150             FenceSignalFutureState::Cleaned => Ok(true),
151             FenceSignalFutureState::Poisoned => unreachable!(),
152         }
153     }
154 
155     /// Blocks the current thread until the fence is signaled by the GPU. Performs a flush if
156     /// necessary.
157     ///
158     /// If `timeout` is `None`, then the wait is infinite. Otherwise the thread will unblock after
159     /// the specified timeout has elapsed and an error will be returned.
160     ///
161     /// If the wait is successful, this function also cleans any resource locked by previous
162     /// submissions.
wait(&self, timeout: Option<Duration>) -> Result<(), FlushError>163     pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FlushError> {
164         let mut state = self.state.lock();
165 
166         self.flush_impl(&mut state)?;
167 
168         match replace(&mut *state, FenceSignalFutureState::Cleaned) {
169             FenceSignalFutureState::Flushed(previous, fence) => {
170                 fence.wait(timeout)?;
171                 unsafe {
172                     previous.signal_finished();
173                 }
174                 Ok(())
175             }
176             FenceSignalFutureState::Cleaned => Ok(()),
177             _ => unreachable!(),
178         }
179     }
180 }
181 
182 impl<F> FenceSignalFuture<F>
183 where
184     F: GpuFuture,
185 {
186     // Implementation of `cleanup_finished`, but takes a `&self` instead of a `&mut self`.
187     // This is an external function so that we can also call it from an `Arc<FenceSignalFuture>`.
cleanup_finished_impl(&self)188     fn cleanup_finished_impl(&self) {
189         let mut state = self.state.lock();
190 
191         match *state {
192             FenceSignalFutureState::Flushed(ref mut prev, ref fence) => {
193                 match fence.wait(Some(Duration::from_secs(0))) {
194                     Ok(()) => {
195                         unsafe { prev.signal_finished() }
196                         *state = FenceSignalFutureState::Cleaned;
197                     }
198                     Err(_) => {
199                         prev.cleanup_finished();
200                     }
201                 }
202             }
203             FenceSignalFutureState::Pending(ref mut prev, _) => {
204                 prev.cleanup_finished();
205             }
206             FenceSignalFutureState::PartiallyFlushed(ref mut prev, _) => {
207                 prev.cleanup_finished();
208             }
209             _ => (),
210         }
211     }
212 
213     // Implementation of `flush`. You must lock the state and pass the mutex guard here.
flush_impl( &self, state: &mut MutexGuard<'_, FenceSignalFutureState<F>>, ) -> Result<(), FlushError>214     fn flush_impl(
215         &self,
216         state: &mut MutexGuard<'_, FenceSignalFutureState<F>>,
217     ) -> Result<(), FlushError> {
218         unsafe {
219             // In this function we temporarily replace the current state with `Poisoned` at the
220             // beginning, and we take care to always put back a value into `state` before
221             // returning (even in case of error).
222             let old_state = replace(&mut **state, FenceSignalFutureState::Poisoned);
223 
224             let (previous, new_fence, partially_flushed) = match old_state {
225                 FenceSignalFutureState::Pending(prev, fence) => (prev, fence, false),
226                 FenceSignalFutureState::PartiallyFlushed(prev, fence) => (prev, fence, true),
227                 other => {
228                     // We were already flushed in the past, or we're already poisoned. Don't do
229                     // anything.
230                     **state = other;
231                     return Ok(());
232                 }
233             };
234 
235             // TODO: meh for unwrap
236             let queue = previous.queue().unwrap();
237 
238             // There are three possible outcomes for the flush operation: success, partial success
239             // in which case `result` will contain `Err(OutcomeErr::Partial)`, or total failure
240             // in which case `result` will contain `Err(OutcomeErr::Full)`.
241             enum OutcomeErr<E> {
242                 Partial(E),
243                 Full(E),
244             }
245             let result = match previous.build_submission()? {
246                 SubmitAnyBuilder::Empty => {
247                     debug_assert!(!partially_flushed);
248 
249                     queue
250                         .with(|mut q| {
251                             q.submit_unchecked([Default::default()], Some(new_fence.clone()))
252                         })
253                         .map_err(|err| OutcomeErr::Full(err.into()))
254                 }
255                 SubmitAnyBuilder::SemaphoresWait(semaphores) => {
256                     debug_assert!(!partially_flushed);
257 
258                     queue
259                         .with(|mut q| {
260                             q.submit_unchecked(
261                                 [SubmitInfo {
262                                     wait_semaphores: semaphores
263                                         .into_iter()
264                                         .map(|semaphore| {
265                                             SemaphoreSubmitInfo {
266                                                 // TODO: correct stages ; hard
267                                                 stages: PipelineStages::ALL_COMMANDS,
268                                                 ..SemaphoreSubmitInfo::semaphore(semaphore)
269                                             }
270                                         })
271                                         .collect(),
272                                     ..Default::default()
273                                 }],
274                                 None,
275                             )
276                         })
277                         .map_err(|err| OutcomeErr::Full(err.into()))
278                 }
279                 SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
280                     debug_assert!(!partially_flushed);
281                     // The assert below could technically be a debug assertion as it is part of the
282                     // safety contract of the trait. However it is easy to get this wrong if you
283                     // write a custom implementation, and if so the consequences would be
284                     // disastrous and hard to debug. Therefore we prefer to just use a regular
285                     // assertion.
286                     assert!(fence.is_none());
287 
288                     queue
289                         .with(|mut q| {
290                             q.submit_with_future(
291                                 submit_info,
292                                 Some(new_fence.clone()),
293                                 &previous,
294                                 &queue,
295                             )
296                         })
297                         .map_err(OutcomeErr::Full)
298                 }
299                 SubmitAnyBuilder::BindSparse(bind_infos, fence) => {
300                     debug_assert!(!partially_flushed);
301                     // Same remark as `CommandBuffer`.
302                     assert!(fence.is_none());
303                     debug_assert!(queue.device().physical_device().queue_family_properties()
304                         [queue.queue_family_index() as usize]
305                         .queue_flags
306                         .intersects(QueueFlags::SPARSE_BINDING));
307 
308                     queue
309                         .with(|mut q| q.bind_sparse_unchecked(bind_infos, Some(new_fence.clone())))
310                         .map_err(|err| OutcomeErr::Full(err.into()))
311                 }
312                 SubmitAnyBuilder::QueuePresent(present_info) => {
313                     let intermediary_result = if partially_flushed {
314                         Ok(())
315                     } else {
316                         // VUID-VkPresentIdKHR-presentIds-04999
317                         for swapchain_info in &present_info.swapchain_infos {
318                             if swapchain_info.present_id.map_or(false, |present_id| {
319                                 !swapchain_info.swapchain.try_claim_present_id(present_id)
320                             }) {
321                                 return Err(FlushError::PresentIdLessThanOrEqual);
322                             }
323 
324                             match previous.check_swapchain_image_acquired(
325                                 &swapchain_info.swapchain,
326                                 swapchain_info.image_index,
327                                 true,
328                             ) {
329                                 Ok(_) => (),
330                                 Err(AccessCheckError::Unknown) => {
331                                     return Err(AccessError::SwapchainImageNotAcquired.into())
332                                 }
333                                 Err(AccessCheckError::Denied(e)) => return Err(e.into()),
334                             }
335                         }
336 
337                         queue
338                             .with(|mut q| q.present_unchecked(present_info))?
339                             .map(|r| r.map(|_| ()))
340                             .fold(Ok(()), Result::and)
341                     };
342 
343                     match intermediary_result {
344                         Ok(()) => queue
345                             .with(|mut q| {
346                                 q.submit_unchecked([Default::default()], Some(new_fence.clone()))
347                             })
348                             .map_err(|err| OutcomeErr::Partial(err.into())),
349                         Err(err) => Err(OutcomeErr::Full(err.into())),
350                     }
351                 }
352             };
353 
354             // Restore the state before returning.
355             match result {
356                 Ok(()) => {
357                     **state = FenceSignalFutureState::Flushed(previous, new_fence);
358                     Ok(())
359                 }
360                 Err(OutcomeErr::Partial(err)) => {
361                     **state = FenceSignalFutureState::PartiallyFlushed(previous, new_fence);
362                     Err(err)
363                 }
364                 Err(OutcomeErr::Full(err)) => {
365                     **state = FenceSignalFutureState::Pending(previous, new_fence);
366                     Err(err)
367                 }
368             }
369         }
370     }
371 }
372 
373 impl<F> Future for FenceSignalFuture<F>
374 where
375     F: GpuFuture,
376 {
377     type Output = Result<(), OomError>;
378 
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>379     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
380         // Implement through fence
381         let state = self.state.lock();
382 
383         match &*state {
384             FenceSignalFutureState::Pending(_, fence)
385             | FenceSignalFutureState::PartiallyFlushed(_, fence)
386             | FenceSignalFutureState::Flushed(_, fence) => fence.poll_impl(cx),
387             FenceSignalFutureState::Cleaned => Poll::Ready(Ok(())),
388             FenceSignalFutureState::Poisoned => unreachable!(),
389         }
390     }
391 }
392 
393 impl<F> FenceSignalFutureState<F> {
get_prev(&self) -> Option<&F>394     fn get_prev(&self) -> Option<&F> {
395         match self {
396             FenceSignalFutureState::Pending(prev, _) => Some(prev),
397             FenceSignalFutureState::PartiallyFlushed(prev, _) => Some(prev),
398             FenceSignalFutureState::Flushed(prev, _) => Some(prev),
399             FenceSignalFutureState::Cleaned => None,
400             FenceSignalFutureState::Poisoned => None,
401         }
402     }
403 }
404 
405 unsafe impl<F> GpuFuture for FenceSignalFuture<F>
406 where
407     F: GpuFuture,
408 {
cleanup_finished(&mut self)409     fn cleanup_finished(&mut self) {
410         self.cleanup_finished_impl()
411     }
412 
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>413     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
414         let mut state = self.state.lock();
415         self.flush_impl(&mut state)?;
416 
417         match &*state {
418             FenceSignalFutureState::Flushed(_, fence) => match self.behavior {
419                 FenceSignalFutureBehavior::Block { timeout } => {
420                     fence.wait(timeout)?;
421                 }
422                 FenceSignalFutureBehavior::Continue => (),
423             },
424             FenceSignalFutureState::Cleaned | FenceSignalFutureState::Poisoned => (),
425             FenceSignalFutureState::Pending(_, _) => unreachable!(),
426             FenceSignalFutureState::PartiallyFlushed(_, _) => unreachable!(),
427         }
428 
429         Ok(SubmitAnyBuilder::Empty)
430     }
431 
flush(&self) -> Result<(), FlushError>432     fn flush(&self) -> Result<(), FlushError> {
433         let mut state = self.state.lock();
434         self.flush_impl(&mut state)
435     }
436 
signal_finished(&self)437     unsafe fn signal_finished(&self) {
438         let state = self.state.lock();
439         match *state {
440             FenceSignalFutureState::Flushed(ref prev, _) => {
441                 prev.signal_finished();
442             }
443             FenceSignalFutureState::Cleaned | FenceSignalFutureState::Poisoned => (),
444             _ => unreachable!(),
445         }
446     }
447 
queue_change_allowed(&self) -> bool448     fn queue_change_allowed(&self) -> bool {
449         match self.behavior {
450             FenceSignalFutureBehavior::Continue => {
451                 let state = self.state.lock();
452                 state.get_prev().is_none()
453             }
454             FenceSignalFutureBehavior::Block { .. } => true,
455         }
456     }
457 
queue(&self) -> Option<Arc<Queue>>458     fn queue(&self) -> Option<Arc<Queue>> {
459         let state = self.state.lock();
460         if let Some(prev) = state.get_prev() {
461             prev.queue()
462         } else {
463             None
464         }
465     }
466 
check_buffer_access( &self, buffer: &Buffer, range: Range<DeviceSize>, exclusive: bool, queue: &Queue, ) -> Result<(), AccessCheckError>467     fn check_buffer_access(
468         &self,
469         buffer: &Buffer,
470         range: Range<DeviceSize>,
471         exclusive: bool,
472         queue: &Queue,
473     ) -> Result<(), AccessCheckError> {
474         let state = self.state.lock();
475         if let Some(previous) = state.get_prev() {
476             previous.check_buffer_access(buffer, range, exclusive, queue)
477         } else {
478             Err(AccessCheckError::Unknown)
479         }
480     }
481 
check_image_access( &self, image: &Image, range: Range<DeviceSize>, exclusive: bool, expected_layout: ImageLayout, queue: &Queue, ) -> Result<(), AccessCheckError>482     fn check_image_access(
483         &self,
484         image: &Image,
485         range: Range<DeviceSize>,
486         exclusive: bool,
487         expected_layout: ImageLayout,
488         queue: &Queue,
489     ) -> Result<(), AccessCheckError> {
490         let state = self.state.lock();
491         if let Some(previous) = state.get_prev() {
492             previous.check_image_access(image, range, exclusive, expected_layout, queue)
493         } else {
494             Err(AccessCheckError::Unknown)
495         }
496     }
497 
498     #[inline]
check_swapchain_image_acquired( &self, swapchain: &Swapchain, image_index: u32, _before: bool, ) -> Result<(), AccessCheckError>499     fn check_swapchain_image_acquired(
500         &self,
501         swapchain: &Swapchain,
502         image_index: u32,
503         _before: bool,
504     ) -> Result<(), AccessCheckError> {
505         if let Some(previous) = self.state.lock().get_prev() {
506             previous.check_swapchain_image_acquired(swapchain, image_index, false)
507         } else {
508             Err(AccessCheckError::Unknown)
509         }
510     }
511 }
512 
513 unsafe impl<F> DeviceOwned for FenceSignalFuture<F>
514 where
515     F: GpuFuture,
516 {
device(&self) -> &Arc<Device>517     fn device(&self) -> &Arc<Device> {
518         &self.device
519     }
520 }
521 
522 impl<F> Drop for FenceSignalFuture<F>
523 where
524     F: GpuFuture,
525 {
drop(&mut self)526     fn drop(&mut self) {
527         if thread::panicking() {
528             return;
529         }
530 
531         let mut state = self.state.lock();
532 
533         // We ignore any possible error while submitting for now. Problems are handled below.
534         let _ = self.flush_impl(&mut state);
535 
536         match replace(&mut *state, FenceSignalFutureState::Cleaned) {
537             FenceSignalFutureState::Flushed(previous, fence) => {
538                 // This is a normal situation. Submitting worked.
539                 // TODO: handle errors?
540                 fence.wait(None).unwrap();
541                 unsafe {
542                     previous.signal_finished();
543                 }
544             }
545             FenceSignalFutureState::Cleaned => {
546                 // Also a normal situation. The user called `cleanup_finished()` before dropping.
547             }
548             FenceSignalFutureState::Poisoned => {
549                 // The previous future was already dropped and blocked the current queue.
550             }
551             FenceSignalFutureState::Pending(_, _)
552             | FenceSignalFutureState::PartiallyFlushed(_, _) => {
553                 // Flushing produced an error. There's nothing more we can do except drop the
554                 // previous future and let it block the current queue.
555             }
556         }
557     }
558 }
559 
560 unsafe impl<F> GpuFuture for Arc<FenceSignalFuture<F>>
561 where
562     F: GpuFuture,
563 {
cleanup_finished(&mut self)564     fn cleanup_finished(&mut self) {
565         self.cleanup_finished_impl()
566     }
567 
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>568     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
569         // Note that this is sound because we always return `SubmitAnyBuilder::Empty`. See the
570         // documentation of `build_submission`.
571         (**self).build_submission()
572     }
573 
flush(&self) -> Result<(), FlushError>574     fn flush(&self) -> Result<(), FlushError> {
575         (**self).flush()
576     }
577 
signal_finished(&self)578     unsafe fn signal_finished(&self) {
579         (**self).signal_finished()
580     }
581 
queue_change_allowed(&self) -> bool582     fn queue_change_allowed(&self) -> bool {
583         (**self).queue_change_allowed()
584     }
585 
queue(&self) -> Option<Arc<Queue>>586     fn queue(&self) -> Option<Arc<Queue>> {
587         (**self).queue()
588     }
589 
check_buffer_access( &self, buffer: &Buffer, range: Range<DeviceSize>, exclusive: bool, queue: &Queue, ) -> Result<(), AccessCheckError>590     fn check_buffer_access(
591         &self,
592         buffer: &Buffer,
593         range: Range<DeviceSize>,
594         exclusive: bool,
595         queue: &Queue,
596     ) -> Result<(), AccessCheckError> {
597         (**self).check_buffer_access(buffer, range, exclusive, queue)
598     }
599 
check_image_access( &self, image: &Image, range: Range<DeviceSize>, exclusive: bool, expected_layout: ImageLayout, queue: &Queue, ) -> Result<(), AccessCheckError>600     fn check_image_access(
601         &self,
602         image: &Image,
603         range: Range<DeviceSize>,
604         exclusive: bool,
605         expected_layout: ImageLayout,
606         queue: &Queue,
607     ) -> Result<(), AccessCheckError> {
608         (**self).check_image_access(image, range, exclusive, expected_layout, queue)
609     }
610 
611     #[inline]
check_swapchain_image_acquired( &self, swapchain: &Swapchain, image_index: u32, before: bool, ) -> Result<(), AccessCheckError>612     fn check_swapchain_image_acquired(
613         &self,
614         swapchain: &Swapchain,
615         image_index: u32,
616         before: bool,
617     ) -> Result<(), AccessCheckError> {
618         (**self).check_swapchain_image_acquired(swapchain, image_index, before)
619     }
620 }
621