diff options
author | crowlKats <13135287+crowlKats@users.noreply.github.com> | 2021-03-01 11:31:13 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-01 11:31:13 +0100 |
commit | 7cd14f97c9300357475e3e461fa57cbb7ec5bfec (patch) | |
tree | 39eb11e8a9c53001ffe814f5aac3ec5e37de6357 /op_crates/webgpu/binding.rs | |
parent | dbdbe7a1cf0d56df85305eb3638bc177d8a0216f (diff) |
feat: WebGPU API (#7977)
Co-authored-by: Luca Casonato <lucacasonato@yahoo.com>
Diffstat (limited to 'op_crates/webgpu/binding.rs')
-rw-r--r-- | op_crates/webgpu/binding.rs | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/op_crates/webgpu/binding.rs b/op_crates/webgpu/binding.rs new file mode 100644 index 000000000..b93b223cf --- /dev/null +++ b/op_crates/webgpu/binding.rs @@ -0,0 +1,362 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::bad_resource_id; +use deno_core::error::AnyError; +use deno_core::serde_json::json; +use deno_core::serde_json::Value; +use deno_core::ZeroCopyBuf; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use std::borrow::Cow; + +use super::error::WebGPUError; + +pub(crate) struct WebGPUBindGroupLayout( + pub(crate) wgpu_core::id::BindGroupLayoutId, +); +impl Resource for WebGPUBindGroupLayout { + fn name(&self) -> Cow<str> { + "webGPUBindGroupLayout".into() + } +} + +pub(crate) struct WebGPUBindGroup(pub(crate) wgpu_core::id::BindGroupId); +impl Resource for WebGPUBindGroup { + fn name(&self) -> Cow<str> { + "webGPUBindGroup".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GPUBufferBindingLayout { + #[serde(rename = "type")] + kind: Option<String>, + has_dynamic_offset: Option<bool>, + min_binding_size: Option<u64>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GPUSamplerBindingLayout { + #[serde(rename = "type")] + kind: Option<String>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GPUTextureBindingLayout { + sample_type: Option<String>, + view_dimension: Option<String>, + multisampled: Option<bool>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GPUStorageTextureBindingLayout { + access: String, + format: String, + view_dimension: Option<String>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GPUBindGroupLayoutEntry { + binding: u32, + visibility: u32, + buffer: Option<GPUBufferBindingLayout>, + sampler: Option<GPUSamplerBindingLayout>, + texture: Option<GPUTextureBindingLayout>, + storage_texture: Option<GPUStorageTextureBindingLayout>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateBindGroupLayoutArgs { + device_rid: u32, + label: Option<String>, + entries: Vec<GPUBindGroupLayoutEntry>, +} + +pub fn op_webgpu_create_bind_group_layout( + state: &mut OpState, + args: CreateBindGroupLayoutArgs, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result<Value, AnyError> { + let instance = state.borrow::<super::Instance>(); + let device_resource = state + .resource_table + .get::<super::WebGPUDevice>(args.device_rid) + .ok_or_else(bad_resource_id)?; + let device = device_resource.0; + + let mut entries = vec![]; + + for entry in &args.entries { + entries.push(wgpu_types::BindGroupLayoutEntry { + binding: entry.binding, + visibility: wgpu_types::ShaderStage::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: false, + 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() { + "read-only" => wgpu_types::StorageTextureAccess::ReadOnly, + "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!() + }, + count: None, // native-only + }); + } + + let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor { + label: args.label.map(Cow::from), + entries: Cow::from(entries), + }; + + let (bind_group_layout, maybe_err) = gfx_select!(device => instance.device_create_bind_group_layout( + device, + &descriptor, + std::marker::PhantomData + )); + + let rid = state + .resource_table + .add(WebGPUBindGroupLayout(bind_group_layout)); + + Ok(json!({ + "rid": rid, + "err": maybe_err.map(WebGPUError::from) + })) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreatePipelineLayoutArgs { + device_rid: u32, + label: Option<String>, + bind_group_layouts: Vec<u32>, +} + +pub fn op_webgpu_create_pipeline_layout( + state: &mut OpState, + args: CreatePipelineLayoutArgs, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result<Value, AnyError> { + let instance = state.borrow::<super::Instance>(); + let device_resource = state + .resource_table + .get::<super::WebGPUDevice>(args.device_rid) + .ok_or_else(bad_resource_id)?; + let device = device_resource.0; + + let mut bind_group_layouts = vec![]; + + for rid in &args.bind_group_layouts { + let bind_group_layout = state + .resource_table + .get::<WebGPUBindGroupLayout>(*rid) + .ok_or_else(bad_resource_id)?; + bind_group_layouts.push(bind_group_layout.0); + } + + let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor { + label: args.label.map(Cow::from), + bind_group_layouts: Cow::from(bind_group_layouts), + push_constant_ranges: Default::default(), + }; + + let (pipeline_layout, maybe_err) = gfx_select!(device => instance.device_create_pipeline_layout( + device, + &descriptor, + std::marker::PhantomData + )); + + let rid = state + .resource_table + .add(super::pipeline::WebGPUPipelineLayout(pipeline_layout)); + + Ok(json!({ + "rid": rid, + "err": maybe_err.map(WebGPUError::from) + })) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GPUBindGroupEntry { + binding: u32, + kind: String, + resource: u32, + offset: Option<u64>, + size: Option<u64>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateBindGroupArgs { + device_rid: u32, + label: Option<String>, + layout: u32, + entries: Vec<GPUBindGroupEntry>, +} + +pub fn op_webgpu_create_bind_group( + state: &mut OpState, + args: CreateBindGroupArgs, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result<Value, AnyError> { + let instance = state.borrow::<super::Instance>(); + let device_resource = state + .resource_table + .get::<super::WebGPUDevice>(args.device_rid) + .ok_or_else(bad_resource_id)?; + let device = device_resource.0; + + let mut entries = vec![]; + + for entry in &args.entries { + let e = wgpu_core::binding_model::BindGroupEntry { + binding: entry.binding, + resource: match entry.kind.as_str() { + "GPUSampler" => { + let sampler_resource = state + .resource_table + .get::<super::sampler::WebGPUSampler>(entry.resource) + .ok_or_else(bad_resource_id)?; + wgpu_core::binding_model::BindingResource::Sampler(sampler_resource.0) + } + "GPUTextureView" => { + let texture_view_resource = state + .resource_table + .get::<super::texture::WebGPUTextureView>(entry.resource) + .ok_or_else(bad_resource_id)?; + wgpu_core::binding_model::BindingResource::TextureView( + texture_view_resource.0, + ) + } + "GPUBufferBinding" => { + let buffer_resource = state + .resource_table + .get::<super::buffer::WebGPUBuffer>(entry.resource) + .ok_or_else(bad_resource_id)?; + wgpu_core::binding_model::BindingResource::Buffer( + wgpu_core::binding_model::BufferBinding { + buffer_id: buffer_resource.0, + offset: entry.offset.unwrap_or(0), + size: std::num::NonZeroU64::new(entry.size.unwrap_or(0)), + }, + ) + } + _ => unreachable!(), + }, + }; + entries.push(e); + } + + let bind_group_layout = state + .resource_table + .get::<WebGPUBindGroupLayout>(args.layout) + .ok_or_else(bad_resource_id)?; + + let descriptor = wgpu_core::binding_model::BindGroupDescriptor { + label: args.label.map(Cow::from), + layout: bind_group_layout.0, + entries: Cow::from(entries), + }; + + let (bind_group, maybe_err) = gfx_select!(device => instance.device_create_bind_group( + device, + &descriptor, + std::marker::PhantomData + )); + + let rid = state.resource_table.add(WebGPUBindGroup(bind_group)); + + Ok(json!({ + "rid": rid, + "err": maybe_err.map(WebGPUError::from) + })) +} |