1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! `gpui-interop`: composite pixels produced outside GPUI's renderer into a GPUI scene.
//!
//! A producer whose graphics device is **not** the window renderer's — another API, another adapter,
//! another process — renders a frame and hands it to the scene through the `surface()` element,
//! without a CPU copy of the pixels.
//!
//! The crate also covers the case where the window renderer *is* wgpu: [`Adapter::wgpu`] hands the
//! producer that renderer's own device and queue, and [`WgpuSurface`] is a render target the same
//! device composites with `paint_texture`. That is the no-export, no-fence path a wgpu viewport
//! wants. Either way, the pixels land in the scene without a round trip through the CPU.
//!
//! # The shape of the bridge
//!
//! [`attach`] takes the device a `gpu_canvas` callback lends
//! (`GpuCanvasContext::device`) and yields an [`Interop`], or [`Unavailable`] when the
//! canvas lent no device — an offscreen or foreign renderer. It is called inside the canvas, not
//! before a frame is painted: the window's renderer, and so its device, does not exist until then.
//! From there:
//!
//! - [`Interop::adapter`] returns an [`Adapter`], the producer's view of the window's device.
//! - With the `wgpu` feature, `Adapter::wgpu` returns a wgpu `Device` and `Queue` the producer can
//! render on. When the window renderer *is* wgpu — the Linux default, or a Windows window whose
//! factory installed `WgpuRenderer` — it is the renderer's own device and queue, cloned: a
//! [`WgpuSurface`] rendered there is composited by the same device with
//! `GpuCanvasContext::paint_texture`, which is the no-copy path a wgpu viewport wants. On Windows
//! with the Direct3D 11 renderer it matches the adapter by LUID and makes a separate DX12 device,
//! and the frame then leaves through the native [`SharedSurface`] transport.
//! - On Linux, `WgpuSharedBuffer` is the wgpu producer's **native** arm: it allocates an exportable
//! image on the wgpu device's own `VkDevice`, wraps it back into wgpu so the producer renders with
//! the ordinary API, and exports the frame as a dma-buf with its modifier, plane layout and a
//! `sync_file` fence. `GpuCanvasContext::paint_surface` imports that handle exactly as it does a
//! decoder's, which is the shape a renderer of another backend consumes.
//! - On Linux, [`SharedBuffer`] is the producer half of the dma-buf transport for a producer that
//! owns its device: a Vulkan pipeline renders into a shareable image and exports it as a dma-buf,
//! and GPUI imports it under its modifier. Single- or two-plane, linear or on a driver-tiled
//! modifier the renderer can import, and ordered by a [`Fence`] that exports the acquire
//! `sync_file`. It covers both sharing contracts: [`SharedBuffer::new`] lets the driver choose the
//! image's layout and reports it back, while [`SharedBuffer::export_at`] pushes bytes at a plane
//! layout the producer declares — the shape a decoder or capture pipeline whose layout comes from
//! elsewhere needs. A wgpu producer does **not** use it: it renders into a `WgpuSharedBuffer` (or,
//! same-device, a `WgpuSurface`).
//! - On Windows, [`SharedSurface`] / [`Fence`] are the producer half of the Direct3D transport: a
//! Direct3D 12 producer renders into a shared texture and signals a fence, and hands GPUI the
//! `DirectXSource::Shared` handles — which the renderer opens on its own Direct3D 11 device, with
//! the shared fence ordering the two queues.
//!
//! # Lifetime
//!
//! A hand-off is a pipeline, not a copy: the consumer samples the buffer after `paint_surface`
//! returns. `WgpuSharedBuffer::submit` submits the write and returns immediately, so a producer that
//! renders continuously must keep a ring and wait for `DmaBufHandle::release` before writing a slot
//! again — or present one frame behind the one being rendered. A fixed "reuse after N submissions"
//! rule is a heuristic and eventually races a deep consumer queue. GPUI also drops a surface whose
//! acquire fence has not signalled within 16 ms, so a frame that runs long is safer presented one
//! frame late than as a black frame.
//!
//! `WgpuSharedBufferRing` (Linux, `wgpu` feature) implements that shape: it owns the slots and
//! release descriptors and only presents a frame whose fence has already signalled, repeating the
//! last good frame while a new one is still running.
//!
//! # The other direction
//!
//! With the `guest` feature, [`Guest`] runs the inverse: headless GPUI on a worker thread for a host
//! loop that owns the window and its cadence. Frames leave as shareable surfaces, so the host samples
//! them on the same device; work and input enter through [`Guest::update`]. Only the frame handle and
//! plain commands cross the thread; the `!Send` renderer stays pinned to the guest.
//!
//! # Sketch
//!
//! ```rust
//! use gpui_interop::{attach, Unavailable, WgpuSurface};
//!
//! fn bridge(gpu: &mut gpui::GpuCanvasContext) -> Result<(), Unavailable> {
//! // The window renderer, where it is wgpu (the Linux default).
//! let interop = attach(gpu.try_device::<gpui_wgpu::WgpuRenderer>())?;
//!
//! // With the `wgpu` feature: the renderer's own device and queue, cloned.
//! let (device, queue) = interop.adapter().wgpu().expect("the renderer's own device");
//!
//! // A surface the ordinary `wgpu` API renders into; `paint_texture` accepts its view on the
//! // same device.
//! let surface = WgpuSurface::new(&device, 640, 480).expect("a render target");
//! let _ = (queue, surface);
//! Ok(())
//! }
//! ```
//!
//! The `wgpu` line requires the `wgpu` feature; without it, `Adapter::wgpu` and [`WgpuSurface`] are
//! not compiled in. The Linux `SharedBuffer`/`Fence` transport and the Windows handles remain
//! available without it, because neither is a `wgpu` client.
//!
//! On Windows, the same snippet is the path when the window's factory installed `WgpuRenderer`.
//! Under the default Direct3D 11 renderer `Adapter::wgpu` makes a separate DX12 device, and the
//! hand-off is [`SharedSurface`] instead — see the module documentation of `windows`.
//!
//! # Provisional
//!
//! The crate is provisional and deliberately incomplete, and its API may change. Only the platform
//! backends that are implemented today are exposed; the rest arrive as they are written.
pub use ;
pub use ;
pub use ;
pub use ;
pub use WgpuSharedBuffer;
pub use ;
pub use WgpuSurface;
pub use ;
use Any;
use Rc;
/// Negotiate with the window renderer a `gpu_canvas` callback reaches.
///
/// Called inside the canvas, with the device the callback lends — `gpu.device::<R>()`, or
/// `gpu.try_device::<R>()` for the fallible form. There is nothing to attach to before a frame is
/// painted, because the window's renderer, and its device, do not exist until then.
///
/// Returns [`Unavailable::NoDevice`] when the canvas lent no device — an offscreen or foreign
/// renderer — so this is a recoverable error rather than a panic.
/// A window's renderer, as a producer sees it.