From 0346b43982effe3d0f6b823403bbb0146b051076 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 27 Jan 2021 14:43:08 -0500 Subject: [PATCH 1/2] Update the render pipeline API --- player/tests/data/bind-group.ron | 2 +- player/tests/data/quad.ron | 50 +++---- wgpu-core/src/command/bundle.rs | 2 +- wgpu-core/src/command/render.rs | 2 +- wgpu-core/src/conv.rs | 75 ++++++---- wgpu-core/src/device/mod.rs | 140 ++++++++---------- wgpu-core/src/pipeline.rs | 81 ++++++----- wgpu-types/src/lib.rs | 240 +++++++++++++++++++++++++------ 8 files changed, 366 insertions(+), 226 deletions(-) diff --git a/player/tests/data/bind-group.ron b/player/tests/data/bind-group.ron index db6c3670db..25fffadf52 100644 --- a/player/tests/data/bind-group.ron +++ b/player/tests/data/bind-group.ron @@ -18,7 +18,7 @@ CreateComputePipeline(Id(0, 1, Empty), ( label: None, layout: Some(Id(0, 1, Empty)), - compute_stage: ( + stage: ( module: Id(0, 1, Empty), entry_point: "main", ), diff --git a/player/tests/data/quad.ron b/player/tests/data/quad.ron index 79f681901a..13400cbbe0 100644 --- a/player/tests/data/quad.ron +++ b/player/tests/data/quad.ron @@ -56,42 +56,24 @@ CreateRenderPipeline(Id(0, 1, Empty), ( label: None, layout: Some(Id(0, 1, Empty)), - vertex_stage: ( - module: Id(0, 1, Empty), - entry_point: "vs_main", - ), - fragment_stage: Some(( - module: Id(0, 1, Empty), - entry_point: "fs_main", - )), - rasterization_state: None, - primitive_topology: TriangleList, - color_states: [ - ( - format: Rgba8Unorm, - alpha_blend: ( - src_factor: One, - dst_factor: Zero, - operation: Add, - ), - color_blend: ( - src_factor: One, - dst_factor: Zero, - operation: Add, - ), - write_mask: ( - bits: 15, - ), + vertex: ( + stage: ( + module: Id(0, 1, Empty), + entry_point: "vs_main", ), - ], - depth_stencil_state: None, - vertex_state: ( - index_format: None, - vertex_buffers: [], + buffers: [], ), - sample_count: 1, - sample_mask: 4294967295, - alpha_to_coverage_enabled: false, + fragment: Some(( + stage: ( + module: Id(0, 1, Empty), + entry_point: "fs_main", + ), + targets: [ + ( + format: Rgba8Unorm, + ), + ], + )), )), Submit(1, [ RunRenderPass( diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index c529b7c464..dcdb5faa30 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -233,7 +233,7 @@ impl RenderBundleEncoder { pipeline_layout_id = Some(pipeline.layout_id.value); state.set_pipeline( - pipeline.index_format, + pipeline.strip_index_format, &pipeline.vertex_strides, &layout.bind_group_layout_ids, &layout.push_constant_ranges, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 3745ad654e..c9ff83af15 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -1248,7 +1248,7 @@ impl Global { } } - state.index.pipeline_format = pipeline.index_format; + state.index.pipeline_format = pipeline.strip_index_format; let vertex_strides_len = pipeline.vertex_strides.len(); state.vertex.buffers_required = vertex_strides_len as u32; diff --git a/wgpu-core/src/conv.rs b/wgpu-core/src/conv.rs index 28289357b7..33d5d195e7 100644 --- a/wgpu-core/src/conv.rs +++ b/wgpu-core/src/conv.rs @@ -177,14 +177,14 @@ pub fn map_primitive_topology(primitive_topology: wgt::PrimitiveTopology) -> hal } } -pub fn map_color_state_descriptor(desc: &wgt::ColorStateDescriptor) -> hal::pso::ColorBlendDesc { +pub fn map_color_target_state(desc: &wgt::ColorTargetState) -> hal::pso::ColorBlendDesc { let color_mask = desc.write_mask; - let blend_state = if desc.color_blend != wgt::BlendDescriptor::REPLACE - || desc.alpha_blend != wgt::BlendDescriptor::REPLACE + let blend_state = if desc.color_blend != wgt::BlendState::REPLACE + || desc.alpha_blend != wgt::BlendState::REPLACE { Some(hal::pso::BlendState { - color: map_blend_descriptor(&desc.color_blend), - alpha: map_blend_descriptor(&desc.alpha_blend), + color: map_blend_state(&desc.color_blend), + alpha: map_blend_state(&desc.alpha_blend), }) } else { None @@ -215,7 +215,7 @@ fn map_color_write_flags(flags: wgt::ColorWrite) -> hal::pso::ColorMask { value } -fn map_blend_descriptor(blend_desc: &wgt::BlendDescriptor) -> hal::pso::BlendOp { +fn map_blend_state(blend_desc: &wgt::BlendState) -> hal::pso::BlendOp { use hal::pso::BlendOp as H; use wgt::BlendOperation as Bo; match blend_desc.operation { @@ -256,9 +256,7 @@ fn map_blend_factor(blend_factor: wgt::BlendFactor) -> hal::pso::Factor { } } -pub fn map_depth_stencil_state_descriptor( - desc: &wgt::DepthStencilStateDescriptor, -) -> hal::pso::DepthStencilDesc { +pub fn map_depth_stencil_state(desc: &wgt::DepthStencilState) -> hal::pso::DepthStencilDesc { hal::pso::DepthStencilDesc { depth: if desc.is_depth_enabled() { Some(hal::pso::DepthTest { @@ -290,9 +288,7 @@ pub fn map_depth_stencil_state_descriptor( } } -fn map_stencil_face( - stencil_state_face_desc: &wgt::StencilStateFaceDescriptor, -) -> hal::pso::StencilFace { +fn map_stencil_face(stencil_state_face_desc: &wgt::StencilStateFace) -> hal::pso::StencilFace { hal::pso::StencilFace { fun: map_compare_function(stencil_state_face_desc.compare), op_fail: map_stencil_operation(stencil_state_face_desc.fail_op), @@ -774,12 +770,38 @@ pub fn map_wrap(address: wgt::AddressMode) -> hal::image::WrapMode { } } -pub fn map_rasterization_state_descriptor( - desc: &wgt::RasterizationStateDescriptor, +pub fn map_primitive_state_to_input_assembler( + desc: &wgt::PrimitiveState, +) -> hal::pso::InputAssemblerDesc { + hal::pso::InputAssemblerDesc { + primitive: map_primitive_topology(desc.topology), + with_adjacency: false, + restart_index: desc.strip_index_format.map(map_index_format), + } +} + +pub fn map_primitive_state_to_rasterizer( + desc: &wgt::PrimitiveState, + depth_stencil: Option<&wgt::DepthStencilState>, ) -> hal::pso::Rasterizer { use hal::pso; + let (depth_clamping, depth_bias) = match depth_stencil { + Some(dsd) => { + let bias = if dsd.has_depth_bias() { + Some(pso::State::Static(pso::DepthBias { + const_factor: dsd.depth_bias as f32, + slope_factor: dsd.depth_bias_slope_scale, + clamp: dsd.depth_bias_clamp, + })) + } else { + None + }; + (dsd.clamp_depth, bias) + } + None => (false, None), + }; pso::Rasterizer { - depth_clamping: desc.clamp_depth, + depth_clamping, polygon_mode: match desc.polygon_mode { wgt::PolygonMode::Fill => pso::PolygonMode::Fill, wgt::PolygonMode::Line => pso::PolygonMode::Line, @@ -794,23 +816,22 @@ pub fn map_rasterization_state_descriptor( wgt::FrontFace::Ccw => pso::FrontFace::CounterClockwise, wgt::FrontFace::Cw => pso::FrontFace::Clockwise, }, - depth_bias: if desc.depth_bias != 0 - || desc.depth_bias_slope_scale != 0.0 - || desc.depth_bias_clamp != 0.0 - { - Some(pso::State::Static(pso::DepthBias { - const_factor: desc.depth_bias as f32, - slope_factor: desc.depth_bias_slope_scale, - clamp: desc.depth_bias_clamp, - })) - } else { - None - }, + depth_bias, conservative: false, line_width: pso::State::Static(1.0), } } +pub fn map_multisample_state(desc: &wgt::MultisampleState) -> hal::pso::Multisampling { + hal::pso::Multisampling { + rasterization_samples: desc.count as _, + sample_shading: None, + sample_mask: desc.mask, + alpha_coverage: desc.alpha_to_coverage_enabled, + alpha_to_one: false, + } +} + pub fn map_index_format(index_format: wgt::IndexFormat) -> hal::IndexType { match index_format { wgt::IndexFormat::Uint16 => hal::IndexType::U16, diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index c0fe121ae6..0103a76b01 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -1778,15 +1778,12 @@ impl Device { ArrayVec::<[binding_model::BindEntryMap; MAX_BIND_GROUPS]>::new(); let io = validation::StageIo::default(); - let pipeline_stage = &desc.compute_stage; let (shader_module_guard, _) = hub.shader_modules.read(&mut token); - let entry_point_name = &pipeline_stage.entry_point; - let shader_module = shader_module_guard - .get(pipeline_stage.module) - .map_err(|_| { - pipeline::CreateComputePipelineError::Stage(validation::StageError::InvalidModule) - })?; + let entry_point_name = &desc.stage.entry_point; + let shader_module = shader_module_guard.get(desc.stage.module).map_err(|_| { + pipeline::CreateComputePipelineError::Stage(validation::StageError::InvalidModule) + })?; let flag = wgt::ShaderStage::COMPUTE; if let Some(ref interface) = shader_module.interface { @@ -1898,47 +1895,37 @@ impl Device { let mut derived_group_layouts = ArrayVec::<[binding_model::BindEntryMap; MAX_BIND_GROUPS]>::new(); - let samples = { - let sc = desc.sample_count; - if sc == 0 || sc > 32 || !conv::is_power_of_two(sc) { - return Err(pipeline::CreateRenderPipelineError::InvalidSampleCount(sc)); - } - sc as u8 - }; - - let color_states = &desc.color_states; - let depth_stencil_state = desc.depth_stencil_state.as_ref(); - - let rasterization_state = desc - .rasterization_state + let color_states = desc + .fragment .as_ref() - .cloned() - .unwrap_or_default(); - let rasterizer = conv::map_rasterization_state_descriptor(&rasterization_state); + .map_or(&[][..], |fragment| &fragment.targets); + let depth_stencil_state = desc.depth_stencil.as_ref(); + let rasterizer = + conv::map_primitive_state_to_rasterizer(&desc.primitive, depth_stencil_state); let mut io = validation::StageIo::default(); let mut validated_stages = wgt::ShaderStage::empty(); - let desc_vbs = &desc.vertex_state.vertex_buffers; + let desc_vbs = &desc.vertex.buffers; let mut vertex_strides = Vec::with_capacity(desc_vbs.len()); let mut vertex_buffers = Vec::with_capacity(desc_vbs.len()); let mut attributes = Vec::new(); for (i, vb_state) in desc_vbs.iter().enumerate() { vertex_strides .alloc() - .init((vb_state.stride, vb_state.step_mode)); + .init((vb_state.array_stride, vb_state.step_mode)); if vb_state.attributes.is_empty() { continue; } - if vb_state.stride % wgt::VERTEX_STRIDE_ALIGNMENT != 0 { + if vb_state.array_stride % wgt::VERTEX_STRIDE_ALIGNMENT != 0 { return Err(pipeline::CreateRenderPipelineError::UnalignedVertexStride { index: i as u32, - stride: vb_state.stride, + stride: vb_state.array_stride, }); } vertex_buffers.alloc().init(hal::pso::VertexBufferDesc { binding: i as u32, - stride: vb_state.stride as u32, + stride: vb_state.array_stride as u32, rate: match vb_state.step_mode { InputStepMode::Vertex => hal::pso::VertexInputRate::Vertex, InputStepMode::Instance => hal::pso::VertexInputRate::Instance(1), @@ -1985,33 +1972,25 @@ impl Device { } } - let input_assembler = hal::pso::InputAssemblerDesc { - primitive: conv::map_primitive_topology(desc.primitive_topology), - with_adjacency: false, - restart_index: None, //TODO - }; + let input_assembler = conv::map_primitive_state_to_input_assembler(&desc.primitive); let blender = hal::pso::BlendDesc { logic_op: None, // TODO targets: color_states .iter() - .map(conv::map_color_state_descriptor) + .map(conv::map_color_target_state) .collect(), }; - let depth_stencil = depth_stencil_state - .map(conv::map_depth_stencil_state_descriptor) - .unwrap_or_default(); - - let multisampling: Option = if samples == 1 { - None - } else { - Some(hal::pso::Multisampling { - rasterization_samples: samples, - sample_shading: None, - sample_mask: desc.sample_mask as u64, - alpha_coverage: desc.alpha_to_coverage_enabled, - alpha_to_one: false, - }) + let depth_stencil = match depth_stencil_state { + Some(dsd) => { + if dsd.clamp_depth && !self.features.contains(wgt::Features::DEPTH_CLAMPING) { + return Err(pipeline::CreateRenderPipelineError::MissingFeature( + wgt::Features::DEPTH_CLAMPING, + )); + } + conv::map_depth_stencil_state(dsd) + } + None => hal::pso::DepthStencilDesc::default(), }; // TODO @@ -2022,13 +2001,7 @@ impl Device { depth_bounds: None, }; - if rasterization_state.clamp_depth && !self.features.contains(wgt::Features::DEPTH_CLAMPING) - { - return Err(pipeline::CreateRenderPipelineError::MissingFeature( - wgt::Features::DEPTH_CLAMPING, - )); - } - if rasterization_state.polygon_mode != wgt::PolygonMode::Fill + if desc.primitive.polygon_mode != wgt::PolygonMode::Fill && !self.features.contains(wgt::Features::NON_FILL_POLYGON_MODE) { return Err(pipeline::CreateRenderPipelineError::MissingFeature( @@ -2042,7 +2015,18 @@ impl Device { } } - let (shader_module_guard, _) = hub.shader_modules.read(&mut token); + let samples = { + let sc = desc.multisample.count; + if sc == 0 || sc > 32 || !conv::is_power_of_two(sc) { + return Err(pipeline::CreateRenderPipelineError::InvalidSampleCount(sc)); + } + sc as u8 + }; + let multisampling = if samples == 1 { + None + } else { + Some(conv::map_multisample_state(&desc.multisample)) + }; let rp_key = RenderPassKey { colors: color_states @@ -2081,17 +2065,18 @@ impl Device { }), }; + let (shader_module_guard, _) = hub.shader_modules.read(&mut token); + let vertex = { - let entry_point_name = &desc.vertex_stage.entry_point; + let stage = &desc.vertex.stage; let flag = wgt::ShaderStage::VERTEX; - let shader_module = - shader_module_guard - .get(desc.vertex_stage.module) - .map_err(|_| pipeline::CreateRenderPipelineError::Stage { - flag, - error: validation::StageError::InvalidModule, - })?; + let shader_module = shader_module_guard.get(stage.module).map_err(|_| { + pipeline::CreateRenderPipelineError::Stage { + flag, + error: validation::StageError::InvalidModule, + } + })?; if let Some(ref interface) = shader_module.interface { let provided_layouts = match desc.layout { @@ -2108,7 +2093,7 @@ impl Device { .check_stage( provided_layouts.as_ref().map(|p| p.as_slice()), &mut derived_group_layouts, - &entry_point_name, + &stage.entry_point, flag, io, ) @@ -2117,23 +2102,24 @@ impl Device { } hal::pso::EntryPoint:: { - entry: &entry_point_name, // TODO + entry: &stage.entry_point, module: &shader_module.raw, specialization: hal::pso::Specialization::EMPTY, } }; - let fragment = match &desc.fragment_stage { - Some(stage) => { - let entry_point_name = &stage.entry_point; + let fragment = match &desc.fragment { + Some(fragment) => { + let entry_point_name = &fragment.stage.entry_point; let flag = wgt::ShaderStage::FRAGMENT; - let shader_module = shader_module_guard.get(stage.module).map_err(|_| { - pipeline::CreateRenderPipelineError::Stage { - flag, - error: validation::StageError::InvalidModule, - } - })?; + let shader_module = + shader_module_guard + .get(fragment.stage.module) + .map_err(|_| pipeline::CreateRenderPipelineError::Stage { + flag, + error: validation::StageError::InvalidModule, + })?; let provided_layouts = match desc.layout { Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts( @@ -2199,7 +2185,7 @@ impl Device { } } } - let last_stage = match desc.fragment_stage { + let last_stage = match desc.fragment { Some(_) => wgt::ShaderStage::FRAGMENT, None => wgt::ShaderStage::VERTEX, }; @@ -2310,7 +2296,7 @@ impl Device { }, pass_context, flags, - index_format: desc.vertex_state.index_format, + strip_index_format: desc.primitive.strip_index_format, vertex_strides, life_guard: LifeGuard::new(desc.label.borrow_or_default()), }; diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 54ac8317fa..2e96b6000b 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -11,7 +11,6 @@ use crate::{ }; use std::borrow::Cow; use thiserror::Error; -use wgt::{BufferAddress, IndexFormat, InputStepMode}; #[derive(Debug)] pub enum ShaderModuleSource<'a> { @@ -99,7 +98,7 @@ pub struct ComputePipelineDescriptor<'a> { /// The layout of bind groups for this pipeline. pub layout: Option, /// The compiled compute stage and its entry point. - pub compute_stage: ProgrammableStageDescriptor<'a>, + pub stage: ProgrammableStageDescriptor<'a>, } #[derive(Clone, Debug, Error)] @@ -134,24 +133,35 @@ impl Resource for ComputePipeline { #[derive(Clone, Debug)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] #[cfg_attr(feature = "replay", derive(serde::Deserialize))] -pub struct VertexBufferDescriptor<'a> { +pub struct VertexBufferLayout<'a> { /// The stride, in bytes, between elements of this buffer. - pub stride: BufferAddress, + pub array_stride: wgt::BufferAddress, /// How often this vertex buffer is "stepped" forward. - pub step_mode: InputStepMode, + pub step_mode: wgt::InputStepMode, /// The list of attributes which comprise a single vertex. - pub attributes: Cow<'a, [wgt::VertexAttributeDescriptor]>, + pub attributes: Cow<'a, [wgt::VertexAttribute]>, } -/// Describes vertex input state for a render pipeline. +/// Describes the vertex process in a render pipeline. #[derive(Clone, Debug)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] #[cfg_attr(feature = "replay", derive(serde::Deserialize))] -pub struct VertexStateDescriptor<'a> { - /// The format of any index buffers used with this pipeline. - pub index_format: Option, +pub struct VertexState<'a> { + /// The compiled vertex stage and its entry point. + pub stage: ProgrammableStageDescriptor<'a>, /// The format of any vertex buffers used with this pipeline. - pub vertex_buffers: Cow<'a, [VertexBufferDescriptor<'a>]>, + pub buffers: Cow<'a, [VertexBufferLayout<'a>]>, +} + +/// Describes fragment processing in a render pipeline. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "trace", derive(serde::Serialize))] +#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +pub struct FragmentState<'a> { + /// The compiled fragment stage and its entry point. + pub stage: ProgrammableStageDescriptor<'a>, + /// The effect of draw calls on the color aspect of the output target. + pub targets: Cow<'a, [wgt::ColorTargetState]>, } /// Describes a render (graphics) pipeline. @@ -162,33 +172,19 @@ pub struct RenderPipelineDescriptor<'a> { pub label: Label<'a>, /// The layout of bind groups for this pipeline. pub layout: Option, - /// The compiled vertex stage and its entry point. - pub vertex_stage: ProgrammableStageDescriptor<'a>, - /// The compiled fragment stage and its entry point, if any. - pub fragment_stage: Option>, - /// The rasterization process for this pipeline. - pub rasterization_state: Option, - /// The primitive topology used to interpret vertices. - pub primitive_topology: wgt::PrimitiveTopology, - /// The effect of draw calls on the color aspect of the output target. - pub color_states: Cow<'a, [wgt::ColorStateDescriptor]>, + /// The vertex processing state for this pipeline. + pub vertex: VertexState<'a>, + /// The properties of the pipeline at the primitive assembly and rasterization level. + #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + pub primitive: wgt::PrimitiveState, /// The effect of draw calls on the depth and stencil aspects of the output target, if any. - pub depth_stencil_state: Option, - /// The vertex input state for this pipeline. - pub vertex_state: VertexStateDescriptor<'a>, - /// The number of samples calculated per pixel (for MSAA). For non-multisampled textures, - /// this should be `1` - pub sample_count: u32, - /// Bitmask that restricts the samples of a pixel modified by this pipeline. All samples - /// can be enabled using the value `!0` - pub sample_mask: u32, - /// When enabled, produces another sample mask per pixel based on the alpha output value, that - /// is ANDed with the sample_mask and the primitive coverage to restrict the set of samples - /// affected by a primitive. - /// - /// The implicit mask produced for alpha of zero is guaranteed to be zero, and for alpha of one - /// is guaranteed to be all 1-s. - pub alpha_to_coverage_enabled: bool, + #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + pub depth_stencil: Option, + /// The multi-sampling properties of the pipeline. + #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + pub multisample: wgt::MultisampleState, + /// The fragment processing state for this pipeline. + pub fragment: Option>, } #[derive(Clone, Debug, Error)] @@ -206,11 +202,14 @@ pub enum CreateRenderPipelineError { #[error("invalid sample count {0}")] InvalidSampleCount(u32), #[error("vertex buffer {index} stride {stride} does not respect `VERTEX_STRIDE_ALIGNMENT`")] - UnalignedVertexStride { index: u32, stride: BufferAddress }, + UnalignedVertexStride { + index: u32, + stride: wgt::BufferAddress, + }, #[error("vertex attribute at location {location} has invalid offset {offset}")] InvalidVertexAttributeOffset { location: wgt::ShaderLocation, - offset: BufferAddress, + offset: wgt::BufferAddress, }, #[error("missing required device features {0:?}")] MissingFeature(wgt::Features), @@ -238,8 +237,8 @@ pub struct RenderPipeline { pub(crate) device_id: Stored, pub(crate) pass_context: RenderPassContext, pub(crate) flags: PipelineFlags, - pub(crate) index_format: Option, - pub(crate) vertex_strides: Vec<(BufferAddress, InputStepMode)>, + pub(crate) strip_index_format: Option, + pub(crate) vertex_strides: Vec<(wgt::BufferAddress, wgt::InputStepMode)>, pub(crate) life_guard: LifeGuard, } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index cba91acb24..78f7e44d13 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2,11 +2,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/*! This library describes the API surface of WebGPU that is agnostic of the backend. + * This API is used for targeting both Web and Native. + */ + // The intra doc links to the wgpu crate in this crate actually succesfully link to the types in the wgpu crate, when built from the wgpu crate. // However when building from both the wgpu crate or this crate cargo doc will claim all the links cannot be resolved // despite the fact that it works fine when it needs to. // So we just disable those warnings. #![allow(broken_intra_doc_links)] +#![warn(missing_docs)] #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -46,12 +51,19 @@ pub const QUERY_SIZE: u32 = 8; #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum Backend { + /// Dummy backend, used for testing. Empty = 0, + /// Vulkan API Vulkan = 1, + /// Metal API (Apple platforms) Metal = 2, + /// Direct3D-12 (Windows) Dx12 = 3, + /// Direct3D-11 (Windows) Dx11 = 4, + /// OpenGL ES-3 (Linux, Android) Gl = 5, + /// WebGPU in the browser BrowserWebGpu = 6, } @@ -529,6 +541,7 @@ pub struct DeviceDescriptor { } impl DeviceDescriptor { + /// pub fn map_label(&self, fun: impl FnOnce(&L) -> K) -> DeviceDescriptor { DeviceDescriptor { label: fun(&self.label), @@ -559,6 +572,9 @@ bitflags::bitflags! { } bitflags::bitflags! { + /// Flags controlling the shader processing. + /// + /// Note: These flags are internal tweaks, they don't affect the API. #[repr(transparent)] #[derive(Default)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] @@ -620,18 +636,31 @@ impl TextureViewDimension { #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum BlendFactor { + /// 0.0 Zero = 0, + /// 1.0 One = 1, + /// S.color SrcColor = 2, + /// 1.0 - S.color OneMinusSrcColor = 3, + /// S.alpha SrcAlpha = 4, + /// 1.0 - S.alpha OneMinusSrcAlpha = 5, + /// D.color DstColor = 6, + /// 1.0 - D.color OneMinusDstColor = 7, + /// D.alpha DstAlpha = 8, + /// 1.0 - D.alpha OneMinusDstAlpha = 9, + /// min(S.alpha, 1.0 - D.alpha) SrcAlphaSaturated = 10, + /// Constant BlendColor = 11, + /// 1.0 - Constant OneMinusBlendColor = 12, } @@ -643,10 +672,15 @@ pub enum BlendFactor { #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum BlendOperation { + /// Src + Dst Add = 0, + /// Src - Dst Subtract = 1, + /// Dst - Src ReverseSubtract = 2, + /// min(Src, Dst) Min = 3, + /// max(Src, Dst) Max = 4, } @@ -663,19 +697,26 @@ impl Default for BlendOperation { #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct BlendDescriptor { +pub struct BlendState { + /// Multiplier for the source, which is produced by the fragment shader. pub src_factor: BlendFactor, + /// Multiplier for the destination, which is stored in the target. pub dst_factor: BlendFactor, + /// The binary operation applied to the source and destination, + /// multiplied by their respective factors. pub operation: BlendOperation, } -impl BlendDescriptor { - pub const REPLACE: Self = BlendDescriptor { +impl BlendState { + /// Default blending state that replaces destination with the source. + pub const REPLACE: Self = BlendState { src_factor: BlendFactor::One, dst_factor: BlendFactor::Zero, operation: BlendOperation::Add, }; + /// Returns true if the state relies on the constant color, which is + /// set independently on a render command encoder. pub fn uses_color(&self) -> bool { match (self.src_factor, self.dst_factor) { (BlendFactor::BlendColor, _) @@ -687,7 +728,7 @@ impl BlendDescriptor { } } -impl Default for BlendDescriptor { +impl Default for BlendState { fn default() -> Self { Self::REPLACE } @@ -698,24 +739,27 @@ impl Default for BlendDescriptor { #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct ColorStateDescriptor { +pub struct ColorTargetState { /// The [`TextureFormat`] of the image that this pipeline will render to. Must match the the format /// of the corresponding color attachment in [`CommandEncoder::begin_render_pass`]. pub format: TextureFormat, /// The alpha blending that is used for this pipeline. - pub alpha_blend: BlendDescriptor, + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + pub alpha_blend: BlendState, /// The color blending that is used for this pipeline. - pub color_blend: BlendDescriptor, + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + pub color_blend: BlendState, /// Mask which enables/disables writes to different color/alpha channel. + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] pub write_mask: ColorWrite, } -impl From for ColorStateDescriptor { +impl From for ColorTargetState { fn from(format: TextureFormat) -> Self { Self { format, - alpha_blend: BlendDescriptor::REPLACE, - color_blend: BlendDescriptor::REPLACE, + alpha_blend: BlendState::REPLACE, + color_blend: BlendState::REPLACE, write_mask: ColorWrite::ALL, } } @@ -747,6 +791,12 @@ pub enum PrimitiveTopology { TriangleStrip = 4, } +impl Default for PrimitiveTopology { + fn default() -> Self { + PrimitiveTopology::TriangleList + } +} + /// Winding order which classifies the "front" face. #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] @@ -809,25 +859,59 @@ impl Default for PolygonMode { } } -/// Describes the state of the rasterizer in a render pipeline. +/// Describes the state of primitive assembly and rasterization in a render pipeline. #[repr(C)] #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct RasterizationStateDescriptor { +pub struct PrimitiveState { + /// The primitive topology used to interpret vertices. + pub topology: PrimitiveTopology, + /// The format of index buffers for strip topologies. Should be left `None` for non-strip. + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + pub strip_index_format: Option, + /// The face to consider the front for the purpose of culling and stencil operations. + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] pub front_face: FrontFace, + /// The fact culling mode. + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] pub cull_mode: CullMode, /// Controls the way each polygon is rasterized. Can be either `Fill` (default), `Line` or `Point` /// /// Setting this to something other than `Fill` requires `Features::NON_FILL_POLYGON_MODE` to be enabled. + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] pub polygon_mode: PolygonMode, - /// If enabled polygon depth is clamped to 0-1 range instead of being clipped. +} + +/// Describes the multi-sampling state of a render pipeline. +#[repr(C)] +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "trace", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct MultisampleState { + /// The number of samples calculated per pixel (for MSAA). For non-multisampled textures, + /// this should be `1` + pub count: u32, + /// Bitmask that restricts the samples of a pixel modified by this pipeline. All samples + /// can be enabled using the value `!0` + pub mask: u64, + /// When enabled, produces another sample mask per pixel based on the alpha output value, that + /// is ANDed with the sample_mask and the primitive coverage to restrict the set of samples + /// affected by a primitive. /// - /// Requires `Features::DEPTH_CLAMPING` enabled. - pub clamp_depth: bool, - pub depth_bias: i32, - pub depth_bias_slope_scale: f32, - pub depth_bias_clamp: f32, + /// The implicit mask produced for alpha of zero is guaranteed to be zero, and for alpha of one + /// is guaranteed to be all 1-s. + pub alpha_to_coverage_enabled: bool, +} + +impl Default for MultisampleState { + fn default() -> Self { + MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + } + } } bitflags::bitflags! { @@ -848,7 +932,9 @@ bitflags::bitflags! { /// Features are defined by WebGPU specification unless `Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES` is enabled. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct TextureFormatFeatures { + /// Valid bits for `TextureDescriptor::Usage` provided for format creation. pub allowed_usages: TextureUsage, + /// Additional property flags for the format. pub flags: TextureFormatFeatureFlags, } @@ -1437,30 +1523,33 @@ impl Default for ColorWrite { } } +/// State of the stencil operation (fixed-pipeline stage). #[repr(C)] #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct StencilStateDescriptor { +pub struct StencilState { /// Front face mode. - pub front: StencilStateFaceDescriptor, + pub front: StencilStateFace, /// Back face mode. - pub back: StencilStateFaceDescriptor, + pub back: StencilStateFace, /// Stencil values are AND'd with this mask when reading and writing from the stencil buffer. Only low 8 bits are used. pub read_mask: u32, /// Stencil values are AND'd with this mask when writing to the stencil buffer. Only low 8 bits are used. pub write_mask: u32, } -impl StencilStateDescriptor { +impl StencilState { + /// Returns true if the stencil test is enabled. pub fn is_enabled(&self) -> bool { - (self.front != StencilStateFaceDescriptor::IGNORE - || self.back != StencilStateFaceDescriptor::IGNORE) + (self.front != StencilStateFace::IGNORE || self.back != StencilStateFace::IGNORE) && (self.read_mask != 0 || self.write_mask != 0) } + /// Returns true if the state doesn't mutate the target values. pub fn is_read_only(&self) -> bool { self.write_mask == 0 } + /// Returns true if the stencil state uses the reference value for testing. pub fn needs_ref_value(&self) -> bool { self.front.compare.needs_ref_value() || self.back.compare.needs_ref_value() } @@ -1468,10 +1557,10 @@ impl StencilStateDescriptor { /// Describes the depth/stencil state in a render pipeline. #[repr(C)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct DepthStencilStateDescriptor { +pub struct DepthStencilState { /// Format of the depth/stencil buffer, must be special depth format. Must match the the format /// of the depth/stencil attachment in [`CommandEncoder::begin_render_pass`]. pub format: TextureFormat, @@ -1479,16 +1568,40 @@ pub struct DepthStencilStateDescriptor { pub depth_write_enabled: bool, /// Comparison function used to compare depth values in the depth test. pub depth_compare: CompareFunction, - pub stencil: StencilStateDescriptor, + /// Stencil state. + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + pub stencil: StencilState, + + /// Constant depth biasing factor, in basic units of the depth format. + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + pub depth_bias: i32, + /// Slope depth biasing factor. + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + pub depth_bias_slope_scale: f32, + /// Depth bias clamp value (absolute). + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + pub depth_bias_clamp: f32, + + /// If enabled polygon depth is clamped to 0-1 range instead of being clipped. + /// + /// Requires `Features::DEPTH_CLAMPING` enabled. + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + pub clamp_depth: bool, } -impl DepthStencilStateDescriptor { +impl DepthStencilState { + /// Returns true if the depth testing is enabled. pub fn is_depth_enabled(&self) -> bool { self.depth_compare != CompareFunction::Always || self.depth_write_enabled } + /// Returns true if the state doesn't mutate either depth or stencil of the target. pub fn is_read_only(&self) -> bool { !self.depth_write_enabled && self.stencil.is_read_only() } + /// Returns true if the depth bias is applied. + pub fn has_depth_bias(&self) -> bool { + self.depth_bias != 0 || self.depth_bias_slope_scale != 0.0 + } } /// Format of indices used with pipeline. @@ -1540,12 +1653,12 @@ impl Default for StencilOperation { /// Describes stencil state in a render pipeline. /// -/// If you are not using stencil state, set this to [`StencilStateFaceDescriptor::IGNORE`]. +/// If you are not using stencil state, set this to [`StencilStateFace::IGNORE`]. #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct StencilStateFaceDescriptor { +pub struct StencilStateFace { /// Comparison function that determines if the fail_op or pass_op is used on the stencil buffer. pub compare: CompareFunction, /// Operation that is preformed when stencil test fails. @@ -1556,8 +1669,9 @@ pub struct StencilStateFaceDescriptor { pub pass_op: StencilOperation, } -impl StencilStateFaceDescriptor { - pub const IGNORE: Self = StencilStateFaceDescriptor { +impl StencilStateFace { + /// Ignore the stencil state for the face. + pub const IGNORE: Self = StencilStateFace { compare: CompareFunction::Always, fail_op: StencilOperation::Keep, depth_fail_op: StencilOperation::Keep, @@ -1565,7 +1679,7 @@ impl StencilStateFaceDescriptor { }; } -impl Default for StencilStateFaceDescriptor { +impl Default for StencilStateFace { fn default() -> Self { Self::IGNORE } @@ -1596,6 +1710,7 @@ pub enum CompareFunction { } impl CompareFunction { + /// Returns true if the comparison depends on the reference value. pub fn needs_ref_value(self) -> bool { match self { Self::Never | Self::Always => false, @@ -1616,6 +1731,12 @@ pub enum InputStepMode { Instance = 1, } +impl Default for InputStepMode { + fn default() -> Self { + InputStepMode::Vertex + } +} + /// Vertex inputs (attributes) to shaders. /// /// Arrays of these can be made with the [`vertex_attr_array`] macro. Vertex attributes are assumed to be tightly packed. @@ -1623,11 +1744,11 @@ pub enum InputStepMode { #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct VertexAttributeDescriptor { - /// Byte offset of the start of the input - pub offset: BufferAddress, +pub struct VertexAttribute { /// Format of the input pub format: VertexFormat, + /// Byte offset of the start of the input + pub offset: BufferAddress, /// Location for this input. Must match the location in the shader. pub shader_location: ShaderLocation, } @@ -1709,6 +1830,7 @@ pub enum VertexFormat { } impl VertexFormat { + /// Returns the byte size of the format. pub const fn size(&self) -> u64 { match self { Self::Uchar2 | Self::Char2 | Self::Uchar2Norm | Self::Char2Norm => 2, @@ -1800,6 +1922,7 @@ pub struct BufferDescriptor { } impl BufferDescriptor { + /// pub fn map_label(&self, fun: impl FnOnce(&L) -> K) -> BufferDescriptor { BufferDescriptor { label: fun(&self.label), @@ -1821,6 +1944,7 @@ pub struct CommandEncoderDescriptor { } impl CommandEncoderDescriptor { + /// pub fn map_label(&self, fun: impl FnOnce(&L) -> K) -> CommandEncoderDescriptor { CommandEncoderDescriptor { label: fun(&self.label), @@ -1904,10 +2028,16 @@ pub struct SwapChainDescriptor { #[repr(C)] #[derive(Debug)] pub enum SwapChainStatus { + /// No issues. Good, + /// The swap chain is operational, but it does no longer perfectly + /// match the surface. A re-configuration is needed. Suboptimal, + /// Unable to get the next frame, timed out. Timeout, + /// The surface under the swap chain has changed. Outdated, + /// The surface under the swap chain is lost. Lost, } @@ -1918,12 +2048,17 @@ pub enum SwapChainStatus { #[derive(Clone, Copy, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Color { + /// pub r: f64, + /// pub g: f64, + /// pub b: f64, + /// pub a: f64, } +#[allow(missing_docs)] impl Color { pub const TRANSPARENT: Self = Self { r: 0.0, @@ -1983,12 +2118,16 @@ pub enum TextureDimension { #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct Origin3d { + /// pub x: u32, + /// pub y: u32, + /// pub z: u32, } impl Origin3d { + /// Zero origin. pub const ZERO: Self = Self { x: 0, y: 0, z: 0 }; } @@ -2004,8 +2143,11 @@ impl Default for Origin3d { #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct Extent3d { + /// pub width: u32, + /// pub height: u32, + /// pub depth: u32, } @@ -2137,6 +2279,7 @@ pub struct TextureDescriptor { } impl TextureDescriptor { + /// pub fn map_label(&self, fun: impl FnOnce(&L) -> K) -> TextureDescriptor { TextureDescriptor { label: fun(&self.label), @@ -2246,10 +2389,12 @@ pub struct PushConstantRange { #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct CommandBufferDescriptor { + /// Debug label of this command buffer. pub label: L, } impl CommandBufferDescriptor { + /// pub fn map_label(&self, fun: impl FnOnce(&L) -> K) -> CommandBufferDescriptor { CommandBufferDescriptor { label: fun(&self.label), @@ -2268,6 +2413,7 @@ pub struct RenderBundleDescriptor { } impl RenderBundleDescriptor { + /// pub fn map_label(&self, fun: impl FnOnce(&L) -> K) -> RenderBundleDescriptor { RenderBundleDescriptor { label: fun(&self.label), @@ -2360,15 +2506,16 @@ impl Default for BufferBindingType { pub enum TextureSampleType { /// Sampling returns floats. /// - /// If `filterable` is false, the texture can't be sampled with - /// a filtering sampler. - /// /// Example GLSL syntax: /// ```cpp,ignore /// layout(binding = 0) /// uniform texture2D t; /// ``` - Float { filterable: bool }, + Float { + /// If `filterable` is false, the texture can't be sampled with + /// a filtering sampler. + filterable: bool, + }, /// Sampling does the depth reference comparison. /// /// Example GLSL syntax: @@ -2445,16 +2592,17 @@ pub enum StorageTextureAccess { pub enum BindingType { /// A buffer binding. Buffer { + /// Sub-type of the buffer binding. ty: BufferBindingType, /// Indicates that the binding has a dynamic offset. /// One offset must be passed to [`RenderPass::set_bind_group`] for each dynamic binding in increasing order of binding number. - #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] has_dynamic_offset: bool, /// Minimum size of the corresponding `BufferBinding` required to match this entry. /// When pipeline is created, the size has to cover at least the corresponding structure in the shader /// plus one element of the unbound array, which can only be last in the structure. /// If `None`, the check is performed at draw call time instead of pipeline and bind group creation. - #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] min_binding_size: Option, }, /// A sampler that can be used to sample a texture. @@ -2510,6 +2658,7 @@ pub enum BindingType { } impl BindingType { + /// Returns true for buffer bindings with dynamic offseting enabled. pub fn has_dynamic_offset(&self) -> bool { match *self { Self::Buffer { @@ -2537,7 +2686,7 @@ pub struct BindGroupLayoutEntry { /// If this value is Some and `ty` is `BindingType::Texture`, [`Features::SAMPLED_TEXTURE_BINDING_ARRAY`] must be supported. /// /// If this value is Some and `ty` is any other variant, bind group creation will fail. - #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] pub count: Option, } @@ -2564,7 +2713,7 @@ pub struct TextureCopyView { /// The target mip level of the texture. pub mip_level: u32, /// The base texel of the texture in the selected `mip_level`. - #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] pub origin: Origin3d, } @@ -2574,8 +2723,11 @@ pub struct TextureCopyView { #[cfg_attr(feature = "trace", derive(serde::Serialize))] #[cfg_attr(feature = "replay", derive(serde::Deserialize))] pub enum SamplerBorderColor { + /// [0, 0, 0, 0] TransparentBlack, + /// [0, 0, 0, 1] OpaqueBlack, + /// [1, 1, 1, 1] OpaqueWhite, } From cef0a30aa20968ce6fb7fcc73ff01d1b24885cec Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 27 Jan 2021 14:57:17 -0500 Subject: [PATCH 2/2] Add 0.7 changelog --- CHANGELOG.md | 21 +++++++++++++++++++++ wgpu-types/src/lib.rs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6655091d0b..8737ad5c48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Change Log +## v0.7 (TBD) + - Major API changes: + - `RenderPipelineDescriptor` + - `BindingType` + - Features: + - (beta) WGSL support, including the ability to bypass SPIR-V entirely + - (beta) implicit bind group layout support + - timestamp and pipeline statistics queries + - ETC2 and ASTC compressed textures + - (beta) targeting WASM with WebGL backend + - reduced dependencies + - Native-only: + - clamp-to-border addressing + - polygon fill modes + - query a format for extra capabilities + - `f64` support in shaders + - Validation: + - shader interface + - render pipeline descriptor + - vertex buffers + ## v0.6 (2020-08-17) - Crates: - C API is moved to [another repository](https://github.com/gfx-rs/wgpu-native) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 78f7e44d13..b457ea54d9 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2658,7 +2658,7 @@ pub enum BindingType { } impl BindingType { - /// Returns true for buffer bindings with dynamic offseting enabled. + /// Returns true for buffer bindings with dynamic offset enabled. pub fn has_dynamic_offset(&self) -> bool { match *self { Self::Buffer {