Merge pull request #473 from tomaka/fence-future-wait

Add FenceSignalFuture::wait()
This commit is contained in:
tomaka 2017-05-25 20:50:06 +02:00 committed by GitHub
commit 7c70dd7e01

View File

@ -58,6 +58,35 @@ pub enum FenceSignalFutureBehavior {
} }
/// Represents a fence being signaled after a previous event. /// Represents a fence being signaled after a previous event.
///
/// Contrary to most other future types, it is possible to block the current thread until the event
/// happens. This is done by calling the `wait()` function.
///
/// Also note that the `GpuFuture` trait is implemented on `Arc<FenceSignalFuture<_>>`.
/// This means that you can put this future in an `Arc` and keep a copy of it somewhere in order
/// to know when the execution reached that point.
///
/// ```
/// use std::sync::Arc;
/// use vulkano::sync::GpuFuture;
///
/// # let future: Box<GpuFuture> = return;
/// // Assuming you have a chain of operations, like this:
/// // let future = ...
/// // .then_execute(foo)
/// // .then_execute(bar)
///
/// // You can signal a fence at this point of the chain, and put the future in an `Arc`.
/// let fence_signal = Arc::new(future.then_signal_fence());
///
/// // And then continue the chain:
/// // fence_signal.clone()
/// // .then_execute(baz)
/// // .then_execute(qux)
///
/// // Later you can wait until you reach the point of `fence_signal`:
/// fence_signal.wait(None).unwrap();
/// ```
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"] #[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
pub struct FenceSignalFuture<F> where F: GpuFuture { pub struct FenceSignalFuture<F> where F: GpuFuture {
// Current state. See the docs of `FenceSignalFutureState`. // Current state. See the docs of `FenceSignalFutureState`.
@ -91,6 +120,32 @@ enum FenceSignalFutureState<F> {
Poisonned, Poisonned,
} }
impl<F> FenceSignalFuture<F> where F: GpuFuture {
/// Blocks the current thread until the fence is signaled by the GPU. Performs a flush if
/// necessary.
///
/// If `timeout` is `None`, then the wait is infinite. Otherwise the thread will unblock after
/// the specified timeout has elapsed and an error will be returned.
///
/// If the wait is successful, this function also cleans any resource locked by previous
/// submissions.
pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FlushError> {
let mut state = self.state.lock().unwrap();
self.flush_impl(&mut state)?;
match mem::replace(&mut *state, FenceSignalFutureState::Cleaned) {
FenceSignalFutureState::Flushed(previous, fence) => {
fence.wait(timeout)?;
unsafe { previous.signal_finished(); }
Ok(())
},
FenceSignalFutureState::Cleaned => Ok(()),
_ => unreachable!()
}
}
}
impl<F> FenceSignalFuture<F> where F: GpuFuture { impl<F> FenceSignalFuture<F> where F: GpuFuture {
// Implementation of `cleanup_finished`, but takes a `&self` instead of a `&mut self`. // Implementation of `cleanup_finished`, but takes a `&self` instead of a `&mut self`.
// This is an external function so that we can also call it from an `Arc<FenceSignalFuture>`. // This is an external function so that we can also call it from an `Arc<FenceSignalFuture>`.