diff --git a/wgpu-core/src/conv.rs b/wgpu-core/src/conv.rs index 0b15c42823..0e88169e41 100644 --- a/wgpu-core/src/conv.rs +++ b/wgpu-core/src/conv.rs @@ -635,7 +635,7 @@ pub fn map_rasterization_state_descriptor( ) -> hal::pso::Rasterizer { use hal::pso; pso::Rasterizer { - depth_clamping: false, + depth_clamping: desc.clamp_depth, polygon_mode: pso::PolygonMode::Fill, cull_face: match desc.cull_mode { wgt::CullMode::None => pso::Face::empty(), diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 3899131af4..7292bff879 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -2109,10 +2109,12 @@ impl Global { let color_states = &desc.color_states; let depth_stencil_state = desc.depth_stencil_state.as_ref(); - let rasterization_state = desc.rasterization_state.as_ref(); - let rasterizer = conv::map_rasterization_state_descriptor( - &rasterization_state.cloned().unwrap_or_default(), - ); + let rasterization_state = desc + .rasterization_state + .as_ref() + .cloned() + .unwrap_or_default(); + let rasterizer = conv::map_rasterization_state_descriptor(&rasterization_state); let mut interface = validation::StageInterface::default(); let mut validated_stages = wgt::ShaderStage::empty(); @@ -2200,6 +2202,14 @@ impl Global { let (device_guard, mut token) = hub.devices.read(&mut token); let device = &device_guard[device_id]; + if rasterization_state.clamp_depth + && !device.features.contains(wgt::Features::DEPTH_CLAMPING) + { + return Err(pipeline::RenderPipelineError::MissingFeature( + wgt::Features::DEPTH_CLAMPING, + )); + } + let (raw_pipeline, layout_ref_count) = { let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); let (bgl_guard, mut token) = hub.bind_group_layouts.read(&mut token); diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 836f46a103..3f840c2208 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -127,6 +127,10 @@ impl Adapter { let mut features = wgt::Features::default() | wgt::Features::MAPPABLE_PRIMARY_BUFFERS | wgt::Features::PUSH_CONSTANTS; + features.set( + wgt::Features::DEPTH_CLAMPING, + adapter_features.contains(hal::Features::DEPTH_CLAMP), + ); features.set( wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY, adapter_features.contains(hal::Features::TEXTURE_DESCRIPTOR_ARRAY), diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 215a9b5c3c..42578b2600 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -55,6 +55,7 @@ pub type RenderPipelineDescriptor<'a> = #[derive(Clone, Debug)] pub enum RenderPipelineError { + MissingFeature(wgt::Features), InvalidVertexAttributeOffset { location: wgt::ShaderLocation, offset: BufferAddress, diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 72059b0b25..ea5824dce9 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -131,6 +131,18 @@ bitflags::bitflags! { #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct Features: u64 { + /// By default, polygon depth is clipped to 0-1 range. Anything outside of that range + /// is rejected, and respective fragments are not touched. + /// + /// With this extension, we can force clamping of the polygon depth to 0-1. That allows + /// shadow map occluders to be rendered into a tighter depth range. + /// + /// Supported platforms: + /// - desktops + /// - some mobile chips + /// + /// This is a web and native feature. + const DEPTH_CLAMPING = 0x0000_0000_0000_0001; /// Webgpu only allows the MAP_READ and MAP_WRITE buffer usage to be matched with /// COPY_DST and COPY_SRC respectively. This removes this requirement. /// @@ -543,6 +555,10 @@ impl Default for CullMode { pub struct RasterizationStateDescriptor { pub front_face: FrontFace, pub cull_mode: CullMode, + /// If enabled polygon depth is clamped to 0-1 range instead of being clipped. + /// + /// Requires `Features::DEPTH_CLAMPING` enabled. + pub clamp_depth: bool, pub depth_bias: i32, pub depth_bias_slope_scale: f32, pub depth_bias_clamp: f32,