Skip to main content

inset_embedder/
composition.rs

1//! Native content the OS compositor shows beside the framework's picture: the capability a host
2//! with a compositor hands out, and the composition layer a producer feeds from a thread of its
3//! own. The Core Animation host's `os/apple/composition` module, in `inset-embedder-winit`, says
4//! why it is shaped as it is. A producer that paces by the screen's refreshes waits on the
5//! platform's [`VsyncWaiter`](crate::VsyncWaiter).
6//!
7//! A composition layer is a node of the compositor's tree, as Core Animation's `CALayer`,
8//! DirectComposition's visual and Android's `SurfaceControl` are: it shows buffers presented to
9//! it, or a layer the system draws itself, and holds children beneath it. It is made on its own
10//! ([`Compositor::make_layer`]) and adopted by whoever places it, as `addSublayer` decides a
11//! `CALayer`'s parent: a view's frame, whose [`Scene`](crate::Scene) places it through its
12//! [`slices`](crate::slices), or another layer, whose [`CompositionLayer::present`] places its
13//! children in its buffer's pixels, beneath its buffer. Each frame names every child it shows, as
14//! a frame-based compositor takes them: Chromium's `SubmitCompositorFrame` lists the surfaces a
15//! frame embeds, and Flutter's embedder hands its compositor each frame's layers. The host lands
16//! a frame in the one transaction its compositor has for it (a `CATransaction`, a parent's
17//! `wl_surface.commit`, `IDCompositionDevice::Commit`, a `SurfaceControl.Transaction`). A
18//! program whose picture is itself a layer in another app's window shows its own layers as that
19//! picture's children, and the placement of the picture moves, clips and scales the whole group
20//! as one.
21//!
22//! The invariant: a layer is on screen only where its parent's last frame placed it, it has one
23//! parent at a time, and the host, not the framework, owns the native object behind it.
24
25use std::any::Any;
26use std::sync::Arc;
27
28use crate::Placement;
29
30/// The host's compositor, as an app reaches it.
31pub trait Compositor: Send + Sync {
32    /// A layer placed nowhere yet, fed by a producer from any thread, and shown wherever the one
33    /// that places it says: a view's scenes, or another layer's presents. `opaque` says whether
34    /// its buffers carry no alpha the compositor must blend; a present that gives it children,
35    /// which show through the clear pixels of its buffer, has that buffer blended all the same.
36    /// The layer goes when its last handle does: its producer's, and those of the frames that
37    /// place it.
38    fn make_layer(&self, opaque: bool) -> Arc<dyn CompositionLayer>;
39}
40
41/// One layer of the compositor's tree. Every method may be called from any thread.
42///
43/// The handle is the layer's identity: a frame places the `Arc` itself, so only a layer that
44/// exists can be placed, and it lives while anything shows it. A host gets its own type back
45/// from a placed layer by downcasting through `Any`.
46pub trait CompositionLayer: Any + Send + Sync {
47    /// Shows `buffer`, which fills the layer, and `children` beneath it, the bottom-most first,
48    /// from the compositor's next frame on, in one step. Each child lies where its placement says
49    /// in the buffer's pixels, as a scene places a layer in its view's, so the buffer's own
50    /// placement moves, clips and scales it with it. A child the last present showed and this one
51    /// does not name is let go; a layer another parent holds is not shown here, and is reported.
52    ///
53    /// Returns once the host holds the buffer, not once it is on screen. `released` runs, on any
54    /// thread, when the compositor has finished with the buffer and the producer may draw into
55    /// it again, as Wayland's `wl_buffer.release`. On Apple platforms the host learns that from
56    /// `IOSurfaceIsInUse` at the layer's next present, or when the layer goes, so a producer
57    /// there never waits for a buffer to come back: it draws into one it knows is free, or a new
58    /// one. Core Animation takes no fence, so a producer that draws the buffer on the GPU
59    /// presents it once that work is scheduled (`waitUntilScheduled`), as Chromium does before
60    /// it hands Core Animation a surface.
61    fn present(
62        &self,
63        buffer: HardwareBuffer,
64        children: Vec<(Arc<dyn CompositionLayer>, Placement)>,
65        released: Box<dyn FnOnce() + Send + Sync>,
66    );
67}
68
69/// One block of pixels in memory the GPU, the system's compositor and other processes all reach,
70/// which a producer draws into and presents: the platform's own type, Android's `HardwareBuffer`,
71/// a dmabuf behind Wayland's `wl_buffer`, on Apple platforms an `IOSurface`.
72#[cfg(target_vendor = "apple")]
73pub type HardwareBuffer = objc2_core_foundation::CFRetained<objc2_io_surface::IOSurfaceRef>;
74
75/// A platform with no host that composites: no buffer can exist, so
76/// [`CompositionLayer::present`] cannot be called, and
77/// [`Platform::compositor`](crate::Platform::compositor) answers `None`.
78#[cfg(not(target_vendor = "apple"))]
79pub enum HardwareBuffer {}