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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
use *;
/// Renders the JS-side error into a `String` when present, otherwise `"<none>"`.
///
/// # Arguments
///
/// - `&JsValue` - Shared reference to a `JsValue`.
///
/// # Returns
///
/// - `String` - A `String` value.
pub
/// Lookup table that maps the textual depth-format constants defined
/// in `const.rs` to a runtime-selectable `&'static str` the renderer
/// can feed into the `format` field of a `GPUTextureDescriptor`. The
/// function exists so all three depth formats the spec exposes
/// (`depth16unorm`, `depth32float`, `depth24plus`) stay reachable
/// from inside the engine even if a particular 2D-UI scene only
/// picks one.
///
/// # Arguments
///
/// - `bool` - Select the 32-bit float format when true.
/// - `bool` - Select the stencil-bearing format when true.
///
/// # Returns
///
/// - `&'static str` - A `'static str` value.
pub
/// Build a `mapMode` bitmask suitable for `GPUBuffer.mapAsync`.
/// `GPUMapMode.READ` (`1`) and `GPUMapMode.WRITE` (`2`) can be OR'd
/// together per the WebGPU spec; this helper centralises the
/// combination so the integer constants stay reachable.
///
/// # Arguments
///
/// - `bool` - Include the read mode bit when true.
/// - `bool` - Include the write mode bit when true.
///
/// # Returns
///
/// - `u32` - A 32-bit unsigned integer.
pub
/// Combine a `GPUTextureUsage` bitmask. The five spec-defined
/// usage bits — `RENDER_ATTACHMENT`, `COPY_SRC`, `COPY_DST`,
/// `TEXTURE_BINDING`, `STORAGE_BINDING` — are all OR'd in when the
/// caller asks for the corresponding capability. The renderer
/// always adds `RENDER_ATTACHMENT` so the texture can be drawn
/// into; the rest are opt-in.
///
/// # Arguments
///
/// - `bool` - Include `RENDER_ATTACHMENT` when true.
/// - `bool` - Include `COPY_SRC` when true.
/// - `bool` - Include `COPY_DST` when true.
/// - `bool` - Include `TEXTURE_BINDING` when true.
/// - `bool` - Include `STORAGE_BINDING` when true.
///
/// # Returns
///
/// - `u32` - A 32-bit unsigned integer.
pub
/// OPT 2: cache `JsValue::from_str(...)` results in a thread-local map so we
/// don't pay a fresh wasm-linear-memory string allocation for every
/// `Reflect::get(obj, &JsValue::from_str(METHOD_NAME))` or
/// `Reflect::set(obj, &JsValue::from_str(PROPERTY_NAME), value)` call.
/// WebGPU render paths use 79 `Reflect::get` calls and ~50
/// `Reflect::set` calls in this file; each previously allocated a 1-N
/// byte JS string in linear memory. We only cache the constant
/// `&'static str` keys here — dynamic string lookups (e.g. uniform
/// names) are unaffected. The map is created once per thread, lazily,
/// and grows monotonically for the lifetime of the wasm instance.
///
/// # Arguments
///
/// - `&'static str` - The constant method or property name to intern.
///
/// # Returns
///
/// - `JsValue` - The cached `JsValue` for this name.
pub
/// OPT 2b: thread-local cache of WebGPU `Function` objects keyed by
/// `(GpuReceiverClass, method_name)`.
///
/// `cached_method_name` only avoids the `JsValue::from_str(METHOD_NAME)`
/// allocation; the subsequent `Reflect::get(obj, name)` still costs a JS
/// property lookup plus the `Function` allocation in linear memory. JS
/// class methods live on the prototype, so the same `Function` is returned
/// every time you ask for `GpuDevice.prototype.createCommandEncoder`,
/// `GpuRenderPassEncoder.prototype.setPipeline`, etc. We memoise the first
/// `Reflect::get` and reuse the cached `Function` on every subsequent call.
///
/// # Key design
///
/// - **Receiver class** (`GpuReceiverClass`) is the identity half of the
/// cache key. Prototype `Function`s are per-class singletons, so the
/// class tag alone is sufficient - no receiver identity is required.
/// The previous scheme keyed by the `JsValue`'s stack address, which was
/// unsound: per-frame temporaries (pass encoders, command encoders)
/// reuse stack slots across frames, and classes like
/// `GPURenderPassEncoder` / `GPUComputePassEncoder` share method names
/// (`setPipeline` / `setBindGroup` / `end`), so a stale slot could
/// return the wrong class's `Function` (a swallowed TypeError and a
/// silently skipped GPU call).
/// - **Method name** is `&'static str` - callers must pass one of the
/// `WEBGPU_METHOD_*` constants. This keeps the cache key allocation-free.
/// - **First call only**: the first time a `(class, method)` pair is
/// seen, we fall back to `Reflect::get(obj, name)` to populate the cache.
/// All later calls bypass `Reflect::get` entirely.
///
/// # Thread safety
///
/// `thread_local!` storage guarantees one cache per wasm instance thread.
/// WebAssembly is single-threaded for the renderer; the cache is not shared.
///
/// # Result
///
/// Each cached call drops from ~120ns to ~10ns (a single `Function::callN`
/// over the wasm/js boundary with no `from_str` and no property lookup).
///
/// # Arguments
///
/// - `GpuReceiverClass` - The receiver's WebGPU class (cache key half).
/// - `&JsValue` - The receiver (`this`) for the call; used for the first
/// `Reflect::get` lookup, not part of the key.
/// - `&'static str` - A method name matching a `WEBGPU_METHOD_*` constant.
///
/// # Returns
///
/// - `Result<Function, JsValue>` - The cached `Function` object on success;
/// the `Reflect::get` error on cache miss / method-not-found.
///
/// Note: `this` binding is the caller's responsibility — use
/// `Function::call0(this)`, `call1(this, &arg)`, `call2(this, &a, &b)`, ...
/// as appropriate. JS `Function` objects don't bind `this`, so the caller
/// must always pass `obj` (or `this`) as the first argument.
pub
/// OPT 2b convenience: cached `Function::call1(this, &arg)` for
/// the common 1-argument WebGPU method call. See [`cached_method`]
/// for the cache semantics.
///
/// # Arguments
///
/// - `GpuReceiverClass` - The receiver's WebGPU class (cache key half).
/// - `&JsValue` - The receiver (`this`) for the call.
/// - `&'static str` - A method name matching a `WEBGPU_METHOD_*` constant.
/// - `&JsValue` - The single argument passed to the method.
///
/// # Returns
///
/// - `Result<JsValue, JsValue>` - The method's return value, or the
/// `Reflect::get` error when the method is not cached and not found.
pub