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 std::mem;
11 use std::sync::Arc;
12 use std::sync::Mutex;
13 use std::sync::MutexGuard;
14 use std::time::Duration;
15
16 use crate::buffer::BufferAccess;
17 use crate::command_buffer::submit::SubmitAnyBuilder;
18 use crate::command_buffer::submit::SubmitCommandBufferBuilder;
19 use crate::device::Device;
20 use crate::device::DeviceOwned;
21 use crate::device::Queue;
22 use crate::image::ImageAccess;
23 use crate::image::ImageLayout;
24 use crate::sync::AccessCheckError;
25 use crate::sync::AccessFlags;
26 use crate::sync::Fence;
27 use crate::sync::FlushError;
28 use crate::sync::GpuFuture;
29 use crate::sync::PipelineStages;
30
31 /// Builds a new fence signal future.
32 #[inline]
then_signal_fence<F>(future: F, behavior: FenceSignalFutureBehavior) -> FenceSignalFuture<F> where F: GpuFuture,33 pub fn then_signal_fence<F>(future: F, behavior: FenceSignalFutureBehavior) -> FenceSignalFuture<F>
34 where
35 F: GpuFuture,
36 {
37 let device = future.device().clone();
38
39 assert!(future.queue().is_some()); // TODO: document
40
41 let fence = Fence::from_pool(device.clone()).unwrap();
42 FenceSignalFuture {
43 device: device,
44 state: Mutex::new(FenceSignalFutureState::Pending(future, fence)),
45 behavior: behavior,
46 }
47 }
48
49 /// Describes the behavior of the future if you submit something after it.
50 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
51 pub enum FenceSignalFutureBehavior {
52 /// Continue execution on the same queue.
53 Continue,
54 /// Wait for the fence to be signalled before submitting any further operation.
55 Block {
56 /// How long to block the current thread.
57 timeout: Option<Duration>,
58 },
59 }
60
61 /// Represents a fence being signaled after a previous event.
62 ///
63 /// Contrary to most other future types, it is possible to block the current thread until the event
64 /// happens. This is done by calling the `wait()` function.
65 ///
66 /// Also note that the `GpuFuture` trait is implemented on `Arc<FenceSignalFuture<_>>`.
67 /// This means that you can put this future in an `Arc` and keep a copy of it somewhere in order
68 /// to know when the execution reached that point.
69 ///
70 /// ```
71 /// use std::sync::Arc;
72 /// use vulkano::sync::GpuFuture;
73 ///
74 /// # let future: Box<GpuFuture> = return;
75 /// // Assuming you have a chain of operations, like this:
76 /// // let future = ...
77 /// // .then_execute(foo)
78 /// // .then_execute(bar)
79 ///
80 /// // You can signal a fence at this point of the chain, and put the future in an `Arc`.
81 /// let fence_signal = Arc::new(future.then_signal_fence());
82 ///
83 /// // And then continue the chain:
84 /// // fence_signal.clone()
85 /// // .then_execute(baz)
86 /// // .then_execute(qux)
87 ///
88 /// // Later you can wait until you reach the point of `fence_signal`:
89 /// fence_signal.wait(None).unwrap();
90 /// ```
91 #[must_use = "Dropping this object will immediately block the thread until the GPU has finished \
92 processing the submission"]
93 pub struct FenceSignalFuture<F>
94 where
95 F: GpuFuture,
96 {
97 // Current state. See the docs of `FenceSignalFutureState`.
98 state: Mutex<FenceSignalFutureState<F>>,
99 // The device of the future.
100 device: Arc<Device>,
101 behavior: FenceSignalFutureBehavior,
102 }
103
104 // This future can be in three different states: pending (ie. newly-created), submitted (ie. the
105 // command that submits the fence has been submitted), or cleaned (ie. the previous future has
106 // been dropped).
107 enum FenceSignalFutureState<F> {
108 // Newly-created. Not submitted yet.
109 Pending(F, Fence),
110
111 // Partially submitted to the queue. Only happens in situations where submitting requires two
112 // steps, and when the first step succeeded while the second step failed.
113 //
114 // Note that if there's ever a submit operation that needs three steps we will need to rework
115 // this code, as it was designed for two-step operations only.
116 PartiallyFlushed(F, Fence),
117
118 // Submitted to the queue.
119 Flushed(F, Fence),
120
121 // The submission is finished. The previous future and the fence have been cleaned.
122 Cleaned,
123
124 // A function panicked while the state was being modified. Should never happen.
125 Poisoned,
126 }
127
128 impl<F> FenceSignalFuture<F>
129 where
130 F: GpuFuture,
131 {
132 /// Blocks the current thread until the fence is signaled by the GPU. Performs a flush if
133 /// necessary.
134 ///
135 /// If `timeout` is `None`, then the wait is infinite. Otherwise the thread will unblock after
136 /// the specified timeout has elapsed and an error will be returned.
137 ///
138 /// If the wait is successful, this function also cleans any resource locked by previous
139 /// submissions.
wait(&self, timeout: Option<Duration>) -> Result<(), FlushError>140 pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FlushError> {
141 let mut state = self.state.lock().unwrap();
142
143 self.flush_impl(&mut state)?;
144
145 match mem::replace(&mut *state, FenceSignalFutureState::Cleaned) {
146 FenceSignalFutureState::Flushed(previous, fence) => {
147 fence.wait(timeout)?;
148 unsafe {
149 previous.signal_finished();
150 }
151 Ok(())
152 }
153 FenceSignalFutureState::Cleaned => Ok(()),
154 _ => unreachable!(),
155 }
156 }
157 }
158
159 impl<F> FenceSignalFuture<F>
160 where
161 F: GpuFuture,
162 {
163 // Implementation of `cleanup_finished`, but takes a `&self` instead of a `&mut self`.
164 // This is an external function so that we can also call it from an `Arc<FenceSignalFuture>`.
165 #[inline]
cleanup_finished_impl(&self)166 fn cleanup_finished_impl(&self) {
167 let mut state = self.state.lock().unwrap();
168
169 match *state {
170 FenceSignalFutureState::Flushed(ref mut prev, ref fence) => {
171 match fence.wait(Some(Duration::from_secs(0))) {
172 Ok(()) => unsafe { prev.signal_finished() },
173 Err(_) => {
174 prev.cleanup_finished();
175 return;
176 }
177 }
178 }
179 FenceSignalFutureState::Pending(ref mut prev, _) => {
180 prev.cleanup_finished();
181 return;
182 }
183 FenceSignalFutureState::PartiallyFlushed(ref mut prev, _) => {
184 prev.cleanup_finished();
185 return;
186 }
187 _ => return,
188 };
189
190 // This code can only be reached if we're already flushed and waiting on the fence
191 // succeeded.
192 *state = FenceSignalFutureState::Cleaned;
193 }
194
195 // Implementation of `flush`. You must lock the state and pass the mutex guard here.
flush_impl( &self, state: &mut MutexGuard<FenceSignalFutureState<F>>, ) -> Result<(), FlushError>196 fn flush_impl(
197 &self,
198 state: &mut MutexGuard<FenceSignalFutureState<F>>,
199 ) -> Result<(), FlushError> {
200 unsafe {
201 // In this function we temporarily replace the current state with `Poisoned` at the
202 // beginning, and we take care to always put back a value into `state` before
203 // returning (even in case of error).
204 let old_state = mem::replace(&mut **state, FenceSignalFutureState::Poisoned);
205
206 let (previous, fence, partially_flushed) = match old_state {
207 FenceSignalFutureState::Pending(prev, fence) => (prev, fence, false),
208 FenceSignalFutureState::PartiallyFlushed(prev, fence) => (prev, fence, true),
209 other => {
210 // We were already flushed in the past, or we're already poisoned. Don't do
211 // anything.
212 **state = other;
213 return Ok(());
214 }
215 };
216
217 // TODO: meh for unwrap
218 let queue = previous.queue().unwrap().clone();
219
220 // There are three possible outcomes for the flush operation: success, partial success
221 // in which case `result` will contain `Err(OutcomeErr::Partial)`, or total failure
222 // in which case `result` will contain `Err(OutcomeErr::Full)`.
223 enum OutcomeErr<E> {
224 Partial(E),
225 Full(E),
226 }
227 let result = match previous.build_submission()? {
228 SubmitAnyBuilder::Empty => {
229 debug_assert!(!partially_flushed);
230 let mut b = SubmitCommandBufferBuilder::new();
231 b.set_fence_signal(&fence);
232 b.submit(&queue).map_err(|err| OutcomeErr::Full(err.into()))
233 }
234 SubmitAnyBuilder::SemaphoresWait(sem) => {
235 debug_assert!(!partially_flushed);
236 let b: SubmitCommandBufferBuilder = sem.into();
237 debug_assert!(!b.has_fence());
238 b.submit(&queue).map_err(|err| OutcomeErr::Full(err.into()))
239 }
240 SubmitAnyBuilder::CommandBuffer(mut cb_builder) => {
241 debug_assert!(!partially_flushed);
242 // The assert below could technically be a debug assertion as it is part of the
243 // safety contract of the trait. However it is easy to get this wrong if you
244 // write a custom implementation, and if so the consequences would be
245 // disastrous and hard to debug. Therefore we prefer to just use a regular
246 // assertion.
247 assert!(!cb_builder.has_fence());
248 cb_builder.set_fence_signal(&fence);
249 cb_builder
250 .submit(&queue)
251 .map_err(|err| OutcomeErr::Full(err.into()))
252 }
253 SubmitAnyBuilder::BindSparse(mut sparse) => {
254 debug_assert!(!partially_flushed);
255 // Same remark as `CommandBuffer`.
256 assert!(!sparse.has_fence());
257 sparse.set_fence_signal(&fence);
258 sparse
259 .submit(&queue)
260 .map_err(|err| OutcomeErr::Full(err.into()))
261 }
262 SubmitAnyBuilder::QueuePresent(present) => {
263 let intermediary_result = if partially_flushed {
264 Ok(())
265 } else {
266 present.submit(&queue)
267 };
268 match intermediary_result {
269 Ok(()) => {
270 let mut b = SubmitCommandBufferBuilder::new();
271 b.set_fence_signal(&fence);
272 b.submit(&queue)
273 .map_err(|err| OutcomeErr::Partial(err.into()))
274 }
275 Err(err) => Err(OutcomeErr::Full(err.into())),
276 }
277 }
278 };
279
280 // Restore the state before returning.
281 match result {
282 Ok(()) => {
283 **state = FenceSignalFutureState::Flushed(previous, fence);
284 Ok(())
285 }
286 Err(OutcomeErr::Partial(err)) => {
287 **state = FenceSignalFutureState::PartiallyFlushed(previous, fence);
288 Err(err)
289 }
290 Err(OutcomeErr::Full(err)) => {
291 **state = FenceSignalFutureState::Pending(previous, fence);
292 Err(err)
293 }
294 }
295 }
296 }
297 }
298
299 impl<F> FenceSignalFutureState<F> {
300 #[inline]
get_prev(&self) -> Option<&F>301 fn get_prev(&self) -> Option<&F> {
302 match *self {
303 FenceSignalFutureState::Pending(ref prev, _) => Some(prev),
304 FenceSignalFutureState::PartiallyFlushed(ref prev, _) => Some(prev),
305 FenceSignalFutureState::Flushed(ref prev, _) => Some(prev),
306 FenceSignalFutureState::Cleaned => None,
307 FenceSignalFutureState::Poisoned => None,
308 }
309 }
310 }
311
312 unsafe impl<F> GpuFuture for FenceSignalFuture<F>
313 where
314 F: GpuFuture,
315 {
316 #[inline]
cleanup_finished(&mut self)317 fn cleanup_finished(&mut self) {
318 self.cleanup_finished_impl()
319 }
320
321 #[inline]
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>322 unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
323 let mut state = self.state.lock().unwrap();
324 self.flush_impl(&mut state)?;
325
326 match *state {
327 FenceSignalFutureState::Flushed(_, ref fence) => match self.behavior {
328 FenceSignalFutureBehavior::Block { timeout } => {
329 fence.wait(timeout)?;
330 }
331 FenceSignalFutureBehavior::Continue => (),
332 },
333 FenceSignalFutureState::Cleaned | FenceSignalFutureState::Poisoned => (),
334 FenceSignalFutureState::Pending(_, _) => unreachable!(),
335 FenceSignalFutureState::PartiallyFlushed(_, _) => unreachable!(),
336 }
337
338 Ok(SubmitAnyBuilder::Empty)
339 }
340
341 #[inline]
flush(&self) -> Result<(), FlushError>342 fn flush(&self) -> Result<(), FlushError> {
343 let mut state = self.state.lock().unwrap();
344 self.flush_impl(&mut state)
345 }
346
347 #[inline]
signal_finished(&self)348 unsafe fn signal_finished(&self) {
349 let state = self.state.lock().unwrap();
350 match *state {
351 FenceSignalFutureState::Flushed(ref prev, _) => {
352 prev.signal_finished();
353 }
354 FenceSignalFutureState::Cleaned | FenceSignalFutureState::Poisoned => (),
355 _ => unreachable!(),
356 }
357 }
358
359 #[inline]
queue_change_allowed(&self) -> bool360 fn queue_change_allowed(&self) -> bool {
361 match self.behavior {
362 FenceSignalFutureBehavior::Continue => {
363 let state = self.state.lock().unwrap();
364 if state.get_prev().is_some() {
365 false
366 } else {
367 true
368 }
369 }
370 FenceSignalFutureBehavior::Block { .. } => true,
371 }
372 }
373
374 #[inline]
queue(&self) -> Option<Arc<Queue>>375 fn queue(&self) -> Option<Arc<Queue>> {
376 let state = self.state.lock().unwrap();
377 if let Some(prev) = state.get_prev() {
378 prev.queue()
379 } else {
380 None
381 }
382 }
383
384 #[inline]
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>385 fn check_buffer_access(
386 &self,
387 buffer: &dyn BufferAccess,
388 exclusive: bool,
389 queue: &Queue,
390 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
391 let state = self.state.lock().unwrap();
392 if let Some(previous) = state.get_prev() {
393 previous.check_buffer_access(buffer, exclusive, queue)
394 } else {
395 Err(AccessCheckError::Unknown)
396 }
397 }
398
399 #[inline]
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>400 fn check_image_access(
401 &self,
402 image: &dyn ImageAccess,
403 layout: ImageLayout,
404 exclusive: bool,
405 queue: &Queue,
406 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
407 let state = self.state.lock().unwrap();
408 if let Some(previous) = state.get_prev() {
409 previous.check_image_access(image, layout, exclusive, queue)
410 } else {
411 Err(AccessCheckError::Unknown)
412 }
413 }
414 }
415
416 unsafe impl<F> DeviceOwned for FenceSignalFuture<F>
417 where
418 F: GpuFuture,
419 {
420 #[inline]
device(&self) -> &Arc<Device>421 fn device(&self) -> &Arc<Device> {
422 &self.device
423 }
424 }
425
426 impl<F> Drop for FenceSignalFuture<F>
427 where
428 F: GpuFuture,
429 {
drop(&mut self)430 fn drop(&mut self) {
431 let mut state = self.state.lock().unwrap();
432
433 // We ignore any possible error while submitting for now. Problems are handled below.
434 let _ = self.flush_impl(&mut state);
435
436 match mem::replace(&mut *state, FenceSignalFutureState::Cleaned) {
437 FenceSignalFutureState::Flushed(previous, fence) => {
438 // This is a normal situation. Submitting worked.
439 // TODO: handle errors?
440 fence.wait(None).unwrap();
441 unsafe {
442 previous.signal_finished();
443 }
444 }
445 FenceSignalFutureState::Cleaned => {
446 // Also a normal situation. The user called `cleanup_finished()` before dropping.
447 }
448 FenceSignalFutureState::Poisoned => {
449 // The previous future was already dropped and blocked the current queue.
450 }
451 FenceSignalFutureState::Pending(_, _)
452 | FenceSignalFutureState::PartiallyFlushed(_, _) => {
453 // Flushing produced an error. There's nothing more we can do except drop the
454 // previous future and let it block the current queue.
455 }
456 }
457 }
458 }
459
460 unsafe impl<F> GpuFuture for Arc<FenceSignalFuture<F>>
461 where
462 F: GpuFuture,
463 {
464 #[inline]
cleanup_finished(&mut self)465 fn cleanup_finished(&mut self) {
466 self.cleanup_finished_impl()
467 }
468
469 #[inline]
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>470 unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
471 // Note that this is sound because we always return `SubmitAnyBuilder::Empty`. See the
472 // documentation of `build_submission`.
473 (**self).build_submission()
474 }
475
476 #[inline]
flush(&self) -> Result<(), FlushError>477 fn flush(&self) -> Result<(), FlushError> {
478 (**self).flush()
479 }
480
481 #[inline]
signal_finished(&self)482 unsafe fn signal_finished(&self) {
483 (**self).signal_finished()
484 }
485
486 #[inline]
queue_change_allowed(&self) -> bool487 fn queue_change_allowed(&self) -> bool {
488 (**self).queue_change_allowed()
489 }
490
491 #[inline]
queue(&self) -> Option<Arc<Queue>>492 fn queue(&self) -> Option<Arc<Queue>> {
493 (**self).queue()
494 }
495
496 #[inline]
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>497 fn check_buffer_access(
498 &self,
499 buffer: &dyn BufferAccess,
500 exclusive: bool,
501 queue: &Queue,
502 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
503 (**self).check_buffer_access(buffer, exclusive, queue)
504 }
505
506 #[inline]
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>507 fn check_image_access(
508 &self,
509 image: &dyn ImageAccess,
510 layout: ImageLayout,
511 exclusive: bool,
512 queue: &Queue,
513 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
514 (**self).check_image_access(image, layout, exclusive, queue)
515 }
516 }
517