|
5 | 5 | //! |
6 | 6 | //! The interface traits are all object safe and listed in the `InterfaceTypes` trait. |
7 | 7 | //! |
8 | | -//! The method for dispatching should optimize well if only one backend is compiled in, |
9 | | -//! as-if there was no dispatching at all. |
| 8 | +//! The method for dispatching should optimize well if only one backend is |
| 9 | +//! compiled in, as-if there was no dispatching at all. See the comments on |
| 10 | +//! [`dispatch_types`] for details. |
| 11 | +//! |
| 12 | +//! [`dispatch_types`]: macro.dispatch_types.html |
10 | 13 |
|
11 | 14 | #![allow(drop_bounds)] // This exists to remind implementors to impl drop. |
12 | 15 | #![allow(clippy::too_many_arguments)] // It's fine. |
@@ -581,16 +584,77 @@ pub trait BufferMappedRangeInterface: CommonTraits { |
581 | 584 | fn as_uint8array(&self) -> &js_sys::Uint8Array; |
582 | 585 | } |
583 | 586 |
|
584 | | -/// Generates Dispatch types for each of the interfaces. Each type is a wrapper around the |
585 | | -/// wgpu_core and webgpu types, and derefs to the appropriate interface trait-object. |
| 587 | +/// Generates a dispatch type for some `wgpu` API type. |
| 588 | +/// |
| 589 | +/// Invocations of this macro take one of the following forms: |
| 590 | +/// |
| 591 | +/// ```ignore |
| 592 | +/// dispatch_types! {mut type D: I = Core, Web, Dyn } |
| 593 | +/// dispatch_types! {ref type D: I = Core, Web, Dyn } |
| 594 | +/// ``` |
| 595 | +/// |
| 596 | +/// This defines `D` as a type that dereferences to a `dyn I` trait object. Most uses of |
| 597 | +/// `D` in the rest of this crate just call the methods from the `dyn I` object, not from |
| 598 | +/// `D` itself. |
| 599 | +/// |
| 600 | +/// Internally, `D` is an enum with up to three variants holding values of type `Core`, |
| 601 | +/// `Web`, and `Dyn`, all of which must implement `I`. `Core`, `Web` and `Dyn` are the |
| 602 | +/// types from the `wgpu_core`, `webgpu`, and `custom` submodules of `wgpu::backend` that |
| 603 | +/// correspond to `D`. The macro generates `Deref` and `DerefMut` implementations that |
| 604 | +/// match on this enum and produce a `dyn I` reference for each variant. |
| 605 | +/// |
| 606 | +/// The macro's `mut type` form defines `D` as the unique owner of the backend type, with |
| 607 | +/// a `DerefMut` implementation, and `as_*_mut` methods that return `&mut` references. |
| 608 | +/// This `D` does not implement `Clone`. |
| 609 | +/// |
| 610 | +/// The macro's `ref type` form defines `D` to hold an `Arc` pointing to the backend type, |
| 611 | +/// permitting `Clone` and `Deref`, but losing exclusive, mutable access. |
| 612 | +/// |
| 613 | +/// For example: |
| 614 | +/// |
| 615 | +/// ```ignore |
| 616 | +/// dispatch_types! {ref type DispatchBuffer: BufferInterface = |
| 617 | +/// CoreBuffer, WebBuffer, DynBuffer} |
| 618 | +/// ``` |
| 619 | +/// |
| 620 | +/// This defines `DispatchBuffer` as a type that dereferences to `&dyn BufferInterface`, |
| 621 | +/// which has methods like `map_async` and `destroy`. The enum would be: |
| 622 | +/// |
| 623 | +/// ```ignore |
| 624 | +/// pub enum DispatchBuffer { |
| 625 | +/// #[cfg(wgpu_core)] |
| 626 | +/// Core(Arc<CoreBuffer>), |
| 627 | +/// #[cfg(webgpu)] |
| 628 | +/// WebGPU(WebBuffer), |
| 629 | +/// #[cfg(custom)] |
| 630 | +/// Custom(DynBuffer), |
| 631 | +/// } |
| 632 | +/// ``` |
| 633 | +/// |
| 634 | +/// This macro also defines `as_*` methods so that the backend implementations can |
| 635 | +/// dereference other arguments. |
| 636 | +/// |
| 637 | +/// ## Devirtualization |
| 638 | +/// |
| 639 | +/// The dispatch types generated by this macro are carefully designed to allow the |
| 640 | +/// compiler to completely devirtualize calls in most circumstances. |
| 641 | +/// |
| 642 | +/// Note that every variant of the enum generated by this macro is under a `#[cfg]`. |
| 643 | +/// Naturally, the `match` expressions in the `Deref` and `DerefMut` implementations have |
| 644 | +/// matching `#[cfg]` attributes on each match arm. |
586 | 645 | /// |
587 | | -/// When there is only one backend, devirtualization fires and all dispatches should turn into |
588 | | -/// direct calls. If there are multiple, some dispatching will occur. |
| 646 | +/// In practice, when `wgpu`'s `"custom"` feature is not enabled, there is usually only |
| 647 | +/// one variant in the `enum`, making it effectively a newtype around the sole variant's |
| 648 | +/// data: it has no discriminant to branch on, and the `match` expressions are removed |
| 649 | +/// entirely by the compiler. |
589 | 650 | /// |
590 | | -/// This also provides `as_*` methods so that the backend implementations can dereference other |
591 | | -/// arguments. These are similarly free when there is only one backend. |
| 651 | +/// In this case, when we invoke a method from the interface trait `I` on a dispatch type, |
| 652 | +/// the `Deref` and `DerefMut` implementations' `match` statements build a `&dyn I` for |
| 653 | +/// the data, on which we immediately invoke a method. The vtable is a constant, allowing |
| 654 | +/// the Rust compiler to turn the `dyn` method call into an ordinary method call. This |
| 655 | +/// creates opportunities for inlining. |
592 | 656 | /// |
593 | | -/// In the future, we may want a truly generic backend, which could be extended from this enum. |
| 657 | +/// Similarly, the `as_*` methods are free when there is only one backend. |
594 | 658 | macro_rules! dispatch_types { |
595 | 659 | ( |
596 | 660 | ref type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident |
|
0 commit comments