diff --git a/CHANGELOG.md b/CHANGELOG.md index 18b305d0d5..8c9f02ed0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,22 @@ Bottom level categories: ## Unreleased +### Major Changes + +#### @invariant Warning + +When using CompareFunction::Equal or CompareFunction::NotEqual on a pipeline, there is now a warning logged if the vertex +shader does not have a @invariant tag on it. On some machines, rendering the same triangles multiple times without an +@invariant tag will result in slightly different depths for every pixel. Because the *Equal functions rely on depth being +the same every time it is rendered, we now warn if it is missing. + +```diff +-@vertex +-fn vert_main(v_in: VertexInput) -> @builtin(position) vec4 {...} ++@vertex ++fn vert_main(v_in: VertexInput) -> @builtin(position) @invariant vec4 {...} +``` + ### Bug Fixes #### General @@ -47,6 +63,9 @@ Bottom level categories: ### Changes +#### General +- Add warning when using CompareFunction::*Equal with vertex shader that is missing @invariant tag by @cwfitzgerald in [#2887](https://github.com/gfx-rs/wgpu/pull/2887) + #### Metal - Extract the generic code into `get_metal_layer` by @jinleili in [#2826](https://github.com/gfx-rs/wgpu/pull/2826) diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index bee775e0d9..bc3553f0bb 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -2379,6 +2379,7 @@ impl Device { &desc.stage.entry_point, flag, io, + None, )?; } } @@ -2704,6 +2705,7 @@ impl Device { &stage.entry_point, flag, io, + desc.depth_stencil.as_ref().map(|d| d.depth_compare), ) .map_err(|error| pipeline::CreateRenderPipelineError::Stage { stage: flag, @@ -2750,6 +2752,7 @@ impl Device { &fragment.stage.entry_point, flag, io, + desc.depth_stencil.as_ref().map(|d| d.depth_compare), ) .map_err(|error| pipeline::CreateRenderPipelineError::Stage { stage: flag, diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 0264edb29d..aef7cc46a9 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -963,6 +963,7 @@ impl Interface { entry_point_name: &str, stage_bit: wgt::ShaderStages, inputs: StageIo, + compare_function: Option, ) -> Result { // Since a shader module can have multiple entry points with the same name, // we need to look for one with the right execution model. @@ -1183,6 +1184,21 @@ impl Interface { Varying::Local { ref iv, .. } => iv.ty.dim.num_components(), Varying::BuiltIn(_) => 0, }; + + if let Some( + cmp @ wgt::CompareFunction::Equal | cmp @ wgt::CompareFunction::NotEqual, + ) = compare_function + { + if let Varying::BuiltIn(naga::BuiltIn::Position { invariant: false }) = *output + { + log::warn!( + "Vertex shader with entry point {entry_point_name} outputs a @builtin(position) without the @invariant \ + attribute and is used in a pipeline with {cmp:?}. On some machines, this can cause bad artifacting as {cmp:?} assumes \ + the values output from the vertex shader exactly match the value in the depth buffer. The @invariant attribute on the \ + @builtin(position) vertex output ensures that the exact same pixel depths are used every render." + ); + } + } } } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index dcdc02b2fb..53f3c2499b 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2602,13 +2602,17 @@ pub enum CompareFunction { Never = 1, /// Function passes if new value less than existing value Less = 2, - /// Function passes if new value is equal to existing value + /// Function passes if new value is equal to existing value. When using + /// this compare function, make sure to mark your Vertex Shader's `@builtin(position)` + /// output as `@invariant` to prevent artifacting. Equal = 3, /// Function passes if new value is less than or equal to existing value LessEqual = 4, /// Function passes if new value is greater than existing value Greater = 5, - /// Function passes if new value is not equal to existing value + /// Function passes if new value is not equal to existing value. When using + /// this compare function, make sure to mark your Vertex Shader's `@builtin(position)` + /// output as `@invariant` to prevent artifacting. NotEqual = 6, /// Function passes if new value is greater than or equal to existing value GreaterEqual = 7,