2021-03-01 05:31:13 -05:00
|
|
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
|
|
|
|
|
|
|
use deno_core::error::AnyError;
|
2021-03-19 13:25:37 -04:00
|
|
|
use deno_core::ResourceId;
|
2021-03-01 05:31:13 -05:00
|
|
|
use deno_core::{OpState, Resource};
|
|
|
|
use serde::Deserialize;
|
|
|
|
use std::borrow::Cow;
|
2021-08-24 14:32:25 -04:00
|
|
|
use std::convert::{TryFrom, TryInto};
|
|
|
|
|
|
|
|
use crate::texture::{GpuTextureFormat, GpuTextureViewDimension};
|
2021-03-01 05:31:13 -05:00
|
|
|
|
2021-04-05 12:40:24 -04:00
|
|
|
use super::error::WebGpuResult;
|
2021-03-01 05:31:13 -05:00
|
|
|
|
2021-03-25 14:17:37 -04:00
|
|
|
pub(crate) struct WebGpuBindGroupLayout(
|
2021-03-01 05:31:13 -05:00
|
|
|
pub(crate) wgpu_core::id::BindGroupLayoutId,
|
|
|
|
);
|
2021-03-25 14:17:37 -04:00
|
|
|
impl Resource for WebGpuBindGroupLayout {
|
2021-03-01 05:31:13 -05:00
|
|
|
fn name(&self) -> Cow<str> {
|
|
|
|
"webGPUBindGroupLayout".into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-25 14:17:37 -04:00
|
|
|
pub(crate) struct WebGpuBindGroup(pub(crate) wgpu_core::id::BindGroupId);
|
|
|
|
impl Resource for WebGpuBindGroup {
|
2021-03-01 05:31:13 -05:00
|
|
|
fn name(&self) -> Cow<str> {
|
|
|
|
"webGPUBindGroup".into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
2021-03-25 14:17:37 -04:00
|
|
|
struct GpuBufferBindingLayout {
|
2021-08-24 14:32:25 -04:00
|
|
|
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 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
2021-03-25 14:17:37 -04:00
|
|
|
struct GpuSamplerBindingLayout {
|
2021-08-24 14:32:25 -04:00
|
|
|
r#type: GpuSamplerBindingType,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "kebab-case")]
|
|
|
|
enum GpuSamplerBindingType {
|
|
|
|
Filtering,
|
|
|
|
NonFiltering,
|
|
|
|
Comparison,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<GpuSamplerBindingType> 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,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
2021-03-25 14:17:37 -04:00
|
|
|
struct GpuTextureBindingLayout {
|
2021-08-24 14:32:25 -04:00
|
|
|
sample_type: GpuTextureSampleType,
|
|
|
|
view_dimension: GpuTextureViewDimension,
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
2021-03-25 14:17:37 -04:00
|
|
|
struct GpuStorageTextureBindingLayout {
|
2021-08-24 14:32:25 -04:00
|
|
|
access: GpuStorageTextureAccess,
|
|
|
|
format: GpuTextureFormat,
|
|
|
|
view_dimension: GpuTextureViewDimension,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
2021-03-25 14:17:37 -04:00
|
|
|
struct GpuBindGroupLayoutEntry {
|
2021-03-01 05:31:13 -05:00
|
|
|
binding: u32,
|
|
|
|
visibility: u32,
|
2021-08-24 14:32:25 -04:00
|
|
|
#[serde(flatten)]
|
|
|
|
binding_type: GpuBindingType,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
enum GpuBindingType {
|
|
|
|
Buffer(GpuBufferBindingLayout),
|
|
|
|
Sampler(GpuSamplerBindingLayout),
|
|
|
|
Texture(GpuTextureBindingLayout),
|
|
|
|
StorageTexture(GpuStorageTextureBindingLayout),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<GpuBindingType> for wgpu_types::BindingType {
|
|
|
|
type Error = AnyError;
|
|
|
|
|
|
|
|
fn try_from(
|
|
|
|
binding_type: GpuBindingType,
|
|
|
|
) -> Result<wgpu_types::BindingType, Self::Error> {
|
|
|
|
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)
|
|
|
|
}
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct CreateBindGroupLayoutArgs {
|
2021-03-19 13:25:37 -04:00
|
|
|
device_rid: ResourceId,
|
2021-03-01 05:31:13 -05:00
|
|
|
label: Option<String>,
|
2021-03-25 14:17:37 -04:00
|
|
|
entries: Vec<GpuBindGroupLayoutEntry>,
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn op_webgpu_create_bind_group_layout(
|
|
|
|
state: &mut OpState,
|
|
|
|
args: CreateBindGroupLayoutArgs,
|
2021-05-08 08:37:42 -04:00
|
|
|
_: (),
|
2021-04-05 12:40:24 -04:00
|
|
|
) -> Result<WebGpuResult, AnyError> {
|
2021-03-01 05:31:13 -05:00
|
|
|
let instance = state.borrow::<super::Instance>();
|
|
|
|
let device_resource = state
|
|
|
|
.resource_table
|
2021-08-15 07:29:19 -04:00
|
|
|
.get::<super::WebGpuDevice>(args.device_rid)?;
|
2021-03-01 05:31:13 -05:00
|
|
|
let device = device_resource.0;
|
|
|
|
|
|
|
|
let mut entries = vec![];
|
|
|
|
|
2021-08-24 14:32:25 -04:00
|
|
|
for entry in args.entries {
|
2021-03-01 05:31:13 -05:00
|
|
|
entries.push(wgpu_types::BindGroupLayoutEntry {
|
|
|
|
binding: entry.binding,
|
2021-08-24 07:29:42 -04:00
|
|
|
visibility: wgpu_types::ShaderStages::from_bits(entry.visibility)
|
|
|
|
.unwrap(),
|
2021-08-24 14:32:25 -04:00
|
|
|
ty: entry.binding_type.try_into()?,
|
2021-03-01 05:31:13 -05:00
|
|
|
count: None, // native-only
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor {
|
|
|
|
label: args.label.map(Cow::from),
|
|
|
|
entries: Cow::from(entries),
|
|
|
|
};
|
|
|
|
|
2021-05-03 10:42:59 -04:00
|
|
|
gfx_put!(device => instance.device_create_bind_group_layout(
|
2021-03-01 05:31:13 -05:00
|
|
|
device,
|
|
|
|
&descriptor,
|
|
|
|
std::marker::PhantomData
|
2021-05-03 10:42:59 -04:00
|
|
|
) => state, WebGpuBindGroupLayout)
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct CreatePipelineLayoutArgs {
|
2021-03-19 13:25:37 -04:00
|
|
|
device_rid: ResourceId,
|
2021-03-01 05:31:13 -05:00
|
|
|
label: Option<String>,
|
|
|
|
bind_group_layouts: Vec<u32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn op_webgpu_create_pipeline_layout(
|
|
|
|
state: &mut OpState,
|
|
|
|
args: CreatePipelineLayoutArgs,
|
2021-05-08 08:37:42 -04:00
|
|
|
_: (),
|
2021-04-05 12:40:24 -04:00
|
|
|
) -> Result<WebGpuResult, AnyError> {
|
2021-03-01 05:31:13 -05:00
|
|
|
let instance = state.borrow::<super::Instance>();
|
|
|
|
let device_resource = state
|
|
|
|
.resource_table
|
2021-08-15 07:29:19 -04:00
|
|
|
.get::<super::WebGpuDevice>(args.device_rid)?;
|
2021-03-01 05:31:13 -05:00
|
|
|
let device = device_resource.0;
|
|
|
|
|
|
|
|
let mut bind_group_layouts = vec![];
|
|
|
|
|
|
|
|
for rid in &args.bind_group_layouts {
|
2021-08-15 07:29:19 -04:00
|
|
|
let bind_group_layout =
|
|
|
|
state.resource_table.get::<WebGpuBindGroupLayout>(*rid)?;
|
2021-03-01 05:31:13 -05:00
|
|
|
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(),
|
|
|
|
};
|
|
|
|
|
2021-05-03 10:42:59 -04:00
|
|
|
gfx_put!(device => instance.device_create_pipeline_layout(
|
2021-03-01 05:31:13 -05:00
|
|
|
device,
|
|
|
|
&descriptor,
|
|
|
|
std::marker::PhantomData
|
2021-05-03 10:42:59 -04:00
|
|
|
) => state, super::pipeline::WebGpuPipelineLayout)
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
2021-03-25 14:17:37 -04:00
|
|
|
struct GpuBindGroupEntry {
|
2021-03-01 05:31:13 -05:00
|
|
|
binding: u32,
|
|
|
|
kind: String,
|
2021-08-24 14:32:25 -04:00
|
|
|
resource: ResourceId,
|
2021-03-01 05:31:13 -05:00
|
|
|
offset: Option<u64>,
|
|
|
|
size: Option<u64>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct CreateBindGroupArgs {
|
2021-03-19 13:25:37 -04:00
|
|
|
device_rid: ResourceId,
|
2021-03-01 05:31:13 -05:00
|
|
|
label: Option<String>,
|
2021-08-24 14:32:25 -04:00
|
|
|
layout: ResourceId,
|
2021-03-25 14:17:37 -04:00
|
|
|
entries: Vec<GpuBindGroupEntry>,
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn op_webgpu_create_bind_group(
|
|
|
|
state: &mut OpState,
|
|
|
|
args: CreateBindGroupArgs,
|
2021-05-08 08:37:42 -04:00
|
|
|
_: (),
|
2021-04-05 12:40:24 -04:00
|
|
|
) -> Result<WebGpuResult, AnyError> {
|
2021-03-01 05:31:13 -05:00
|
|
|
let instance = state.borrow::<super::Instance>();
|
|
|
|
let device_resource = state
|
|
|
|
.resource_table
|
2021-08-15 07:29:19 -04:00
|
|
|
.get::<super::WebGpuDevice>(args.device_rid)?;
|
2021-03-01 05:31:13 -05:00
|
|
|
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" => {
|
2021-08-15 07:29:19 -04:00
|
|
|
let sampler_resource =
|
|
|
|
state
|
|
|
|
.resource_table
|
|
|
|
.get::<super::sampler::WebGpuSampler>(entry.resource)?;
|
2021-03-01 05:31:13 -05:00
|
|
|
wgpu_core::binding_model::BindingResource::Sampler(sampler_resource.0)
|
|
|
|
}
|
|
|
|
"GPUTextureView" => {
|
2021-08-15 07:29:19 -04:00
|
|
|
let texture_view_resource =
|
|
|
|
state
|
|
|
|
.resource_table
|
|
|
|
.get::<super::texture::WebGpuTextureView>(entry.resource)?;
|
2021-03-01 05:31:13 -05:00
|
|
|
wgpu_core::binding_model::BindingResource::TextureView(
|
|
|
|
texture_view_resource.0,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
"GPUBufferBinding" => {
|
2021-08-15 07:29:19 -04:00
|
|
|
let buffer_resource =
|
|
|
|
state
|
|
|
|
.resource_table
|
|
|
|
.get::<super::buffer::WebGpuBuffer>(entry.resource)?;
|
2021-03-01 05:31:13 -05:00
|
|
|
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
|
2021-08-15 07:29:19 -04:00
|
|
|
.get::<WebGpuBindGroupLayout>(args.layout)?;
|
2021-03-01 05:31:13 -05:00
|
|
|
|
|
|
|
let descriptor = wgpu_core::binding_model::BindGroupDescriptor {
|
|
|
|
label: args.label.map(Cow::from),
|
|
|
|
layout: bind_group_layout.0,
|
|
|
|
entries: Cow::from(entries),
|
|
|
|
};
|
|
|
|
|
2021-05-03 10:42:59 -04:00
|
|
|
gfx_put!(device => instance.device_create_bind_group(
|
2021-03-01 05:31:13 -05:00
|
|
|
device,
|
|
|
|
&descriptor,
|
|
|
|
std::marker::PhantomData
|
2021-05-03 10:42:59 -04:00
|
|
|
) => state, WebGpuBindGroup)
|
2021-03-01 05:31:13 -05:00
|
|
|
}
|