diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ed59bed423..1cedb848196 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,40 @@ Bottom level categories: ## Unreleased +### Major Changes + +#### Depth/stencil state changes + +BREAKING CHANGE: Pipeline descriptors now use `DepthStencilStateIdl` instead of `DepthStencilState`. +The new struct makes the `depth_write_enabled` and `depth_compare` fields optional, to match WebGPU. + +The simplest way to adapt to this change is to use `.into()` to convert to the new struct: + +```diff +-depth_stencil: Some(wgpu::DepthStencilState { +- format: wgpu::TextureFormat::Depth32Float, +- depth_write_enabled: true, +- depth_compare: wgpu::CompareFunction::Less, +- stencil: wgpu::StencilState::default(), +- bias: wgpu::DepthBiasState::default(), +-}), ++depth_stencil: Some(wgpu::DepthStencilState { ++ format: wgpu::TextureFormat::Depth32Float, ++ depth_write_enabled: true, ++ depth_compare: wgpu::CompareFunction::Less, ++ stencil: wgpu::StencilState::default(), ++ bias: wgpu::DepthBiasState::default(), ++}.into()), +``` + +There are also new constructors which may be used instead of a struct literal: +`DepthStencilState::new` (for simultaneous depth and stencil operations), +`DepthStencilState::depth` (for depth operations), and `DepthStencilState::stencil` (for stencil operations). + +`DepthStencilState` may be updated to match `DepthStencilStateIdl` in the future. +In anticipation of this, the constructors are associated methods on +`DepthStencilState` even though they construct `DepthStencilStateIdl`. + ### New Features #### General diff --git a/cts_runner/test.lst b/cts_runner/test.lst index 5c079fbf6c7..6c4bca6a8a1 100644 --- a/cts_runner/test.lst +++ b/cts_runner/test.lst @@ -229,13 +229,7 @@ webgpu:api,validation,render_pass,render_pass_descriptor:resolveTarget,* webgpu:api,validation,render_pass,render_pass_descriptor:timestampWrite,query_index:* webgpu:api,validation,render_pass,render_pass_descriptor:timestampWrites,query_set_type:* webgpu:api,validation,render_pass,resolve:resolve_attachment:* -webgpu:api,validation,render_pipeline,depth_stencil_state:depth_bias:* -webgpu:api,validation,render_pipeline,depth_stencil_state:depth_test:* -webgpu:api,validation,render_pipeline,depth_stencil_state:depth_write,frag_depth:* -webgpu:api,validation,render_pipeline,depth_stencil_state:depth_write:* -webgpu:api,validation,render_pipeline,depth_stencil_state:format:* -webgpu:api,validation,render_pipeline,depth_stencil_state:stencil_test:* -webgpu:api,validation,render_pipeline,depth_stencil_state:stencil_write:* +webgpu:api,validation,render_pipeline,depth_stencil_state:* webgpu:api,validation,render_pipeline,float32_blendable:* webgpu:api,validation,render_pipeline,fragment_state:color_target_exists:* webgpu:api,validation,render_pipeline,fragment_state:dual_source_blending,use_blend_src:* diff --git a/deno_webgpu/device.rs b/deno_webgpu/device.rs index d3f7811dbc4..657b58c98b7 100644 --- a/deno_webgpu/device.rs +++ b/deno_webgpu/device.rs @@ -882,15 +882,10 @@ impl GPUDevice { pass_op: depth_stencil.stencil_back.pass_op.into(), }; - wgpu_types::DepthStencilState { + wgpu_types::DepthStencilStateIdl { format: depth_stencil.format.into(), - depth_write_enabled: depth_stencil - .depth_write_enabled - .unwrap_or_default(), - depth_compare: depth_stencil - .depth_compare - .map(Into::into) - .unwrap_or(wgpu_types::CompareFunction::Never), // TODO(wgpu): should be optional here + depth_write_enabled: depth_stencil.depth_write_enabled, + depth_compare: depth_stencil.depth_compare.map(Into::into), stencil: wgpu_types::StencilState { front, back, diff --git a/examples/features/src/shadow/mod.rs b/examples/features/src/shadow/mod.rs index 7a4fb9ea97d..fb5f495c0aa 100644 --- a/examples/features/src/shadow/mod.rs +++ b/examples/features/src/shadow/mod.rs @@ -506,17 +506,20 @@ impl crate::framework::Example for Example { .contains(wgpu::Features::DEPTH_CLIP_CONTROL), ..Default::default() }, - depth_stencil: Some(wgpu::DepthStencilState { - format: Self::SHADOW_FORMAT, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::LessEqual, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState { - constant: 2, // corresponds to bilinear filtering - slope_scale: 2.0, - clamp: 0.0, - }, - }), + depth_stencil: Some( + wgpu::DepthStencilState { + format: Self::SHADOW_FORMAT, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::LessEqual, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState { + constant: 2, // corresponds to bilinear filtering + slope_scale: 2.0, + clamp: 0.0, + }, + } + .into(), + ), multisample: wgpu::MultisampleState::default(), multiview_mask: None, cache: None, @@ -645,13 +648,16 @@ impl crate::framework::Example for Example { cull_mode: Some(wgpu::Face::Back), ..Default::default() }, - depth_stencil: Some(wgpu::DepthStencilState { - format: Self::DEPTH_FORMAT, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::Less, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), + depth_stencil: Some( + wgpu::DepthStencilState { + format: Self::DEPTH_FORMAT, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + } + .into(), + ), multisample: wgpu::MultisampleState::default(), multiview_mask: None, cache: None, diff --git a/examples/features/src/skybox/mod.rs b/examples/features/src/skybox/mod.rs index e5c5df7ff75..e4cf316b4cd 100644 --- a/examples/features/src/skybox/mod.rs +++ b/examples/features/src/skybox/mod.rs @@ -210,13 +210,16 @@ impl crate::framework::Example for Example { front_face: wgpu::FrontFace::Cw, ..Default::default() }, - depth_stencil: Some(wgpu::DepthStencilState { - format: Self::DEPTH_FORMAT, - depth_write_enabled: false, - depth_compare: wgpu::CompareFunction::LessEqual, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), + depth_stencil: Some( + wgpu::DepthStencilState { + format: Self::DEPTH_FORMAT, + depth_write_enabled: false, + depth_compare: wgpu::CompareFunction::LessEqual, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + } + .into(), + ), multisample: wgpu::MultisampleState::default(), multiview_mask: None, cache: None, @@ -244,13 +247,16 @@ impl crate::framework::Example for Example { front_face: wgpu::FrontFace::Cw, ..Default::default() }, - depth_stencil: Some(wgpu::DepthStencilState { - format: Self::DEPTH_FORMAT, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::LessEqual, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), + depth_stencil: Some( + wgpu::DepthStencilState { + format: Self::DEPTH_FORMAT, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::LessEqual, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + } + .into(), + ), multisample: wgpu::MultisampleState::default(), multiview_mask: None, cache: None, diff --git a/examples/features/src/stencil_triangles/mod.rs b/examples/features/src/stencil_triangles/mod.rs index 05e782470e1..a5c29dae0c6 100644 --- a/examples/features/src/stencil_triangles/mod.rs +++ b/examples/features/src/stencil_triangles/mod.rs @@ -83,22 +83,25 @@ impl crate::framework::Example for Example { })], }), primitive: Default::default(), - depth_stencil: Some(wgpu::DepthStencilState { - format: wgpu::TextureFormat::Stencil8, - depth_write_enabled: false, - depth_compare: wgpu::CompareFunction::Always, - stencil: wgpu::StencilState { - front: wgpu::StencilFaceState { - compare: wgpu::CompareFunction::Always, - pass_op: wgpu::StencilOperation::Replace, - ..Default::default() + depth_stencil: Some( + wgpu::DepthStencilState { + format: wgpu::TextureFormat::Stencil8, + depth_write_enabled: false, + depth_compare: wgpu::CompareFunction::Always, + stencil: wgpu::StencilState { + front: wgpu::StencilFaceState { + compare: wgpu::CompareFunction::Always, + pass_op: wgpu::StencilOperation::Replace, + ..Default::default() + }, + back: wgpu::StencilFaceState::IGNORE, + read_mask: !0, + write_mask: !0, }, - back: wgpu::StencilFaceState::IGNORE, - read_mask: !0, - write_mask: !0, - }, - bias: Default::default(), - }), + bias: Default::default(), + } + .into(), + ), multisample: wgpu::MultisampleState::default(), multiview_mask: None, cache: None, @@ -120,11 +123,9 @@ impl crate::framework::Example for Example { targets: &[Some(config.view_formats[0].into())], }), primitive: Default::default(), - depth_stencil: Some(wgpu::DepthStencilState { - format: wgpu::TextureFormat::Stencil8, - depth_write_enabled: false, - depth_compare: wgpu::CompareFunction::Always, - stencil: wgpu::StencilState { + depth_stencil: Some(wgpu::DepthStencilState::stencil( + wgpu::TextureFormat::Stencil8, + wgpu::StencilState { front: wgpu::StencilFaceState { compare: wgpu::CompareFunction::Greater, ..Default::default() @@ -133,8 +134,7 @@ impl crate::framework::Example for Example { read_mask: !0, write_mask: !0, }, - bias: Default::default(), - }), + )), multisample: wgpu::MultisampleState::default(), multiview_mask: None, cache: None, diff --git a/examples/features/src/water/mod.rs b/examples/features/src/water/mod.rs index e07200fb7b4..756b4fe6c8d 100644 --- a/examples/features/src/water/mod.rs +++ b/examples/features/src/water/mod.rs @@ -555,16 +555,14 @@ impl crate::framework::Example for Example { // will work. Since this is water, we need to read from the // depth buffer both as a texture in the shader, and as an // input attachment to do depth-testing. We don't write, so - // depth_write_enabled is set to false. This is called - // RODS or read-only depth stencil. - depth_stencil: Some(wgpu::DepthStencilState { - // We don't use stencil. - format: wgpu::TextureFormat::Depth32Float, - depth_write_enabled: false, - depth_compare: wgpu::CompareFunction::Less, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), + // depth_write_enabled is set to false. This is called RODS, + // or read-only depth stencil. Here, we don't use stencil. + depth_stencil: Some(wgpu::DepthStencilState::depth( + wgpu::TextureFormat::Depth32Float, + false, + wgpu::CompareFunction::Less, + wgpu::DepthBiasState::default(), + )), // No multisampling is used. multisample: wgpu::MultisampleState::default(), multiview_mask: None, @@ -603,7 +601,7 @@ impl crate::framework::Example for Example { depth_compare: wgpu::CompareFunction::Less, stencil: wgpu::StencilState::default(), bias: wgpu::DepthBiasState::default(), - }), + }.into()), multisample: wgpu::MultisampleState::default(), multiview_mask: None, cache: None diff --git a/tests/tests/wgpu-gpu/mesh_shader/mod.rs b/tests/tests/wgpu-gpu/mesh_shader/mod.rs index 6cb3e04686c..f31c6c24a23 100644 --- a/tests/tests/wgpu-gpu/mesh_shader/mod.rs +++ b/tests/tests/wgpu-gpu/mesh_shader/mod.rs @@ -238,7 +238,7 @@ fn mesh_pipeline_build(ctx: &TestingContext, info: MeshPipelineTestInfo) { cull_mode: Some(wgpu::Face::Back), ..Default::default() }, - depth_stencil: Some(depth_state), + depth_stencil: Some(depth_state.into()), multisample: Default::default(), multiview: None, cache: None, @@ -324,7 +324,7 @@ fn mesh_draw(ctx: &TestingContext, draw_type: DrawType, info: MeshPipelineTestIn cull_mode: Some(wgpu::Face::Back), ..Default::default() }, - depth_stencil: Some(depth_state), + depth_stencil: Some(depth_state.into()), multisample: Default::default(), multiview: None, cache: None, diff --git a/tests/tests/wgpu-gpu/occlusion_query/mod.rs b/tests/tests/wgpu-gpu/occlusion_query/mod.rs index 0f6de327c58..b9694f6b805 100644 --- a/tests/tests/wgpu-gpu/occlusion_query/mod.rs +++ b/tests/tests/wgpu-gpu/occlusion_query/mod.rs @@ -48,13 +48,16 @@ static OCCLUSION_QUERY: GpuTestConfiguration = GpuTestConfiguration::new() }, fragment: None, primitive: wgpu::PrimitiveState::default(), - depth_stencil: Some(wgpu::DepthStencilState { - format: wgpu::TextureFormat::Depth32Float, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::Less, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), + depth_stencil: Some( + wgpu::DepthStencilState { + format: wgpu::TextureFormat::Depth32Float, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + } + .into(), + ), multisample: wgpu::MultisampleState::default(), multiview_mask: None, cache: None, diff --git a/tests/tests/wgpu-gpu/render_pass_ownership.rs b/tests/tests/wgpu-gpu/render_pass_ownership.rs index 140851d6937..8bc7a75499a 100644 --- a/tests/tests/wgpu-gpu/render_pass_ownership.rs +++ b/tests/tests/wgpu-gpu/render_pass_ownership.rs @@ -537,13 +537,16 @@ fn resource_setup(ctx: &TestingContext) -> ResourceSetup { strip_index_format: Some(wgpu::IndexFormat::Uint32), ..Default::default() }, - depth_stencil: Some(wgpu::DepthStencilState { - format: depth_stencil_format, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::LessEqual, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), + depth_stencil: Some( + wgpu::DepthStencilState { + format: depth_stencil_format, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::LessEqual, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + } + .into(), + ), multisample: wgpu::MultisampleState { count: target_msaa, mask: !0, diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 99898d77de2..fd7d7801f25 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -4159,6 +4159,7 @@ impl Device { .map_err(pipeline::CreateRenderPipelineError::ColorAttachment)?; if let Some(ds) = depth_stencil_state { + // See . target_specified = true; let error = 'error: { if !ds.format.is_depth_stencil_format() { @@ -4185,6 +4186,23 @@ impl Device { } else if ds.is_depth_enabled() { break 'error Some(pipeline::DepthStencilStateError::FormatNotDepth(ds.format)); } + if has_depth_attachment { + let Some(depth_write_enabled) = ds.depth_write_enabled else { + break 'error Some( + pipeline::DepthStencilStateError::MissingDepthWriteEnabled(ds.format), + ); + }; + + let depth_compare_required = depth_write_enabled + || ds.stencil.front.depth_fail_op != wgt::StencilOperation::Keep + || ds.stencil.back.depth_fail_op != wgt::StencilOperation::Keep; + if depth_compare_required && ds.depth_compare.is_none() { + break 'error Some(pipeline::DepthStencilStateError::MissingDepthCompare( + ds.format, + )); + } + } + if ds.stencil.is_enabled() && !aspect.contains(hal::FormatAspects::STENCIL) { break 'error Some(pipeline::DepthStencilStateError::FormatNotStencil( ds.format, @@ -4272,7 +4290,7 @@ impl Device { let stage_desc = &vertex.stage; let stage = validation::ShaderStageForValidation::Vertex { topology: desc.primitive.topology, - compare_function: desc.depth_stencil.as_ref().map(|d| d.depth_compare), + compare_function: desc.depth_stencil.as_ref().and_then(|d| d.depth_compare), }; let stage_bit = stage.to_wgt_bit(); diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 9991c20a6a9..064e607c7a2 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -476,7 +476,7 @@ pub struct RenderPipelineDescriptor< pub primitive: wgt::PrimitiveState, /// The effect of draw calls on the depth and stencil aspects of the output target, if any. #[cfg_attr(feature = "serde", serde(default))] - pub depth_stencil: Option, + pub depth_stencil: Option, /// The multi-sampling properties of the pipeline. #[cfg_attr(feature = "serde", serde(default))] pub multisample: wgt::MultisampleState, @@ -509,7 +509,7 @@ pub struct MeshPipelineDescriptor< pub primitive: wgt::PrimitiveState, /// The effect of draw calls on the depth and stencil aspects of the output target, if any. #[cfg_attr(feature = "serde", serde(default))] - pub depth_stencil: Option, + pub depth_stencil: Option, /// The multi-sampling properties of the pipeline. #[cfg_attr(feature = "serde", serde(default))] pub multisample: wgt::MultisampleState, @@ -548,7 +548,7 @@ pub struct GeneralRenderPipelineDescriptor< pub primitive: wgt::PrimitiveState, /// The effect of draw calls on the depth and stencil aspects of the output target, if any. #[cfg_attr(feature = "serde", serde(default))] - pub depth_stencil: Option, + pub depth_stencil: Option, /// The multi-sampling properties of the pipeline. #[cfg_attr(feature = "serde", serde(default))] pub multisample: wgt::MultisampleState, @@ -644,6 +644,10 @@ pub enum DepthStencilStateError { InvalidSampleCount(u32, wgt::TextureFormat, Vec, Vec), #[error("Depth bias is not compatible with non-triangle topology {0:?}")] DepthBiasWithIncompatibleTopology(wgt::PrimitiveTopology), + #[error("Depth compare function must be specified for depth format {0:?}")] + MissingDepthCompare(wgt::TextureFormat), + #[error("Depth write enabled must be specified for depth format {0:?}")] + MissingDepthWriteEnabled(wgt::TextureFormat), } #[derive(Clone, Debug, Error)] diff --git a/wgpu-hal/src/dx12/conv.rs b/wgpu-hal/src/dx12/conv.rs index aa241364ce8..7baec511ae1 100644 --- a/wgpu-hal/src/dx12/conv.rs +++ b/wgpu-hal/src/dx12/conv.rs @@ -370,15 +370,15 @@ fn map_stencil_face(face: &wgt::StencilFaceState) -> Direct3D12::D3D12_DEPTH_STE } } -pub fn map_depth_stencil(ds: &wgt::DepthStencilState) -> Direct3D12::D3D12_DEPTH_STENCIL_DESC { +pub fn map_depth_stencil(ds: &wgt::DepthStencilStateIdl) -> Direct3D12::D3D12_DEPTH_STENCIL_DESC { Direct3D12::D3D12_DEPTH_STENCIL_DESC { DepthEnable: ds.is_depth_enabled().into(), - DepthWriteMask: if ds.depth_write_enabled { + DepthWriteMask: if ds.depth_write_enabled.unwrap_or_default() { Direct3D12::D3D12_DEPTH_WRITE_MASK_ALL } else { Direct3D12::D3D12_DEPTH_WRITE_MASK_ZERO }, - DepthFunc: map_comparison(ds.depth_compare), + DepthFunc: map_comparison(ds.depth_compare.unwrap_or_default()), StencilEnable: ds.stencil.is_enabled().into(), StencilReadMask: ds.stencil.read_mask as u8, StencilWriteMask: ds.stencil.write_mask as u8, diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index d8c00d3871f..ab127317acf 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -755,9 +755,7 @@ impl crate::Device for super::Device { MipLODBias: 0f32, MaxAnisotropy: desc.anisotropy_clamp as u32, - ComparisonFunc: conv::map_comparison( - desc.compare.unwrap_or(wgt::CompareFunction::Always), - ), + ComparisonFunc: conv::map_comparison(desc.compare.unwrap_or_default()), BorderColor: border_color, MinLOD: desc.lod_clamp.start, MaxLOD: desc.lod_clamp.end, diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 720a7d84e76..53a882d47ae 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1436,8 +1436,8 @@ impl crate::Device for super::Device { vertex_attributes, color_targets, depth: desc.depth_stencil.as_ref().map(|ds| super::DepthState { - function: conv::map_compare_func(ds.depth_compare), - mask: ds.depth_write_enabled, + function: conv::map_compare_func(ds.depth_compare.unwrap_or_default()), + mask: ds.depth_write_enabled.unwrap_or_default(), }), depth_bias: desc .depth_stencil diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 8bafcfe80b7..1c67a77738e 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -2469,7 +2469,7 @@ pub struct RenderPipelineDescriptor< /// The properties of the pipeline at the primitive assembly and rasterization level. pub primitive: wgt::PrimitiveState, /// The effect of draw calls on the depth and stencil aspects of the output target, if any. - pub depth_stencil: Option, + pub depth_stencil: Option, /// The multi-sampling properties of the pipeline. pub multisample: wgt::MultisampleState, /// The fragment stage for this pipeline. diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 7dc84d3f66e..bf8e751b467 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -66,11 +66,13 @@ fn create_stencil_desc( } fn create_depth_stencil_desc( - state: &wgt::DepthStencilState, + state: &wgt::DepthStencilStateIdl, ) -> Retained { let desc = MTLDepthStencilDescriptor::new(); - desc.setDepthCompareFunction(conv::map_compare_function(state.depth_compare)); - desc.setDepthWriteEnabled(state.depth_write_enabled); + desc.setDepthCompareFunction(conv::map_compare_function( + state.depth_compare.unwrap_or_default() + )); + desc.setDepthWriteEnabled(state.depth_write_enabled.unwrap_or_default()); let s = &state.stencil; if s.is_enabled() { let front_desc = create_stencil_desc(&s.front, s.read_mask, s.write_mask); diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 415841d6afa..581f60f9be3 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -1908,8 +1908,8 @@ impl crate::Device for super::Device { if ds.is_depth_enabled() { vk_depth_stencil = vk_depth_stencil .depth_test_enable(true) - .depth_write_enable(ds.depth_write_enabled) - .depth_compare_op(conv::map_comparison(ds.depth_compare)); + .depth_write_enable(ds.depth_write_enabled.unwrap_or_default()) + .depth_compare_op(conv::map_comparison(ds.depth_compare.unwrap_or_default())); } if ds.stencil.is_enabled() { let s = &ds.stencil; diff --git a/wgpu-types/src/render.rs b/wgpu-types/src/render.rs index edee8794554..9d888ddd1fb 100644 --- a/wgpu-types/src/render.rs +++ b/wgpu-types/src/render.rs @@ -554,7 +554,7 @@ impl Default for StencilFaceState { /// Corresponds to [WebGPU `GPUCompareFunction`]( /// https://gpuweb.github.io/gpuweb/#enumdef-gpucomparefunction). #[repr(C)] -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum CompareFunction { @@ -577,6 +577,7 @@ pub enum CompareFunction { /// Function passes if new value is greater than or equal to existing value GreaterEqual = 7, /// Function always passes + #[default] Always = 8, } @@ -798,6 +799,14 @@ impl Default for Operations { /// /// Corresponds to [WebGPU `GPUDepthStencilState`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate). +/// +/// For backwards-compatibility reasons, this struct has non-optional +/// `depth_write_enabled` and `depth_compare` fields. They may change in the +/// future to be optional, i.e., to match `DepthStencilStateIdl`. +/// +/// It is recommended to use one of the `DepthStencilState::new`, +/// `DepthStencilState::depth`, or `DepthStencilState::stencil` constructors. +/// These will continue to work even if this struct changes in the future. #[repr(C)] #[derive(Clone, Debug, Hash, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -819,17 +828,148 @@ pub struct DepthStencilState { pub bias: DepthBiasState, } +/// Describes the depth/stencil state in a render pipeline. +/// +/// Corresponds to [WebGPU `GPUDepthStencilState`]( +/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate). +/// +/// This version more closely matches the IDL in the WebGPU spec by +/// making the `depth_write_enabled` and `depth_compare` fields +/// optional. +#[repr(C)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct DepthStencilStateIdl { + /// Format of the depth/stencil buffer, must be special depth format. Must match the format + /// of the depth/stencil attachment in [`CommandEncoder::begin_render_pass`][CEbrp]. + /// + #[doc = link_to_wgpu_docs!(["CEbrp"]: "struct.CommandEncoder.html#method.begin_render_pass")] + pub format: crate::TextureFormat, + /// If disabled, depth will not be written to. Specify if `format` is a + /// depth format. + pub depth_write_enabled: Option, + /// Comparison function used to compare depth values in the depth test. + /// Specify if `depth_write_enabled` is `true` or either stencil face + /// `depth_fail_op` is not `Keep`. + pub depth_compare: Option, + /// Stencil state. + #[cfg_attr(feature = "serde", serde(default))] + pub stencil: StencilState, + /// Depth bias state. + #[cfg_attr(feature = "serde", serde(default))] + pub bias: DepthBiasState, +} + impl DepthStencilState { + /// Construct `DepthStencilState` for both depth and stencil operations. + /// + /// (For one or the other, use [`DepthStencilState::depth`] or + /// [`DepthStencilState::stencil`].) + /// + /// Note that this method returns the forwards-compatible struct + /// `DepthStencilStateIdl`. + /// + /// Panics if `format` is not a depth-and-stencil format. + #[expect(clippy::new_ret_no_self)] // forwards compatibility + pub fn new( + format: crate::TextureFormat, + depth_write_enabled: bool, + depth_compare: CompareFunction, + stencil: StencilState, + bias: DepthBiasState, + ) -> DepthStencilStateIdl { + assert!( + format.has_depth_aspect() && format.has_stencil_aspect(), + "{format:?} is not a depth-and-stencil format" + ); + DepthStencilStateIdl { + format, + depth_write_enabled: Some(depth_write_enabled), + depth_compare: Some(depth_compare), + stencil, + bias, + } + } + + /// Construct `DepthStencilState` for a depth operation. + /// + /// Note that this method returns the forwards-compatible struct + /// `DepthStencilStateIdl`. + /// + /// Panics if `format` does not have a depth aspect. + pub fn depth( + format: crate::TextureFormat, + depth_write_enabled: bool, + depth_compare: CompareFunction, + bias: DepthBiasState, + ) -> DepthStencilStateIdl { + assert!( + format.has_depth_aspect(), + "{format:?} is not a depth format" + ); + DepthStencilStateIdl { + format, + depth_write_enabled: Some(depth_write_enabled), + depth_compare: Some(depth_compare), + stencil: StencilState::default(), + bias, + } + } + + /// Construct `DepthStencilState` for a stencil operation. + /// + /// Note that this method returns the forwards-compatible struct + /// `DepthStencilStateIdl`. + /// + /// Panics if `format` does not have a stencil aspect. + pub fn stencil(format: crate::TextureFormat, stencil: StencilState) -> DepthStencilStateIdl { + assert!( + format.has_stencil_aspect(), + "{format:?} is not a stencil format" + ); + DepthStencilStateIdl { + format, + depth_write_enabled: None, + depth_compare: None, + stencil, + bias: DepthBiasState::default(), + } + } +} + +/// Converts `DepthStencilState` to the new `DepthStencilStateIdl`. +/// +/// This is provided for ease of migration. Prefer to use the +/// `DepthStencilState` associated constructor methods, as they will continue to +/// work even if `DepthStencilState` is updated to match `DepthStencilStateIdl` +/// in the future. +impl From for DepthStencilStateIdl { + fn from(state: DepthStencilState) -> Self { + // We need to blank out the depth-related fields if it's not a depth + // format, because validation will check. + let is_depth = state.format.has_depth_aspect(); + Self { + format: state.format, + depth_write_enabled: is_depth.then_some(state.depth_write_enabled), + depth_compare: is_depth.then_some(state.depth_compare), + stencil: state.stencil, + bias: state.bias, + } + } +} + +impl DepthStencilStateIdl { /// Returns true if the depth testing is enabled. #[must_use] pub fn is_depth_enabled(&self) -> bool { - self.depth_compare != CompareFunction::Always || self.depth_write_enabled + self.depth_compare.unwrap_or_default() != CompareFunction::Always + || self.depth_write_enabled.unwrap_or_default() } /// Returns true if the state doesn't mutate the depth buffer. #[must_use] pub fn is_depth_read_only(&self) -> bool { - !self.depth_write_enabled + !self.depth_write_enabled.unwrap_or_default() } /// Returns true if the state doesn't mutate the stencil. diff --git a/wgpu/src/api/render_pipeline.rs b/wgpu/src/api/render_pipeline.rs index ebc89633b3b..a8d070de196 100644 --- a/wgpu/src/api/render_pipeline.rs +++ b/wgpu/src/api/render_pipeline.rs @@ -224,7 +224,7 @@ pub struct RenderPipelineDescriptor<'a> { /// The properties of the pipeline at the primitive assembly and rasterization level. pub primitive: PrimitiveState, /// The effect of draw calls on the depth and stencil aspects of the output target, if any. - pub depth_stencil: Option, + pub depth_stencil: Option, /// The multi-sampling properties of the pipeline. pub multisample: MultisampleState, /// The compiled fragment stage, its entry point, and the color targets. @@ -319,7 +319,7 @@ pub struct MeshPipelineDescriptor<'a> { /// The properties of the pipeline at the primitive assembly and rasterization level. pub primitive: PrimitiveState, /// The effect of draw calls on the depth and stencil aspects of the output target, if any. - pub depth_stencil: Option, + pub depth_stencil: Option, /// The multi-sampling properties of the pipeline. pub multisample: MultisampleState, /// The compiled fragment stage, its entry point, and the color targets. diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 742e33cfb08..92c894b45ab 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -433,10 +433,14 @@ fn map_stencil_state_face(desc: &wgt::StencilFaceState) -> webgpu_sys::GpuStenci mapped } -fn map_depth_stencil_state(desc: &wgt::DepthStencilState) -> webgpu_sys::GpuDepthStencilState { +fn map_depth_stencil_state(desc: &wgt::DepthStencilStateIdl) -> webgpu_sys::GpuDepthStencilState { let mapped = webgpu_sys::GpuDepthStencilState::new(map_texture_format(desc.format)); - mapped.set_depth_compare(map_compare_function(desc.depth_compare)); - mapped.set_depth_write_enabled(desc.depth_write_enabled); + if let Some(compare) = desc.depth_compare { + mapped.set_depth_compare(map_compare_function(compare)); + } + if let Some(write_enabled) = desc.depth_write_enabled { + mapped.set_depth_write_enabled(write_enabled); + } mapped.set_depth_bias(desc.bias.constant); mapped.set_depth_bias_clamp(desc.bias.clamp); mapped.set_depth_bias_slope_scale(desc.bias.slope_scale); diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 7f8dad864c1..6a9ecfc7ded 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -134,8 +134,8 @@ pub use wgt::{ BufferTransition, BufferUsages, BufferUses, Color, ColorTargetState, ColorWrites, CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, CooperativeMatrixProperties, CooperativeScalarType, CopyExternalImageDestInfo, CoreCounters, DepthBiasState, - DepthStencilState, DeviceLostReason, DeviceType, DownlevelCapabilities, DownlevelFlags, - DownlevelLimits, Dx12BackendOptions, Dx12Compiler, Dx12SwapchainKind, + DepthStencilState, DepthStencilStateIdl, DeviceLostReason, DeviceType, DownlevelCapabilities, + DownlevelFlags, DownlevelLimits, Dx12BackendOptions, Dx12Compiler, Dx12SwapchainKind, Dx12UseFrameLatencyWaitableObject, DxcShaderModel, DynamicOffset, ExperimentalFeatures, Extent3d, ExternalTextureFormat, ExternalTextureTransferFunction, Face, Features, FeaturesWGPU, FeaturesWebGPU, FilterMode, FrontFace, GlBackendOptions, GlFenceBehavior, Gles3MinorVersion,