1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-26 09:10:40 -05:00
denoland-deno/extensions/webgpu/binding.rs

335 lines
10 KiB
Rust

// 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::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
use std::borrow::Cow;
use super::error::WebGpuResult;
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: ResourceId,
label: Option<String>,
entries: Vec<GpuBindGroupLayoutEntry>,
}
pub fn op_webgpu_create_bind_group_layout(
state: &mut OpState,
args: CreateBindGroupLayoutArgs,
_: (),
) -> Result<WebGpuResult, 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: 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() {
"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),
};
gfx_put!(device => instance.device_create_bind_group_layout(
device,
&descriptor,
std::marker::PhantomData
) => state, WebGpuBindGroupLayout)
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreatePipelineLayoutArgs {
device_rid: ResourceId,
label: Option<String>,
bind_group_layouts: Vec<u32>,
}
pub fn op_webgpu_create_pipeline_layout(
state: &mut OpState,
args: CreatePipelineLayoutArgs,
_: (),
) -> Result<WebGpuResult, 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(),
};
gfx_put!(device => instance.device_create_pipeline_layout(
device,
&descriptor,
std::marker::PhantomData
) => state, super::pipeline::WebGpuPipelineLayout)
}
#[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: ResourceId,
label: Option<String>,
layout: u32,
entries: Vec<GpuBindGroupEntry>,
}
pub fn op_webgpu_create_bind_group(
state: &mut OpState,
args: CreateBindGroupArgs,
_: (),
) -> Result<WebGpuResult, 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),
};
gfx_put!(device => instance.device_create_bind_group(
device,
&descriptor,
std::marker::PhantomData
) => state, WebGpuBindGroup)
}