Skip to main content

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