diff options
Diffstat (limited to 'ext/webgpu/pipeline.rs')
-rw-r--r-- | ext/webgpu/pipeline.rs | 645 |
1 files changed, 380 insertions, 265 deletions
diff --git a/ext/webgpu/pipeline.rs b/ext/webgpu/pipeline.rs index 877143f94..77edcadfb 100644 --- a/ext/webgpu/pipeline.rs +++ b/ext/webgpu/pipeline.rs @@ -6,6 +6,10 @@ use deno_core::{OpState, Resource}; use serde::Deserialize; use serde::Serialize; use std::borrow::Cow; +use std::convert::{TryFrom, TryInto}; + +use crate::sampler::GpuCompareFunction; +use crate::texture::GpuTextureFormat; use super::error::{WebGpuError, WebGpuResult}; @@ -38,121 +42,196 @@ impl Resource for WebGpuRenderPipeline { } } -pub fn serialize_index_format(format: String) -> wgpu_types::IndexFormat { - match format.as_str() { - "uint16" => wgpu_types::IndexFormat::Uint16, - "uint32" => wgpu_types::IndexFormat::Uint32, - _ => unreachable!(), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuIndexFormat { + Uint16, + Uint32, +} + +impl From<GpuIndexFormat> for wgpu_types::IndexFormat { + fn from(value: GpuIndexFormat) -> wgpu_types::IndexFormat { + match value { + GpuIndexFormat::Uint16 => wgpu_types::IndexFormat::Uint16, + GpuIndexFormat::Uint32 => wgpu_types::IndexFormat::Uint32, + } } } -fn serialize_stencil_operation( - operation: &str, -) -> wgpu_types::StencilOperation { - match operation { - "keep" => wgpu_types::StencilOperation::Keep, - "zero" => wgpu_types::StencilOperation::Zero, - "replace" => wgpu_types::StencilOperation::Replace, - "invert" => wgpu_types::StencilOperation::Invert, - "increment-clamp" => wgpu_types::StencilOperation::IncrementClamp, - "decrement-clamp" => wgpu_types::StencilOperation::DecrementClamp, - "increment-wrap" => wgpu_types::StencilOperation::IncrementWrap, - "decrement-wrap" => wgpu_types::StencilOperation::DecrementWrap, - _ => unreachable!(), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GPUStencilOperation { + Keep, + Zero, + Replace, + Invert, + IncrementClamp, + DecrementClamp, + IncrementWrap, + DecrementWrap, +} + +impl From<GPUStencilOperation> for wgpu_types::StencilOperation { + fn from(value: GPUStencilOperation) -> wgpu_types::StencilOperation { + match value { + GPUStencilOperation::Keep => wgpu_types::StencilOperation::Keep, + GPUStencilOperation::Zero => wgpu_types::StencilOperation::Zero, + GPUStencilOperation::Replace => wgpu_types::StencilOperation::Replace, + GPUStencilOperation::Invert => wgpu_types::StencilOperation::Invert, + GPUStencilOperation::IncrementClamp => { + wgpu_types::StencilOperation::IncrementClamp + } + GPUStencilOperation::DecrementClamp => { + wgpu_types::StencilOperation::DecrementClamp + } + GPUStencilOperation::IncrementWrap => { + wgpu_types::StencilOperation::IncrementWrap + } + GPUStencilOperation::DecrementWrap => { + wgpu_types::StencilOperation::DecrementWrap + } + } } } -fn serialize_stencil_face_state( - state: GpuStencilFaceState, -) -> wgpu_types::StencilFaceState { - wgpu_types::StencilFaceState { - compare: state - .compare - .as_ref() - .map_or(wgpu_types::CompareFunction::Always, |op| { - super::sampler::serialize_compare_function(op) - }), - fail_op: state - .fail_op - .as_ref() - .map_or(wgpu_types::StencilOperation::Keep, |op| { - serialize_stencil_operation(op) - }), - depth_fail_op: state - .depth_fail_op - .as_ref() - .map_or(wgpu_types::StencilOperation::Keep, |op| { - serialize_stencil_operation(op) - }), - pass_op: state - .pass_op - .as_ref() - .map_or(wgpu_types::StencilOperation::Keep, |op| { - serialize_stencil_operation(op) - }), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuBlendFactor { + Zero, + One, + Src, + OneMinusSrc, + SrcAlpha, + OneMinusSrcAlpha, + Dst, + OneMinusDst, + DstAlpha, + OneMinusDstAlpha, + SrcAlphaSaturated, + Constant, + OneMinusConstant, +} + +impl From<GpuBlendFactor> for wgpu_types::BlendFactor { + fn from(value: GpuBlendFactor) -> wgpu_types::BlendFactor { + match value { + GpuBlendFactor::Zero => wgpu_types::BlendFactor::Zero, + GpuBlendFactor::One => wgpu_types::BlendFactor::One, + GpuBlendFactor::Src => wgpu_types::BlendFactor::Src, + GpuBlendFactor::OneMinusSrc => wgpu_types::BlendFactor::OneMinusSrc, + GpuBlendFactor::SrcAlpha => wgpu_types::BlendFactor::SrcAlpha, + GpuBlendFactor::OneMinusSrcAlpha => { + wgpu_types::BlendFactor::OneMinusSrcAlpha + } + GpuBlendFactor::Dst => wgpu_types::BlendFactor::Dst, + GpuBlendFactor::OneMinusDst => wgpu_types::BlendFactor::OneMinusDst, + GpuBlendFactor::DstAlpha => wgpu_types::BlendFactor::DstAlpha, + GpuBlendFactor::OneMinusDstAlpha => { + wgpu_types::BlendFactor::OneMinusDstAlpha + } + GpuBlendFactor::SrcAlphaSaturated => { + wgpu_types::BlendFactor::SrcAlphaSaturated + } + GpuBlendFactor::Constant => wgpu_types::BlendFactor::Constant, + GpuBlendFactor::OneMinusConstant => { + wgpu_types::BlendFactor::OneMinusConstant + } + } } } -fn serialize_blend_factor(blend_factor: &str) -> wgpu_types::BlendFactor { - match blend_factor { - "zero" => wgpu_types::BlendFactor::Zero, - "one" => wgpu_types::BlendFactor::One, - "src" => wgpu_types::BlendFactor::Src, - "one-minus-src" => wgpu_types::BlendFactor::OneMinusSrc, - "src-alpha" => wgpu_types::BlendFactor::SrcAlpha, - "one-minus-src-alpha" => wgpu_types::BlendFactor::OneMinusSrcAlpha, - "dst" => wgpu_types::BlendFactor::Dst, - "one-minus-dst" => wgpu_types::BlendFactor::OneMinusDst, - "dst-alpha" => wgpu_types::BlendFactor::DstAlpha, - "one-minus-dst-alpha" => wgpu_types::BlendFactor::OneMinusDstAlpha, - "src-alpha-saturated" => wgpu_types::BlendFactor::SrcAlphaSaturated, - "constant" => wgpu_types::BlendFactor::Constant, - "one-minus-constant" => wgpu_types::BlendFactor::OneMinusConstant, - _ => unreachable!(), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuBlendOperation { + Add, + Subtract, + ReverseSubtract, + Min, + Max, +} + +impl From<GpuBlendOperation> for wgpu_types::BlendOperation { + fn from(value: GpuBlendOperation) -> wgpu_types::BlendOperation { + match value { + GpuBlendOperation::Add => wgpu_types::BlendOperation::Add, + GpuBlendOperation::Subtract => wgpu_types::BlendOperation::Subtract, + GpuBlendOperation::ReverseSubtract => { + wgpu_types::BlendOperation::ReverseSubtract + } + GpuBlendOperation::Min => wgpu_types::BlendOperation::Min, + GpuBlendOperation::Max => wgpu_types::BlendOperation::Max, + } } } -fn serialize_blend_state(state: GpuBlendState) -> wgpu_types::BlendState { - wgpu_types::BlendState { - alpha: serialize_blend_component(state.alpha), - color: serialize_blend_component(state.color), +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuPrimitiveTopology { + PointList, + LineList, + LineStrip, + TriangleList, + TriangleStrip, +} + +impl From<GpuPrimitiveTopology> for wgpu_types::PrimitiveTopology { + fn from(value: GpuPrimitiveTopology) -> wgpu_types::PrimitiveTopology { + match value { + GpuPrimitiveTopology::PointList => { + wgpu_types::PrimitiveTopology::PointList + } + GpuPrimitiveTopology::LineList => wgpu_types::PrimitiveTopology::LineList, + GpuPrimitiveTopology::LineStrip => { + wgpu_types::PrimitiveTopology::LineStrip + } + GpuPrimitiveTopology::TriangleList => { + wgpu_types::PrimitiveTopology::TriangleList + } + GpuPrimitiveTopology::TriangleStrip => { + wgpu_types::PrimitiveTopology::TriangleStrip + } + } } } -fn serialize_blend_component( - blend: GpuBlendComponent, -) -> wgpu_types::BlendComponent { - wgpu_types::BlendComponent { - src_factor: blend - .src_factor - .as_ref() - .map_or(wgpu_types::BlendFactor::One, |factor| { - serialize_blend_factor(factor) - }), - dst_factor: blend - .dst_factor - .as_ref() - .map_or(wgpu_types::BlendFactor::Zero, |factor| { - serialize_blend_factor(factor) - }), - operation: match &blend.operation { - Some(operation) => match operation.as_str() { - "add" => wgpu_types::BlendOperation::Add, - "subtract" => wgpu_types::BlendOperation::Subtract, - "reverse-subtract" => wgpu_types::BlendOperation::ReverseSubtract, - "min" => wgpu_types::BlendOperation::Min, - "max" => wgpu_types::BlendOperation::Max, - _ => unreachable!(), - }, - None => wgpu_types::BlendOperation::Add, - }, +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuFrontFace { + Ccw, + Cw, +} + +impl From<GpuFrontFace> for wgpu_types::FrontFace { + fn from(value: GpuFrontFace) -> wgpu_types::FrontFace { + match value { + GpuFrontFace::Ccw => wgpu_types::FrontFace::Ccw, + GpuFrontFace::Cw => wgpu_types::FrontFace::Cw, + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuCullMode { + None, + Front, + Back, +} + +impl From<GpuCullMode> for Option<wgpu_types::Face> { + fn from(value: GpuCullMode) -> Option<wgpu_types::Face> { + match value { + GpuCullMode::None => None, + GpuCullMode::Front => Some(wgpu_types::Face::Front), + GpuCullMode::Back => Some(wgpu_types::Face::Back), + } } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuProgrammableStage { - module: u32, + module: ResourceId, entry_point: String, // constants: HashMap<String, GPUPipelineConstantValue> } @@ -162,7 +241,7 @@ struct GpuProgrammableStage { pub struct CreateComputePipelineArgs { device_rid: ResourceId, label: Option<String>, - layout: Option<u32>, + layout: Option<ResourceId>, compute: GpuProgrammableStage, } @@ -264,58 +343,138 @@ pub fn op_webgpu_compute_pipeline_get_bind_group_layout( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuPrimitiveState { - topology: Option<String>, - strip_index_format: Option<String>, - front_face: Option<String>, - cull_mode: Option<String>, + topology: GpuPrimitiveTopology, + strip_index_format: Option<GpuIndexFormat>, + front_face: GpuFrontFace, + cull_mode: GpuCullMode, clamp_depth: bool, } -#[derive(Deserialize, Clone)] +impl From<GpuPrimitiveState> for wgpu_types::PrimitiveState { + fn from(value: GpuPrimitiveState) -> wgpu_types::PrimitiveState { + wgpu_types::PrimitiveState { + topology: value.topology.into(), + strip_index_format: value.strip_index_format.map(Into::into), + front_face: value.front_face.into(), + cull_mode: value.cull_mode.into(), + clamp_depth: value.clamp_depth, + polygon_mode: Default::default(), // native-only + conservative: false, // native-only + } + } +} +#[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuBlendComponent { - src_factor: Option<String>, - dst_factor: Option<String>, - operation: Option<String>, + src_factor: GpuBlendFactor, + dst_factor: GpuBlendFactor, + operation: GpuBlendOperation, +} + +impl From<GpuBlendComponent> for wgpu_types::BlendComponent { + fn from(component: GpuBlendComponent) -> Self { + wgpu_types::BlendComponent { + src_factor: component.src_factor.into(), + dst_factor: component.dst_factor.into(), + operation: component.operation.into(), + } + } } -#[derive(Deserialize, Clone)] +#[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuBlendState { color: GpuBlendComponent, alpha: GpuBlendComponent, } +impl From<GpuBlendState> for wgpu_types::BlendState { + fn from(state: GpuBlendState) -> wgpu_types::BlendState { + wgpu_types::BlendState { + color: state.color.into(), + alpha: state.alpha.into(), + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuColorTargetState { - format: String, + format: GpuTextureFormat, blend: Option<GpuBlendState>, - write_mask: Option<u32>, + write_mask: u32, +} + +impl TryFrom<GpuColorTargetState> for wgpu_types::ColorTargetState { + type Error = AnyError; + fn try_from( + state: GpuColorTargetState, + ) -> Result<wgpu_types::ColorTargetState, AnyError> { + Ok(wgpu_types::ColorTargetState { + format: state.format.try_into()?, + blend: state.blend.map(Into::into), + write_mask: wgpu_types::ColorWrites::from_bits_truncate(state.write_mask), + }) + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuStencilFaceState { - compare: Option<String>, - fail_op: Option<String>, - depth_fail_op: Option<String>, - pass_op: Option<String>, + compare: GpuCompareFunction, + fail_op: GPUStencilOperation, + depth_fail_op: GPUStencilOperation, + pass_op: GPUStencilOperation, +} + +impl From<GpuStencilFaceState> for wgpu_types::StencilFaceState { + fn from(state: GpuStencilFaceState) -> Self { + wgpu_types::StencilFaceState { + compare: state.compare.into(), + fail_op: state.fail_op.into(), + depth_fail_op: state.depth_fail_op.into(), + pass_op: state.pass_op.into(), + } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuDepthStencilState { - format: String, - depth_write_enabled: Option<bool>, - depth_compare: Option<String>, - stencil_front: Option<GpuStencilFaceState>, - stencil_back: Option<GpuStencilFaceState>, - stencil_read_mask: Option<u32>, - stencil_write_mask: Option<u32>, - depth_bias: Option<i32>, - depth_bias_slope_scale: Option<f32>, - depth_bias_clamp: Option<f32>, + format: GpuTextureFormat, + depth_write_enabled: bool, + depth_compare: GpuCompareFunction, + stencil_front: GpuStencilFaceState, + stencil_back: GpuStencilFaceState, + stencil_read_mask: u32, + stencil_write_mask: u32, + depth_bias: i32, + depth_bias_slope_scale: f32, + depth_bias_clamp: f32, +} + +impl TryFrom<GpuDepthStencilState> for wgpu_types::DepthStencilState { + type Error = AnyError; + fn try_from( + state: GpuDepthStencilState, + ) -> Result<wgpu_types::DepthStencilState, AnyError> { + Ok(wgpu_types::DepthStencilState { + format: state.format.try_into()?, + depth_write_enabled: state.depth_write_enabled, + depth_compare: state.depth_compare.into(), + stencil: wgpu_types::StencilState { + front: state.stencil_front.into(), + back: state.stencil_back.into(), + read_mask: state.stencil_read_mask, + write_mask: state.stencil_write_mask, + }, + bias: wgpu_types::DepthBiasState { + constant: state.depth_bias, + slope_scale: state.depth_bias_slope_scale, + clamp: state.depth_bias_clamp, + }, + }) + } } #[derive(Deserialize)] @@ -326,6 +485,16 @@ struct GpuVertexAttribute { shader_location: u32, } +impl From<GpuVertexAttribute> for wgpu_types::VertexAttribute { + fn from(attribute: GpuVertexAttribute) -> Self { + wgpu_types::VertexAttribute { + format: attribute.format.into(), + offset: attribute.offset, + shader_location: attribute.shader_location, + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "lowercase")] enum GpuVertexFormat { @@ -409,26 +578,69 @@ impl From<GpuVertexFormat> for wgpu_types::VertexFormat { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] +enum GpuVertexStepMode { + Vertex, + Instance, +} + +impl From<GpuVertexStepMode> for wgpu_types::VertexStepMode { + fn from(vsm: GpuVertexStepMode) -> wgpu_types::VertexStepMode { + use wgpu_types::VertexStepMode; + match vsm { + GpuVertexStepMode::Vertex => VertexStepMode::Vertex, + GpuVertexStepMode::Instance => VertexStepMode::Instance, + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] struct GpuVertexBufferLayout { array_stride: u64, - step_mode: Option<String>, + step_mode: GpuVertexStepMode, attributes: Vec<GpuVertexAttribute>, } +impl<'a> From<GpuVertexBufferLayout> + for wgpu_core::pipeline::VertexBufferLayout<'a> +{ + fn from( + layout: GpuVertexBufferLayout, + ) -> wgpu_core::pipeline::VertexBufferLayout<'a> { + wgpu_core::pipeline::VertexBufferLayout { + array_stride: layout.array_stride, + step_mode: layout.step_mode.into(), + attributes: Cow::Owned( + layout.attributes.into_iter().map(Into::into).collect(), + ), + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuVertexState { - module: u32, + module: ResourceId, entry_point: String, - buffers: Option<Vec<Option<GpuVertexBufferLayout>>>, + buffers: Vec<Option<GpuVertexBufferLayout>>, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuMultisampleState { - count: Option<u32>, - mask: Option<u64>, // against spec, but future proof - alpha_to_coverage_enabled: Option<bool>, + count: u32, + mask: u64, + alpha_to_coverage_enabled: bool, +} + +impl From<GpuMultisampleState> for wgpu_types::MultisampleState { + fn from(gms: GpuMultisampleState) -> wgpu_types::MultisampleState { + wgpu_types::MultisampleState { + count: gms.count, + mask: gms.mask, + alpha_to_coverage_enabled: gms.alpha_to_coverage_enabled, + } + } } #[derive(Deserialize)] @@ -437,6 +649,7 @@ struct GpuFragmentState { targets: Vec<GpuColorTargetState>, module: u32, entry_point: String, + // TODO(lucacasonato): constants } #[derive(Deserialize)] @@ -444,11 +657,11 @@ struct GpuFragmentState { pub struct CreateRenderPipelineArgs { device_rid: ResourceId, label: Option<String>, - layout: Option<u32>, + layout: Option<ResourceId>, vertex: GpuVertexState, - primitive: Option<GpuPrimitiveState>, + primitive: GpuPrimitiveState, depth_stencil: Option<GpuDepthStencilState>, - multisample: Option<GpuMultisampleState>, + multisample: GpuMultisampleState, fragment: Option<GpuFragmentState>, } @@ -476,149 +689,51 @@ pub fn op_webgpu_create_render_pipeline( .resource_table .get::<super::shader::WebGpuShaderModule>(args.vertex.module)?; + let fragment = if let Some(fragment) = args.fragment { + let fragment_shader_module_resource = + state + .resource_table + .get::<super::shader::WebGpuShaderModule>(fragment.module)?; + + let mut targets = Vec::with_capacity(fragment.targets.len()); + + for target in fragment.targets { + targets.push(target.try_into()?); + } + + Some(wgpu_core::pipeline::FragmentState { + stage: wgpu_core::pipeline::ProgrammableStageDescriptor { + module: fragment_shader_module_resource.0, + entry_point: Cow::from(fragment.entry_point), + }, + targets: Cow::from(targets), + }) + } else { + None + }; + + let vertex_buffers = args + .vertex + .buffers + .into_iter() + .flatten() + .map(Into::into) + .collect(); + let descriptor = wgpu_core::pipeline::RenderPipelineDescriptor { - label: args.label.map(Cow::from), + label: args.label.map(Cow::Owned), layout, vertex: wgpu_core::pipeline::VertexState { stage: wgpu_core::pipeline::ProgrammableStageDescriptor { module: vertex_shader_module_resource.0, - entry_point: Cow::from(args.vertex.entry_point), + entry_point: Cow::Owned(args.vertex.entry_point), }, - buffers: Cow::from(if let Some(buffers) = args.vertex.buffers { - let mut return_buffers = vec![]; - for buffer in buffers.into_iter().flatten() { - return_buffers.push(wgpu_core::pipeline::VertexBufferLayout { - array_stride: buffer.array_stride, - step_mode: match buffer.step_mode { - Some(step_mode) => match step_mode.as_str() { - "vertex" => wgpu_types::VertexStepMode::Vertex, - "instance" => wgpu_types::VertexStepMode::Instance, - _ => unreachable!(), - }, - None => wgpu_types::VertexStepMode::Vertex, - }, - attributes: Cow::from( - buffer - .attributes - .into_iter() - .map(|attribute| wgpu_types::VertexAttribute { - format: attribute.format.into(), - offset: attribute.offset, - shader_location: attribute.shader_location, - }) - .collect::<Vec<wgpu_types::VertexAttribute>>(), - ), - }); - } - return_buffers - } else { - vec![] - }), + buffers: Cow::Owned(vertex_buffers), }, - primitive: args.primitive.map_or(Default::default(), |primitive| { - wgpu_types::PrimitiveState { - topology: match primitive.topology { - Some(topology) => match topology.as_str() { - "point-list" => wgpu_types::PrimitiveTopology::PointList, - "line-list" => wgpu_types::PrimitiveTopology::LineList, - "line-strip" => wgpu_types::PrimitiveTopology::LineStrip, - "triangle-list" => wgpu_types::PrimitiveTopology::TriangleList, - "triangle-strip" => wgpu_types::PrimitiveTopology::TriangleStrip, - _ => unreachable!(), - }, - None => wgpu_types::PrimitiveTopology::TriangleList, - }, - strip_index_format: primitive - .strip_index_format - .map(serialize_index_format), - front_face: match primitive.front_face { - Some(front_face) => match front_face.as_str() { - "ccw" => wgpu_types::FrontFace::Ccw, - "cw" => wgpu_types::FrontFace::Cw, - _ => unreachable!(), - }, - None => wgpu_types::FrontFace::Ccw, - }, - cull_mode: match primitive.cull_mode { - Some(cull_mode) => match cull_mode.as_str() { - "none" => None, - "front" => Some(wgpu_types::Face::Front), - "back" => Some(wgpu_types::Face::Back), - _ => unreachable!(), - }, - None => None, - }, - polygon_mode: Default::default(), // native-only - conservative: false, // native-only - clamp_depth: primitive.clamp_depth, - } - }), - depth_stencil: args.depth_stencil.map(|depth_stencil| { - wgpu_types::DepthStencilState { - format: super::texture::serialize_texture_format(&depth_stencil.format) - .unwrap(), - depth_write_enabled: depth_stencil.depth_write_enabled.unwrap_or(false), - depth_compare: match depth_stencil.depth_compare { - Some(depth_compare) => { - super::sampler::serialize_compare_function(&depth_compare) - } - None => wgpu_types::CompareFunction::Always, - }, - stencil: wgpu_types::StencilState { - front: depth_stencil - .stencil_front - .map_or(Default::default(), serialize_stencil_face_state), - back: depth_stencil - .stencil_back - .map_or(Default::default(), serialize_stencil_face_state), - read_mask: depth_stencil.stencil_read_mask.unwrap_or(0xFFFFFFFF), - write_mask: depth_stencil.stencil_write_mask.unwrap_or(0xFFFFFFFF), - }, - bias: wgpu_types::DepthBiasState { - constant: depth_stencil.depth_bias.unwrap_or(0), - slope_scale: depth_stencil.depth_bias_slope_scale.unwrap_or(0.0), - clamp: depth_stencil.depth_bias_clamp.unwrap_or(0.0), - }, - } - }), - multisample: args.multisample.map_or(Default::default(), |multisample| { - wgpu_types::MultisampleState { - count: multisample.count.unwrap_or(1), - mask: multisample.mask.unwrap_or(0xFFFFFFFF), - alpha_to_coverage_enabled: multisample - .alpha_to_coverage_enabled - .unwrap_or(false), - } - }), - fragment: args.fragment.map(|fragment| { - let fragment_shader_module_resource = state - .resource_table - .get::<super::shader::WebGpuShaderModule>(fragment.module) - .unwrap(); - - wgpu_core::pipeline::FragmentState { - stage: wgpu_core::pipeline::ProgrammableStageDescriptor { - module: fragment_shader_module_resource.0, - entry_point: Cow::from(fragment.entry_point), - }, - targets: Cow::from( - fragment - .targets - .into_iter() - .map(|target| wgpu_types::ColorTargetState { - format: super::texture::serialize_texture_format(&target.format) - .unwrap(), - blend: target.blend.map(serialize_blend_state), - write_mask: target - .write_mask - .map_or(Default::default(), |mask| { - wgpu_types::ColorWrites::from_bits(mask).unwrap() - }), - }) - .collect::<Vec<wgpu_types::ColorTargetState>>(), - ), - } - }), + primitive: args.primitive.into(), + depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?, + multisample: args.multisample.into(), + fragment, }; let implicit_pipelines = match args.layout { |