• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 pub use self::fence_signal::{FenceSignalFuture, FenceSignalFutureBehavior};
11 pub use self::join::JoinFuture;
12 pub use self::now::{now, NowFuture};
13 pub use self::semaphore_signal::SemaphoreSignalFuture;
14 use crate::buffer::BufferAccess;
15 use crate::command_buffer::submit::SubmitAnyBuilder;
16 use crate::command_buffer::submit::SubmitBindSparseError;
17 use crate::command_buffer::submit::SubmitCommandBufferError;
18 use crate::command_buffer::submit::SubmitPresentError;
19 use crate::command_buffer::CommandBufferExecError;
20 use crate::command_buffer::CommandBufferExecFuture;
21 use crate::command_buffer::PrimaryCommandBuffer;
22 use crate::device::DeviceOwned;
23 use crate::device::Queue;
24 use crate::image::ImageAccess;
25 use crate::image::ImageLayout;
26 use crate::swapchain;
27 use crate::swapchain::PresentFuture;
28 use crate::swapchain::PresentRegion;
29 use crate::swapchain::Swapchain;
30 use crate::sync::AccessFlags;
31 use crate::sync::FenceWaitError;
32 use crate::sync::PipelineStages;
33 use crate::OomError;
34 use std::error;
35 use std::fmt;
36 use std::sync::Arc;
37 
38 mod fence_signal;
39 mod join;
40 mod now;
41 mod semaphore_signal;
42 
43 /// Represents an event that will happen on the GPU in the future.
44 ///
45 /// See the documentation of the `sync` module for explanations about futures.
46 // TODO: consider switching all methods to take `&mut self` for optimization purposes
47 pub unsafe trait GpuFuture: DeviceOwned {
48     /// If possible, checks whether the submission has finished. If so, gives up ownership of the
49     /// resources used by these submissions.
50     ///
51     /// It is highly recommended to call `cleanup_finished` from time to time. Doing so will
52     /// prevent memory usage from increasing over time, and will also destroy the locks on
53     /// resources used by the GPU.
cleanup_finished(&mut self)54     fn cleanup_finished(&mut self);
55 
56     /// Builds a submission that, if submitted, makes sure that the event represented by this
57     /// `GpuFuture` will happen, and possibly contains extra elements (eg. a semaphore wait or an
58     /// event wait) that makes the dependency with subsequent operations work.
59     ///
60     /// It is the responsibility of the caller to ensure that the submission is going to be
61     /// submitted only once. However keep in mind that this function can perfectly be called
62     /// multiple times (as long as the returned object is only submitted once).
63     /// Also note that calling `flush()` on the future  may change the value returned by
64     /// `build_submission()`.
65     ///
66     /// It is however the responsibility of the implementation to not return the same submission
67     /// from multiple different future objects. For example if you implement `GpuFuture` on
68     /// `Arc<Foo>` then `build_submission()` must always return `SubmitAnyBuilder::Empty`,
69     /// otherwise it would be possible for the user to clone the `Arc` and make the same
70     /// submission be submitted multiple times.
71     ///
72     /// It is also the responsibility of the implementation to ensure that it works if you call
73     /// `build_submission()` and submits the returned value without calling `flush()` first. In
74     /// other words, `build_submission()` should perform an implicit flush if necessary.
75     ///
76     /// Once the caller has submitted the submission and has determined that the GPU has finished
77     /// executing it, it should call `signal_finished`. Failure to do so will incur a large runtime
78     /// overhead, as the future will have to block to make sure that it is finished.
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>79     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>;
80 
81     /// Flushes the future and submits to the GPU the actions that will permit this future to
82     /// occur.
83     ///
84     /// The implementation must remember that it was flushed. If the function is called multiple
85     /// times, only the first time must result in a flush.
flush(&self) -> Result<(), FlushError>86     fn flush(&self) -> Result<(), FlushError>;
87 
88     /// Sets the future to its "complete" state, meaning that it can safely be destroyed.
89     ///
90     /// This must only be done if you called `build_submission()`, submitted the returned
91     /// submission, and determined that it was finished.
92     ///
93     /// The implementation must be aware that this function can be called multiple times on the
94     /// same future.
signal_finished(&self)95     unsafe fn signal_finished(&self);
96 
97     /// Returns the queue that triggers the event. Returns `None` if unknown or irrelevant.
98     ///
99     /// If this function returns `None` and `queue_change_allowed` returns `false`, then a panic
100     /// is likely to occur if you use this future. This is only a problem if you implement
101     /// the `GpuFuture` trait yourself for a type outside of vulkano.
queue(&self) -> Option<Arc<Queue>>102     fn queue(&self) -> Option<Arc<Queue>>;
103 
104     /// Returns `true` if elements submitted after this future can be submitted to a different
105     /// queue than the other returned by `queue()`.
queue_change_allowed(&self) -> bool106     fn queue_change_allowed(&self) -> bool;
107 
108     /// Checks whether submitting something after this future grants access (exclusive or shared,
109     /// depending on the parameter) to the given buffer on the given queue.
110     ///
111     /// If the access is granted, returns the pipeline stage and access flags of the latest usage
112     /// of this resource, or `None` if irrelevant.
113     ///
114     /// > **Note**: Returning `Ok` means "access granted", while returning `Err` means
115     /// > "don't know". Therefore returning `Err` is never unsafe.
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>116     fn check_buffer_access(
117         &self,
118         buffer: &dyn BufferAccess,
119         exclusive: bool,
120         queue: &Queue,
121     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
122 
123     /// Checks whether submitting something after this future grants access (exclusive or shared,
124     /// depending on the parameter) to the given image on the given queue.
125     ///
126     /// If the access is granted, returns the pipeline stage and access flags of the latest usage
127     /// of this resource, or `None` if irrelevant.
128     ///
129     /// Implementations must ensure that the image is in the given layout. However if the `layout`
130     /// is `Undefined` then the implementation should accept any actual layout.
131     ///
132     /// > **Note**: Returning `Ok` means "access granted", while returning `Err` means
133     /// > "don't know". Therefore returning `Err` is never unsafe.
134     ///
135     /// > **Note**: Keep in mind that changing the layout of an image also requires exclusive
136     /// > access.
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>137     fn check_image_access(
138         &self,
139         image: &dyn ImageAccess,
140         layout: ImageLayout,
141         exclusive: bool,
142         queue: &Queue,
143     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
144 
145     /// Joins this future with another one, representing the moment when both events have happened.
146     // TODO: handle errors
join<F>(self, other: F) -> JoinFuture<Self, F> where Self: Sized, F: GpuFuture,147     fn join<F>(self, other: F) -> JoinFuture<Self, F>
148     where
149         Self: Sized,
150         F: GpuFuture,
151     {
152         join::join(self, other)
153     }
154 
155     /// Executes a command buffer after this future.
156     ///
157     /// > **Note**: This is just a shortcut function. The actual implementation is in the
158     /// > `CommandBuffer` trait.
159     #[inline]
then_execute<Cb>( self, queue: Arc<Queue>, command_buffer: Cb, ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError> where Self: Sized, Cb: PrimaryCommandBuffer + 'static,160     fn then_execute<Cb>(
161         self,
162         queue: Arc<Queue>,
163         command_buffer: Cb,
164     ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError>
165     where
166         Self: Sized,
167         Cb: PrimaryCommandBuffer + 'static,
168     {
169         command_buffer.execute_after(self, queue)
170     }
171 
172     /// Executes a command buffer after this future, on the same queue as the future.
173     ///
174     /// > **Note**: This is just a shortcut function. The actual implementation is in the
175     /// > `CommandBuffer` trait.
176     #[inline]
then_execute_same_queue<Cb>( self, command_buffer: Cb, ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError> where Self: Sized, Cb: PrimaryCommandBuffer + 'static,177     fn then_execute_same_queue<Cb>(
178         self,
179         command_buffer: Cb,
180     ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError>
181     where
182         Self: Sized,
183         Cb: PrimaryCommandBuffer + 'static,
184     {
185         let queue = self.queue().unwrap().clone();
186         command_buffer.execute_after(self, queue)
187     }
188 
189     /// Signals a semaphore after this future. Returns another future that represents the signal.
190     ///
191     /// Call this function when you want to execute some operations on a queue and want to see the
192     /// result on another queue.
193     #[inline]
then_signal_semaphore(self) -> SemaphoreSignalFuture<Self> where Self: Sized,194     fn then_signal_semaphore(self) -> SemaphoreSignalFuture<Self>
195     where
196         Self: Sized,
197     {
198         semaphore_signal::then_signal_semaphore(self)
199     }
200 
201     /// Signals a semaphore after this future and flushes it. Returns another future that
202     /// represents the moment when the semaphore is signalled.
203     ///
204     /// This is a just a shortcut for `then_signal_semaphore()` followed with `flush()`.
205     ///
206     /// When you want to execute some operations A on a queue and some operations B on another
207     /// queue that need to see the results of A, it can be a good idea to submit A as soon as
208     /// possible while you're preparing B.
209     ///
210     /// If you ran A and B on the same queue, you would have to decide between submitting A then
211     /// B, or A and B simultaneously. Both approaches have their trade-offs. But if A and B are
212     /// on two different queues, then you would need two submits anyway and it is always
213     /// advantageous to submit A as soon as possible.
214     #[inline]
then_signal_semaphore_and_flush(self) -> Result<SemaphoreSignalFuture<Self>, FlushError> where Self: Sized,215     fn then_signal_semaphore_and_flush(self) -> Result<SemaphoreSignalFuture<Self>, FlushError>
216     where
217         Self: Sized,
218     {
219         let f = self.then_signal_semaphore();
220         f.flush()?;
221         Ok(f)
222     }
223 
224     /// Signals a fence after this future. Returns another future that represents the signal.
225     ///
226     /// > **Note**: More often than not you want to immediately flush the future after calling this
227     /// > function. If so, consider using `then_signal_fence_and_flush`.
228     #[inline]
then_signal_fence(self) -> FenceSignalFuture<Self> where Self: Sized,229     fn then_signal_fence(self) -> FenceSignalFuture<Self>
230     where
231         Self: Sized,
232     {
233         fence_signal::then_signal_fence(self, FenceSignalFutureBehavior::Continue)
234     }
235 
236     /// Signals a fence after this future. Returns another future that represents the signal.
237     ///
238     /// This is a just a shortcut for `then_signal_fence()` followed with `flush()`.
239     #[inline]
then_signal_fence_and_flush(self) -> Result<FenceSignalFuture<Self>, FlushError> where Self: Sized,240     fn then_signal_fence_and_flush(self) -> Result<FenceSignalFuture<Self>, FlushError>
241     where
242         Self: Sized,
243     {
244         let f = self.then_signal_fence();
245         f.flush()?;
246         Ok(f)
247     }
248 
249     /// Presents a swapchain image after this future.
250     ///
251     /// You should only ever do this indirectly after a `SwapchainAcquireFuture` of the same image,
252     /// otherwise an error will occur when flushing.
253     ///
254     /// > **Note**: This is just a shortcut for the `Swapchain::present()` function.
255     #[inline]
then_swapchain_present<W>( self, queue: Arc<Queue>, swapchain: Arc<Swapchain<W>>, image_index: usize, ) -> PresentFuture<Self, W> where Self: Sized,256     fn then_swapchain_present<W>(
257         self,
258         queue: Arc<Queue>,
259         swapchain: Arc<Swapchain<W>>,
260         image_index: usize,
261     ) -> PresentFuture<Self, W>
262     where
263         Self: Sized,
264     {
265         swapchain::present(swapchain, self, queue, image_index)
266     }
267 
268     /// Same as `then_swapchain_present`, except it allows specifying a present region.
269     ///
270     /// > **Note**: This is just a shortcut for the `Swapchain::present_incremental()` function.
271     #[inline]
then_swapchain_present_incremental<W>( self, queue: Arc<Queue>, swapchain: Arc<Swapchain<W>>, image_index: usize, present_region: PresentRegion, ) -> PresentFuture<Self, W> where Self: Sized,272     fn then_swapchain_present_incremental<W>(
273         self,
274         queue: Arc<Queue>,
275         swapchain: Arc<Swapchain<W>>,
276         image_index: usize,
277         present_region: PresentRegion,
278     ) -> PresentFuture<Self, W>
279     where
280         Self: Sized,
281     {
282         swapchain::present_incremental(swapchain, self, queue, image_index, present_region)
283     }
284 
285     /// Turn the current future into a `Box<dyn GpuFuture>`.
286     ///
287     /// This is a helper function that calls `Box::new(yourFuture) as Box<dyn GpuFuture>`.
boxed(self) -> Box<dyn GpuFuture> where Self: Sized + 'static,288     fn boxed(self) -> Box<dyn GpuFuture>
289     where
290         Self: Sized + 'static,
291     {
292         Box::new(self) as _
293     }
294 }
295 
296 unsafe impl<F: ?Sized> GpuFuture for Box<F>
297 where
298     F: GpuFuture,
299 {
300     #[inline]
cleanup_finished(&mut self)301     fn cleanup_finished(&mut self) {
302         (**self).cleanup_finished()
303     }
304 
305     #[inline]
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>306     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
307         (**self).build_submission()
308     }
309 
310     #[inline]
flush(&self) -> Result<(), FlushError>311     fn flush(&self) -> Result<(), FlushError> {
312         (**self).flush()
313     }
314 
315     #[inline]
signal_finished(&self)316     unsafe fn signal_finished(&self) {
317         (**self).signal_finished()
318     }
319 
320     #[inline]
queue_change_allowed(&self) -> bool321     fn queue_change_allowed(&self) -> bool {
322         (**self).queue_change_allowed()
323     }
324 
325     #[inline]
queue(&self) -> Option<Arc<Queue>>326     fn queue(&self) -> Option<Arc<Queue>> {
327         (**self).queue()
328     }
329 
330     #[inline]
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>331     fn check_buffer_access(
332         &self,
333         buffer: &dyn BufferAccess,
334         exclusive: bool,
335         queue: &Queue,
336     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
337         (**self).check_buffer_access(buffer, exclusive, queue)
338     }
339 
340     #[inline]
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>341     fn check_image_access(
342         &self,
343         image: &dyn ImageAccess,
344         layout: ImageLayout,
345         exclusive: bool,
346         queue: &Queue,
347     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
348         (**self).check_image_access(image, layout, exclusive, queue)
349     }
350 }
351 
352 /// Access to a resource was denied.
353 #[derive(Clone, Debug, PartialEq, Eq)]
354 pub enum AccessError {
355     /// Exclusive access is denied.
356     ExclusiveDenied,
357 
358     /// The resource is already in use, and there is no tracking of concurrent usages.
359     AlreadyInUse,
360 
361     UnexpectedImageLayout {
362         allowed: ImageLayout,
363         requested: ImageLayout,
364     },
365 
366     /// Trying to use an image without transitioning it from the "undefined" or "preinitialized"
367     /// layouts first.
368     ImageNotInitialized {
369         /// The layout that was requested for the image.
370         requested: ImageLayout,
371     },
372 
373     /// Trying to use a buffer that still contains garbage data.
374     BufferNotInitialized,
375 
376     /// Trying to use a swapchain image without depending on a corresponding acquire image future.
377     SwapchainImageAcquireOnly,
378 }
379 
380 impl error::Error for AccessError {}
381 
382 impl fmt::Display for AccessError {
383     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>384     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
385         write!(
386             fmt,
387             "{}",
388             match *self {
389                 AccessError::ExclusiveDenied => "only shared access is allowed for this resource",
390                 AccessError::AlreadyInUse => {
391                     "the resource is already in use, and there is no tracking of concurrent usages"
392                 }
393                 AccessError::UnexpectedImageLayout { .. } => {
394                     unimplemented!() // TODO: find a description
395                 }
396                 AccessError::ImageNotInitialized { .. } => {
397                     "trying to use an image without transitioning it from the undefined or \
398                  preinitialized layouts first"
399                 }
400                 AccessError::BufferNotInitialized => {
401                     "trying to use a buffer that still contains garbage data"
402                 }
403                 AccessError::SwapchainImageAcquireOnly => {
404                     "trying to use a swapchain image without depending on a corresponding acquire \
405                  image future"
406                 }
407             }
408         )
409     }
410 }
411 
412 /// Error that can happen when checking whether we have access to a resource.
413 #[derive(Clone, Debug, PartialEq, Eq)]
414 pub enum AccessCheckError {
415     /// Access to the resource has been denied.
416     Denied(AccessError),
417     /// The resource is unknown, therefore we cannot possibly answer whether we have access or not.
418     Unknown,
419 }
420 
421 impl error::Error for AccessCheckError {}
422 
423 impl fmt::Display for AccessCheckError {
424     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>425     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
426         write!(
427             fmt,
428             "{}",
429             match *self {
430                 AccessCheckError::Denied(_) => "access to the resource has been denied",
431                 AccessCheckError::Unknown => "the resource is unknown",
432             }
433         )
434     }
435 }
436 
437 impl From<AccessError> for AccessCheckError {
438     #[inline]
from(err: AccessError) -> AccessCheckError439     fn from(err: AccessError) -> AccessCheckError {
440         AccessCheckError::Denied(err)
441     }
442 }
443 
444 /// Error that can happen when creating a graphics pipeline.
445 #[derive(Clone, Debug, PartialEq, Eq)]
446 pub enum FlushError {
447     /// Access to a resource has been denied.
448     AccessError(AccessError),
449 
450     /// Not enough memory.
451     OomError(OomError),
452 
453     /// The connection to the device has been lost.
454     DeviceLost,
455 
456     /// The surface is no longer accessible and must be recreated.
457     SurfaceLost,
458 
459     /// The surface has changed in a way that makes the swapchain unusable. You must query the
460     /// surface's new properties and recreate a new swapchain if you want to continue drawing.
461     OutOfDate,
462 
463     /// The swapchain has lost or doesn't have fullscreen exclusivity possibly for
464     /// implementation-specific reasons outside of the application’s control.
465     FullscreenExclusiveLost,
466 
467     /// The flush operation needed to block, but the timeout has elapsed.
468     Timeout,
469 }
470 
471 impl error::Error for FlushError {
472     #[inline]
source(&self) -> Option<&(dyn error::Error + 'static)>473     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
474         match *self {
475             FlushError::AccessError(ref err) => Some(err),
476             FlushError::OomError(ref err) => Some(err),
477             _ => None,
478         }
479     }
480 }
481 
482 impl fmt::Display for FlushError {
483     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>484     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
485         write!(
486             fmt,
487             "{}",
488             match *self {
489                 FlushError::AccessError(_) => "access to a resource has been denied",
490                 FlushError::OomError(_) => "not enough memory",
491                 FlushError::DeviceLost => "the connection to the device has been lost",
492                 FlushError::SurfaceLost => "the surface of this swapchain is no longer valid",
493                 FlushError::OutOfDate => "the swapchain needs to be recreated",
494                 FlushError::FullscreenExclusiveLost => {
495                     "the swapchain no longer has fullscreen exclusivity"
496                 }
497                 FlushError::Timeout => {
498                     "the flush operation needed to block, but the timeout has \
499                                     elapsed"
500                 }
501             }
502         )
503     }
504 }
505 
506 impl From<AccessError> for FlushError {
507     #[inline]
from(err: AccessError) -> FlushError508     fn from(err: AccessError) -> FlushError {
509         FlushError::AccessError(err)
510     }
511 }
512 
513 impl From<SubmitPresentError> for FlushError {
514     #[inline]
from(err: SubmitPresentError) -> FlushError515     fn from(err: SubmitPresentError) -> FlushError {
516         match err {
517             SubmitPresentError::OomError(err) => FlushError::OomError(err),
518             SubmitPresentError::DeviceLost => FlushError::DeviceLost,
519             SubmitPresentError::SurfaceLost => FlushError::SurfaceLost,
520             SubmitPresentError::OutOfDate => FlushError::OutOfDate,
521             SubmitPresentError::FullscreenExclusiveLost => FlushError::FullscreenExclusiveLost,
522         }
523     }
524 }
525 
526 impl From<SubmitCommandBufferError> for FlushError {
527     #[inline]
from(err: SubmitCommandBufferError) -> FlushError528     fn from(err: SubmitCommandBufferError) -> FlushError {
529         match err {
530             SubmitCommandBufferError::OomError(err) => FlushError::OomError(err),
531             SubmitCommandBufferError::DeviceLost => FlushError::DeviceLost,
532         }
533     }
534 }
535 
536 impl From<SubmitBindSparseError> for FlushError {
537     #[inline]
from(err: SubmitBindSparseError) -> FlushError538     fn from(err: SubmitBindSparseError) -> FlushError {
539         match err {
540             SubmitBindSparseError::OomError(err) => FlushError::OomError(err),
541             SubmitBindSparseError::DeviceLost => FlushError::DeviceLost,
542         }
543     }
544 }
545 
546 impl From<FenceWaitError> for FlushError {
547     #[inline]
from(err: FenceWaitError) -> FlushError548     fn from(err: FenceWaitError) -> FlushError {
549         match err {
550             FenceWaitError::OomError(err) => FlushError::OomError(err),
551             FenceWaitError::Timeout => FlushError::Timeout,
552             FenceWaitError::DeviceLostError => FlushError::DeviceLost,
553         }
554     }
555 }
556