diff --git a/ext/webgpu/01_webgpu.js b/ext/webgpu/01_webgpu.js index f7ad6caa7f..3954a93b7d 100644 --- a/ext/webgpu/01_webgpu.js +++ b/ext/webgpu/01_webgpu.js @@ -2646,9 +2646,9 @@ depthStencilAttachment.depthLoadOp = descriptor.depthStencilAttachment.depthLoadValue; } else { - depthStencilAttachment.depthLoadOp = "clear"; - depthStencilAttachment.depthLoadValue = - descriptor.depthStencilAttachment.depthLoadValue; + depthStencilAttachment.depthLoadOp = { + clear: descriptor.depthStencilAttachment.depthLoadValue, + }; } if ( @@ -2656,11 +2656,10 @@ ) { depthStencilAttachment.stencilLoadOp = descriptor.depthStencilAttachment.stencilLoadValue; - depthStencilAttachment.stencilLoadValue = undefined; } else { - depthStencilAttachment.stencilLoadOp = "clear"; - depthStencilAttachment.stencilLoadValue = - descriptor.depthStencilAttachment.stencilLoadValue; + depthStencilAttachment.stencilLoadOp = { + clear: descriptor.depthStencilAttachment.stencilLoadValue, + }; } } const colorAttachments = ArrayPrototypeMap( @@ -2717,10 +2716,9 @@ if (typeof colorAttachment.loadValue === "string") { attachment.loadOp = colorAttachment.loadValue; } else { - attachment.loadOp = "clear"; - attachment.loadValue = normalizeGPUColor( - colorAttachment.loadValue, - ); + attachment.loadOp = { + clear: normalizeGPUColor(colorAttachment.loadValue), + }; } return attachment; @@ -3674,29 +3672,19 @@ resourceContext: "Argument 2", selfContext: "this", }); - if (dynamicOffsetsData instanceof Uint32Array) { - core.opSync( - "op_webgpu_render_pass_set_bind_group", - { - renderPassRid, - index, - bindGroup: bindGroupRid, - dynamicOffsetsDataStart, - dynamicOffsetsDataLength, - }, - dynamicOffsetsData, - ); - } else { - dynamicOffsetsData ??= []; - core.opSync("op_webgpu_render_pass_set_bind_group", { - renderPassRid, - index, - bindGroup: bindGroupRid, - dynamicOffsetsData, - dynamicOffsetsDataStart: 0, - dynamicOffsetsDataLength: dynamicOffsetsData.length, - }); + if (!(dynamicOffsetsData instanceof Uint32Array)) { + dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []); + dynamicOffsetsDataStart = 0; + dynamicOffsetsDataLength = dynamicOffsetsData.length; } + core.opSync("op_webgpu_render_pass_set_bind_group", { + renderPassRid, + index, + bindGroup: bindGroupRid, + dynamicOffsetsData, + dynamicOffsetsDataStart, + dynamicOffsetsDataLength, + }); } /** @@ -4410,29 +4398,19 @@ resourceContext: "Argument 2", selfContext: "this", }); - if (dynamicOffsetsData instanceof Uint32Array) { - core.opSync( - "op_webgpu_compute_pass_set_bind_group", - { - computePassRid, - index, - bindGroup: bindGroupRid, - dynamicOffsetsDataStart, - dynamicOffsetsDataLength, - }, - dynamicOffsetsData, - ); - } else { - dynamicOffsetsData ??= []; - core.opSync("op_webgpu_compute_pass_set_bind_group", { - computePassRid, - index, - bindGroup: bindGroupRid, - dynamicOffsetsData, - dynamicOffsetsDataStart: 0, - dynamicOffsetsDataLength: dynamicOffsetsData.length, - }); + if (!(dynamicOffsetsData instanceof Uint32Array)) { + dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []); + dynamicOffsetsDataStart = 0; + dynamicOffsetsDataLength = dynamicOffsetsData.length; } + core.opSync("op_webgpu_compute_pass_set_bind_group", { + computePassRid, + index, + bindGroup: bindGroupRid, + dynamicOffsetsData, + dynamicOffsetsDataStart, + dynamicOffsetsDataLength, + }); } /** @@ -4659,29 +4637,19 @@ resourceContext: "Argument 2", selfContext: "this", }); - if (dynamicOffsetsData instanceof Uint32Array) { - core.opSync( - "op_webgpu_render_bundle_encoder_set_bind_group", - { - renderBundleEncoderRid, - index, - bindGroup: bindGroupRid, - dynamicOffsetsDataStart, - dynamicOffsetsDataLength, - }, - dynamicOffsetsData, - ); - } else { - dynamicOffsetsData ??= []; - core.opSync("op_webgpu_render_bundle_encoder_set_bind_group", { - renderBundleEncoderRid, - index, - bindGroup: bindGroupRid, - dynamicOffsetsData, - dynamicOffsetsDataStart: 0, - dynamicOffsetsDataLength: dynamicOffsetsData.length, - }); + if (!(dynamicOffsetsData instanceof Uint32Array)) { + dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []); + dynamicOffsetsDataStart = 0; + dynamicOffsetsDataLength = dynamicOffsetsData.length; } + core.opSync("op_webgpu_render_bundle_encoder_set_bind_group", { + renderBundleEncoderRid, + index, + bindGroup: bindGroupRid, + dynamicOffsetsData, + dynamicOffsetsDataStart, + dynamicOffsetsDataLength, + }); } /** diff --git a/ext/webgpu/02_idl_types.js b/ext/webgpu/02_idl_types.js index 364a397477..6f871a4ff2 100644 --- a/ext/webgpu/02_idl_types.js +++ b/ext/webgpu/02_idl_types.js @@ -950,6 +950,7 @@ webidl.converters["GPUComputePipelineDescriptor"] = webidl .createDictionaryConverter( "GPUComputePipelineDescriptor", + dictMembersGPUObjectDescriptorBase, dictMembersGPUPipelineDescriptorBase, dictMembersGPUComputePipelineDescriptor, ); @@ -1422,6 +1423,7 @@ webidl.converters["GPURenderPipelineDescriptor"] = webidl .createDictionaryConverter( "GPURenderPipelineDescriptor", + dictMembersGPUObjectDescriptorBase, dictMembersGPUPipelineDescriptorBase, dictMembersGPURenderPipelineDescriptor, ); diff --git a/ext/webgpu/binding.rs b/ext/webgpu/binding.rs index c1b98fcef6..c2dbcf455e 100644 --- a/ext/webgpu/binding.rs +++ b/ext/webgpu/binding.rs @@ -5,6 +5,9 @@ use deno_core::ResourceId; use deno_core::{OpState, Resource}; use serde::Deserialize; use std::borrow::Cow; +use std::convert::{TryFrom, TryInto}; + +use crate::texture::{GpuTextureFormat, GpuTextureViewDimension}; use super::error::WebGpuResult; @@ -27,33 +30,122 @@ impl Resource for WebGpuBindGroup { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuBufferBindingLayout { - #[serde(rename = "type")] - kind: Option, - has_dynamic_offset: Option, - min_binding_size: Option, + r#type: GpuBufferBindingType, + has_dynamic_offset: bool, + min_binding_size: u64, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuBufferBindingType { + Uniform, + Storage, + ReadOnlyStorage, +} + +impl From for wgpu_types::BufferBindingType { + fn from(binding_type: GpuBufferBindingType) -> Self { + match binding_type { + GpuBufferBindingType::Uniform => wgpu_types::BufferBindingType::Uniform, + GpuBufferBindingType::Storage => { + wgpu_types::BufferBindingType::Storage { read_only: false } + } + GpuBufferBindingType::ReadOnlyStorage => { + wgpu_types::BufferBindingType::Storage { read_only: true } + } + } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuSamplerBindingLayout { - #[serde(rename = "type")] - kind: Option, + r#type: GpuSamplerBindingType, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuSamplerBindingType { + Filtering, + NonFiltering, + Comparison, +} + +impl From for wgpu_types::BindingType { + fn from(binding_type: GpuSamplerBindingType) -> Self { + match binding_type { + GpuSamplerBindingType::Filtering => wgpu_types::BindingType::Sampler { + filtering: true, + comparison: false, + }, + GpuSamplerBindingType::NonFiltering => wgpu_types::BindingType::Sampler { + filtering: false, + comparison: false, + }, + GpuSamplerBindingType::Comparison => wgpu_types::BindingType::Sampler { + filtering: true, + comparison: true, + }, + } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuTextureBindingLayout { - sample_type: Option, - view_dimension: Option, - multisampled: Option, + sample_type: GpuTextureSampleType, + view_dimension: GpuTextureViewDimension, + multisampled: bool, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuTextureSampleType { + Float, + UnfilterableFloat, + Depth, + Sint, + Uint, +} + +impl From for wgpu_types::TextureSampleType { + fn from(sample_type: GpuTextureSampleType) -> Self { + match sample_type { + GpuTextureSampleType::Float => { + wgpu_types::TextureSampleType::Float { filterable: true } + } + GpuTextureSampleType::UnfilterableFloat => { + wgpu_types::TextureSampleType::Float { filterable: false } + } + GpuTextureSampleType::Depth => wgpu_types::TextureSampleType::Depth, + GpuTextureSampleType::Sint => wgpu_types::TextureSampleType::Sint, + GpuTextureSampleType::Uint => wgpu_types::TextureSampleType::Uint, + } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuStorageTextureBindingLayout { - access: String, - format: String, - view_dimension: Option, + access: GpuStorageTextureAccess, + format: GpuTextureFormat, + view_dimension: GpuTextureViewDimension, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuStorageTextureAccess { + WriteOnly, +} + +impl From for wgpu_types::StorageTextureAccess { + fn from(access: GpuStorageTextureAccess) -> Self { + match access { + GpuStorageTextureAccess::WriteOnly => { + wgpu_types::StorageTextureAccess::WriteOnly + } + } + } } #[derive(Deserialize)] @@ -61,10 +153,47 @@ struct GpuStorageTextureBindingLayout { struct GpuBindGroupLayoutEntry { binding: u32, visibility: u32, - buffer: Option, - sampler: Option, - texture: Option, - storage_texture: Option, + #[serde(flatten)] + binding_type: GpuBindingType, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +enum GpuBindingType { + Buffer(GpuBufferBindingLayout), + Sampler(GpuSamplerBindingLayout), + Texture(GpuTextureBindingLayout), + StorageTexture(GpuStorageTextureBindingLayout), +} + +impl TryFrom for wgpu_types::BindingType { + type Error = AnyError; + + fn try_from( + binding_type: GpuBindingType, + ) -> Result { + let binding_type = match binding_type { + GpuBindingType::Buffer(buffer) => wgpu_types::BindingType::Buffer { + ty: buffer.r#type.into(), + has_dynamic_offset: buffer.has_dynamic_offset, + min_binding_size: std::num::NonZeroU64::new(buffer.min_binding_size), + }, + GpuBindingType::Sampler(sampler) => sampler.r#type.into(), + GpuBindingType::Texture(texture) => wgpu_types::BindingType::Texture { + sample_type: texture.sample_type.into(), + view_dimension: texture.view_dimension.into(), + multisampled: texture.multisampled, + }, + GpuBindingType::StorageTexture(storage_texture) => { + wgpu_types::BindingType::StorageTexture { + access: storage_texture.access.into(), + format: storage_texture.format.try_into()?, + view_dimension: storage_texture.view_dimension.into(), + } + } + }; + Ok(binding_type) + } } #[derive(Deserialize)] @@ -88,101 +217,12 @@ pub fn op_webgpu_create_bind_group_layout( let mut entries = vec![]; - for entry in &args.entries { + for entry in args.entries { entries.push(wgpu_types::BindGroupLayoutEntry { binding: entry.binding, visibility: wgpu_types::ShaderStages::from_bits(entry.visibility) .unwrap(), - ty: if let Some(buffer) = &entry.buffer { - wgpu_types::BindingType::Buffer { - ty: match &buffer.kind { - Some(kind) => match kind.as_str() { - "uniform" => wgpu_types::BufferBindingType::Uniform, - "storage" => { - wgpu_types::BufferBindingType::Storage { read_only: false } - } - "read-only-storage" => { - wgpu_types::BufferBindingType::Storage { read_only: true } - } - _ => unreachable!(), - }, - None => wgpu_types::BufferBindingType::Uniform, - }, - has_dynamic_offset: buffer.has_dynamic_offset.unwrap_or(false), - min_binding_size: if let Some(min_binding_size) = - buffer.min_binding_size - { - std::num::NonZeroU64::new(min_binding_size) - } else { - None - }, - } - } else if let Some(sampler) = &entry.sampler { - match &sampler.kind { - Some(kind) => match kind.as_str() { - "filtering" => wgpu_types::BindingType::Sampler { - filtering: true, - comparison: false, - }, - "non-filtering" => wgpu_types::BindingType::Sampler { - filtering: false, - comparison: false, - }, - "comparison" => wgpu_types::BindingType::Sampler { - filtering: true, - comparison: true, - }, - _ => unreachable!(), - }, - None => wgpu_types::BindingType::Sampler { - filtering: true, - comparison: false, - }, - } - } else if let Some(texture) = &entry.texture { - wgpu_types::BindingType::Texture { - sample_type: match &texture.sample_type { - Some(sample_type) => match sample_type.as_str() { - "float" => { - wgpu_types::TextureSampleType::Float { filterable: true } - } - "unfilterable-float" => { - wgpu_types::TextureSampleType::Float { filterable: false } - } - "depth" => wgpu_types::TextureSampleType::Depth, - "sint" => wgpu_types::TextureSampleType::Sint, - "uint" => wgpu_types::TextureSampleType::Uint, - _ => unreachable!(), - }, - None => wgpu_types::TextureSampleType::Float { filterable: true }, - }, - view_dimension: match &texture.view_dimension { - Some(view_dimension) => { - super::texture::serialize_dimension(view_dimension) - } - None => wgpu_types::TextureViewDimension::D2, - }, - multisampled: texture.multisampled.unwrap_or(false), - } - } else if let Some(storage_texture) = &entry.storage_texture { - wgpu_types::BindingType::StorageTexture { - access: match storage_texture.access.as_str() { - "write-only" => wgpu_types::StorageTextureAccess::WriteOnly, - _ => unreachable!(), - }, - format: super::texture::serialize_texture_format( - &storage_texture.format, - )?, - view_dimension: match &storage_texture.view_dimension { - Some(view_dimension) => { - super::texture::serialize_dimension(view_dimension) - } - None => wgpu_types::TextureViewDimension::D2, - }, - } - } else { - unreachable!() - }, + ty: entry.binding_type.try_into()?, count: None, // native-only }); } @@ -244,7 +284,7 @@ pub fn op_webgpu_create_pipeline_layout( struct GpuBindGroupEntry { binding: u32, kind: String, - resource: u32, + resource: ResourceId, offset: Option, size: Option, } @@ -254,7 +294,7 @@ struct GpuBindGroupEntry { pub struct CreateBindGroupArgs { device_rid: ResourceId, label: Option, - layout: u32, + layout: ResourceId, entries: Vec, } diff --git a/ext/webgpu/buffer.rs b/ext/webgpu/buffer.rs index b87982aecb..92afd2ef90 100644 --- a/ext/webgpu/buffer.rs +++ b/ext/webgpu/buffer.rs @@ -38,7 +38,7 @@ pub struct CreateBufferArgs { label: Option, size: u64, usage: u32, - mapped_at_creation: Option, + mapped_at_creation: bool, } pub fn op_webgpu_create_buffer( @@ -57,7 +57,7 @@ pub fn op_webgpu_create_buffer( size: args.size, usage: wgpu_types::BufferUsages::from_bits(args.usage) .ok_or_else(|| type_error("usage is not valid"))?, - mapped_at_creation: args.mapped_at_creation.unwrap_or(false), + mapped_at_creation: args.mapped_at_creation, }; gfx_put!(device => instance.device_create_buffer( diff --git a/ext/webgpu/bundle.rs b/ext/webgpu/bundle.rs index 3a228ba627..df91104f5d 100644 --- a/ext/webgpu/bundle.rs +++ b/ext/webgpu/bundle.rs @@ -1,6 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::null_opbuf; use deno_core::error::AnyError; use deno_core::ResourceId; use deno_core::ZeroCopyBuf; @@ -8,10 +7,13 @@ use deno_core::{OpState, Resource}; use serde::Deserialize; use std::borrow::Cow; use std::cell::RefCell; +use std::convert::TryInto; use std::rc::Rc; +use crate::pipeline::GpuIndexFormat; +use crate::texture::GpuTextureFormat; + use super::error::WebGpuResult; -use super::texture::serialize_texture_format; struct WebGpuRenderBundleEncoder( RefCell, @@ -34,9 +36,9 @@ impl Resource for WebGpuRenderBundle { pub struct CreateRenderBundleEncoderArgs { device_rid: ResourceId, label: Option, - color_formats: Vec, - depth_stencil_format: Option, - sample_count: Option, + color_formats: Vec, + depth_stencil_format: Option, + sample_count: u32, depth_read_only: bool, stencil_read_only: bool, } @@ -53,24 +55,25 @@ pub fn op_webgpu_create_render_bundle_encoder( let mut color_formats = vec![]; - for format in &args.color_formats { - color_formats.push(serialize_texture_format(format)?); + for format in args.color_formats { + color_formats.push(format.try_into()?); } + let depth_stencil = if let Some(format) = args.depth_stencil_format { + Some(wgpu_types::RenderBundleDepthStencil { + format: format.try_into()?, + depth_read_only: args.depth_read_only, + stencil_read_only: args.stencil_read_only, + }) + } else { + None + }; + let descriptor = wgpu_core::command::RenderBundleEncoderDescriptor { label: args.label.map(Cow::from), color_formats: Cow::from(color_formats), - sample_count: args.sample_count.unwrap_or(1), - depth_stencil: if let Some(depth_stencil_format) = args.depth_stencil_format - { - Some(wgpu_types::RenderBundleDepthStencil { - format: serialize_texture_format(&depth_stencil_format)?, - depth_read_only: args.depth_read_only, - stencil_read_only: args.stencil_read_only, - }) - } else { - None - }, + sample_count: args.sample_count, + depth_stencil, }; let res = @@ -129,8 +132,8 @@ pub fn op_webgpu_render_bundle_encoder_finish( pub struct RenderBundleEncoderSetBindGroupArgs { render_bundle_encoder_rid: ResourceId, index: u32, - bind_group: u32, - dynamic_offsets_data: Option>, + bind_group: ResourceId, + dynamic_offsets_data: ZeroCopyBuf, dynamic_offsets_data_start: usize, dynamic_offsets_data_length: usize, } @@ -138,7 +141,7 @@ pub struct RenderBundleEncoderSetBindGroupArgs { pub fn op_webgpu_render_bundle_encoder_set_bind_group( state: &mut OpState, args: RenderBundleEncoderSetBindGroupArgs, - zero_copy: Option, + _: (), ) -> Result { let bind_group_resource = state @@ -149,37 +152,35 @@ pub fn op_webgpu_render_bundle_encoder_set_bind_group( .resource_table .get::(args.render_bundle_encoder_rid)?; - // I know this might look like it can be easily deduplicated, but it can not - // be due to the lifetime of the args.dynamic_offsets_data slice. Because we - // need to use a raw pointer here the slice can be freed before the pointer - // is used in wgpu_render_pass_set_bind_group. See - // https://matrix.to/#/!XFRnMvAfptAHthwBCx:matrix.org/$HgrlhD-Me1DwsGb8UdMu2Hqubgks8s7ILwWRwigOUAg - match args.dynamic_offsets_data { - Some(data) => unsafe { - wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - data.as_slice().as_ptr(), - args.dynamic_offsets_data_length, - ); - }, - None => { - let zero_copy = zero_copy.ok_or_else(null_opbuf)?; - let (prefix, data, suffix) = unsafe { zero_copy.align_to::() }; - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - unsafe { - wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - data[args.dynamic_offsets_data_start..].as_ptr(), - args.dynamic_offsets_data_length, - ); - } - } - }; + // Align the data + assert!(args.dynamic_offsets_data.len() % std::mem::size_of::() == 0); + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. + let (prefix, dynamic_offsets_data, suffix) = + unsafe { args.dynamic_offsets_data.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + + let start = args.dynamic_offsets_data_start; + let len = args.dynamic_offsets_data_length; + + // Assert that length and start are both in bounds + assert!(start <= dynamic_offsets_data.len()); + assert!(len <= dynamic_offsets_data.len() - start); + + let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group( + &mut render_bundle_encoder_resource.0.borrow_mut(), + args.index, + bind_group_resource.0, + dynamic_offsets_data.as_ptr(), + dynamic_offsets_data.len(), + ); + } Ok(WebGpuResult::empty()) } @@ -201,8 +202,10 @@ pub fn op_webgpu_render_bundle_encoder_push_debug_group( .resource_table .get::(args.render_bundle_encoder_rid)?; + let label = std::ffi::CString::new(args.group_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. unsafe { - let label = std::ffi::CString::new(args.group_label).unwrap(); wgpu_core::command::bundle_ffi::wgpu_render_bundle_push_debug_group( &mut render_bundle_encoder_resource.0.borrow_mut(), label.as_ptr(), @@ -252,8 +255,10 @@ pub fn op_webgpu_render_bundle_encoder_insert_debug_marker( .resource_table .get::(args.render_bundle_encoder_rid)?; + let label = std::ffi::CString::new(args.marker_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. unsafe { - let label = std::ffi::CString::new(args.marker_label).unwrap(); wgpu_core::command::bundle_ffi::wgpu_render_bundle_insert_debug_marker( &mut render_bundle_encoder_resource.0.borrow_mut(), label.as_ptr(), @@ -267,7 +272,7 @@ pub fn op_webgpu_render_bundle_encoder_insert_debug_marker( #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderSetPipelineArgs { render_bundle_encoder_rid: ResourceId, - pipeline: u32, + pipeline: ResourceId, } pub fn op_webgpu_render_bundle_encoder_set_pipeline( @@ -296,8 +301,8 @@ pub fn op_webgpu_render_bundle_encoder_set_pipeline( #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderSetIndexBufferArgs { render_bundle_encoder_rid: ResourceId, - buffer: u32, - index_format: String, + buffer: ResourceId, + index_format: GpuIndexFormat, offset: u64, size: u64, } @@ -320,7 +325,7 @@ pub fn op_webgpu_render_bundle_encoder_set_index_buffer( .borrow_mut() .set_index_buffer( buffer_resource.0, - super::pipeline::serialize_index_format(args.index_format), + args.index_format.into(), args.offset, std::num::NonZeroU64::new(args.size), ); @@ -333,7 +338,7 @@ pub fn op_webgpu_render_bundle_encoder_set_index_buffer( pub struct RenderBundleEncoderSetVertexBufferArgs { render_bundle_encoder_rid: ResourceId, slot: u32, - buffer: u32, + buffer: ResourceId, offset: u64, size: u64, } @@ -430,7 +435,7 @@ pub fn op_webgpu_render_bundle_encoder_draw_indexed( #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderDrawIndirectArgs { render_bundle_encoder_rid: ResourceId, - indirect_buffer: u32, + indirect_buffer: ResourceId, indirect_offset: u64, } diff --git a/ext/webgpu/command_encoder.rs b/ext/webgpu/command_encoder.rs index b68bab7bd0..afffe77a0f 100644 --- a/ext/webgpu/command_encoder.rs +++ b/ext/webgpu/command_encoder.rs @@ -8,6 +8,8 @@ use std::borrow::Cow; use std::cell::RefCell; use std::num::NonZeroU32; +use crate::texture::GpuTextureAspect; + use super::error::WebGpuResult; pub(crate) struct WebGpuCommandEncoder( @@ -28,14 +30,6 @@ impl Resource for WebGpuCommandBuffer { } } -fn serialize_store_op(store_op: String) -> wgpu_core::command::StoreOp { - match store_op.as_str() { - "store" => wgpu_core::command::StoreOp::Store, - "discard" => wgpu_core::command::StoreOp::Discard, - _ => unreachable!(), - } -} - #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateCommandEncoderArgs { @@ -69,25 +63,45 @@ pub fn op_webgpu_create_command_encoder( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct GpuRenderPassColorAttachment { - view: u32, - resolve_target: Option, - load_op: String, - load_value: Option, - store_op: Option, + view: ResourceId, + resolve_target: Option, + load_op: GpuLoadOp, + store_op: GpuStoreOp, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuLoadOp { + Load, + Clear(T), +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuStoreOp { + Store, + Discard, +} + +impl From for wgpu_core::command::StoreOp { + fn from(value: GpuStoreOp) -> wgpu_core::command::StoreOp { + match value { + GpuStoreOp::Store => wgpu_core::command::StoreOp::Store, + GpuStoreOp::Discard => wgpu_core::command::StoreOp::Discard, + } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuRenderPassDepthStencilAttachment { - view: u32, - depth_load_op: String, - depth_load_value: Option, - depth_store_op: String, - depth_read_only: Option, - stencil_load_op: String, - stencil_load_value: Option, - stencil_store_op: String, - stencil_read_only: Option, + view: ResourceId, + depth_load_op: GpuLoadOp, + depth_store_op: GpuStoreOp, + depth_read_only: bool, + stencil_load_op: GpuLoadOp, + stencil_store_op: GpuStoreOp, + stencil_read_only: bool, } #[derive(Deserialize)] @@ -117,43 +131,37 @@ pub fn op_webgpu_command_encoder_begin_render_pass( .resource_table .get::(color_attachment.view)?; + let resolve_target = color_attachment + .resolve_target + .map(|rid| { + state + .resource_table + .get::(rid) + }) + .transpose()? + .map(|texture| texture.0); + let attachment = wgpu_core::command::RenderPassColorAttachment { view: texture_view_resource.0, - resolve_target: color_attachment - .resolve_target - .map(|rid| { - state - .resource_table - .get::(rid) - }) - .transpose()? - .map(|texture| texture.0), - channel: match color_attachment.load_op.as_str() { - "load" => wgpu_core::command::PassChannel { + resolve_target, + channel: match color_attachment.load_op { + GpuLoadOp::Load => wgpu_core::command::PassChannel { load_op: wgpu_core::command::LoadOp::Load, - store_op: color_attachment - .store_op - .map_or(wgpu_core::command::StoreOp::Store, serialize_store_op), + store_op: color_attachment.store_op.into(), clear_value: Default::default(), read_only: false, }, - "clear" => { - let color = color_attachment.load_value.unwrap(); - wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Clear, - store_op: color_attachment - .store_op - .map_or(wgpu_core::command::StoreOp::Store, serialize_store_op), - clear_value: wgpu_types::Color { - r: color.r, - g: color.g, - b: color.b, - a: color.a, - }, - read_only: false, - } - } - _ => unreachable!(), + GpuLoadOp::Clear(color) => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Clear, + store_op: color_attachment.store_op.into(), + clear_value: wgpu_types::Color { + r: color.r, + g: color.g, + b: color.b, + a: color.a, + }, + read_only: false, + }, }, }; @@ -171,35 +179,33 @@ pub fn op_webgpu_command_encoder_begin_render_pass( depth_stencil_attachment = Some(wgpu_core::command::RenderPassDepthStencilAttachment { view: texture_view_resource.0, - depth: match attachment.depth_load_op.as_str() { - "load" => wgpu_core::command::PassChannel { + depth: match attachment.depth_load_op { + GpuLoadOp::Load => wgpu_core::command::PassChannel { load_op: wgpu_core::command::LoadOp::Load, - store_op: serialize_store_op(attachment.depth_store_op), + store_op: attachment.depth_store_op.into(), clear_value: 0.0, - read_only: attachment.depth_read_only.unwrap_or(false), + read_only: attachment.depth_read_only, }, - "clear" => wgpu_core::command::PassChannel { + GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { load_op: wgpu_core::command::LoadOp::Clear, - store_op: serialize_store_op(attachment.depth_store_op), - clear_value: attachment.depth_load_value.unwrap(), - read_only: attachment.depth_read_only.unwrap_or(false), + store_op: attachment.depth_store_op.into(), + clear_value: value, + read_only: attachment.depth_read_only, }, - _ => unreachable!(), }, - stencil: match attachment.stencil_load_op.as_str() { - "load" => wgpu_core::command::PassChannel { + stencil: match attachment.stencil_load_op { + GpuLoadOp::Load => wgpu_core::command::PassChannel { load_op: wgpu_core::command::LoadOp::Load, - store_op: serialize_store_op(attachment.stencil_store_op), + store_op: attachment.stencil_store_op.into(), clear_value: 0, - read_only: attachment.stencil_read_only.unwrap_or(false), + read_only: attachment.stencil_read_only, }, - "clear" => wgpu_core::command::PassChannel { + GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { load_op: wgpu_core::command::LoadOp::Clear, - store_op: serialize_store_op(attachment.stencil_store_op), - clear_value: attachment.stencil_load_value.unwrap(), - read_only: attachment.stencil_read_only.unwrap_or(false), + store_op: attachment.stencil_store_op.into(), + clear_value: value, + read_only: attachment.stencil_read_only, }, - _ => unreachable!(), }, }); } @@ -262,9 +268,9 @@ pub fn op_webgpu_command_encoder_begin_compute_pass( #[serde(rename_all = "camelCase")] pub struct CommandEncoderCopyBufferToBufferArgs { command_encoder_rid: ResourceId, - source: u32, + source: ResourceId, source_offset: u64, - destination: u32, + destination: ResourceId, destination_offset: u64, size: u64, } @@ -303,8 +309,8 @@ pub fn op_webgpu_command_encoder_copy_buffer_to_buffer( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct GpuImageCopyBuffer { - buffer: u32, - offset: Option, + buffer: ResourceId, + offset: u64, bytes_per_row: Option, rows_per_image: Option, } @@ -312,18 +318,28 @@ pub struct GpuImageCopyBuffer { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct GpuOrigin3D { - pub x: Option, - pub y: Option, - pub z: Option, + pub x: u32, + pub y: u32, + pub z: u32, +} + +impl From for wgpu_types::Origin3d { + fn from(origin: GpuOrigin3D) -> wgpu_types::Origin3d { + wgpu_types::Origin3d { + x: origin.x, + y: origin.y, + z: origin.z, + } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct GpuImageCopyTexture { - pub texture: u32, - pub mip_level: Option, - pub origin: Option, - pub aspect: String, + pub texture: ResourceId, + pub mip_level: u32, + pub origin: GpuOrigin3D, + pub aspect: GpuTextureAspect, } #[derive(Deserialize)] @@ -357,38 +373,22 @@ pub fn op_webgpu_command_encoder_copy_buffer_to_texture( let source = wgpu_core::command::ImageCopyBuffer { buffer: source_buffer_resource.0, layout: wgpu_types::ImageDataLayout { - offset: args.source.offset.unwrap_or(0), + offset: args.source.offset, bytes_per_row: NonZeroU32::new(args.source.bytes_per_row.unwrap_or(0)), rows_per_image: NonZeroU32::new(args.source.rows_per_image.unwrap_or(0)), }, }; let destination = wgpu_core::command::ImageCopyTexture { texture: destination_texture_resource.0, - mip_level: args.destination.mip_level.unwrap_or(0), - origin: args - .destination - .origin - .map_or(Default::default(), |origin| wgpu_types::Origin3d { - x: origin.x.unwrap_or(0), - y: origin.y.unwrap_or(0), - z: origin.z.unwrap_or(0), - }), - aspect: match args.destination.aspect.as_str() { - "all" => wgpu_types::TextureAspect::All, - "stencil-only" => wgpu_types::TextureAspect::StencilOnly, - "depth-only" => wgpu_types::TextureAspect::DepthOnly, - _ => unreachable!(), - }, + mip_level: args.destination.mip_level, + origin: args.destination.origin.into(), + aspect: args.destination.aspect.into(), }; gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_texture( command_encoder, &source, &destination, - &wgpu_types::Extent3d { - width: args.copy_size.width.unwrap_or(1), - height: args.copy_size.height.unwrap_or(1), - depth_or_array_layers: args.copy_size.depth_or_array_layers.unwrap_or(1), - } + &args.copy_size.into() )) } @@ -422,25 +422,14 @@ pub fn op_webgpu_command_encoder_copy_texture_to_buffer( let source = wgpu_core::command::ImageCopyTexture { texture: source_texture_resource.0, - mip_level: args.source.mip_level.unwrap_or(0), - origin: args.source.origin.map_or(Default::default(), |origin| { - wgpu_types::Origin3d { - x: origin.x.unwrap_or(0), - y: origin.y.unwrap_or(0), - z: origin.z.unwrap_or(0), - } - }), - aspect: match args.source.aspect.as_str() { - "all" => wgpu_types::TextureAspect::All, - "stencil-only" => wgpu_types::TextureAspect::StencilOnly, - "depth-only" => wgpu_types::TextureAspect::DepthOnly, - _ => unreachable!(), - }, + mip_level: args.source.mip_level, + origin: args.source.origin.into(), + aspect: args.source.aspect.into(), }; let destination = wgpu_core::command::ImageCopyBuffer { buffer: destination_buffer_resource.0, layout: wgpu_types::ImageDataLayout { - offset: args.destination.offset.unwrap_or(0), + offset: args.destination.offset, bytes_per_row: NonZeroU32::new( args.destination.bytes_per_row.unwrap_or(0), ), @@ -453,11 +442,7 @@ pub fn op_webgpu_command_encoder_copy_texture_to_buffer( command_encoder, &source, &destination, - &wgpu_types::Extent3d { - width: args.copy_size.width.unwrap_or(1), - height: args.copy_size.height.unwrap_or(1), - depth_or_array_layers: args.copy_size.depth_or_array_layers.unwrap_or(1), - } + &args.copy_size.into() )) } @@ -491,48 +476,21 @@ pub fn op_webgpu_command_encoder_copy_texture_to_texture( let source = wgpu_core::command::ImageCopyTexture { texture: source_texture_resource.0, - mip_level: args.source.mip_level.unwrap_or(0), - origin: args.source.origin.map_or(Default::default(), |origin| { - wgpu_types::Origin3d { - x: origin.x.unwrap_or(0), - y: origin.y.unwrap_or(0), - z: origin.z.unwrap_or(0), - } - }), - aspect: match args.source.aspect.as_str() { - "all" => wgpu_types::TextureAspect::All, - "stencil-only" => wgpu_types::TextureAspect::StencilOnly, - "depth-only" => wgpu_types::TextureAspect::DepthOnly, - _ => unreachable!(), - }, + mip_level: args.source.mip_level, + origin: args.source.origin.into(), + aspect: args.source.aspect.into(), }; let destination = wgpu_core::command::ImageCopyTexture { texture: destination_texture_resource.0, - mip_level: args.destination.mip_level.unwrap_or(0), - origin: args - .destination - .origin - .map_or(Default::default(), |origin| wgpu_types::Origin3d { - x: origin.x.unwrap_or(0), - y: origin.y.unwrap_or(0), - z: origin.z.unwrap_or(0), - }), - aspect: match args.destination.aspect.as_str() { - "all" => wgpu_types::TextureAspect::All, - "stencil-only" => wgpu_types::TextureAspect::StencilOnly, - "depth-only" => wgpu_types::TextureAspect::DepthOnly, - _ => unreachable!(), - }, + mip_level: args.destination.mip_level, + origin: args.destination.origin.into(), + aspect: args.destination.aspect.into(), }; gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_texture( command_encoder, &source, &destination, - &wgpu_types::Extent3d { - width: args.copy_size.width.unwrap_or(1), - height: args.copy_size.height.unwrap_or(1), - depth_or_array_layers: args.copy_size.depth_or_array_layers.unwrap_or(1), - } + &args.copy_size.into() )) } @@ -606,7 +564,7 @@ pub fn op_webgpu_command_encoder_insert_debug_marker( #[serde(rename_all = "camelCase")] pub struct CommandEncoderWriteTimestampArgs { command_encoder_rid: ResourceId, - query_set: u32, + query_set: ResourceId, query_index: u32, } @@ -635,10 +593,10 @@ pub fn op_webgpu_command_encoder_write_timestamp( #[serde(rename_all = "camelCase")] pub struct CommandEncoderResolveQuerySetArgs { command_encoder_rid: ResourceId, - query_set: u32, + query_set: ResourceId, first_query: u32, query_count: u32, - destination: u32, + destination: ResourceId, destination_offset: u64, } diff --git a/ext/webgpu/compute_pass.rs b/ext/webgpu/compute_pass.rs index 4fc0af5385..fe1186c4e6 100644 --- a/ext/webgpu/compute_pass.rs +++ b/ext/webgpu/compute_pass.rs @@ -1,6 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::null_opbuf; use deno_core::error::AnyError; use deno_core::ResourceId; use deno_core::ZeroCopyBuf; @@ -24,7 +23,7 @@ impl Resource for WebGpuComputePass { #[serde(rename_all = "camelCase")] pub struct ComputePassSetPipelineArgs { compute_pass_rid: ResourceId, - pipeline: u32, + pipeline: ResourceId, } pub fn op_webgpu_compute_pass_set_pipeline( @@ -80,7 +79,7 @@ pub fn op_webgpu_compute_pass_dispatch( #[serde(rename_all = "camelCase")] pub struct ComputePassDispatchIndirectArgs { compute_pass_rid: ResourceId, - indirect_buffer: u32, + indirect_buffer: ResourceId, indirect_offset: u64, } @@ -109,7 +108,7 @@ pub fn op_webgpu_compute_pass_dispatch_indirect( #[serde(rename_all = "camelCase")] pub struct ComputePassBeginPipelineStatisticsQueryArgs { compute_pass_rid: ResourceId, - query_set: u32, + query_set: ResourceId, query_index: u32, } @@ -160,7 +159,7 @@ pub fn op_webgpu_compute_pass_end_pipeline_statistics_query( #[serde(rename_all = "camelCase")] pub struct ComputePassWriteTimestampArgs { compute_pass_rid: ResourceId, - query_set: u32, + query_set: ResourceId, query_index: u32, } @@ -220,8 +219,8 @@ pub fn op_webgpu_compute_pass_end_pass( pub struct ComputePassSetBindGroupArgs { compute_pass_rid: ResourceId, index: u32, - bind_group: u32, - dynamic_offsets_data: Option>, + bind_group: ResourceId, + dynamic_offsets_data: ZeroCopyBuf, dynamic_offsets_data_start: usize, dynamic_offsets_data_length: usize, } @@ -229,7 +228,7 @@ pub struct ComputePassSetBindGroupArgs { pub fn op_webgpu_compute_pass_set_bind_group( state: &mut OpState, args: ComputePassSetBindGroupArgs, - zero_copy: Option, + _: (), ) -> Result { let bind_group_resource = state @@ -239,22 +238,33 @@ pub fn op_webgpu_compute_pass_set_bind_group( .resource_table .get::(args.compute_pass_rid)?; + // Align the data + assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. + let (prefix, dynamic_offsets_data, suffix) = + unsafe { args.dynamic_offsets_data.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + + let start = args.dynamic_offsets_data_start; + let len = args.dynamic_offsets_data_length; + + // Assert that length and start are both in bounds + assert!(start <= dynamic_offsets_data.len()); + assert!(len <= dynamic_offsets_data.len() - start); + + let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. unsafe { wgpu_core::command::compute_ffi::wgpu_compute_pass_set_bind_group( &mut compute_pass_resource.0.borrow_mut(), args.index, bind_group_resource.0, - match args.dynamic_offsets_data { - Some(data) => data.as_ptr(), - None => { - let zero_copy = zero_copy.ok_or_else(null_opbuf)?; - let (prefix, data, suffix) = zero_copy.align_to::(); - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - data[args.dynamic_offsets_data_start..].as_ptr() - } - }, - args.dynamic_offsets_data_length, + dynamic_offsets_data.as_ptr(), + dynamic_offsets_data.len(), ); } @@ -277,8 +287,10 @@ pub fn op_webgpu_compute_pass_push_debug_group( .resource_table .get::(args.compute_pass_rid)?; + let label = std::ffi::CString::new(args.group_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. unsafe { - let label = std::ffi::CString::new(args.group_label).unwrap(); wgpu_core::command::compute_ffi::wgpu_compute_pass_push_debug_group( &mut compute_pass_resource.0.borrow_mut(), label.as_ptr(), @@ -327,8 +339,10 @@ pub fn op_webgpu_compute_pass_insert_debug_marker( .resource_table .get::(args.compute_pass_rid)?; + let label = std::ffi::CString::new(args.marker_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. unsafe { - let label = std::ffi::CString::new(args.marker_label).unwrap(); wgpu_core::command::compute_ffi::wgpu_compute_pass_insert_debug_marker( &mut compute_pass_resource.0.borrow_mut(), label.as_ptr(), diff --git a/ext/webgpu/lib.rs b/ext/webgpu/lib.rs index d2b0a239b4..0fdd30dd3e 100644 --- a/ext/webgpu/lib.rs +++ b/ext/webgpu/lib.rs @@ -1,6 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::not_supported; use deno_core::error::AnyError; use deno_core::include_js_files; use deno_core::op_async; @@ -14,10 +13,12 @@ use serde::Deserialize; use serde::Serialize; use std::borrow::Cow; use std::cell::RefCell; +use std::collections::HashSet; use std::path::PathBuf; use std::rc::Rc; pub use wgpu_core; pub use wgpu_types; +use wgpu_types::PowerPreference; use error::DomExceptionOperationError; use error::WebGpuResult; @@ -217,10 +218,28 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { return_features } +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuPowerPreference { + LowPower, + HighPerformance, +} + +impl From for wgpu_types::PowerPreference { + fn from(value: GpuPowerPreference) -> wgpu_types::PowerPreference { + match value { + GpuPowerPreference::LowPower => wgpu_types::PowerPreference::LowPower, + GpuPowerPreference::HighPerformance => { + wgpu_types::PowerPreference::HighPerformance + } + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RequestAdapterArgs { - power_preference: Option, + power_preference: Option, } #[derive(Serialize)] @@ -260,12 +279,8 @@ pub async fn op_webgpu_request_adapter( let descriptor = wgpu_core::instance::RequestAdapterOptions { power_preference: match args.power_preference { - Some(power_preference) => match power_preference.as_str() { - "low-power" => wgpu_types::PowerPreference::LowPower, - "high-performance" => wgpu_types::PowerPreference::HighPerformance, - _ => unreachable!(), - }, - None => Default::default(), + Some(power_preference) => power_preference.into(), + None => PowerPreference::default(), }, // TODO(lucacasonato): respect forceFallbackAdapter compatible_surface: None, // windowless @@ -412,10 +427,116 @@ impl From for wgpu_types::Limits { pub struct RequestDeviceArgs { adapter_rid: ResourceId, label: Option, - required_features: Option>, + required_features: Option, required_limits: Option, } +#[derive(Deserialize)] +pub struct GpuRequiredFeatures(HashSet); + +impl From for wgpu_types::Features { + fn from(required_features: GpuRequiredFeatures) -> wgpu_types::Features { + let mut features: wgpu_types::Features = wgpu_types::Features::empty(); + + if required_features.0.contains("depth-clamping") { + features.set(wgpu_types::Features::DEPTH_CLAMPING, true); + } + if required_features.0.contains("pipeline-statistics-query") { + features.set(wgpu_types::Features::PIPELINE_STATISTICS_QUERY, true); + } + if required_features.0.contains("texture-compression-bc") { + features.set(wgpu_types::Features::TEXTURE_COMPRESSION_BC, true); + } + if required_features.0.contains("timestamp-query") { + features.set(wgpu_types::Features::TIMESTAMP_QUERY, true); + } + + // extended from spec + if required_features.0.contains("mappable-primary-buffers") { + features.set(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, true); + } + if required_features.0.contains("texture-binding-array") { + features.set(wgpu_types::Features::TEXTURE_BINDING_ARRAY, true); + } + if required_features.0.contains("buffer-binding-array") { + features.set(wgpu_types::Features::BUFFER_BINDING_ARRAY, true); + } + if required_features + .0 + .contains("storage-resource-binding-array") + { + features.set(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY, true); + } + if required_features + .0 + .contains("sampled-texture-and-storage-buffer-array-non-uniform-indexing") + { + features.set(wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, true); + } + if required_features.0.contains( + "uniform-buffer-and-storage-buffer-texture-non-uniform-indexing", + ) { + features.set(wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, true); + } + if required_features.0.contains("unsized-binding-array") { + features.set(wgpu_types::Features::UNSIZED_BINDING_ARRAY, true); + } + if required_features.0.contains("multi-draw-indirect") { + features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT, true); + } + if required_features.0.contains("multi-draw-indirect-count") { + features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, true); + } + if required_features.0.contains("push-constants") { + features.set(wgpu_types::Features::PUSH_CONSTANTS, true); + } + if required_features.0.contains("address-mode-clamp-to-border") { + features.set(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, true); + } + if required_features.0.contains("non-fill-polygon-mode") { + features.set(wgpu_types::Features::NON_FILL_POLYGON_MODE, true); + } + if required_features.0.contains("texture-compression-etc2") { + features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, true); + } + if required_features.0.contains("texture-compression-astc-ldr") { + features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, true); + } + if required_features + .0 + .contains("texture-adapter-specific-format-features") + { + features.set( + wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, + true, + ); + } + if required_features.0.contains("shader-float64") { + features.set(wgpu_types::Features::SHADER_FLOAT64, true); + } + if required_features.0.contains("vertex-attribute-64bit") { + features.set(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, true); + } + if required_features.0.contains("conservative-rasterization") { + features.set(wgpu_types::Features::CONSERVATIVE_RASTERIZATION, true); + } + if required_features.0.contains("vertex-writable-storage") { + features.set(wgpu_types::Features::VERTEX_WRITABLE_STORAGE, true); + } + if required_features.0.contains("clear-commands") { + features.set(wgpu_types::Features::CLEAR_COMMANDS, true); + } + if required_features.0.contains("spirv-shader-passthrough") { + features.set(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH, true); + } + if required_features.0.contains("shader-primitive-index") { + features.set(wgpu_types::Features::SHADER_PRIMITIVE_INDEX, true); + } + + features + } +} + pub async fn op_webgpu_request_device( state: Rc>, args: RequestDeviceArgs, @@ -428,108 +549,10 @@ pub async fn op_webgpu_request_device( let adapter = adapter_resource.0; let instance = state.borrow::(); - let mut features: wgpu_types::Features = wgpu_types::Features::empty(); - - if let Some(passed_features) = args.required_features { - if passed_features.contains(&"depth-clamping".to_string()) { - features.set(wgpu_types::Features::DEPTH_CLAMPING, true); - } - if passed_features.contains(&"pipeline-statistics-query".to_string()) { - features.set(wgpu_types::Features::PIPELINE_STATISTICS_QUERY, true); - } - if passed_features.contains(&"texture-compression-bc".to_string()) { - features.set(wgpu_types::Features::TEXTURE_COMPRESSION_BC, true); - } - if passed_features.contains(&"timestamp-query".to_string()) { - features.set(wgpu_types::Features::TIMESTAMP_QUERY, true); - } - - // extended from spec - if passed_features.contains(&"mappable-primary-buffers".to_string()) { - features.set(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, true); - } - if passed_features.contains(&"texture-binding-array".to_string()) { - features.set(wgpu_types::Features::TEXTURE_BINDING_ARRAY, true); - } - if passed_features.contains(&"buffer-binding-array".to_string()) { - features.set(wgpu_types::Features::BUFFER_BINDING_ARRAY, true); - } - if passed_features.contains(&"storage-resource-binding-array".to_string()) { - features.set(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY, true); - } - if passed_features.contains( - &"sampled-texture-and-storage-buffer-array-non-uniform-indexing" - .to_string(), - ) { - features.set(wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, true); - } - if passed_features.contains( - &"uniform-buffer-and-storage-buffer-texture-non-uniform-indexing" - .to_string(), - ) { - features.set(wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, true); - } - if passed_features.contains(&"unsized-binding-array".to_string()) { - features.set(wgpu_types::Features::UNSIZED_BINDING_ARRAY, true); - } - if passed_features.contains(&"multi-draw-indirect".to_string()) { - features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT, true); - } - if passed_features.contains(&"multi-draw-indirect-count".to_string()) { - features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, true); - } - if passed_features.contains(&"push-constants".to_string()) { - features.set(wgpu_types::Features::PUSH_CONSTANTS, true); - } - if passed_features.contains(&"address-mode-clamp-to-border".to_string()) { - features.set(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, true); - } - if passed_features.contains(&"non-fill-polygon-mode".to_string()) { - features.set(wgpu_types::Features::NON_FILL_POLYGON_MODE, true); - } - if passed_features.contains(&"texture-compression-etc2".to_string()) { - features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, true); - } - if passed_features.contains(&"texture-compression-astc-ldr".to_string()) { - features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, true); - } - if passed_features - .contains(&"texture-adapter-specific-format-features".to_string()) - { - features.set( - wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, - true, - ); - } - if passed_features.contains(&"shader-float64".to_string()) { - features.set(wgpu_types::Features::SHADER_FLOAT64, true); - } - if passed_features.contains(&"vertex-attribute-64bit".to_string()) { - features.set(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, true); - } - if passed_features.contains(&"conservative-rasterization".to_string()) { - features.set(wgpu_types::Features::CONSERVATIVE_RASTERIZATION, true); - } - if passed_features.contains(&"vertex-writable-storage".to_string()) { - features.set(wgpu_types::Features::VERTEX_WRITABLE_STORAGE, true); - } - if passed_features.contains(&"clear-commands".to_string()) { - features.set(wgpu_types::Features::CLEAR_COMMANDS, true); - } - if passed_features.contains(&"spirv-shader-passthrough".to_string()) { - features.set(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH, true); - } - if passed_features.contains(&"shader-primitive-index".to_string()) { - features.set(wgpu_types::Features::SHADER_PRIMITIVE_INDEX, true); - } - } - let descriptor = wgpu_types::DeviceDescriptor { label: args.label.map(Cow::from), - features, - limits: args - .required_limits - .map_or(wgpu_types::Limits::default(), Into::into), + features: args.required_features.map(Into::into).unwrap_or_default(), + limits: args.required_limits.map(Into::into).unwrap_or_default(), }; let (device, maybe_err) = gfx_select!(adapter => instance.adapter_request_device( @@ -564,10 +587,54 @@ pub async fn op_webgpu_request_device( pub struct CreateQuerySetArgs { device_rid: ResourceId, label: Option, - #[serde(rename = "type")] - kind: String, + #[serde(flatten)] + r#type: GpuQueryType, count: u32, - pipeline_statistics: Option>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", tag = "type")] +enum GpuQueryType { + Occlusion, + #[serde(rename_all = "camelCase")] + PipelineStatistics { + pipeline_statistics: HashSet, + }, + Timestamp, +} + +impl From for wgpu_types::QueryType { + fn from(query_type: GpuQueryType) -> Self { + match query_type { + GpuQueryType::Occlusion => wgpu_types::QueryType::Occlusion, + GpuQueryType::PipelineStatistics { + pipeline_statistics, + } => { + use wgpu_types::PipelineStatisticsTypes; + + let mut types = PipelineStatisticsTypes::empty(); + + if pipeline_statistics.contains("vertex-shader-invocations") { + types.set(PipelineStatisticsTypes::VERTEX_SHADER_INVOCATIONS, true); + } + if pipeline_statistics.contains("clipper-invocations") { + types.set(PipelineStatisticsTypes::CLIPPER_INVOCATIONS, true); + } + if pipeline_statistics.contains("clipper-primitives-out") { + types.set(PipelineStatisticsTypes::CLIPPER_PRIMITIVES_OUT, true); + } + if pipeline_statistics.contains("fragment-shader-invocations") { + types.set(PipelineStatisticsTypes::FRAGMENT_SHADER_INVOCATIONS, true); + } + if pipeline_statistics.contains("compute-shader-invocations") { + types.set(PipelineStatisticsTypes::COMPUTE_SHADER_INVOCATIONS, true); + } + + wgpu_types::QueryType::PipelineStatistics(types) + } + GpuQueryType::Timestamp => wgpu_types::QueryType::Timestamp, + } + } } pub fn op_webgpu_create_query_set( @@ -582,57 +649,7 @@ pub fn op_webgpu_create_query_set( let descriptor = wgpu_types::QuerySetDescriptor { label: args.label.map(Cow::from), - ty: match args.kind.as_str() { - "pipeline-statistics" => { - let mut pipeline_statistics_names = - wgpu_types::PipelineStatisticsTypes::empty(); - - if let Some(pipeline_statistics) = args.pipeline_statistics { - if pipeline_statistics - .contains(&"vertex-shader-invocations".to_string()) - { - pipeline_statistics_names.set( - wgpu_types::PipelineStatisticsTypes::VERTEX_SHADER_INVOCATIONS, - true, - ); - } - if pipeline_statistics.contains(&"clipper-invocations".to_string()) { - pipeline_statistics_names.set( - wgpu_types::PipelineStatisticsTypes::CLIPPER_INVOCATIONS, - true, - ); - } - if pipeline_statistics.contains(&"clipper-primitives-out".to_string()) - { - pipeline_statistics_names.set( - wgpu_types::PipelineStatisticsTypes::CLIPPER_PRIMITIVES_OUT, - true, - ); - } - if pipeline_statistics - .contains(&"fragment-shader-invocations".to_string()) - { - pipeline_statistics_names.set( - wgpu_types::PipelineStatisticsTypes::FRAGMENT_SHADER_INVOCATIONS, - true, - ); - } - if pipeline_statistics - .contains(&"compute-shader-invocations".to_string()) - { - pipeline_statistics_names.set( - wgpu_types::PipelineStatisticsTypes::COMPUTE_SHADER_INVOCATIONS, - true, - ); - } - }; - - wgpu_types::QueryType::PipelineStatistics(pipeline_statistics_names) - } - "occlusion" => return Err(not_supported()), - "timestamp" => wgpu_types::QueryType::Timestamp, - _ => unreachable!(), - }, + ty: args.r#type.into(), count: args.count, }; diff --git a/ext/webgpu/pipeline.rs b/ext/webgpu/pipeline.rs index 877143f943..77edcadfb3 100644 --- a/ext/webgpu/pipeline.rs +++ b/ext/webgpu/pipeline.rs @@ -6,6 +6,10 @@ use deno_core::{OpState, Resource}; use serde::Deserialize; use serde::Serialize; use std::borrow::Cow; +use std::convert::{TryFrom, TryInto}; + +use crate::sampler::GpuCompareFunction; +use crate::texture::GpuTextureFormat; use super::error::{WebGpuError, WebGpuResult}; @@ -38,121 +42,196 @@ impl Resource for WebGpuRenderPipeline { } } -pub fn serialize_index_format(format: String) -> wgpu_types::IndexFormat { - match format.as_str() { - "uint16" => wgpu_types::IndexFormat::Uint16, - "uint32" => wgpu_types::IndexFormat::Uint32, - _ => unreachable!(), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuIndexFormat { + Uint16, + Uint32, +} + +impl From for wgpu_types::IndexFormat { + fn from(value: GpuIndexFormat) -> wgpu_types::IndexFormat { + match value { + GpuIndexFormat::Uint16 => wgpu_types::IndexFormat::Uint16, + GpuIndexFormat::Uint32 => wgpu_types::IndexFormat::Uint32, + } } } -fn serialize_stencil_operation( - operation: &str, -) -> wgpu_types::StencilOperation { - match operation { - "keep" => wgpu_types::StencilOperation::Keep, - "zero" => wgpu_types::StencilOperation::Zero, - "replace" => wgpu_types::StencilOperation::Replace, - "invert" => wgpu_types::StencilOperation::Invert, - "increment-clamp" => wgpu_types::StencilOperation::IncrementClamp, - "decrement-clamp" => wgpu_types::StencilOperation::DecrementClamp, - "increment-wrap" => wgpu_types::StencilOperation::IncrementWrap, - "decrement-wrap" => wgpu_types::StencilOperation::DecrementWrap, - _ => unreachable!(), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GPUStencilOperation { + Keep, + Zero, + Replace, + Invert, + IncrementClamp, + DecrementClamp, + IncrementWrap, + DecrementWrap, +} + +impl From for wgpu_types::StencilOperation { + fn from(value: GPUStencilOperation) -> wgpu_types::StencilOperation { + match value { + GPUStencilOperation::Keep => wgpu_types::StencilOperation::Keep, + GPUStencilOperation::Zero => wgpu_types::StencilOperation::Zero, + GPUStencilOperation::Replace => wgpu_types::StencilOperation::Replace, + GPUStencilOperation::Invert => wgpu_types::StencilOperation::Invert, + GPUStencilOperation::IncrementClamp => { + wgpu_types::StencilOperation::IncrementClamp + } + GPUStencilOperation::DecrementClamp => { + wgpu_types::StencilOperation::DecrementClamp + } + GPUStencilOperation::IncrementWrap => { + wgpu_types::StencilOperation::IncrementWrap + } + GPUStencilOperation::DecrementWrap => { + wgpu_types::StencilOperation::DecrementWrap + } + } } } -fn serialize_stencil_face_state( - state: GpuStencilFaceState, -) -> wgpu_types::StencilFaceState { - wgpu_types::StencilFaceState { - compare: state - .compare - .as_ref() - .map_or(wgpu_types::CompareFunction::Always, |op| { - super::sampler::serialize_compare_function(op) - }), - fail_op: state - .fail_op - .as_ref() - .map_or(wgpu_types::StencilOperation::Keep, |op| { - serialize_stencil_operation(op) - }), - depth_fail_op: state - .depth_fail_op - .as_ref() - .map_or(wgpu_types::StencilOperation::Keep, |op| { - serialize_stencil_operation(op) - }), - pass_op: state - .pass_op - .as_ref() - .map_or(wgpu_types::StencilOperation::Keep, |op| { - serialize_stencil_operation(op) - }), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuBlendFactor { + Zero, + One, + Src, + OneMinusSrc, + SrcAlpha, + OneMinusSrcAlpha, + Dst, + OneMinusDst, + DstAlpha, + OneMinusDstAlpha, + SrcAlphaSaturated, + Constant, + OneMinusConstant, +} + +impl From for wgpu_types::BlendFactor { + fn from(value: GpuBlendFactor) -> wgpu_types::BlendFactor { + match value { + GpuBlendFactor::Zero => wgpu_types::BlendFactor::Zero, + GpuBlendFactor::One => wgpu_types::BlendFactor::One, + GpuBlendFactor::Src => wgpu_types::BlendFactor::Src, + GpuBlendFactor::OneMinusSrc => wgpu_types::BlendFactor::OneMinusSrc, + GpuBlendFactor::SrcAlpha => wgpu_types::BlendFactor::SrcAlpha, + GpuBlendFactor::OneMinusSrcAlpha => { + wgpu_types::BlendFactor::OneMinusSrcAlpha + } + GpuBlendFactor::Dst => wgpu_types::BlendFactor::Dst, + GpuBlendFactor::OneMinusDst => wgpu_types::BlendFactor::OneMinusDst, + GpuBlendFactor::DstAlpha => wgpu_types::BlendFactor::DstAlpha, + GpuBlendFactor::OneMinusDstAlpha => { + wgpu_types::BlendFactor::OneMinusDstAlpha + } + GpuBlendFactor::SrcAlphaSaturated => { + wgpu_types::BlendFactor::SrcAlphaSaturated + } + GpuBlendFactor::Constant => wgpu_types::BlendFactor::Constant, + GpuBlendFactor::OneMinusConstant => { + wgpu_types::BlendFactor::OneMinusConstant + } + } } } -fn serialize_blend_factor(blend_factor: &str) -> wgpu_types::BlendFactor { - match blend_factor { - "zero" => wgpu_types::BlendFactor::Zero, - "one" => wgpu_types::BlendFactor::One, - "src" => wgpu_types::BlendFactor::Src, - "one-minus-src" => wgpu_types::BlendFactor::OneMinusSrc, - "src-alpha" => wgpu_types::BlendFactor::SrcAlpha, - "one-minus-src-alpha" => wgpu_types::BlendFactor::OneMinusSrcAlpha, - "dst" => wgpu_types::BlendFactor::Dst, - "one-minus-dst" => wgpu_types::BlendFactor::OneMinusDst, - "dst-alpha" => wgpu_types::BlendFactor::DstAlpha, - "one-minus-dst-alpha" => wgpu_types::BlendFactor::OneMinusDstAlpha, - "src-alpha-saturated" => wgpu_types::BlendFactor::SrcAlphaSaturated, - "constant" => wgpu_types::BlendFactor::Constant, - "one-minus-constant" => wgpu_types::BlendFactor::OneMinusConstant, - _ => unreachable!(), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuBlendOperation { + Add, + Subtract, + ReverseSubtract, + Min, + Max, +} + +impl From for wgpu_types::BlendOperation { + fn from(value: GpuBlendOperation) -> wgpu_types::BlendOperation { + match value { + GpuBlendOperation::Add => wgpu_types::BlendOperation::Add, + GpuBlendOperation::Subtract => wgpu_types::BlendOperation::Subtract, + GpuBlendOperation::ReverseSubtract => { + wgpu_types::BlendOperation::ReverseSubtract + } + GpuBlendOperation::Min => wgpu_types::BlendOperation::Min, + GpuBlendOperation::Max => wgpu_types::BlendOperation::Max, + } } } -fn serialize_blend_state(state: GpuBlendState) -> wgpu_types::BlendState { - wgpu_types::BlendState { - alpha: serialize_blend_component(state.alpha), - color: serialize_blend_component(state.color), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuPrimitiveTopology { + PointList, + LineList, + LineStrip, + TriangleList, + TriangleStrip, +} + +impl From for wgpu_types::PrimitiveTopology { + fn from(value: GpuPrimitiveTopology) -> wgpu_types::PrimitiveTopology { + match value { + GpuPrimitiveTopology::PointList => { + wgpu_types::PrimitiveTopology::PointList + } + GpuPrimitiveTopology::LineList => wgpu_types::PrimitiveTopology::LineList, + GpuPrimitiveTopology::LineStrip => { + wgpu_types::PrimitiveTopology::LineStrip + } + GpuPrimitiveTopology::TriangleList => { + wgpu_types::PrimitiveTopology::TriangleList + } + GpuPrimitiveTopology::TriangleStrip => { + wgpu_types::PrimitiveTopology::TriangleStrip + } + } } } -fn serialize_blend_component( - blend: GpuBlendComponent, -) -> wgpu_types::BlendComponent { - wgpu_types::BlendComponent { - src_factor: blend - .src_factor - .as_ref() - .map_or(wgpu_types::BlendFactor::One, |factor| { - serialize_blend_factor(factor) - }), - dst_factor: blend - .dst_factor - .as_ref() - .map_or(wgpu_types::BlendFactor::Zero, |factor| { - serialize_blend_factor(factor) - }), - operation: match &blend.operation { - Some(operation) => match operation.as_str() { - "add" => wgpu_types::BlendOperation::Add, - "subtract" => wgpu_types::BlendOperation::Subtract, - "reverse-subtract" => wgpu_types::BlendOperation::ReverseSubtract, - "min" => wgpu_types::BlendOperation::Min, - "max" => wgpu_types::BlendOperation::Max, - _ => unreachable!(), - }, - None => wgpu_types::BlendOperation::Add, - }, +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuFrontFace { + Ccw, + Cw, +} + +impl From for wgpu_types::FrontFace { + fn from(value: GpuFrontFace) -> wgpu_types::FrontFace { + match value { + GpuFrontFace::Ccw => wgpu_types::FrontFace::Ccw, + GpuFrontFace::Cw => wgpu_types::FrontFace::Cw, + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuCullMode { + None, + Front, + Back, +} + +impl From for Option { + fn from(value: GpuCullMode) -> Option { + match value { + GpuCullMode::None => None, + GpuCullMode::Front => Some(wgpu_types::Face::Front), + GpuCullMode::Back => Some(wgpu_types::Face::Back), + } } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuProgrammableStage { - module: u32, + module: ResourceId, entry_point: String, // constants: HashMap } @@ -162,7 +241,7 @@ struct GpuProgrammableStage { pub struct CreateComputePipelineArgs { device_rid: ResourceId, label: Option, - layout: Option, + layout: Option, compute: GpuProgrammableStage, } @@ -264,58 +343,138 @@ pub fn op_webgpu_compute_pipeline_get_bind_group_layout( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuPrimitiveState { - topology: Option, - strip_index_format: Option, - front_face: Option, - cull_mode: Option, + topology: GpuPrimitiveTopology, + strip_index_format: Option, + front_face: GpuFrontFace, + cull_mode: GpuCullMode, clamp_depth: bool, } -#[derive(Deserialize, Clone)] +impl From for wgpu_types::PrimitiveState { + fn from(value: GpuPrimitiveState) -> wgpu_types::PrimitiveState { + wgpu_types::PrimitiveState { + topology: value.topology.into(), + strip_index_format: value.strip_index_format.map(Into::into), + front_face: value.front_face.into(), + cull_mode: value.cull_mode.into(), + clamp_depth: value.clamp_depth, + polygon_mode: Default::default(), // native-only + conservative: false, // native-only + } + } +} +#[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuBlendComponent { - src_factor: Option, - dst_factor: Option, - operation: Option, + src_factor: GpuBlendFactor, + dst_factor: GpuBlendFactor, + operation: GpuBlendOperation, } -#[derive(Deserialize, Clone)] +impl From for wgpu_types::BlendComponent { + fn from(component: GpuBlendComponent) -> Self { + wgpu_types::BlendComponent { + src_factor: component.src_factor.into(), + dst_factor: component.dst_factor.into(), + operation: component.operation.into(), + } + } +} + +#[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuBlendState { color: GpuBlendComponent, alpha: GpuBlendComponent, } +impl From for wgpu_types::BlendState { + fn from(state: GpuBlendState) -> wgpu_types::BlendState { + wgpu_types::BlendState { + color: state.color.into(), + alpha: state.alpha.into(), + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuColorTargetState { - format: String, + format: GpuTextureFormat, blend: Option, - write_mask: Option, + write_mask: u32, +} + +impl TryFrom for wgpu_types::ColorTargetState { + type Error = AnyError; + fn try_from( + state: GpuColorTargetState, + ) -> Result { + Ok(wgpu_types::ColorTargetState { + format: state.format.try_into()?, + blend: state.blend.map(Into::into), + write_mask: wgpu_types::ColorWrites::from_bits_truncate(state.write_mask), + }) + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuStencilFaceState { - compare: Option, - fail_op: Option, - depth_fail_op: Option, - pass_op: Option, + compare: GpuCompareFunction, + fail_op: GPUStencilOperation, + depth_fail_op: GPUStencilOperation, + pass_op: GPUStencilOperation, +} + +impl From for wgpu_types::StencilFaceState { + fn from(state: GpuStencilFaceState) -> Self { + wgpu_types::StencilFaceState { + compare: state.compare.into(), + fail_op: state.fail_op.into(), + depth_fail_op: state.depth_fail_op.into(), + pass_op: state.pass_op.into(), + } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuDepthStencilState { - format: String, - depth_write_enabled: Option, - depth_compare: Option, - stencil_front: Option, - stencil_back: Option, - stencil_read_mask: Option, - stencil_write_mask: Option, - depth_bias: Option, - depth_bias_slope_scale: Option, - depth_bias_clamp: Option, + format: GpuTextureFormat, + depth_write_enabled: bool, + depth_compare: GpuCompareFunction, + stencil_front: GpuStencilFaceState, + stencil_back: GpuStencilFaceState, + stencil_read_mask: u32, + stencil_write_mask: u32, + depth_bias: i32, + depth_bias_slope_scale: f32, + depth_bias_clamp: f32, +} + +impl TryFrom for wgpu_types::DepthStencilState { + type Error = AnyError; + fn try_from( + state: GpuDepthStencilState, + ) -> Result { + Ok(wgpu_types::DepthStencilState { + format: state.format.try_into()?, + depth_write_enabled: state.depth_write_enabled, + depth_compare: state.depth_compare.into(), + stencil: wgpu_types::StencilState { + front: state.stencil_front.into(), + back: state.stencil_back.into(), + read_mask: state.stencil_read_mask, + write_mask: state.stencil_write_mask, + }, + bias: wgpu_types::DepthBiasState { + constant: state.depth_bias, + slope_scale: state.depth_bias_slope_scale, + clamp: state.depth_bias_clamp, + }, + }) + } } #[derive(Deserialize)] @@ -326,6 +485,16 @@ struct GpuVertexAttribute { shader_location: u32, } +impl From for wgpu_types::VertexAttribute { + fn from(attribute: GpuVertexAttribute) -> Self { + wgpu_types::VertexAttribute { + format: attribute.format.into(), + offset: attribute.offset, + shader_location: attribute.shader_location, + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "lowercase")] enum GpuVertexFormat { @@ -407,28 +576,71 @@ impl From for wgpu_types::VertexFormat { } } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +enum GpuVertexStepMode { + Vertex, + Instance, +} + +impl From for wgpu_types::VertexStepMode { + fn from(vsm: GpuVertexStepMode) -> wgpu_types::VertexStepMode { + use wgpu_types::VertexStepMode; + match vsm { + GpuVertexStepMode::Vertex => VertexStepMode::Vertex, + GpuVertexStepMode::Instance => VertexStepMode::Instance, + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuVertexBufferLayout { array_stride: u64, - step_mode: Option, + step_mode: GpuVertexStepMode, attributes: Vec, } +impl<'a> From + for wgpu_core::pipeline::VertexBufferLayout<'a> +{ + fn from( + layout: GpuVertexBufferLayout, + ) -> wgpu_core::pipeline::VertexBufferLayout<'a> { + wgpu_core::pipeline::VertexBufferLayout { + array_stride: layout.array_stride, + step_mode: layout.step_mode.into(), + attributes: Cow::Owned( + layout.attributes.into_iter().map(Into::into).collect(), + ), + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuVertexState { - module: u32, + module: ResourceId, entry_point: String, - buffers: Option>>, + buffers: Vec>, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuMultisampleState { - count: Option, - mask: Option, // against spec, but future proof - alpha_to_coverage_enabled: Option, + count: u32, + mask: u64, + alpha_to_coverage_enabled: bool, +} + +impl From for wgpu_types::MultisampleState { + fn from(gms: GpuMultisampleState) -> wgpu_types::MultisampleState { + wgpu_types::MultisampleState { + count: gms.count, + mask: gms.mask, + alpha_to_coverage_enabled: gms.alpha_to_coverage_enabled, + } + } } #[derive(Deserialize)] @@ -437,6 +649,7 @@ struct GpuFragmentState { targets: Vec, module: u32, entry_point: String, + // TODO(lucacasonato): constants } #[derive(Deserialize)] @@ -444,11 +657,11 @@ struct GpuFragmentState { pub struct CreateRenderPipelineArgs { device_rid: ResourceId, label: Option, - layout: Option, + layout: Option, vertex: GpuVertexState, - primitive: Option, + primitive: GpuPrimitiveState, depth_stencil: Option, - multisample: Option, + multisample: GpuMultisampleState, fragment: Option, } @@ -476,149 +689,51 @@ pub fn op_webgpu_create_render_pipeline( .resource_table .get::(args.vertex.module)?; + let fragment = if let Some(fragment) = args.fragment { + let fragment_shader_module_resource = + state + .resource_table + .get::(fragment.module)?; + + let mut targets = Vec::with_capacity(fragment.targets.len()); + + for target in fragment.targets { + targets.push(target.try_into()?); + } + + Some(wgpu_core::pipeline::FragmentState { + stage: wgpu_core::pipeline::ProgrammableStageDescriptor { + module: fragment_shader_module_resource.0, + entry_point: Cow::from(fragment.entry_point), + }, + targets: Cow::from(targets), + }) + } else { + None + }; + + let vertex_buffers = args + .vertex + .buffers + .into_iter() + .flatten() + .map(Into::into) + .collect(); + let descriptor = wgpu_core::pipeline::RenderPipelineDescriptor { - label: args.label.map(Cow::from), + label: args.label.map(Cow::Owned), layout, vertex: wgpu_core::pipeline::VertexState { stage: wgpu_core::pipeline::ProgrammableStageDescriptor { module: vertex_shader_module_resource.0, - entry_point: Cow::from(args.vertex.entry_point), + entry_point: Cow::Owned(args.vertex.entry_point), }, - buffers: Cow::from(if let Some(buffers) = args.vertex.buffers { - let mut return_buffers = vec![]; - for buffer in buffers.into_iter().flatten() { - return_buffers.push(wgpu_core::pipeline::VertexBufferLayout { - array_stride: buffer.array_stride, - step_mode: match buffer.step_mode { - Some(step_mode) => match step_mode.as_str() { - "vertex" => wgpu_types::VertexStepMode::Vertex, - "instance" => wgpu_types::VertexStepMode::Instance, - _ => unreachable!(), - }, - None => wgpu_types::VertexStepMode::Vertex, - }, - attributes: Cow::from( - buffer - .attributes - .into_iter() - .map(|attribute| wgpu_types::VertexAttribute { - format: attribute.format.into(), - offset: attribute.offset, - shader_location: attribute.shader_location, - }) - .collect::>(), - ), - }); - } - return_buffers - } else { - vec![] - }), + buffers: Cow::Owned(vertex_buffers), }, - primitive: args.primitive.map_or(Default::default(), |primitive| { - wgpu_types::PrimitiveState { - topology: match primitive.topology { - Some(topology) => match topology.as_str() { - "point-list" => wgpu_types::PrimitiveTopology::PointList, - "line-list" => wgpu_types::PrimitiveTopology::LineList, - "line-strip" => wgpu_types::PrimitiveTopology::LineStrip, - "triangle-list" => wgpu_types::PrimitiveTopology::TriangleList, - "triangle-strip" => wgpu_types::PrimitiveTopology::TriangleStrip, - _ => unreachable!(), - }, - None => wgpu_types::PrimitiveTopology::TriangleList, - }, - strip_index_format: primitive - .strip_index_format - .map(serialize_index_format), - front_face: match primitive.front_face { - Some(front_face) => match front_face.as_str() { - "ccw" => wgpu_types::FrontFace::Ccw, - "cw" => wgpu_types::FrontFace::Cw, - _ => unreachable!(), - }, - None => wgpu_types::FrontFace::Ccw, - }, - cull_mode: match primitive.cull_mode { - Some(cull_mode) => match cull_mode.as_str() { - "none" => None, - "front" => Some(wgpu_types::Face::Front), - "back" => Some(wgpu_types::Face::Back), - _ => unreachable!(), - }, - None => None, - }, - polygon_mode: Default::default(), // native-only - conservative: false, // native-only - clamp_depth: primitive.clamp_depth, - } - }), - depth_stencil: args.depth_stencil.map(|depth_stencil| { - wgpu_types::DepthStencilState { - format: super::texture::serialize_texture_format(&depth_stencil.format) - .unwrap(), - depth_write_enabled: depth_stencil.depth_write_enabled.unwrap_or(false), - depth_compare: match depth_stencil.depth_compare { - Some(depth_compare) => { - super::sampler::serialize_compare_function(&depth_compare) - } - None => wgpu_types::CompareFunction::Always, - }, - stencil: wgpu_types::StencilState { - front: depth_stencil - .stencil_front - .map_or(Default::default(), serialize_stencil_face_state), - back: depth_stencil - .stencil_back - .map_or(Default::default(), serialize_stencil_face_state), - read_mask: depth_stencil.stencil_read_mask.unwrap_or(0xFFFFFFFF), - write_mask: depth_stencil.stencil_write_mask.unwrap_or(0xFFFFFFFF), - }, - bias: wgpu_types::DepthBiasState { - constant: depth_stencil.depth_bias.unwrap_or(0), - slope_scale: depth_stencil.depth_bias_slope_scale.unwrap_or(0.0), - clamp: depth_stencil.depth_bias_clamp.unwrap_or(0.0), - }, - } - }), - multisample: args.multisample.map_or(Default::default(), |multisample| { - wgpu_types::MultisampleState { - count: multisample.count.unwrap_or(1), - mask: multisample.mask.unwrap_or(0xFFFFFFFF), - alpha_to_coverage_enabled: multisample - .alpha_to_coverage_enabled - .unwrap_or(false), - } - }), - fragment: args.fragment.map(|fragment| { - let fragment_shader_module_resource = state - .resource_table - .get::(fragment.module) - .unwrap(); - - wgpu_core::pipeline::FragmentState { - stage: wgpu_core::pipeline::ProgrammableStageDescriptor { - module: fragment_shader_module_resource.0, - entry_point: Cow::from(fragment.entry_point), - }, - targets: Cow::from( - fragment - .targets - .into_iter() - .map(|target| wgpu_types::ColorTargetState { - format: super::texture::serialize_texture_format(&target.format) - .unwrap(), - blend: target.blend.map(serialize_blend_state), - write_mask: target - .write_mask - .map_or(Default::default(), |mask| { - wgpu_types::ColorWrites::from_bits(mask).unwrap() - }), - }) - .collect::>(), - ), - } - }), + primitive: args.primitive.into(), + depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?, + multisample: args.multisample.into(), + fragment, }; let implicit_pipelines = match args.layout { diff --git a/ext/webgpu/queue.rs b/ext/webgpu/queue.rs index da1f7a1ad9..ddb653fca1 100644 --- a/ext/webgpu/queue.rs +++ b/ext/webgpu/queue.rs @@ -17,7 +17,7 @@ type WebGpuQueue = super::WebGpuDevice; #[serde(rename_all = "camelCase")] pub struct QueueSubmitArgs { queue_rid: ResourceId, - command_buffers: Vec, + command_buffers: Vec, } pub fn op_webgpu_queue_submit( @@ -49,16 +49,26 @@ pub fn op_webgpu_queue_submit( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuImageDataLayout { - offset: Option, + offset: u64, bytes_per_row: Option, rows_per_image: Option, } +impl From for wgpu_types::ImageDataLayout { + fn from(layout: GpuImageDataLayout) -> Self { + wgpu_types::ImageDataLayout { + offset: layout.offset, + bytes_per_row: NonZeroU32::new(layout.bytes_per_row.unwrap_or(0)), + rows_per_image: NonZeroU32::new(layout.rows_per_image.unwrap_or(0)), + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct QueueWriteBufferArgs { queue_rid: ResourceId, - buffer: u32, + buffer: ResourceId, buffer_offset: u64, data_offset: usize, size: Option, @@ -119,39 +129,17 @@ pub fn op_webgpu_write_texture( let destination = wgpu_core::command::ImageCopyTexture { texture: texture_resource.0, - mip_level: args.destination.mip_level.unwrap_or(0), - origin: args - .destination - .origin - .map_or(Default::default(), |origin| wgpu_types::Origin3d { - x: origin.x.unwrap_or(0), - y: origin.y.unwrap_or(0), - z: origin.z.unwrap_or(0), - }), - aspect: match args.destination.aspect.as_str() { - "all" => wgpu_types::TextureAspect::All, - "stencil-only" => wgpu_types::TextureAspect::StencilOnly, - "depth-only" => wgpu_types::TextureAspect::DepthOnly, - _ => unreachable!(), - }, - }; - let data_layout = wgpu_types::ImageDataLayout { - offset: args.data_layout.offset.unwrap_or(0), - bytes_per_row: NonZeroU32::new(args.data_layout.bytes_per_row.unwrap_or(0)), - rows_per_image: NonZeroU32::new( - args.data_layout.rows_per_image.unwrap_or(0), - ), + mip_level: args.destination.mip_level, + origin: args.destination.origin.into(), + aspect: args.destination.aspect.into(), }; + let data_layout = args.data_layout.into(); gfx_ok!(queue => instance.queue_write_texture( queue, &destination, &*zero_copy, &data_layout, - &wgpu_types::Extent3d { - width: args.size.width.unwrap_or(1), - height: args.size.height.unwrap_or(1), - depth_or_array_layers: args.size.depth_or_array_layers.unwrap_or(1), - } + &args.size.into() )) } diff --git a/ext/webgpu/render_pass.rs b/ext/webgpu/render_pass.rs index e01a6d478f..125579b52d 100644 --- a/ext/webgpu/render_pass.rs +++ b/ext/webgpu/render_pass.rs @@ -1,6 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::null_opbuf; use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::ResourceId; @@ -10,6 +9,8 @@ use serde::Deserialize; use std::borrow::Cow; use std::cell::RefCell; +use crate::pipeline::GpuIndexFormat; + use super::error::WebGpuResult; pub(crate) struct WebGpuRenderPass( @@ -253,11 +254,13 @@ pub fn op_webgpu_render_pass_execute_bundles( .resource_table .get::(args.render_pass_rid)?; + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. unsafe { wgpu_core::command::render_ffi::wgpu_render_pass_execute_bundles( &mut render_pass_resource.0.borrow_mut(), render_bundle_ids.as_ptr(), - args.bundles.len(), + render_bundle_ids.len(), ); } @@ -297,7 +300,7 @@ pub struct RenderPassSetBindGroupArgs { render_pass_rid: ResourceId, index: u32, bind_group: u32, - dynamic_offsets_data: Option>, + dynamic_offsets_data: ZeroCopyBuf, dynamic_offsets_data_start: usize, dynamic_offsets_data_length: usize, } @@ -305,7 +308,7 @@ pub struct RenderPassSetBindGroupArgs { pub fn op_webgpu_render_pass_set_bind_group( state: &mut OpState, args: RenderPassSetBindGroupArgs, - zero_copy: Option, + _: (), ) -> Result { let bind_group_resource = state @@ -315,37 +318,35 @@ pub fn op_webgpu_render_pass_set_bind_group( .resource_table .get::(args.render_pass_rid)?; - // I know this might look like it can be easily deduplicated, but it can not - // be due to the lifetime of the args.dynamic_offsets_data slice. Because we - // need to use a raw pointer here the slice can be freed before the pointer - // is used in wgpu_render_pass_set_bind_group. See - // https://matrix.to/#/!XFRnMvAfptAHthwBCx:matrix.org/$HgrlhD-Me1DwsGb8UdMu2Hqubgks8s7ILwWRwigOUAg - match args.dynamic_offsets_data { - Some(data) => unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group( - &mut render_pass_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - data.as_slice().as_ptr(), - args.dynamic_offsets_data_length, - ); - }, - None => { - let zero_copy = zero_copy.ok_or_else(null_opbuf)?; - let (prefix, data, suffix) = unsafe { zero_copy.align_to::() }; - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group( - &mut render_pass_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - data[args.dynamic_offsets_data_start..].as_ptr(), - args.dynamic_offsets_data_length, - ); - } - } - }; + // Align the data + assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. + let (prefix, dynamic_offsets_data, suffix) = + unsafe { args.dynamic_offsets_data.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + + let start = args.dynamic_offsets_data_start; + let len = args.dynamic_offsets_data_length; + + // Assert that length and start are both in bounds + assert!(start <= dynamic_offsets_data.len()); + assert!(len <= dynamic_offsets_data.len() - start); + + let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group( + &mut render_pass_resource.0.borrow_mut(), + args.index, + bind_group_resource.0, + dynamic_offsets_data.as_ptr(), + dynamic_offsets_data.len(), + ); + } Ok(WebGpuResult::empty()) } @@ -366,8 +367,10 @@ pub fn op_webgpu_render_pass_push_debug_group( .resource_table .get::(args.render_pass_rid)?; + let label = std::ffi::CString::new(args.group_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. unsafe { - let label = std::ffi::CString::new(args.group_label).unwrap(); wgpu_core::command::render_ffi::wgpu_render_pass_push_debug_group( &mut render_pass_resource.0.borrow_mut(), label.as_ptr(), @@ -416,8 +419,10 @@ pub fn op_webgpu_render_pass_insert_debug_marker( .resource_table .get::(args.render_pass_rid)?; + let label = std::ffi::CString::new(args.marker_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. unsafe { - let label = std::ffi::CString::new(args.marker_label).unwrap(); wgpu_core::command::render_ffi::wgpu_render_pass_insert_debug_marker( &mut render_pass_resource.0.borrow_mut(), label.as_ptr(), @@ -461,7 +466,7 @@ pub fn op_webgpu_render_pass_set_pipeline( pub struct RenderPassSetIndexBufferArgs { render_pass_rid: ResourceId, buffer: u32, - index_format: String, + index_format: GpuIndexFormat, offset: u64, size: Option, } @@ -489,7 +494,7 @@ pub fn op_webgpu_render_pass_set_index_buffer( render_pass_resource.0.borrow_mut().set_index_buffer( buffer_resource.0, - super::pipeline::serialize_index_format(args.index_format), + args.index_format.into(), args.offset, size, ); diff --git a/ext/webgpu/sampler.rs b/ext/webgpu/sampler.rs index 63c475d376..95fb167ace 100644 --- a/ext/webgpu/sampler.rs +++ b/ext/webgpu/sampler.rs @@ -15,46 +15,67 @@ impl Resource for WebGpuSampler { } } -fn serialize_address_mode( - address_mode: Option, -) -> wgpu_types::AddressMode { - match address_mode { - Some(address_mode) => match address_mode.as_str() { - "clamp-to-edge" => wgpu_types::AddressMode::ClampToEdge, - "repeat" => wgpu_types::AddressMode::Repeat, - "mirror-repeat" => wgpu_types::AddressMode::MirrorRepeat, - _ => unreachable!(), - }, - None => wgpu_types::AddressMode::ClampToEdge, +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuAddressMode { + ClampToEdge, + Repeat, + MirrorRepeat, +} + +impl From for wgpu_types::AddressMode { + fn from(value: GpuAddressMode) -> wgpu_types::AddressMode { + match value { + GpuAddressMode::ClampToEdge => wgpu_types::AddressMode::ClampToEdge, + GpuAddressMode::Repeat => wgpu_types::AddressMode::Repeat, + GpuAddressMode::MirrorRepeat => wgpu_types::AddressMode::MirrorRepeat, + } } } -fn serialize_filter_mode( - filter_mode: Option, -) -> wgpu_types::FilterMode { - match filter_mode { - Some(filter_mode) => match filter_mode.as_str() { - "nearest" => wgpu_types::FilterMode::Nearest, - "linear" => wgpu_types::FilterMode::Linear, - _ => unreachable!(), - }, - None => wgpu_types::FilterMode::Nearest, +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuFilterMode { + Nearest, + Linear, +} + +impl From for wgpu_types::FilterMode { + fn from(value: GpuFilterMode) -> wgpu_types::FilterMode { + match value { + GpuFilterMode::Nearest => wgpu_types::FilterMode::Nearest, + GpuFilterMode::Linear => wgpu_types::FilterMode::Linear, + } } } -pub fn serialize_compare_function( - compare: &str, -) -> wgpu_types::CompareFunction { - match compare { - "never" => wgpu_types::CompareFunction::Never, - "less" => wgpu_types::CompareFunction::Less, - "equal" => wgpu_types::CompareFunction::Equal, - "less-equal" => wgpu_types::CompareFunction::LessEqual, - "greater" => wgpu_types::CompareFunction::Greater, - "not-equal" => wgpu_types::CompareFunction::NotEqual, - "greater-equal" => wgpu_types::CompareFunction::GreaterEqual, - "always" => wgpu_types::CompareFunction::Always, - _ => unreachable!(), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuCompareFunction { + Never, + Less, + Equal, + LessEqual, + Greater, + NotEqual, + GreaterEqual, + Always, +} + +impl From for wgpu_types::CompareFunction { + fn from(value: GpuCompareFunction) -> wgpu_types::CompareFunction { + match value { + GpuCompareFunction::Never => wgpu_types::CompareFunction::Never, + GpuCompareFunction::Less => wgpu_types::CompareFunction::Less, + GpuCompareFunction::Equal => wgpu_types::CompareFunction::Equal, + GpuCompareFunction::LessEqual => wgpu_types::CompareFunction::LessEqual, + GpuCompareFunction::Greater => wgpu_types::CompareFunction::Greater, + GpuCompareFunction::NotEqual => wgpu_types::CompareFunction::NotEqual, + GpuCompareFunction::GreaterEqual => { + wgpu_types::CompareFunction::GreaterEqual + } + GpuCompareFunction::Always => wgpu_types::CompareFunction::Always, + } } } @@ -63,16 +84,16 @@ pub fn serialize_compare_function( pub struct CreateSamplerArgs { device_rid: ResourceId, label: Option, - address_mode_u: Option, - address_mode_v: Option, - address_mode_w: Option, - mag_filter: Option, - min_filter: Option, - mipmap_filter: Option, - lod_min_clamp: Option, - lod_max_clamp: Option, - compare: Option, - max_anisotropy: Option, + address_mode_u: GpuAddressMode, + address_mode_v: GpuAddressMode, + address_mode_w: GpuAddressMode, + mag_filter: GpuFilterMode, + min_filter: GpuFilterMode, + mipmap_filter: GpuFilterMode, + lod_min_clamp: f32, + lod_max_clamp: f32, + compare: Option, + max_anisotropy: u8, } pub fn op_webgpu_create_sampler( @@ -89,22 +110,17 @@ pub fn op_webgpu_create_sampler( let descriptor = wgpu_core::resource::SamplerDescriptor { label: args.label.map(Cow::from), address_modes: [ - serialize_address_mode(args.address_mode_u), - serialize_address_mode(args.address_mode_v), - serialize_address_mode(args.address_mode_w), + args.address_mode_u.into(), + args.address_mode_v.into(), + args.address_mode_w.into(), ], - mag_filter: serialize_filter_mode(args.mag_filter), - min_filter: serialize_filter_mode(args.min_filter), - mipmap_filter: serialize_filter_mode(args.mipmap_filter), - lod_min_clamp: args.lod_min_clamp.unwrap_or(0.0), - lod_max_clamp: args.lod_max_clamp.unwrap_or(32.0), - compare: args - .compare - .as_ref() - .map(|compare| serialize_compare_function(compare)), - anisotropy_clamp: std::num::NonZeroU8::new( - args.max_anisotropy.unwrap_or(0), - ), + mag_filter: args.mag_filter.into(), + min_filter: args.min_filter.into(), + mipmap_filter: args.mipmap_filter.into(), + lod_min_clamp: args.lod_min_clamp, + lod_max_clamp: args.lod_max_clamp, + compare: args.compare.map(Into::into), + anisotropy_clamp: std::num::NonZeroU8::new(args.max_anisotropy), border_color: None, // native-only }; diff --git a/ext/webgpu/texture.rs b/ext/webgpu/texture.rs index a0ea7a1bdf..47e7a14d2c 100644 --- a/ext/webgpu/texture.rs +++ b/ext/webgpu/texture.rs @@ -6,6 +6,8 @@ use deno_core::ResourceId; use deno_core::{OpState, Resource}; use serde::Deserialize; use std::borrow::Cow; +use std::convert::TryFrom; +use std::convert::TryInto; use super::error::WebGpuResult; pub(crate) struct WebGpuTexture(pub(crate) wgpu_core::id::TextureId); @@ -22,110 +24,310 @@ impl Resource for WebGpuTextureView { } } -pub fn serialize_texture_format( - format: &str, -) -> Result { - Ok(match format { - // 8-bit formats - "r8unorm" => wgpu_types::TextureFormat::R8Unorm, - "r8snorm" => wgpu_types::TextureFormat::R8Snorm, - "r8uint" => wgpu_types::TextureFormat::R8Uint, - "r8sint" => wgpu_types::TextureFormat::R8Sint, +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuTextureFormat { + // 8-bit formats + #[serde(rename = "r8unorm")] + R8Unorm, + #[serde(rename = "r8snorm")] + R8Snorm, + #[serde(rename = "r8uint")] + R8Uint, + #[serde(rename = "r8sint")] + R8Sint, - // 16-bit formats - "r16uint" => wgpu_types::TextureFormat::R16Uint, - "r16sint" => wgpu_types::TextureFormat::R16Sint, - "r16float" => wgpu_types::TextureFormat::R16Float, - "rg8unorm" => wgpu_types::TextureFormat::Rg8Unorm, - "rg8snorm" => wgpu_types::TextureFormat::Rg8Snorm, - "rg8uint" => wgpu_types::TextureFormat::Rg8Uint, - "rg8sint" => wgpu_types::TextureFormat::Rg8Sint, + // 16-bit formats + #[serde(rename = "r16uint")] + R16Uint, + #[serde(rename = "r16sint")] + R16Sint, + #[serde(rename = "r16float")] + R16Float, + #[serde(rename = "rg8unorm")] + Rg8Unorm, + #[serde(rename = "rg8snorm")] + Rg8Snorm, + #[serde(rename = "rg8uint")] + Rg8Uint, + #[serde(rename = "rg8sint")] + Rg8Sint, - // 32-bit formats - "r32uint" => wgpu_types::TextureFormat::R32Uint, - "r32sint" => wgpu_types::TextureFormat::R32Sint, - "r32float" => wgpu_types::TextureFormat::R32Float, - "rg16uint" => wgpu_types::TextureFormat::Rg16Uint, - "rg16sint" => wgpu_types::TextureFormat::Rg16Sint, - "rg16float" => wgpu_types::TextureFormat::Rg16Float, - "rgba8unorm" => wgpu_types::TextureFormat::Rgba8Unorm, - "rgba8unorm-srgb" => wgpu_types::TextureFormat::Rgba8UnormSrgb, - "rgba8snorm" => wgpu_types::TextureFormat::Rgba8Snorm, - "rgba8uint" => wgpu_types::TextureFormat::Rgba8Uint, - "rgba8sint" => wgpu_types::TextureFormat::Rgba8Sint, - "bgra8unorm" => wgpu_types::TextureFormat::Bgra8Unorm, - "bgra8unorm-srgb" => wgpu_types::TextureFormat::Bgra8UnormSrgb, - // Packed 32-bit formats - "rgb9e5ufloat" => return Err(not_supported()), // wgpu#967 - "rgb10a2unorm" => wgpu_types::TextureFormat::Rgb10a2Unorm, - "rg11b10ufloat" => wgpu_types::TextureFormat::Rg11b10Float, + // 32-bit formats + #[serde(rename = "r32uint")] + R32Uint, + #[serde(rename = "r32sint")] + R32Sint, + #[serde(rename = "r32float")] + R32Float, + #[serde(rename = "rg16uint")] + Rg16Uint, + #[serde(rename = "rg16sint")] + Rg16Sint, + #[serde(rename = "rg16float")] + Rg16Float, + #[serde(rename = "rgba8unorm")] + Rgba8Unorm, + #[serde(rename = "rgba8unorm-srgb")] + Rgba8UnormSrgb, + #[serde(rename = "rgba8snorm")] + Rgba8Snorm, + #[serde(rename = "rgba8uint")] + Rgba8Uint, + #[serde(rename = "rgba8sint")] + Rgba8Sint, + #[serde(rename = "bgra8unorm")] + Bgra8Unorm, + #[serde(rename = "bgra8unorm-srgb")] + Bgra8UnormSrgb, + // Packed 32-bit formats + #[serde(rename = "rgb9e5ufloat")] + RgB9E5UFloat, + #[serde(rename = "rgb10a2unorm")] + Rgb10a2Unorm, + #[serde(rename = "rg11b10ufloat")] + Rg11b10Float, - // 64-bit formats - "rg32uint" => wgpu_types::TextureFormat::Rg32Uint, - "rg32sint" => wgpu_types::TextureFormat::Rg32Sint, - "rg32float" => wgpu_types::TextureFormat::Rg32Float, - "rgba16uint" => wgpu_types::TextureFormat::Rgba16Uint, - "rgba16sint" => wgpu_types::TextureFormat::Rgba16Sint, - "rgba16float" => wgpu_types::TextureFormat::Rgba16Float, + // 64-bit formats + #[serde(rename = "rg32uint")] + Rg32Uint, + #[serde(rename = "rg32sint")] + Rg32Sint, + #[serde(rename = "rg32float")] + Rg32Float, + #[serde(rename = "rgba16uint")] + Rgba16Uint, + #[serde(rename = "rgba16sint")] + Rgba16Sint, + #[serde(rename = "rgba16float")] + Rgba16Float, - // 128-bit formats - "rgba32uint" => wgpu_types::TextureFormat::Rgba32Uint, - "rgba32sint" => wgpu_types::TextureFormat::Rgba32Sint, - "rgba32float" => wgpu_types::TextureFormat::Rgba32Float, + // 128-bit formats + #[serde(rename = "rgba32uint")] + Rgba32Uint, + #[serde(rename = "rgba32sint")] + Rgba32Sint, + #[serde(rename = "rgba32float")] + Rgba32Float, - // Depth and stencil formats - "stencil8" => return Err(not_supported()), // wgpu#967 - "depth16unorm" => return Err(not_supported()), // wgpu#967 - "depth24plus" => wgpu_types::TextureFormat::Depth24Plus, - "depth24plus-stencil8" => wgpu_types::TextureFormat::Depth24PlusStencil8, - "depth32float" => wgpu_types::TextureFormat::Depth32Float, + // Depth and stencil formats + #[serde(rename = "stencil8")] + Stencil8, + #[serde(rename = "depth16unorm")] + Depth16Unorm, + #[serde(rename = "depth24plus")] + Depth24Plus, + #[serde(rename = "depth24plus-stencil8")] + Depth24PlusStencil8, + #[serde(rename = "depth32float")] + Depth32Float, - // BC compressed formats usable if "texture-compression-bc" is both - // supported by the device/user agent and enabled in requestDevice. - "bc1-rgba-unorm" => wgpu_types::TextureFormat::Bc1RgbaUnorm, - "bc1-rgba-unorm-srgb" => wgpu_types::TextureFormat::Bc1RgbaUnormSrgb, - "bc2-rgba-unorm" => wgpu_types::TextureFormat::Bc2RgbaUnorm, - "bc2-rgba-unorm-srgb" => wgpu_types::TextureFormat::Bc2RgbaUnormSrgb, - "bc3-rgba-unorm" => wgpu_types::TextureFormat::Bc3RgbaUnorm, - "bc3-rgba-unorm-srgb" => wgpu_types::TextureFormat::Bc3RgbaUnormSrgb, - "bc4-r-unorm" => wgpu_types::TextureFormat::Bc4RUnorm, - "bc4-r-snorm" => wgpu_types::TextureFormat::Bc4RSnorm, - "bc5-rg-unorm" => wgpu_types::TextureFormat::Bc5RgUnorm, - "bc5-rg-snorm" => wgpu_types::TextureFormat::Bc5RgSnorm, - "bc6h-rgb-ufloat" => wgpu_types::TextureFormat::Bc6hRgbUfloat, - "bc6h-rgb-float" => wgpu_types::TextureFormat::Bc6hRgbSfloat, // wgpu#967 - "bc7-rgba-unorm" => wgpu_types::TextureFormat::Bc7RgbaUnorm, - "bc7-rgba-unorm-srgb" => wgpu_types::TextureFormat::Bc7RgbaUnormSrgb, + // BC compressed formats usable if "texture-compression-bc" is both + // supported by the device/user agent and enabled in requestDevice. + #[serde(rename = "bc1-rgba-unorm")] + Bc1RgbaUnorm, + #[serde(rename = "bc1-rgba-unorm-srgb")] + Bc1RgbaUnormSrgb, + #[serde(rename = "bc2-rgba-unorm")] + Bc2RgbaUnorm, + #[serde(rename = "bc2-rgba-unorm-srgb")] + Bc2RgbaUnormSrgb, + #[serde(rename = "bc3-rgba-unorm")] + Bc3RgbaUnorm, + #[serde(rename = "bc3-rgba-unorm-srgb")] + Bc3RgbaUnormSrgb, + #[serde(rename = "bc4-r-unorm")] + Bc4RUnorm, + #[serde(rename = "bc4-r-snorm")] + Bc4RSnorm, + #[serde(rename = "bc5-rg-unorm")] + Bc5RgUnorm, + #[serde(rename = "bc5-rg-snorm")] + Bc5RgSnorm, + #[serde(rename = "bc6h-rgb-ufloat")] + Bc6hRgbUfloat, + #[serde(rename = "bc6h-rgb-float")] + Bc6HRgbFloat, + #[serde(rename = "bc7-rgba-unorm")] + Bc7RgbaUnorm, + #[serde(rename = "bc7-rgba-unorm-srgb")] + Bc7RgbaUnormSrgb, - // "depth24unorm-stencil8" extension - "depth24unorm-stencil8" => return Err(not_supported()), // wgpu#967 + // "depth24unorm-stencil8" feature + #[serde(rename = "depth24unorm-stencil8")] + Depth24UnormStencil8, - // "depth32float-stencil8" extension - "depth32float-stencil8" => return Err(not_supported()), // wgpu#967 - _ => unreachable!(), - }) + // "depth32float-stencil8" feature + #[serde(rename = "depth32float-stencil8")] + Depth32FloatStencil8, } -pub fn serialize_dimension( - dimension: &str, -) -> wgpu_types::TextureViewDimension { - match dimension { - "1d" => wgpu_types::TextureViewDimension::D1, - "2d" => wgpu_types::TextureViewDimension::D2, - "2d-array" => wgpu_types::TextureViewDimension::D2Array, - "cube" => wgpu_types::TextureViewDimension::Cube, - "cube-array" => wgpu_types::TextureViewDimension::CubeArray, - "3d" => wgpu_types::TextureViewDimension::D3, - _ => unreachable!(), +impl TryFrom for wgpu_types::TextureFormat { + type Error = AnyError; + + fn try_from(value: GpuTextureFormat) -> Result { + use wgpu_types::TextureFormat; + match value { + GpuTextureFormat::R8Unorm => Ok(TextureFormat::R8Unorm), + GpuTextureFormat::R8Snorm => Ok(TextureFormat::R8Snorm), + GpuTextureFormat::R8Uint => Ok(TextureFormat::R8Uint), + GpuTextureFormat::R8Sint => Ok(TextureFormat::R8Sint), + + GpuTextureFormat::R16Uint => Ok(TextureFormat::R16Uint), + GpuTextureFormat::R16Sint => Ok(TextureFormat::R16Sint), + GpuTextureFormat::R16Float => Ok(TextureFormat::R16Float), + GpuTextureFormat::Rg8Unorm => Ok(TextureFormat::Rg8Unorm), + GpuTextureFormat::Rg8Snorm => Ok(TextureFormat::Rg8Snorm), + GpuTextureFormat::Rg8Uint => Ok(TextureFormat::Rg8Uint), + GpuTextureFormat::Rg8Sint => Ok(TextureFormat::Rg8Sint), + + GpuTextureFormat::R32Uint => Ok(TextureFormat::R32Uint), + GpuTextureFormat::R32Sint => Ok(TextureFormat::R32Sint), + GpuTextureFormat::R32Float => Ok(TextureFormat::R32Float), + GpuTextureFormat::Rg16Uint => Ok(TextureFormat::Rg16Uint), + GpuTextureFormat::Rg16Sint => Ok(TextureFormat::Rg16Sint), + GpuTextureFormat::Rg16Float => Ok(TextureFormat::Rg16Float), + GpuTextureFormat::Rgba8Unorm => Ok(TextureFormat::Rgba8Unorm), + GpuTextureFormat::Rgba8UnormSrgb => Ok(TextureFormat::Rgba8UnormSrgb), + GpuTextureFormat::Rgba8Snorm => Ok(TextureFormat::Rgba8Snorm), + GpuTextureFormat::Rgba8Uint => Ok(TextureFormat::Rgba8Uint), + GpuTextureFormat::Rgba8Sint => Ok(TextureFormat::Rgba8Sint), + GpuTextureFormat::Bgra8Unorm => Ok(TextureFormat::Bgra8Unorm), + GpuTextureFormat::Bgra8UnormSrgb => Ok(TextureFormat::Bgra8UnormSrgb), + GpuTextureFormat::RgB9E5UFloat => Err(not_supported()), // wgpu#967 + GpuTextureFormat::Rgb10a2Unorm => Ok(TextureFormat::Rgb10a2Unorm), + GpuTextureFormat::Rg11b10Float => Ok(TextureFormat::Rg11b10Float), + + GpuTextureFormat::Rg32Uint => Ok(TextureFormat::Rg32Uint), + GpuTextureFormat::Rg32Sint => Ok(TextureFormat::Rg32Sint), + GpuTextureFormat::Rg32Float => Ok(TextureFormat::Rg32Float), + GpuTextureFormat::Rgba16Uint => Ok(TextureFormat::Rgba16Uint), + GpuTextureFormat::Rgba16Sint => Ok(TextureFormat::Rgba16Sint), + GpuTextureFormat::Rgba16Float => Ok(TextureFormat::Rgba16Float), + + GpuTextureFormat::Rgba32Uint => Ok(TextureFormat::Rgba32Uint), + GpuTextureFormat::Rgba32Sint => Ok(TextureFormat::Rgba32Sint), + GpuTextureFormat::Rgba32Float => Ok(TextureFormat::Rgba32Float), + + GpuTextureFormat::Stencil8 => Err(not_supported()), // wgpu#967 + GpuTextureFormat::Depth16Unorm => Err(not_supported()), // wgpu#967 + GpuTextureFormat::Depth24Plus => Ok(TextureFormat::Depth24Plus), + GpuTextureFormat::Depth24PlusStencil8 => { + Ok(TextureFormat::Depth24PlusStencil8) + } + GpuTextureFormat::Depth32Float => Ok(TextureFormat::Depth32Float), + + GpuTextureFormat::Bc1RgbaUnorm => Ok(TextureFormat::Bc1RgbaUnorm), + GpuTextureFormat::Bc1RgbaUnormSrgb => Ok(TextureFormat::Bc1RgbaUnormSrgb), + GpuTextureFormat::Bc2RgbaUnorm => Ok(TextureFormat::Bc2RgbaUnorm), + GpuTextureFormat::Bc2RgbaUnormSrgb => Ok(TextureFormat::Bc2RgbaUnormSrgb), + GpuTextureFormat::Bc3RgbaUnorm => Ok(TextureFormat::Bc3RgbaUnorm), + GpuTextureFormat::Bc3RgbaUnormSrgb => Ok(TextureFormat::Bc3RgbaUnormSrgb), + GpuTextureFormat::Bc4RUnorm => Ok(TextureFormat::Bc4RUnorm), + GpuTextureFormat::Bc4RSnorm => Ok(TextureFormat::Bc4RSnorm), + GpuTextureFormat::Bc5RgUnorm => Ok(TextureFormat::Bc5RgUnorm), + GpuTextureFormat::Bc5RgSnorm => Ok(TextureFormat::Bc5RgSnorm), + GpuTextureFormat::Bc6hRgbUfloat => Ok(TextureFormat::Bc6hRgbUfloat), + GpuTextureFormat::Bc6HRgbFloat => Ok(TextureFormat::Bc6hRgbSfloat), // wgpu#967 + GpuTextureFormat::Bc7RgbaUnorm => Ok(TextureFormat::Bc7RgbaUnorm), + GpuTextureFormat::Bc7RgbaUnormSrgb => Ok(TextureFormat::Bc7RgbaUnormSrgb), + + GpuTextureFormat::Depth24UnormStencil8 => Err(not_supported()), // wgpu#967, + + GpuTextureFormat::Depth32FloatStencil8 => Err(not_supported()), // wgpu#967 + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuTextureViewDimension { + #[serde(rename = "1d")] + D1, + #[serde(rename = "2d")] + D2, + #[serde(rename = "2d-array")] + D2Array, + #[serde(rename = "cube")] + Cube, + #[serde(rename = "cube-array")] + CubeArray, + #[serde(rename = "3d")] + D3, +} + +impl From for wgpu_types::TextureViewDimension { + fn from(view_dimension: GpuTextureViewDimension) -> Self { + match view_dimension { + GpuTextureViewDimension::D1 => wgpu_types::TextureViewDimension::D1, + GpuTextureViewDimension::D2 => wgpu_types::TextureViewDimension::D2, + GpuTextureViewDimension::D2Array => { + wgpu_types::TextureViewDimension::D2Array + } + GpuTextureViewDimension::Cube => wgpu_types::TextureViewDimension::Cube, + GpuTextureViewDimension::CubeArray => { + wgpu_types::TextureViewDimension::CubeArray + } + GpuTextureViewDimension::D3 => wgpu_types::TextureViewDimension::D3, + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuTextureDimension { + #[serde(rename = "1d")] + D1, + #[serde(rename = "2d")] + D2, + #[serde(rename = "3d")] + D3, +} + +impl From for wgpu_types::TextureDimension { + fn from(texture_dimension: GpuTextureDimension) -> Self { + match texture_dimension { + GpuTextureDimension::D1 => wgpu_types::TextureDimension::D1, + GpuTextureDimension::D2 => wgpu_types::TextureDimension::D2, + GpuTextureDimension::D3 => wgpu_types::TextureDimension::D3, + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuTextureAspect { + All, + StencilOnly, + DepthOnly, +} + +impl From for wgpu_types::TextureAspect { + fn from(aspect: GpuTextureAspect) -> wgpu_types::TextureAspect { + match aspect { + GpuTextureAspect::All => wgpu_types::TextureAspect::All, + GpuTextureAspect::StencilOnly => wgpu_types::TextureAspect::StencilOnly, + GpuTextureAspect::DepthOnly => wgpu_types::TextureAspect::DepthOnly, + } } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct GpuExtent3D { - pub width: Option, - pub height: Option, - pub depth_or_array_layers: Option, + pub width: u32, + pub height: u32, + pub depth_or_array_layers: u32, +} + +impl From for wgpu_types::Extent3d { + fn from(extent: GpuExtent3D) -> Self { + wgpu_types::Extent3d { + width: extent.width, + height: extent.height, + depth_or_array_layers: extent.depth_or_array_layers, + } + } } #[derive(Deserialize)] @@ -134,10 +336,10 @@ pub struct CreateTextureArgs { device_rid: ResourceId, label: Option, size: GpuExtent3D, - mip_level_count: Option, - sample_count: Option, - dimension: Option, - format: String, + mip_level_count: u32, + sample_count: u32, + dimension: GpuTextureDimension, + format: GpuTextureFormat, usage: u32, } @@ -154,24 +356,12 @@ pub fn op_webgpu_create_texture( let descriptor = wgpu_core::resource::TextureDescriptor { label: args.label.map(Cow::from), - size: wgpu_types::Extent3d { - width: args.size.width.unwrap_or(1), - height: args.size.height.unwrap_or(1), - depth_or_array_layers: args.size.depth_or_array_layers.unwrap_or(1), - }, - mip_level_count: args.mip_level_count.unwrap_or(1), - sample_count: args.sample_count.unwrap_or(1), - dimension: match args.dimension { - Some(dimension) => match dimension.as_str() { - "1d" => wgpu_types::TextureDimension::D1, - "2d" => wgpu_types::TextureDimension::D2, - "3d" => wgpu_types::TextureDimension::D3, - _ => unreachable!(), - }, - None => wgpu_types::TextureDimension::D2, - }, - format: serialize_texture_format(&args.format)?, - usage: wgpu_types::TextureUsages::from_bits(args.usage).unwrap(), + size: args.size.into(), + mip_level_count: args.mip_level_count, + sample_count: args.sample_count, + dimension: args.dimension.into(), + format: args.format.try_into()?, + usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage), }; gfx_put!(device => instance.device_create_texture( @@ -186,12 +376,12 @@ pub fn op_webgpu_create_texture( pub struct CreateTextureViewArgs { texture_rid: ResourceId, label: Option, - format: Option, - dimension: Option, - aspect: Option, - base_mip_level: Option, + format: Option, + dimension: Option, + aspect: GpuTextureAspect, + base_mip_level: u32, mip_level_count: Option, - base_array_layer: Option, + base_array_layer: u32, array_layer_count: Option, } @@ -208,26 +398,15 @@ pub fn op_webgpu_create_texture_view( let descriptor = wgpu_core::resource::TextureViewDescriptor { label: args.label.map(Cow::from), - format: args - .format - .map(|s| serialize_texture_format(&s)) - .transpose()?, - dimension: args.dimension.map(|s| serialize_dimension(&s)), + format: args.format.map(|s| s.try_into()).transpose()?, + dimension: args.dimension.map(|s| s.into()), range: wgpu_types::ImageSubresourceRange { - aspect: match args.aspect { - Some(aspect) => match aspect.as_str() { - "all" => wgpu_types::TextureAspect::All, - "stencil-only" => wgpu_types::TextureAspect::StencilOnly, - "depth-only" => wgpu_types::TextureAspect::DepthOnly, - _ => unreachable!(), - }, - None => wgpu_types::TextureAspect::All, - }, - base_mip_level: args.base_mip_level.unwrap_or(0), + aspect: args.aspect.into(), + base_mip_level: args.base_mip_level, mip_level_count: std::num::NonZeroU32::new( args.mip_level_count.unwrap_or(0), ), - base_array_layer: args.base_array_layer.unwrap_or(0), + base_array_layer: args.base_array_layer, array_layer_count: std::num::NonZeroU32::new( args.array_layer_count.unwrap_or(0), ), diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 40250afe12..b756163543 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -701,11 +701,11 @@ imvType === "string" || imvType === "bigint" || imvType === "undefined" ) { - defaultValues[member.key] = idlMemberValue; + defaultValues[member.key] = member.converter(idlMemberValue, {}); } else { ObjectDefineProperty(defaultValues, member.key, { get() { - return member.defaultValue; + return member.converter(idlMemberValue, member.defaultValue); }, enumerable: true, });