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
// SPDX-License-Identifier: MIT OR Apache-2.0
//! `WebGpuResource` — the browser-platform arm of [`crate::GpuResource`].
//!
//! Every variant wraps a `web_sys::*` handle. Those handles are thin
//! `wasm_bindgen::JsValue` smart wrappers around a JS-side object:
//!
//! - **`Clone` is cheap** — it bumps a JS-side reference count (the
//! `JsValue` ABI), never a driver round-trip. Cloning a
//! [`WebGpuResource`] therefore does the right thing automatically:
//! no explicit `Retain` / `Release` choreography as with
//! `CVPixelBuffer`, `AHardwareBuffer`, or a Win32 `HANDLE`.
//! - **`Drop` is the single release mechanism** — the field-by-field
//! drop decrements the JS reference count synchronously on the
//! current thread (which on wasm is the only thread). JS GC reclaims
//! the underlying object once nothing else references it. There is no
//! `CVPixelBufferRelease` / `CloseHandle` / `AHardwareBuffer_release`
//! equivalent to run.
//!
//! A Rust `Clone` of a `web_sys` handle references the **same** JS
//! object — it does not survive `ImageBitmap.close()` / `VideoFrame.close()`
//! and must never be treated as a lifetime extension. `close()` is the
//! caller's explicit lifecycle action, distinct from GC.
//!
//! # Thread safety
//!
//! `web_sys::*` handles are thin `JsValue` wrappers, and `JsValue`'s
//! thread-safety is target-dependent: wasm-bindgen provides
//! `unsafe impl Send/Sync for JsValue` **only** on the non-atomics target
//! (gated `cfg(not(target_feature = "atomics"))`) and withholds it on the
//! threaded `atomics` target, where a JS handle is genuinely realm-affine.
//! So on `atomics` `web_sys::*` — and this [`WebGpuResource`] — are
//! `!Send + !Sync`; on non-atomics they are (fragile-)`Send + Sync`.
//!
//! [`WebGpuResource`] carries **no** `unsafe impl Send + Sync` (unlike the
//! native newtypes in [`crate::gpu_resource`]), so it simply inherits that
//! payload behaviour. This is deliberate: on `atomics` the missing impl is
//! a real pin keeping [`crate::GpuResource`] `!Send + !Sync`; on
//! non-atomics this variant *is* `Send`, and the crate's `!Send` guarantee
//! rests instead on the `Arc<dyn ResourceKeepAlive>` keep-alive in the
//! sibling `WgpuTexture` variant (its `MaybeSendSync` bound is empty on
//! wasm) — see the [`crate::gpu_resource`] `# Thread safety` note. Nothing
//! here relies on wasm-bindgen's fragile non-atomics `Send`; do **not**
//! add an `unsafe impl` "for symmetry".
/// Browser GPU / media resource handle — the payload of
/// [`crate::GpuResource::Web`].
///
/// `#[non_exhaustive]`, so adding a browser source is not a breaking
/// change.
///
/// Routing summary: same-device `GpuTexture` and same-context `WebGlTexture`
/// import zero-copy; every `copyExternalImageToTexture` source is a
/// [`crate::ExecutionPath::BrowserGpuCopy`]; `ImageData` is CPU-resident.