mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
[wgpu] Document dispatch_type! macro. (#8483)
Add more documentation for the `dispatch_type` macro, and provide a more detailed explanation of how it enables devirtualization in the single-backend case.
This commit is contained in:
parent
3443224e78
commit
6e06ec99ee
@ -5,8 +5,11 @@
|
||||
//!
|
||||
//! The interface traits are all object safe and listed in the `InterfaceTypes` trait.
|
||||
//!
|
||||
//! The method for dispatching should optimize well if only one backend is compiled in,
|
||||
//! as-if there was no dispatching at all.
|
||||
//! The method for dispatching should optimize well if only one backend is
|
||||
//! compiled in, as-if there was no dispatching at all. See the comments on
|
||||
//! [`dispatch_types`] for details.
|
||||
//!
|
||||
//! [`dispatch_types`]: macro.dispatch_types.html
|
||||
|
||||
#![allow(drop_bounds)] // This exists to remind implementors to impl drop.
|
||||
#![allow(clippy::too_many_arguments)] // It's fine.
|
||||
@ -581,16 +584,77 @@ pub trait BufferMappedRangeInterface: CommonTraits {
|
||||
fn as_uint8array(&self) -> &js_sys::Uint8Array;
|
||||
}
|
||||
|
||||
/// Generates Dispatch types for each of the interfaces. Each type is a wrapper around the
|
||||
/// wgpu_core and webgpu types, and derefs to the appropriate interface trait-object.
|
||||
/// Generates a dispatch type for some `wgpu` API type.
|
||||
///
|
||||
/// When there is only one backend, devirtualization fires and all dispatches should turn into
|
||||
/// direct calls. If there are multiple, some dispatching will occur.
|
||||
/// Invocations of this macro take one of the following forms:
|
||||
///
|
||||
/// This also provides `as_*` methods so that the backend implementations can dereference other
|
||||
/// arguments. These are similarly free when there is only one backend.
|
||||
/// ```ignore
|
||||
/// dispatch_types! {mut type D: I = Core, Web, Dyn }
|
||||
/// dispatch_types! {ref type D: I = Core, Web, Dyn }
|
||||
/// ```
|
||||
///
|
||||
/// In the future, we may want a truly generic backend, which could be extended from this enum.
|
||||
/// This defines `D` as a type that dereferences to a `dyn I` trait object. Most uses of
|
||||
/// `D` in the rest of this crate just call the methods from the `dyn I` object, not from
|
||||
/// `D` itself.
|
||||
///
|
||||
/// Internally, `D` is an enum with up to three variants holding values of type `Core`,
|
||||
/// `Web`, and `Dyn`, all of which must implement `I`. `Core`, `Web` and `Dyn` are the
|
||||
/// types from the `wgpu_core`, `webgpu`, and `custom` submodules of `wgpu::backend` that
|
||||
/// correspond to `D`. The macro generates `Deref` and `DerefMut` implementations that
|
||||
/// match on this enum and produce a `dyn I` reference for each variant.
|
||||
///
|
||||
/// The macro's `mut type` form defines `D` as the unique owner of the backend type, with
|
||||
/// a `DerefMut` implementation, and `as_*_mut` methods that return `&mut` references.
|
||||
/// This `D` does not implement `Clone`.
|
||||
///
|
||||
/// The macro's `ref type` form defines `D` to hold an `Arc` pointing to the backend type,
|
||||
/// permitting `Clone` and `Deref`, but losing exclusive, mutable access.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```ignore
|
||||
/// dispatch_types! {ref type DispatchBuffer: BufferInterface =
|
||||
/// CoreBuffer, WebBuffer, DynBuffer}
|
||||
/// ```
|
||||
///
|
||||
/// This defines `DispatchBuffer` as a type that dereferences to `&dyn BufferInterface`,
|
||||
/// which has methods like `map_async` and `destroy`. The enum would be:
|
||||
///
|
||||
/// ```ignore
|
||||
/// pub enum DispatchBuffer {
|
||||
/// #[cfg(wgpu_core)]
|
||||
/// Core(Arc<CoreBuffer>),
|
||||
/// #[cfg(webgpu)]
|
||||
/// WebGPU(WebBuffer),
|
||||
/// #[cfg(custom)]
|
||||
/// Custom(DynBuffer),
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This macro also defines `as_*` methods so that the backend implementations can
|
||||
/// dereference other arguments.
|
||||
///
|
||||
/// ## Devirtualization
|
||||
///
|
||||
/// The dispatch types generated by this macro are carefully designed to allow the
|
||||
/// compiler to completely devirtualize calls in most circumstances.
|
||||
///
|
||||
/// Note that every variant of the enum generated by this macro is under a `#[cfg]`.
|
||||
/// Naturally, the `match` expressions in the `Deref` and `DerefMut` implementations have
|
||||
/// matching `#[cfg]` attributes on each match arm.
|
||||
///
|
||||
/// In practice, when `wgpu`'s `"custom"` feature is not enabled, there is usually only
|
||||
/// one variant in the `enum`, making it effectively a newtype around the sole variant's
|
||||
/// data: it has no discriminant to branch on, and the `match` expressions are removed
|
||||
/// entirely by the compiler.
|
||||
///
|
||||
/// In this case, when we invoke a method from the interface trait `I` on a dispatch type,
|
||||
/// the `Deref` and `DerefMut` implementations' `match` statements build a `&dyn I` for
|
||||
/// the data, on which we immediately invoke a method. The vtable is a constant, allowing
|
||||
/// the Rust compiler to turn the `dyn` method call into an ordinary method call. This
|
||||
/// creates opportunities for inlining.
|
||||
///
|
||||
/// Similarly, the `as_*` methods are free when there is only one backend.
|
||||
macro_rules! dispatch_types {
|
||||
(
|
||||
ref type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user