diff --git a/wgpu/src/backend/native_gpu_future.rs b/wgpu/src/backend/native_gpu_future.rs index a37b975385..f80fba7c37 100644 --- a/wgpu/src/backend/native_gpu_future.rs +++ b/wgpu/src/backend/native_gpu_future.rs @@ -1,25 +1,83 @@ +//! Futures that can be resolved when the GPU completes a task. +//! +//! This module defines the [`GpuFuture`] and [`GpuFutureCompletion`] +//! types, which `wgpu` uses to communicate to users when GPU +//! operations have completed, and when resources are ready to access. +//! This is only used by the `direct` back end, not on the web. +//! +//! The life cycle of a `GpuFuture` is as follows: +//! +//! - Calling [`new_gpu_future`] constructs a paired `GpuFuture` and +//! `GpuFutureCompletion`. +//! +//! - Calling [`complete(v)`] on a `GpuFutureCompletion` marks its +//! paired `GpuFuture` as ready with value `v`. This also wakes +//! the most recent [`Waker`] the future was polled with, if any. +//! +//! - Polling a `GpuFuture` either returns `v` if it is ready, or +//! saves the `Waker` passed to [`Future::poll`], to be awoken +//! when `complete` is called on the paired `GpuFutureCompletion`. +//! +//! ## Communicating with `wgpu_core` +//! +//! The `wgpu_core` crate uses various specialized callback types, +//! like [`wgpu_core::resource::BufferMapOperation`] for reporting +//! buffers that are ready to map, or +//! [`wgpu_core::device::queue::SubmittedWorkDoneClosure`] for +//! reporting the completion of submitted commands. To support FFI +//! bindings, these are unsafe, low-level structures that usually have +//! a function pointer and a untyped, raw "closure" pointer. +//! +//! Calling [`GpuFutureCompletion::into_raw`] returns a raw opaque +//! pointer suitable for use as the "closure" pointer in `wgpu_core`'s +//! callbacks. The [`GpuFutureCompletion::from_raw`] converts such a +//! raw opaque pointer back into a [`GpuFutureCompletion`]. See the +//! direct back end's implementation of [`Context::buffer_map_async`] +//! for an example of this. +//! +//! [`complete(v)`]: GpuFutureCompletion::complete +//! [`Waker`]: std::task::Waker +//! [`Future::poll`]: std::future::Future::poll +//! [`wgpu_core::resource::BufferMapOperation`]: https://docs.rs/wgpu-core/latest/wgpu_core/resource/struct.BufferMapOperation.html +//! [`wgpu_core::device::queue::SubmittedWorkDoneClosure`]: https://docs.rs/wgpu-core/latest/wgpu_core/device/queue/struct.SubmittedWorkDoneClosure.html +//! [`Context::buffer_map_async`]: crate::Context::buffer_map_async use parking_lot::Mutex; use std::future::Future; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll, Waker}; +/// The current state of a `GpuFuture`. enum WakerOrResult { + /// The last [`Waker`] used to poll this future, if any. + /// + /// [`Waker`]: std::task::Waker Waker(Waker), + + /// The value this future resolves to, if it is ready. Result(T), } +/// The shared state of a [`GpuFuture`] and its [`GpuFutureCompletion`]. +/// +/// Polling the future when it is not yet ready stores the [`Waker`] +/// here; completing the future when it has not yet been polled stores +/// the value here. See [`WakerOrResult`] for details. type GpuFutureData = Mutex>>; -/// A Future that can poll the wgpu::Device +/// A [`Future`] that will be ready when some sort of GPU activity has finished. +/// +/// Call [`new_gpu_future`] to create a `GpuFuture`, along with a +/// paired `GpuFutureCompletion` that can be used to mark it as ready. pub struct GpuFuture { data: Arc>, } +/// An opaque type used for pointers to a [`GpuFutureCompletion`]'s guts. pub enum OpaqueData {} //TODO: merge this with `GpuFuture` and avoid `Arc` on the data. -/// A completion handle to set the result on a GpuFuture +/// A completion handle to set the result on a [`GpuFuture`]. pub struct GpuFutureCompletion { data: Arc>, } @@ -41,6 +99,7 @@ impl Future for GpuFuture { } impl GpuFutureCompletion { + /// Mark our paired [`GpuFuture`] as ready, with the given `value`. pub fn complete(self, value: T) { let mut waker_or_result = self.data.lock(); @@ -55,10 +114,14 @@ impl GpuFutureCompletion { }; } + /// Convert this `GpuFutureCompletion` into a raw pointer for `wgpu_core` to hold. pub(crate) fn into_raw(self) -> *mut OpaqueData { Arc::into_raw(self.data) as _ } + /// Convert a raw pointer returned by [`into_raw`] back into a `GpuFutureCompletion`. + /// + /// [`into_raw`]: GpuFutureCompletion::into_raw pub(crate) unsafe fn from_raw(this: *mut OpaqueData) -> Self { Self { data: Arc::from_raw(this as _), @@ -66,6 +129,9 @@ impl GpuFutureCompletion { } } +/// Construct a fresh [`GpuFuture`] and a paired [`GpuFutureCompletion`]. +/// +/// See the module docs for details. pub(crate) fn new_gpu_future() -> (GpuFuture, GpuFutureCompletion) { let data = Arc::new(Mutex::new(None)); (