2024-01-01 14:58:21 -05:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2023-12-08 19:19:16 -05:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|