summaryrefslogtreecommitdiff
path: root/ext/webgpu/binding.rs
diff options
context:
space:
mode:
authorLeo Kettmeir <crowlkats@toaxl.com>2023-12-09 01:19:16 +0100
committerGitHub <noreply@github.com>2023-12-09 01:19:16 +0100
commit393abed3873d83019feb5bcebb10a6929133862a (patch)
treec346e6d628e6b037fb8f881a70ca2ae6f70692b6 /ext/webgpu/binding.rs
parent123d9ea047a2e10803e260ebf00f31fcc98463ee (diff)
feat: bring back WebGPU (#20812)
Signed-off-by: Leo Kettmeir <crowlkats@toaxl.com> Co-authored-by: Kenta Moriuchi <moriken@kimamass.com> Co-authored-by: Bartek IwaƄczuk <biwanczuk@gmail.com>
Diffstat (limited to 'ext/webgpu/binding.rs')
-rw-r--r--ext/webgpu/binding.rs340
1 files changed, 340 insertions, 0 deletions
diff --git a/ext/webgpu/binding.rs b/ext/webgpu/binding.rs
new file mode 100644
index 000000000..81d1f7e8c
--- /dev/null
+++ b/ext/webgpu/binding.rs
@@ -0,0 +1,340 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+use deno_core::error::AnyError;
+use deno_core::op2;
+use deno_core::OpState;
+use deno_core::Resource;
+use deno_core::ResourceId;
+use serde::Deserialize;
+use std::borrow::Cow;
+use std::rc::Rc;
+
+use super::error::WebGpuResult;
+
+pub(crate) struct WebGpuBindGroupLayout(
+ pub(crate) crate::Instance,
+ pub(crate) wgpu_core::id::BindGroupLayoutId,
+);
+impl Resource for WebGpuBindGroupLayout {
+ fn name(&self) -> Cow<str> {
+ "webGPUBindGroupLayout".into()
+ }
+
+ fn close(self: Rc<Self>) {
+ let instance = &self.0;
+ gfx_select!(self.1 => instance.bind_group_layout_drop(self.1));
+ }
+}
+
+pub(crate) struct WebGpuBindGroup(
+ pub(crate) crate::Instance,
+ pub(crate) wgpu_core::id::BindGroupId,
+);
+impl Resource for WebGpuBindGroup {
+ fn name(&self) -> Cow<str> {
+ "webGPUBindGroup".into()
+ }
+
+ fn close(self: Rc<Self>) {
+ let instance = &self.0;
+ gfx_select!(self.1 => instance.bind_group_drop(self.1));
+ }
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct GpuBufferBindingLayout {
+ 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<GpuBufferBindingType> 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 {
+ r#type: wgpu_types::SamplerBindingType,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct GpuTextureBindingLayout {
+ sample_type: GpuTextureSampleType,
+ view_dimension: wgpu_types::TextureViewDimension,
+ multisampled: bool,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "kebab-case")]
+enum GpuTextureSampleType {
+ Float,
+ UnfilterableFloat,
+ Depth,
+ Sint,
+ Uint,
+}
+
+impl From<GpuTextureSampleType> 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: GpuStorageTextureAccess,
+ format: wgpu_types::TextureFormat,
+ view_dimension: wgpu_types::TextureViewDimension,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "kebab-case")]
+enum GpuStorageTextureAccess {
+ WriteOnly,
+}
+
+impl From<GpuStorageTextureAccess> for wgpu_types::StorageTextureAccess {
+ fn from(access: GpuStorageTextureAccess) -> Self {
+ match access {
+ GpuStorageTextureAccess::WriteOnly => {
+ wgpu_types::StorageTextureAccess::WriteOnly
+ }
+ }
+ }
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct GpuBindGroupLayoutEntry {
+ binding: u32,
+ visibility: u32,
+ #[serde(flatten)]
+ binding_type: GpuBindingType,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+enum GpuBindingType {
+ Buffer(GpuBufferBindingLayout),
+ Sampler(GpuSamplerBindingLayout),
+ Texture(GpuTextureBindingLayout),
+ StorageTexture(GpuStorageTextureBindingLayout),
+}
+
+impl From<GpuBindingType> for wgpu_types::BindingType {
+ fn from(binding_type: GpuBindingType) -> wgpu_types::BindingType {
+ 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) => {
+ wgpu_types::BindingType::Sampler(sampler.r#type)
+ }
+ GpuBindingType::Texture(texture) => wgpu_types::BindingType::Texture {
+ sample_type: texture.sample_type.into(),
+ view_dimension: texture.view_dimension,
+ multisampled: texture.multisampled,
+ },
+ GpuBindingType::StorageTexture(storage_texture) => {
+ wgpu_types::BindingType::StorageTexture {
+ access: storage_texture.access.into(),
+ format: storage_texture.format,
+ view_dimension: storage_texture.view_dimension,
+ }
+ }
+ }
+ }
+}
+
+#[op2]
+#[serde]
+pub fn op_webgpu_create_bind_group_layout(
+ state: &mut OpState,
+ #[smi] device_rid: ResourceId,
+ #[string] label: Cow<str>,
+ #[serde] entries: Vec<GpuBindGroupLayoutEntry>,
+) -> Result<WebGpuResult, AnyError> {
+ let instance = state.borrow::<super::Instance>();
+ let device_resource = state
+ .resource_table
+ .get::<super::WebGpuDevice>(device_rid)?;
+ let device = device_resource.1;
+
+ let entries = entries
+ .into_iter()
+ .map(|entry| {
+ wgpu_types::BindGroupLayoutEntry {
+ binding: entry.binding,
+ visibility: wgpu_types::ShaderStages::from_bits(entry.visibility)
+ .unwrap(),
+ ty: entry.binding_type.into(),
+ count: None, // native-only
+ }
+ })
+ .collect::<Vec<_>>();
+
+ let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor {
+ label: Some(label),
+ entries: Cow::from(entries),
+ };
+
+ gfx_put!(device => instance.device_create_bind_group_layout(
+ device,
+ &descriptor,
+ ()
+ ) => state, WebGpuBindGroupLayout)
+}
+
+#[op2]
+#[serde]
+pub fn op_webgpu_create_pipeline_layout(
+ state: &mut OpState,
+ #[smi] device_rid: ResourceId,
+ #[string] label: Cow<str>,
+ #[serde] bind_group_layouts: Vec<u32>,
+) -> Result<WebGpuResult, AnyError> {
+ let instance = state.borrow::<super::Instance>();
+ let device_resource = state
+ .resource_table
+ .get::<super::WebGpuDevice>(device_rid)?;
+ let device = device_resource.1;
+
+ let bind_group_layouts = bind_group_layouts
+ .into_iter()
+ .map(|rid| {
+ let bind_group_layout =
+ state.resource_table.get::<WebGpuBindGroupLayout>(rid)?;
+ Ok(bind_group_layout.1)
+ })
+ .collect::<Result<Vec<_>, AnyError>>()?;
+
+ let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor {
+ label: Some(label),
+ bind_group_layouts: Cow::from(bind_group_layouts),
+ push_constant_ranges: Default::default(),
+ };
+
+ gfx_put!(device => instance.device_create_pipeline_layout(
+ device,
+ &descriptor,
+ ()
+ ) => state, super::pipeline::WebGpuPipelineLayout)
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct GpuBindGroupEntry {
+ binding: u32,
+ kind: String,
+ resource: ResourceId,
+ offset: Option<u64>,
+ size: Option<u64>,
+}
+
+#[op2]
+#[serde]
+pub fn op_webgpu_create_bind_group(
+ state: &mut OpState,
+ #[smi] device_rid: ResourceId,
+ #[string] label: Cow<str>,
+ #[smi] layout: ResourceId,
+ #[serde] entries: Vec<GpuBindGroupEntry>,
+) -> Result<WebGpuResult, AnyError> {
+ let instance = state.borrow::<super::Instance>();
+ let device_resource = state
+ .resource_table
+ .get::<super::WebGpuDevice>(device_rid)?;
+ let device = device_resource.1;
+
+ let entries = entries
+ .into_iter()
+ .map(|entry| {
+ Ok(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)?;
+ wgpu_core::binding_model::BindingResource::Sampler(
+ sampler_resource.1,
+ )
+ }
+ "GPUTextureView" => {
+ let texture_view_resource =
+ state
+ .resource_table
+ .get::<super::texture::WebGpuTextureView>(entry.resource)?;
+ wgpu_core::binding_model::BindingResource::TextureView(
+ texture_view_resource.1,
+ )
+ }
+ "GPUBufferBinding" => {
+ let buffer_resource =
+ state
+ .resource_table
+ .get::<super::buffer::WebGpuBuffer>(entry.resource)?;
+ wgpu_core::binding_model::BindingResource::Buffer(
+ wgpu_core::binding_model::BufferBinding {
+ buffer_id: buffer_resource.1,
+ offset: entry.offset.unwrap_or(0),
+ size: std::num::NonZeroU64::new(entry.size.unwrap_or(0)),
+ },
+ )
+ }
+ _ => unreachable!(),
+ },
+ })
+ })
+ .collect::<Result<Vec<_>, AnyError>>()?;
+
+ let bind_group_layout =
+ state.resource_table.get::<WebGpuBindGroupLayout>(layout)?;
+
+ let descriptor = wgpu_core::binding_model::BindGroupDescriptor {
+ label: Some(label),
+ layout: bind_group_layout.1,
+ entries: Cow::from(entries),
+ };
+
+ gfx_put!(device => instance.device_create_bind_group(
+ device,
+ &descriptor,
+ ()
+ ) => state, WebGpuBindGroup)
+}