Skip to main content

script_webgpu/
gpuconvert.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::borrow::Cow;
6use std::num::NonZeroU64;
7
8use js::context::JSContext;
9use script_bindings::codegen::GenericBindings::CanvasRenderingContext2DBinding::PredefinedColorSpace;
10use script_bindings::codegen::GenericBindings::WebGPUBinding::{
11    GPUAddressMode, GPUBindGroupEntry, GPUBindGroupLayoutEntry, GPUBindingResource,
12    GPUBlendComponent, GPUBlendFactor, GPUBlendOperation, GPUBufferBindingType, GPUColor,
13    GPUCompareFunction, GPUComputePassDescriptor, GPUComputePassTimestampWrites, GPUCullMode,
14    GPUExtent3D, GPUFilterMode, GPUFrontFace, GPUIndexFormat, GPULoadOp, GPUMipmapFilterMode,
15    GPUObjectDescriptorBase, GPUOrigin2D, GPUOrigin3D, GPUPrimitiveState, GPUPrimitiveTopology,
16    GPUProgrammableStage, GPUQuerySetDescriptor, GPUQueryType, GPURenderPassTimestampWrites,
17    GPUSamplerBindingType, GPUStencilOperation, GPUStorageTextureAccess, GPUStoreOp,
18    GPUTexelCopyBufferInfo, GPUTexelCopyBufferLayout, GPUTexelCopyTextureInfo, GPUTextureAspect,
19    GPUTextureDescriptor, GPUTextureDimension, GPUTextureFormat, GPUTextureSampleType,
20    GPUTextureViewDimension, GPUVertexFormat,
21};
22use script_bindings::codegen::GenericUnionTypes::GPUTextureOrGPUTextureView;
23use script_bindings::interfaces::PromiseHelpers;
24use webgpu_traits::{
25    AddressMode, AstcBlock, AstcChannel, BindGroupEntry, BindGroupLayoutEntry, BindingResource,
26    BindingType, BlendComponent, BlendFactor, BlendOperation, BufferAddress, BufferBinding,
27    BufferBindingType, Color, CompareFunction, ComputePassDescriptor, Extent3d, Face, FilterMode,
28    FrontFace, IndexFormat, LoadOp, MipmapFilterMode, Origin2d, Origin3d, PassTimestampWrites,
29    PredefinedColorSpace as WGPUPredefinedColorSpace, PrimitiveState, PrimitiveTopology,
30    ProgrammableStageDescriptor, QuerySetDescriptor, QueryType, SamplerBindingType, ShaderStages,
31    StencilOperation, StorageTextureAccess, StoreOp, TexelCopyBufferInfo, TexelCopyBufferLayout,
32    TexelCopyTextureInfo, TextureAspect, TextureDescriptor, TextureDimension, TextureFormat,
33    TextureSampleType, TextureUsages, TextureViewDimension, VertexFormat, WebGPUTextureView,
34};
35
36use crate::dom::bindings::error::{Error, Fallible};
37use crate::traits::{Equivalence, WebGPUPromise};
38
39/// A version of the `Into<T>` trait from the standard library that can be used
40/// to convert between two types that are not defined in the script crate.
41/// This is intended to be used on dict/enum types generated from WebIDL once
42/// those types are moved out of the script crate.
43/// Only for WebGPU.
44pub trait WebGPUConvert<T> {
45    fn convert(self) -> T;
46}
47
48/// A version of the `TryInto<T>` trait from the standard library that can be used
49/// to convert between two types that are not defined in the script crate.
50/// This is intended to be used on dict/enum types generated from WebIDL once
51/// those types are moved out of the script crate.
52/// Only for WebGPU.
53pub trait WebGPUTryConvert<T> {
54    type Error;
55
56    fn try_convert(self) -> Result<T, Self::Error>;
57}
58
59impl WebGPUConvert<TextureFormat> for GPUTextureFormat {
60    fn convert(self) -> TextureFormat {
61        match self {
62            // 8-bit formats
63            GPUTextureFormat::R8unorm => TextureFormat::R8Unorm,
64            GPUTextureFormat::R8snorm => TextureFormat::R8Snorm,
65            GPUTextureFormat::R8uint => TextureFormat::R8Uint,
66            GPUTextureFormat::R8sint => TextureFormat::R8Sint,
67            // 16-bit formats
68            GPUTextureFormat::R16unorm => TextureFormat::R16Unorm,
69            GPUTextureFormat::R16snorm => TextureFormat::R16Snorm,
70            GPUTextureFormat::R16uint => TextureFormat::R16Uint,
71            GPUTextureFormat::R16sint => TextureFormat::R16Sint,
72            GPUTextureFormat::R16float => TextureFormat::R16Float,
73            GPUTextureFormat::Rg8unorm => TextureFormat::Rg8Unorm,
74            GPUTextureFormat::Rg8snorm => TextureFormat::Rg8Snorm,
75            GPUTextureFormat::Rg8uint => TextureFormat::Rg8Uint,
76            GPUTextureFormat::Rg8sint => TextureFormat::Rg8Sint,
77            // 32-bit formats
78            GPUTextureFormat::R32uint => TextureFormat::R32Uint,
79            GPUTextureFormat::R32sint => TextureFormat::R32Sint,
80            GPUTextureFormat::R32float => TextureFormat::R32Float,
81            GPUTextureFormat::Rg16unorm => TextureFormat::Rg16Unorm,
82            GPUTextureFormat::Rg16snorm => TextureFormat::Rg16Snorm,
83            GPUTextureFormat::Rg16uint => TextureFormat::Rg16Uint,
84            GPUTextureFormat::Rg16sint => TextureFormat::Rg16Sint,
85            GPUTextureFormat::Rg16float => TextureFormat::Rg16Float,
86            GPUTextureFormat::Rgba8unorm => TextureFormat::Rgba8Unorm,
87            GPUTextureFormat::Rgba8unorm_srgb => TextureFormat::Rgba8UnormSrgb,
88            GPUTextureFormat::Rgba8snorm => TextureFormat::Rgba8Snorm,
89            GPUTextureFormat::Rgba8uint => TextureFormat::Rgba8Uint,
90            GPUTextureFormat::Rgba8sint => TextureFormat::Rgba8Sint,
91            GPUTextureFormat::Bgra8unorm => TextureFormat::Bgra8Unorm,
92            GPUTextureFormat::Bgra8unorm_srgb => TextureFormat::Bgra8UnormSrgb,
93            // Packed 32-bit formats
94            GPUTextureFormat::Rgb9e5ufloat => TextureFormat::Rgb9e5Ufloat,
95            GPUTextureFormat::Rgb10a2uint => TextureFormat::Rgb10a2Uint,
96            GPUTextureFormat::Rgb10a2unorm => TextureFormat::Rgb10a2Unorm,
97            GPUTextureFormat::Rg11b10ufloat => TextureFormat::Rg11b10Ufloat,
98            // 64-bit formats
99            GPUTextureFormat::Rg32uint => TextureFormat::Rg32Uint,
100            GPUTextureFormat::Rg32sint => TextureFormat::Rg32Sint,
101            GPUTextureFormat::Rg32float => TextureFormat::Rg32Float,
102            GPUTextureFormat::Rgba16unorm => TextureFormat::Rgba16Unorm,
103            GPUTextureFormat::Rgba16snorm => TextureFormat::Rgba16Snorm,
104            GPUTextureFormat::Rgba16uint => TextureFormat::Rgba16Uint,
105            GPUTextureFormat::Rgba16sint => TextureFormat::Rgba16Sint,
106            GPUTextureFormat::Rgba16float => TextureFormat::Rgba16Float,
107            // 96-bit formats
108            GPUTextureFormat::Rgba32uint => TextureFormat::Rgba32Uint,
109            GPUTextureFormat::Rgba32sint => TextureFormat::Rgba32Sint,
110            GPUTextureFormat::Rgba32float => TextureFormat::Rgba32Float,
111            // Depth/stencil formats
112            GPUTextureFormat::Stencil8 => TextureFormat::Stencil8,
113            GPUTextureFormat::Depth16unorm => TextureFormat::Depth16Unorm,
114            GPUTextureFormat::Depth24plus => TextureFormat::Depth24Plus,
115            GPUTextureFormat::Depth24plus_stencil8 => TextureFormat::Depth24PlusStencil8,
116            GPUTextureFormat::Depth32float => TextureFormat::Depth32Float,
117            // "depth32float-stencil8" feature
118            GPUTextureFormat::Depth32float_stencil8 => TextureFormat::Depth32FloatStencil8,
119            // BC compressed formats usable if "texture-compression-bc" is both
120            // supported by the device/user agent and enabled in requestDevice.
121            GPUTextureFormat::Bc1_rgba_unorm => TextureFormat::Bc1RgbaUnorm,
122            GPUTextureFormat::Bc1_rgba_unorm_srgb => TextureFormat::Bc1RgbaUnormSrgb,
123            GPUTextureFormat::Bc2_rgba_unorm => TextureFormat::Bc2RgbaUnorm,
124            GPUTextureFormat::Bc2_rgba_unorm_srgb => TextureFormat::Bc2RgbaUnormSrgb,
125            GPUTextureFormat::Bc3_rgba_unorm => TextureFormat::Bc3RgbaUnorm,
126            GPUTextureFormat::Bc3_rgba_unorm_srgb => TextureFormat::Bc3RgbaUnormSrgb,
127            GPUTextureFormat::Bc4_r_unorm => TextureFormat::Bc4RUnorm,
128            GPUTextureFormat::Bc4_r_snorm => TextureFormat::Bc4RSnorm,
129            GPUTextureFormat::Bc5_rg_unorm => TextureFormat::Bc5RgUnorm,
130            GPUTextureFormat::Bc5_rg_snorm => TextureFormat::Bc5RgSnorm,
131            GPUTextureFormat::Bc6h_rgb_ufloat => TextureFormat::Bc6hRgbUfloat,
132            GPUTextureFormat::Bc6h_rgb_float => TextureFormat::Bc6hRgbFloat,
133            GPUTextureFormat::Bc7_rgba_unorm => TextureFormat::Bc7RgbaUnorm,
134            GPUTextureFormat::Bc7_rgba_unorm_srgb => TextureFormat::Bc7RgbaUnormSrgb,
135            // ETC2 compressed formats usable if "texture-compression-etc2" is both
136            // supported by the device/user agent and enabled in requestDevice.
137            GPUTextureFormat::Etc2_rgb8unorm => TextureFormat::Etc2Rgb8Unorm,
138            GPUTextureFormat::Etc2_rgb8unorm_srgb => TextureFormat::Etc2Rgb8UnormSrgb,
139            GPUTextureFormat::Etc2_rgb8a1unorm => TextureFormat::Etc2Rgb8A1Unorm,
140            GPUTextureFormat::Etc2_rgb8a1unorm_srgb => TextureFormat::Etc2Rgb8A1UnormSrgb,
141            GPUTextureFormat::Etc2_rgba8unorm => TextureFormat::Etc2Rgba8Unorm,
142            GPUTextureFormat::Etc2_rgba8unorm_srgb => TextureFormat::Etc2Rgba8UnormSrgb,
143            GPUTextureFormat::Eac_r11unorm => TextureFormat::EacR11Unorm,
144            GPUTextureFormat::Eac_r11snorm => TextureFormat::EacR11Snorm,
145            GPUTextureFormat::Eac_rg11unorm => TextureFormat::EacRg11Unorm,
146            GPUTextureFormat::Eac_rg11snorm => TextureFormat::EacRg11Snorm,
147            // ASTC compressed formats usable if "texture-compression-astc" is both
148            // supported by the device/user agent and enabled in requestDevice.
149            GPUTextureFormat::Astc_4x4_unorm => TextureFormat::Astc {
150                block: AstcBlock::B4x4,
151                channel: AstcChannel::Unorm,
152            },
153            GPUTextureFormat::Astc_4x4_unorm_srgb => TextureFormat::Astc {
154                block: AstcBlock::B4x4,
155                channel: AstcChannel::UnormSrgb,
156            },
157            GPUTextureFormat::Astc_5x4_unorm => TextureFormat::Astc {
158                block: AstcBlock::B5x4,
159                channel: AstcChannel::Unorm,
160            },
161            GPUTextureFormat::Astc_5x4_unorm_srgb => TextureFormat::Astc {
162                block: AstcBlock::B5x4,
163                channel: AstcChannel::UnormSrgb,
164            },
165            GPUTextureFormat::Astc_5x5_unorm => TextureFormat::Astc {
166                block: AstcBlock::B5x5,
167                channel: AstcChannel::Unorm,
168            },
169            GPUTextureFormat::Astc_5x5_unorm_srgb => TextureFormat::Astc {
170                block: AstcBlock::B5x5,
171                channel: AstcChannel::UnormSrgb,
172            },
173            GPUTextureFormat::Astc_6x5_unorm => TextureFormat::Astc {
174                block: AstcBlock::B6x5,
175                channel: AstcChannel::Unorm,
176            },
177            GPUTextureFormat::Astc_6x5_unorm_srgb => TextureFormat::Astc {
178                block: AstcBlock::B6x5,
179                channel: AstcChannel::UnormSrgb,
180            },
181            GPUTextureFormat::Astc_6x6_unorm => TextureFormat::Astc {
182                block: AstcBlock::B6x6,
183                channel: AstcChannel::Unorm,
184            },
185            GPUTextureFormat::Astc_6x6_unorm_srgb => TextureFormat::Astc {
186                block: AstcBlock::B6x6,
187                channel: AstcChannel::UnormSrgb,
188            },
189            GPUTextureFormat::Astc_8x5_unorm => TextureFormat::Astc {
190                block: AstcBlock::B8x5,
191                channel: AstcChannel::Unorm,
192            },
193            GPUTextureFormat::Astc_8x5_unorm_srgb => TextureFormat::Astc {
194                block: AstcBlock::B8x5,
195                channel: AstcChannel::UnormSrgb,
196            },
197            GPUTextureFormat::Astc_8x6_unorm => TextureFormat::Astc {
198                block: AstcBlock::B8x6,
199                channel: AstcChannel::Unorm,
200            },
201            GPUTextureFormat::Astc_8x6_unorm_srgb => TextureFormat::Astc {
202                block: AstcBlock::B8x6,
203                channel: AstcChannel::UnormSrgb,
204            },
205            GPUTextureFormat::Astc_8x8_unorm => TextureFormat::Astc {
206                block: AstcBlock::B8x8,
207                channel: AstcChannel::Unorm,
208            },
209            GPUTextureFormat::Astc_8x8_unorm_srgb => TextureFormat::Astc {
210                block: AstcBlock::B8x8,
211                channel: AstcChannel::UnormSrgb,
212            },
213            GPUTextureFormat::Astc_10x5_unorm => TextureFormat::Astc {
214                block: AstcBlock::B10x5,
215                channel: AstcChannel::Unorm,
216            },
217            GPUTextureFormat::Astc_10x5_unorm_srgb => TextureFormat::Astc {
218                block: AstcBlock::B10x5,
219                channel: AstcChannel::UnormSrgb,
220            },
221            GPUTextureFormat::Astc_10x6_unorm => TextureFormat::Astc {
222                block: AstcBlock::B10x6,
223                channel: AstcChannel::Unorm,
224            },
225            GPUTextureFormat::Astc_10x6_unorm_srgb => TextureFormat::Astc {
226                block: AstcBlock::B10x6,
227                channel: AstcChannel::UnormSrgb,
228            },
229            GPUTextureFormat::Astc_10x8_unorm => TextureFormat::Astc {
230                block: AstcBlock::B10x8,
231                channel: AstcChannel::Unorm,
232            },
233            GPUTextureFormat::Astc_10x8_unorm_srgb => TextureFormat::Astc {
234                block: AstcBlock::B10x8,
235                channel: AstcChannel::UnormSrgb,
236            },
237            GPUTextureFormat::Astc_10x10_unorm => TextureFormat::Astc {
238                block: AstcBlock::B10x10,
239                channel: AstcChannel::Unorm,
240            },
241            GPUTextureFormat::Astc_10x10_unorm_srgb => TextureFormat::Astc {
242                block: AstcBlock::B10x10,
243                channel: AstcChannel::UnormSrgb,
244            },
245            GPUTextureFormat::Astc_12x10_unorm => TextureFormat::Astc {
246                block: AstcBlock::B12x10,
247                channel: AstcChannel::Unorm,
248            },
249            GPUTextureFormat::Astc_12x10_unorm_srgb => TextureFormat::Astc {
250                block: AstcBlock::B12x10,
251                channel: AstcChannel::UnormSrgb,
252            },
253            GPUTextureFormat::Astc_12x12_unorm => TextureFormat::Astc {
254                block: AstcBlock::B12x12,
255                channel: AstcChannel::Unorm,
256            },
257            GPUTextureFormat::Astc_12x12_unorm_srgb => TextureFormat::Astc {
258                block: AstcBlock::B12x12,
259                channel: AstcChannel::UnormSrgb,
260            },
261        }
262    }
263}
264
265impl WebGPUTryConvert<Extent3d> for &GPUExtent3D {
266    type Error = Error;
267
268    fn try_convert(self) -> Result<Extent3d, Self::Error> {
269        match *self {
270            GPUExtent3D::GPUExtent3DDict(ref dict) => Ok(Extent3d {
271                width: dict.width,
272                height: dict.height,
273                depth_or_array_layers: dict.depthOrArrayLayers,
274            }),
275            GPUExtent3D::RangeEnforcedUnsignedLongSequence(ref v) => {
276                // https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpuextent3d-shape
277                if v.is_empty() || v.len() > 3 {
278                    Err(Error::Type(
279                        c"GPUExtent3D size must be between 1 and 3 (inclusive)".to_owned(),
280                    ))
281                } else {
282                    Ok(Extent3d {
283                        width: v[0],
284                        height: v.get(1).copied().unwrap_or(1),
285                        depth_or_array_layers: v.get(2).copied().unwrap_or(1),
286                    })
287                }
288            },
289        }
290    }
291}
292
293impl WebGPUConvert<TexelCopyBufferLayout> for &GPUTexelCopyBufferLayout {
294    fn convert(self) -> TexelCopyBufferLayout {
295        TexelCopyBufferLayout {
296            offset: self.offset as BufferAddress,
297            bytes_per_row: self.bytesPerRow,
298            rows_per_image: self.rowsPerImage,
299        }
300    }
301}
302
303impl WebGPUConvert<VertexFormat> for GPUVertexFormat {
304    fn convert(self) -> VertexFormat {
305        match self {
306            GPUVertexFormat::Uint8 => VertexFormat::Uint8,
307            GPUVertexFormat::Uint8x2 => VertexFormat::Uint8x2,
308            GPUVertexFormat::Uint8x4 => VertexFormat::Uint8x4,
309            GPUVertexFormat::Sint8 => VertexFormat::Sint8,
310            GPUVertexFormat::Sint8x2 => VertexFormat::Sint8x2,
311            GPUVertexFormat::Sint8x4 => VertexFormat::Sint8x4,
312            GPUVertexFormat::Unorm8 => VertexFormat::Unorm8,
313            GPUVertexFormat::Unorm8x2 => VertexFormat::Unorm8x2,
314            GPUVertexFormat::Unorm8x4 => VertexFormat::Unorm8x4,
315            GPUVertexFormat::Snorm8 => VertexFormat::Snorm8,
316            GPUVertexFormat::Snorm8x2 => VertexFormat::Snorm8x2,
317            GPUVertexFormat::Snorm8x4 => VertexFormat::Snorm8x4,
318            GPUVertexFormat::Uint16 => VertexFormat::Uint16,
319            GPUVertexFormat::Uint16x2 => VertexFormat::Uint16x2,
320            GPUVertexFormat::Uint16x4 => VertexFormat::Uint16x4,
321            GPUVertexFormat::Sint16 => VertexFormat::Sint16,
322            GPUVertexFormat::Sint16x2 => VertexFormat::Sint16x2,
323            GPUVertexFormat::Sint16x4 => VertexFormat::Sint16x4,
324            GPUVertexFormat::Unorm16 => VertexFormat::Unorm16,
325            GPUVertexFormat::Unorm16x2 => VertexFormat::Unorm16x2,
326            GPUVertexFormat::Unorm16x4 => VertexFormat::Unorm16x4,
327            GPUVertexFormat::Snorm16 => VertexFormat::Snorm16,
328            GPUVertexFormat::Snorm16x2 => VertexFormat::Snorm16x2,
329            GPUVertexFormat::Snorm16x4 => VertexFormat::Snorm16x4,
330            GPUVertexFormat::Float16 => VertexFormat::Float16,
331            GPUVertexFormat::Float16x2 => VertexFormat::Float16x2,
332            GPUVertexFormat::Float16x4 => VertexFormat::Float16x4,
333            GPUVertexFormat::Float32 => VertexFormat::Float32,
334            GPUVertexFormat::Float32x2 => VertexFormat::Float32x2,
335            GPUVertexFormat::Float32x3 => VertexFormat::Float32x3,
336            GPUVertexFormat::Float32x4 => VertexFormat::Float32x4,
337            GPUVertexFormat::Uint32 => VertexFormat::Uint32,
338            GPUVertexFormat::Uint32x2 => VertexFormat::Uint32x2,
339            GPUVertexFormat::Uint32x3 => VertexFormat::Uint32x3,
340            GPUVertexFormat::Uint32x4 => VertexFormat::Uint32x4,
341            GPUVertexFormat::Sint32 => VertexFormat::Sint32,
342            GPUVertexFormat::Sint32x2 => VertexFormat::Sint32x2,
343            GPUVertexFormat::Sint32x3 => VertexFormat::Sint32x3,
344            GPUVertexFormat::Sint32x4 => VertexFormat::Sint32x4,
345            GPUVertexFormat::Unorm10_10_10_2 => VertexFormat::Unorm10_10_10_2,
346            GPUVertexFormat::Unorm8x4_bgra => VertexFormat::Unorm8x4Bgra,
347        }
348    }
349}
350
351impl WebGPUConvert<PrimitiveState> for &GPUPrimitiveState {
352    fn convert(self) -> PrimitiveState {
353        PrimitiveState {
354            topology: self.topology.convert(),
355            strip_index_format: self
356                .stripIndexFormat
357                .map(|index_format| match index_format {
358                    GPUIndexFormat::Uint16 => IndexFormat::Uint16,
359                    GPUIndexFormat::Uint32 => IndexFormat::Uint32,
360                }),
361            front_face: match self.frontFace {
362                GPUFrontFace::Ccw => FrontFace::Ccw,
363                GPUFrontFace::Cw => FrontFace::Cw,
364            },
365            cull_mode: match self.cullMode {
366                GPUCullMode::None => None,
367                GPUCullMode::Front => Some(Face::Front),
368                GPUCullMode::Back => Some(Face::Back),
369            },
370            unclipped_depth: self.clampDepth,
371            ..Default::default()
372        }
373    }
374}
375
376impl WebGPUConvert<PrimitiveTopology> for &GPUPrimitiveTopology {
377    fn convert(self) -> PrimitiveTopology {
378        match self {
379            GPUPrimitiveTopology::Point_list => PrimitiveTopology::PointList,
380            GPUPrimitiveTopology::Line_list => PrimitiveTopology::LineList,
381            GPUPrimitiveTopology::Line_strip => PrimitiveTopology::LineStrip,
382            GPUPrimitiveTopology::Triangle_list => PrimitiveTopology::TriangleList,
383            GPUPrimitiveTopology::Triangle_strip => PrimitiveTopology::TriangleStrip,
384        }
385    }
386}
387
388impl WebGPUConvert<AddressMode> for GPUAddressMode {
389    fn convert(self) -> AddressMode {
390        match self {
391            GPUAddressMode::Clamp_to_edge => AddressMode::ClampToEdge,
392            GPUAddressMode::Repeat => AddressMode::Repeat,
393            GPUAddressMode::Mirror_repeat => AddressMode::MirrorRepeat,
394        }
395    }
396}
397
398impl WebGPUConvert<FilterMode> for GPUFilterMode {
399    fn convert(self) -> FilterMode {
400        match self {
401            GPUFilterMode::Nearest => FilterMode::Nearest,
402            GPUFilterMode::Linear => FilterMode::Linear,
403        }
404    }
405}
406
407impl WebGPUConvert<MipmapFilterMode> for GPUMipmapFilterMode {
408    fn convert(self) -> MipmapFilterMode {
409        match self {
410            GPUMipmapFilterMode::Nearest => MipmapFilterMode::Nearest,
411            GPUMipmapFilterMode::Linear => MipmapFilterMode::Linear,
412        }
413    }
414}
415
416impl WebGPUConvert<TextureViewDimension> for GPUTextureViewDimension {
417    fn convert(self) -> TextureViewDimension {
418        match self {
419            GPUTextureViewDimension::_1d => TextureViewDimension::D1,
420            GPUTextureViewDimension::_2d => TextureViewDimension::D2,
421            GPUTextureViewDimension::_2d_array => TextureViewDimension::D2Array,
422            GPUTextureViewDimension::Cube => TextureViewDimension::Cube,
423            GPUTextureViewDimension::Cube_array => TextureViewDimension::CubeArray,
424            GPUTextureViewDimension::_3d => TextureViewDimension::D3,
425        }
426    }
427}
428
429impl WebGPUConvert<CompareFunction> for GPUCompareFunction {
430    fn convert(self) -> CompareFunction {
431        match self {
432            GPUCompareFunction::Never => CompareFunction::Never,
433            GPUCompareFunction::Less => CompareFunction::Less,
434            GPUCompareFunction::Equal => CompareFunction::Equal,
435            GPUCompareFunction::Less_equal => CompareFunction::LessEqual,
436            GPUCompareFunction::Greater => CompareFunction::Greater,
437            GPUCompareFunction::Not_equal => CompareFunction::NotEqual,
438            GPUCompareFunction::Greater_equal => CompareFunction::GreaterEqual,
439            GPUCompareFunction::Always => CompareFunction::Always,
440        }
441    }
442}
443
444impl WebGPUConvert<BlendFactor> for &GPUBlendFactor {
445    fn convert(self) -> BlendFactor {
446        match self {
447            GPUBlendFactor::Zero => BlendFactor::Zero,
448            GPUBlendFactor::One => BlendFactor::One,
449            GPUBlendFactor::Src => BlendFactor::Src,
450            GPUBlendFactor::One_minus_src => BlendFactor::OneMinusSrc,
451            GPUBlendFactor::Src_alpha => BlendFactor::SrcAlpha,
452            GPUBlendFactor::One_minus_src_alpha => BlendFactor::OneMinusSrcAlpha,
453            GPUBlendFactor::Dst => BlendFactor::Dst,
454            GPUBlendFactor::One_minus_dst => BlendFactor::OneMinusDst,
455            GPUBlendFactor::Dst_alpha => BlendFactor::DstAlpha,
456            GPUBlendFactor::One_minus_dst_alpha => BlendFactor::OneMinusDstAlpha,
457            GPUBlendFactor::Src_alpha_saturated => BlendFactor::SrcAlphaSaturated,
458            GPUBlendFactor::Constant => BlendFactor::Constant,
459            GPUBlendFactor::One_minus_constant => BlendFactor::OneMinusConstant,
460            GPUBlendFactor::Src1 => BlendFactor::Src1,
461            GPUBlendFactor::One_minus_src1 => BlendFactor::OneMinusSrc1,
462            GPUBlendFactor::Src1_alpha => BlendFactor::Src1Alpha,
463            GPUBlendFactor::One_minus_src1_alpha => BlendFactor::OneMinusSrc1Alpha,
464        }
465    }
466}
467
468impl WebGPUConvert<BlendComponent> for &GPUBlendComponent {
469    fn convert(self) -> BlendComponent {
470        BlendComponent {
471            src_factor: self.srcFactor.convert(),
472            dst_factor: self.dstFactor.convert(),
473            operation: match self.operation {
474                GPUBlendOperation::Add => BlendOperation::Add,
475                GPUBlendOperation::Subtract => BlendOperation::Subtract,
476                GPUBlendOperation::Reverse_subtract => BlendOperation::ReverseSubtract,
477                GPUBlendOperation::Min => BlendOperation::Min,
478                GPUBlendOperation::Max => BlendOperation::Max,
479            },
480        }
481    }
482}
483
484pub fn convert_load_op<T>(load: &GPULoadOp, clear: T) -> LoadOp<T> {
485    match load {
486        GPULoadOp::Load => LoadOp::Load,
487        GPULoadOp::Clear => LoadOp::Clear(clear),
488    }
489}
490
491impl WebGPUConvert<StoreOp> for &GPUStoreOp {
492    fn convert(self) -> StoreOp {
493        match self {
494            GPUStoreOp::Store => StoreOp::Store,
495            GPUStoreOp::Discard => StoreOp::Discard,
496        }
497    }
498}
499
500impl WebGPUConvert<StencilOperation> for GPUStencilOperation {
501    fn convert(self) -> StencilOperation {
502        match self {
503            GPUStencilOperation::Keep => StencilOperation::Keep,
504            GPUStencilOperation::Zero => StencilOperation::Zero,
505            GPUStencilOperation::Replace => StencilOperation::Replace,
506            GPUStencilOperation::Invert => StencilOperation::Invert,
507            GPUStencilOperation::Increment_clamp => StencilOperation::IncrementClamp,
508            GPUStencilOperation::Decrement_clamp => StencilOperation::DecrementClamp,
509            GPUStencilOperation::Increment_wrap => StencilOperation::IncrementWrap,
510            GPUStencilOperation::Decrement_wrap => StencilOperation::DecrementWrap,
511        }
512    }
513}
514
515impl<D> WebGPUConvert<TexelCopyBufferInfo> for &GPUTexelCopyBufferInfo<D>
516where
517    D: Equivalence,
518    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
519{
520    fn convert(self) -> TexelCopyBufferInfo {
521        TexelCopyBufferInfo {
522            buffer: self.buffer.id().0,
523            layout: self.parent.convert(),
524        }
525    }
526}
527
528impl WebGPUTryConvert<Origin3d> for &GPUOrigin3D {
529    type Error = Error;
530
531    fn try_convert(self) -> Result<Origin3d, Self::Error> {
532        match self {
533            GPUOrigin3D::RangeEnforcedUnsignedLongSequence(v) => {
534                // https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpuorigin3d-shape
535                if v.len() > 3 {
536                    Err(Error::Type(
537                        c"sequence is too long for GPUOrigin3D".to_owned(),
538                    ))
539                } else {
540                    Ok(Origin3d {
541                        x: v.first().copied().unwrap_or(0),
542                        y: v.get(1).copied().unwrap_or(0),
543                        z: v.get(2).copied().unwrap_or(0),
544                    })
545                }
546            },
547            GPUOrigin3D::GPUOrigin3DDict(d) => Ok(Origin3d {
548                x: d.x,
549                y: d.y,
550                z: d.z,
551            }),
552        }
553    }
554}
555
556impl WebGPUTryConvert<Origin2d> for &GPUOrigin2D {
557    type Error = Error;
558
559    /// <https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpuorigin2d-shape>
560    fn try_convert(self) -> Result<Origin2d, Self::Error> {
561        match self {
562            GPUOrigin2D::RangeEnforcedUnsignedLongSequence(v) => {
563                if v.len() > 2 {
564                    Err(Error::Type(
565                        c"sequence is too long for GPUOrigin2D".to_owned(),
566                    ))
567                } else {
568                    Ok(Origin2d {
569                        x: v.first().copied().unwrap_or(0),
570                        y: v.get(1).copied().unwrap_or(0),
571                    })
572                }
573            },
574            GPUOrigin2D::GPUOrigin2DDict(d) => Ok(Origin2d { x: d.x, y: d.y }),
575        }
576    }
577}
578
579impl<D> WebGPUTryConvert<TexelCopyTextureInfo> for &GPUTexelCopyTextureInfo<D>
580where
581    D: Equivalence,
582    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
583{
584    type Error = Error;
585
586    fn try_convert(self) -> Result<TexelCopyTextureInfo, Self::Error> {
587        Ok(TexelCopyTextureInfo {
588            texture: self.texture.id().0,
589            mip_level: self.mipLevel,
590            origin: self
591                .origin
592                .as_ref()
593                .map(WebGPUTryConvert::<Origin3d>::try_convert)
594                .transpose()?
595                .unwrap_or_default(),
596            aspect: match self.aspect {
597                GPUTextureAspect::All => TextureAspect::All,
598                GPUTextureAspect::Stencil_only => TextureAspect::StencilOnly,
599                GPUTextureAspect::Depth_only => TextureAspect::DepthOnly,
600            },
601        })
602    }
603}
604
605impl<'a> WebGPUConvert<Option<Cow<'a, str>>> for &GPUObjectDescriptorBase {
606    fn convert(self) -> Option<Cow<'a, str>> {
607        if self.label.is_empty() {
608            None
609        } else {
610            Some(Cow::Owned(self.label.to_string()))
611        }
612    }
613}
614
615pub(crate) fn convert_bind_group_layout_entry<D>(
616    bgle: &GPUBindGroupLayoutEntry,
617    device: &D::GPUDevice,
618) -> Fallible<Result<BindGroupLayoutEntry, webgpu_traits::Error>>
619where
620    D: Equivalence,
621    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
622{
623    let number_of_provided_bindings = bgle.buffer.is_some() as u8 +
624        bgle.sampler.is_some() as u8 +
625        bgle.storageTexture.is_some() as u8 +
626        bgle.texture.is_some() as u8;
627    let ty = if let Some(buffer) = &bgle.buffer {
628        Some(BindingType::Buffer {
629            ty: match buffer.type_ {
630                GPUBufferBindingType::Uniform => BufferBindingType::Uniform,
631                GPUBufferBindingType::Storage => BufferBindingType::Storage { read_only: false },
632                GPUBufferBindingType::Read_only_storage => {
633                    BufferBindingType::Storage { read_only: true }
634                },
635            },
636            has_dynamic_offset: buffer.hasDynamicOffset,
637            min_binding_size: NonZeroU64::new(buffer.minBindingSize),
638        })
639    } else if let Some(sampler) = &bgle.sampler {
640        Some(BindingType::Sampler(match sampler.type_ {
641            GPUSamplerBindingType::Filtering => SamplerBindingType::Filtering,
642            GPUSamplerBindingType::Non_filtering => SamplerBindingType::NonFiltering,
643            GPUSamplerBindingType::Comparison => SamplerBindingType::Comparison,
644        }))
645    } else if let Some(storage) = &bgle.storageTexture {
646        Some(BindingType::StorageTexture {
647            access: match storage.access {
648                GPUStorageTextureAccess::Write_only => StorageTextureAccess::WriteOnly,
649                GPUStorageTextureAccess::Read_only => StorageTextureAccess::ReadOnly,
650                GPUStorageTextureAccess::Read_write => StorageTextureAccess::ReadWrite,
651            },
652            format: device.validate_texture_format_required_features(&storage.format)?,
653            view_dimension: storage.viewDimension.convert(),
654        })
655    } else if let Some(texture) = &bgle.texture {
656        Some(BindingType::Texture {
657            sample_type: match texture.sampleType {
658                GPUTextureSampleType::Float => TextureSampleType::Float { filterable: true },
659                GPUTextureSampleType::Unfilterable_float => {
660                    TextureSampleType::Float { filterable: false }
661                },
662                GPUTextureSampleType::Depth => TextureSampleType::Depth,
663                GPUTextureSampleType::Sint => TextureSampleType::Sint,
664                GPUTextureSampleType::Uint => TextureSampleType::Uint,
665            },
666            view_dimension: texture.viewDimension.convert(),
667            multisampled: texture.multisampled,
668        })
669    } else {
670        assert_eq!(number_of_provided_bindings, 0);
671        None
672    };
673    // Check for number of bindings should actually be done in device-timeline,
674    // but we do it last on content-timeline to have some visible effect
675    let ty = if number_of_provided_bindings != 1 {
676        None
677    } else {
678        ty
679    }
680    .ok_or(webgpu_traits::Error::Validation(
681        "Exactly on entry type must be provided".to_string(),
682    ));
683
684    Ok(ty.map(|ty| BindGroupLayoutEntry {
685        binding: bgle.binding,
686        visibility: ShaderStages::from_bits_retain(bgle.visibility),
687        ty,
688        count: None,
689    }))
690}
691
692pub fn convert_texture_descriptor<D>(
693    descriptor: &GPUTextureDescriptor,
694    device: &D::GPUDevice,
695) -> Fallible<(TextureDescriptor<'static>, Extent3d)>
696where
697    D: Equivalence,
698    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
699{
700    let size = (&descriptor.size).try_convert()?;
701    let desc = TextureDescriptor {
702        label: (&descriptor.parent).convert(),
703        size,
704        mip_level_count: descriptor.mipLevelCount,
705        sample_count: descriptor.sampleCount,
706        dimension: descriptor.dimension.convert(),
707        format: device.validate_texture_format_required_features(&descriptor.format)?,
708        usage: TextureUsages::from_bits_retain(descriptor.usage),
709        view_formats: descriptor
710            .viewFormats
711            .iter()
712            .map(|tf| device.validate_texture_format_required_features(tf))
713            .collect::<Fallible<_>>()?,
714    };
715    Ok((desc, size))
716}
717
718impl WebGPUTryConvert<Color> for &GPUColor {
719    type Error = Error;
720
721    fn try_convert(self) -> Result<Color, Self::Error> {
722        match self {
723            GPUColor::DoubleSequence(s) => {
724                // https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpucolor-shape
725                if s.len() != 4 {
726                    Err(Error::Type(c"GPUColor sequence must be len 4".to_owned()))
727                } else {
728                    Ok(Color {
729                        r: *s[0],
730                        g: *s[1],
731                        b: *s[2],
732                        a: *s[3],
733                    })
734                }
735            },
736            GPUColor::GPUColorDict(d) => Ok(Color {
737                r: *d.r,
738                g: *d.g,
739                b: *d.b,
740                a: *d.a,
741            }),
742        }
743    }
744}
745
746impl<'a, D> WebGPUConvert<ProgrammableStageDescriptor<'a>> for &GPUProgrammableStage<D>
747where
748    D: Equivalence,
749    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
750{
751    fn convert(self) -> ProgrammableStageDescriptor<'a> {
752        ProgrammableStageDescriptor {
753            module: self.module.id().0,
754            entry_point: self
755                .entryPoint
756                .as_ref()
757                .map(|ep| Cow::Owned(ep.to_string())),
758            constants: self
759                .constants
760                .as_ref()
761                .map(|records| records.iter().map(|(k, v)| (k.0.clone(), **v)).collect())
762                .unwrap_or_default(),
763            zero_initialize_workgroup_memory: true,
764        }
765    }
766}
767
768pub fn convert_texture_for_wgpu_with_cx<D>(
769    cx: &mut JSContext,
770    texture_view: &GPUTextureOrGPUTextureView<D>,
771) -> WebGPUTextureView
772where
773    D: Equivalence,
774    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
775{
776    match texture_view {
777        GPUTextureOrGPUTextureView::GPUTextureView(view) => view.id(),
778        GPUTextureOrGPUTextureView::GPUTexture(texture) => texture.get_default_view(cx),
779    }
780}
781
782pub(crate) fn convert_bind_group_entry<'a, D>(
783    cx: &mut JSContext,
784    bind_group: &GPUBindGroupEntry<D>,
785) -> BindGroupEntry<'a>
786where
787    D: Equivalence,
788    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
789{
790    BindGroupEntry {
791        binding: bind_group.binding,
792        resource: match bind_group.resource {
793            GPUBindingResource::GPUSampler(ref s) => BindingResource::Sampler(s.id().0),
794            GPUBindingResource::GPUTextureView(ref t) => BindingResource::TextureView(t.id().0),
795            GPUBindingResource::GPUTexture(ref t) => {
796                BindingResource::TextureView(t.get_default_view(cx).0)
797            },
798            GPUBindingResource::GPUBufferBinding(ref b) => BindingResource::Buffer(BufferBinding {
799                buffer: b.buffer.id().0,
800                offset: b.offset,
801                size: b.size,
802            }),
803            GPUBindingResource::GPUBuffer(ref b) => BindingResource::Buffer(BufferBinding {
804                buffer: b.id().0,
805                offset: 0,
806                size: None,
807            }),
808            GPUBindingResource::GPUExternalTexture(ref t) => {
809                BindingResource::ExternalTexture(t.id().0)
810            },
811        },
812    }
813}
814
815impl WebGPUConvert<TextureDimension> for GPUTextureDimension {
816    fn convert(self) -> TextureDimension {
817        match self {
818            GPUTextureDimension::_1d => TextureDimension::D1,
819            GPUTextureDimension::_2d => TextureDimension::D2,
820            GPUTextureDimension::_3d => TextureDimension::D3,
821        }
822    }
823}
824
825impl WebGPUConvert<WGPUPredefinedColorSpace> for PredefinedColorSpace {
826    fn convert(self) -> WGPUPredefinedColorSpace {
827        match self {
828            PredefinedColorSpace::Srgb | PredefinedColorSpace::Srgb_linear => {
829                WGPUPredefinedColorSpace::Srgb
830            },
831            PredefinedColorSpace::Display_p3 | PredefinedColorSpace::Display_p3_linear => {
832                WGPUPredefinedColorSpace::DisplayP3
833            },
834        }
835    }
836}
837
838impl WebGPUConvert<QuerySetDescriptor<'static>> for &GPUQuerySetDescriptor {
839    fn convert(self) -> QuerySetDescriptor<'static> {
840        QuerySetDescriptor {
841            label: (&self.parent).convert(),
842            count: self.count,
843            ty: match self.type_ {
844                GPUQueryType::Occlusion => QueryType::Occlusion,
845                GPUQueryType::Timestamp => QueryType::Timestamp,
846            },
847        }
848    }
849}
850
851impl<D> WebGPUConvert<PassTimestampWrites> for &GPUComputePassTimestampWrites<D>
852where
853    D: Equivalence,
854    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
855{
856    fn convert(self) -> PassTimestampWrites {
857        PassTimestampWrites {
858            query_set: self.querySet.id().0,
859            beginning_of_pass_write_index: self.beginningOfPassWriteIndex,
860            end_of_pass_write_index: self.endOfPassWriteIndex,
861        }
862    }
863}
864
865impl<D> WebGPUConvert<PassTimestampWrites> for &GPURenderPassTimestampWrites<D>
866where
867    D: Equivalence,
868    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
869{
870    fn convert(self) -> PassTimestampWrites {
871        PassTimestampWrites {
872            query_set: self.querySet.id().0,
873            beginning_of_pass_write_index: self.beginningOfPassWriteIndex,
874            end_of_pass_write_index: self.endOfPassWriteIndex,
875        }
876    }
877}
878
879impl<D> WebGPUConvert<ComputePassDescriptor<'static>> for &GPUComputePassDescriptor<D>
880where
881    D: Equivalence,
882    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
883{
884    fn convert(self) -> ComputePassDescriptor<'static> {
885        ComputePassDescriptor {
886            label: (&self.parent).convert(),
887            timestamp_writes: self.timestampWrites.as_ref().map(WebGPUConvert::convert),
888        }
889    }
890}
891
892impl WebGPUConvert<IndexFormat> for GPUIndexFormat {
893    fn convert(self) -> IndexFormat {
894        match self {
895            GPUIndexFormat::Uint16 => IndexFormat::Uint16,
896            GPUIndexFormat::Uint32 => IndexFormat::Uint32,
897        }
898    }
899}