Evolve depth clamping into clip control (#2171)

This commit is contained in:
Dzmitry Malyshau 2021-11-10 16:55:27 -05:00 committed by GitHub
parent 27aae2a2a2
commit f25a45f4e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 126 additions and 148 deletions

View File

@ -127,8 +127,8 @@ pub fn init(unstable: bool) -> Extension {
fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
let mut return_features: Vec<&'static str> = vec![];
if features.contains(wgpu_types::Features::DEPTH_CLAMPING) {
return_features.push("depth-clamping");
if features.contains(wgpu_types::Features::DEPTH_CLIP_CONTROL) {
return_features.push("depth-clip-control");
}
if features.contains(wgpu_types::Features::PIPELINE_STATISTICS_QUERY) {
return_features.push("pipeline-statistics-query");
@ -309,105 +309,50 @@ pub struct GpuRequiredFeatures(HashSet<String>);
impl From<GpuRequiredFeatures> for wgpu_types::Features {
fn from(required_features: GpuRequiredFeatures) -> wgpu_types::Features {
let mut features: wgpu_types::Features = wgpu_types::Features::empty();
if required_features.0.contains("depth-clamping") {
features.set(wgpu_types::Features::DEPTH_CLAMPING, true);
}
if required_features.0.contains("pipeline-statistics-query") {
features.set(wgpu_types::Features::PIPELINE_STATISTICS_QUERY, true);
}
if required_features.0.contains("texture-compression-bc") {
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_BC, true);
}
if required_features.0.contains("timestamp-query") {
features.set(wgpu_types::Features::TIMESTAMP_QUERY, true);
}
features.set(wgpu_types::Features::DEPTH_CLIP_CONTROL, required_features.0.contains("depth-clip-control"));
features.set(wgpu_types::Features::PIPELINE_STATISTICS_QUERY, required_features.0.contains("pipeline-statistics-query"));
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_BC, required_features.0.contains("texture-compression-bc"));
features.set(wgpu_types::Features::TIMESTAMP_QUERY, required_features.0.contains("timestamp-query"));
// extended from spec
if required_features.0.contains("mappable-primary-buffers") {
features.set(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, true);
}
if required_features.0.contains("texture-binding-array") {
features.set(wgpu_types::Features::TEXTURE_BINDING_ARRAY, true);
}
if required_features.0.contains("buffer-binding-array") {
features.set(wgpu_types::Features::BUFFER_BINDING_ARRAY, true);
}
if required_features
features.set(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, required_features.0.contains("mappable-primary-buffers"));
features.set(wgpu_types::Features::TEXTURE_BINDING_ARRAY, required_features.0.contains("texture-binding-array"));
features.set(wgpu_types::Features::BUFFER_BINDING_ARRAY, required_features.0.contains("buffer-binding-array"));
features.set(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY, required_features
.0
.contains("storage-resource-binding-array")
{
features.set(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY, true);
}
if required_features
.0
.contains("sampled-texture-and-storage-buffer-array-non-uniform-indexing")
{
.contains("storage-resource-binding-array"));
features.set(
wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
true,
);
}
if required_features
required_features
.0
.contains("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing")
{
.contains("sampled-texture-and-storage-buffer-array-non-uniform-indexing"),
);
features.set(
wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
true,
);
}
if required_features.0.contains("unsized-binding-array") {
features.set(wgpu_types::Features::UNSIZED_BINDING_ARRAY, true);
}
if required_features.0.contains("multi-draw-indirect") {
features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT, true);
}
if required_features.0.contains("multi-draw-indirect-count") {
features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, true);
}
if required_features.0.contains("push-constants") {
features.set(wgpu_types::Features::PUSH_CONSTANTS, true);
}
if required_features.0.contains("address-mode-clamp-to-border") {
features.set(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, true);
}
if required_features.0.contains("texture-compression-etc2") {
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, true);
}
if required_features.0.contains("texture-compression-astc-ldr") {
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, true);
}
if required_features
required_features
.0
.contains("texture-adapter-specific-format-features")
{
.contains("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing"),
);
features.set(wgpu_types::Features::UNSIZED_BINDING_ARRAY, required_features.0.contains("unsized-binding-array"));
features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT, required_features.0.contains("multi-draw-indirect"));
features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, required_features.0.contains("multi-draw-indirect-count"));
features.set(wgpu_types::Features::PUSH_CONSTANTS, required_features.0.contains("push-constants"));
features.set(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, required_features.0.contains("address-mode-clamp-to-border"));
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, required_features.0.contains("texture-compression-etc2"));
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, required_features.0.contains("texture-compression-astc-ldr"));
features.set(
wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
true,
required_features
.0
.contains("texture-adapter-specific-format-features"),
);
}
if required_features.0.contains("shader-float64") {
features.set(wgpu_types::Features::SHADER_FLOAT64, true);
}
if required_features.0.contains("vertex-attribute-64bit") {
features.set(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, true);
}
if required_features.0.contains("conservative-rasterization") {
features.set(wgpu_types::Features::CONSERVATIVE_RASTERIZATION, true);
}
if required_features.0.contains("vertex-writable-storage") {
features.set(wgpu_types::Features::VERTEX_WRITABLE_STORAGE, true);
}
if required_features.0.contains("clear-commands") {
features.set(wgpu_types::Features::CLEAR_COMMANDS, true);
}
if required_features.0.contains("spirv-shader-passthrough") {
features.set(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH, true);
}
if required_features.0.contains("shader-primitive-index") {
features.set(wgpu_types::Features::SHADER_PRIMITIVE_INDEX, true);
}
features.set(wgpu_types::Features::SHADER_FLOAT64, required_features.0.contains("shader-float64"));
features.set(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, required_features.0.contains("vertex-attribute-64bit"));
features.set(wgpu_types::Features::CONSERVATIVE_RASTERIZATION, required_features.0.contains("conservative-rasterization"));
features.set(wgpu_types::Features::VERTEX_WRITABLE_STORAGE, required_features.0.contains("vertex-writable-storage"));
features.set(wgpu_types::Features::CLEAR_COMMANDS, required_features.0.contains("clear-commands"));
features.set(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH, required_features.0.contains("spirv-shader-passthrough"));
features.set(wgpu_types::Features::SHADER_PRIMITIVE_INDEX, required_features.0.contains("shader-primitive-index"));
features
}

View File

@ -171,7 +171,7 @@ struct GpuPrimitiveState {
strip_index_format: Option<wgpu_types::IndexFormat>,
front_face: wgpu_types::FrontFace,
cull_mode: GpuCullMode,
clamp_depth: bool,
unclipped_depth: bool,
}
impl From<GpuPrimitiveState> for wgpu_types::PrimitiveState {
@ -181,7 +181,7 @@ impl From<GpuPrimitiveState> for wgpu_types::PrimitiveState {
strip_index_format: value.strip_index_format,
front_face: value.front_face,
cull_mode: value.cull_mode.into(),
clamp_depth: value.clamp_depth,
unclipped_depth: value.unclipped_depth,
polygon_mode: Default::default(), // native-only
conservative: false, // native-only
}

View File

@ -1,35 +1,35 @@
/*! Render Bundles
## Software implementation
## Software implementation
The path from nothing to using a render bundle consists of 3 phases.
The path from nothing to using a render bundle consists of 3 phases.
### Initial command encoding
### Initial command encoding
User creates a `RenderBundleEncoder` and populates it by issuing commands
from `bundle_ffi` module, just like with `RenderPass`, except that the
set of available commands is reduced. Everything is written into a `RawPass`.
User creates a `RenderBundleEncoder` and populates it by issuing commands
from `bundle_ffi` module, just like with `RenderPass`, except that the
set of available commands is reduced. Everything is written into a `RawPass`.
### Bundle baking
### Bundle baking
Once the commands are encoded, user calls `render_bundle_encoder_finish`.
This is perhaps the most complex part of the logic. It consumes the
commands stored in `RawPass`, while validating everything, tracking the state,
and re-recording the commands into a separate `Vec<RenderCommand>`. It
doesn't actually execute any commands.
Once the commands are encoded, user calls `render_bundle_encoder_finish`.
This is perhaps the most complex part of the logic. It consumes the
commands stored in `RawPass`, while validating everything, tracking the state,
and re-recording the commands into a separate `Vec<RenderCommand>`. It
doesn't actually execute any commands.
What's more important, is that the produced vector of commands is "normalized",
which means it can be executed verbatim without any state tracking. More
formally, "normalized" command stream guarantees that any state required by
a draw call is set explicitly by one of the commands between the draw call
and the last changing of the pipeline.
What's more important, is that the produced vector of commands is "normalized",
which means it can be executed verbatim without any state tracking. More
formally, "normalized" command stream guarantees that any state required by
a draw call is set explicitly by one of the commands between the draw call
and the last changing of the pipeline.
### Execution
### Execution
When the bundle is used in an actual render pass, `RenderBundle::execute` is
called. It goes through the commands and issues them into the native command
buffer. Thanks to the "normalized" property, it doesn't track any bind group
invalidations or index format changes.
When the bundle is used in an actual render pass, `RenderBundle::execute` is
called. It goes through the commands and issues them into the native command
buffer. Thanks to the "normalized" property, it doesn't track any bind group
invalidations or index format changes.
!*/
#![allow(clippy::reversed_empty_ranges)]

View File

@ -2211,8 +2211,8 @@ impl<A: HalApi> Device<A> {
);
}
if desc.primitive.clamp_depth {
self.require_features(wgt::Features::DEPTH_CLAMPING)?;
if desc.primitive.unclipped_depth {
self.require_features(wgt::Features::DEPTH_CLIP_CONTROL)?;
}
if desc.primitive.polygon_mode == wgt::PolygonMode::Line {

View File

@ -1,12 +1,12 @@
/*! Presentation.
## Lifecycle
## Lifecycle
Whenever a submission detects the use of any surface texture, it adds it to the device
tracker for the duration of the submission (temporarily, while recording).
It's added with `UNINITIALIZED` state and transitioned into `empty()` state.
When this texture is presented, we remove it from the device tracker as well as
extract it from the hub.
Whenever a submission detects the use of any surface texture, it adds it to the device
tracker for the duration of the submission (temporarily, while recording).
It's added with `UNINITIALIZED` state and transitioned into `empty()` state.
When this texture is presented, we remove it from the device tracker as well as
extract it from the hub.
!*/
#[cfg(feature = "trace")]

View File

@ -169,7 +169,7 @@ impl super::Adapter {
};
let mut features = wgt::Features::empty()
| wgt::Features::DEPTH_CLAMPING
| wgt::Features::DEPTH_CLIP_CONTROL
| wgt::Features::MAPPABLE_PRIMARY_BUFFERS
//TODO: Naga part
//| wgt::Features::TEXTURE_BINDING_ARRAY

View File

@ -1275,7 +1275,7 @@ impl crate::Device<super::Api> for super::Device {
DepthBias: bias.constant,
DepthBiasClamp: bias.clamp,
SlopeScaledDepthBias: bias.slope_scale,
DepthClipEnable: if desc.primitive.clamp_depth { 0 } else { 1 },
DepthClipEnable: if desc.primitive.unclipped_depth { 0 } else { 1 },
MultisampleEnable: if desc.multisample.count > 1 { 1 } else { 0 },
ForcedSampleCount: 0,
AntialiasedLineEnable: 0,

View File

@ -280,7 +280,7 @@ impl super::Adapter {
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
| wgt::Features::CLEAR_COMMANDS;
features.set(
wgt::Features::DEPTH_CLAMPING,
wgt::Features::DEPTH_CLIP_CONTROL,
extensions.contains("GL_EXT_depth_clamp"),
);
features.set(

View File

@ -254,7 +254,7 @@ pub(super) fn map_primitive_state(state: &wgt::PrimitiveState) -> super::Primiti
Some(wgt::Face::Back) => glow::BACK,
None => 0,
},
clamp_depth: state.clamp_depth,
unclipped_depth: state.unclipped_depth,
}
}

View File

@ -546,7 +546,7 @@ struct StencilState {
struct PrimitiveState {
front_face: u32,
cull_face: u32,
clamp_depth: bool,
unclipped_depth: bool,
}
type InvalidatedAttachments = ArrayVec<u32, { crate::MAX_COLOR_TARGETS + 2 }>;

View File

@ -66,7 +66,7 @@ impl super::Queue {
gl.disable(glow::BLEND);
gl.disable(glow::CULL_FACE);
gl.disable(glow::POLYGON_OFFSET_FILL);
if self.features.contains(wgt::Features::DEPTH_CLAMPING) {
if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
gl.disable(glow::DEPTH_CLAMP);
}
}
@ -927,8 +927,9 @@ impl super::Queue {
} else {
gl.disable(glow::CULL_FACE);
}
if self.features.contains(wgt::Features::DEPTH_CLAMPING) {
if state.clamp_depth {
if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
//Note: this is a bit tricky, since we are controlling the clip, not the clamp.
if state.unclipped_depth {
gl.enable(glow::DEPTH_CLAMP);
} else {
gl.disable(glow::DEPTH_CLAMP);

View File

@ -861,7 +861,8 @@ impl super::PrivateCapabilities {
Self::version_at_least(major, minor, 11, 0)
},
//Depth clipping is supported on all macOS GPU families and iOS family 4 and later
supports_depth_clamping: device.supports_feature_set(MTLFeatureSet::iOS_GPUFamily4_v1)
supports_depth_clip_control: device
.supports_feature_set(MTLFeatureSet::iOS_GPUFamily4_v1)
|| os_is_mac,
}
}
@ -877,7 +878,7 @@ impl super::PrivateCapabilities {
| F::POLYGON_MODE_LINE
| F::CLEAR_COMMANDS;
features.set(F::DEPTH_CLAMPING, self.supports_depth_clamping);
features.set(F::DEPTH_CLIP_CONTROL, self.supports_depth_clip_control);
features.set(
F::TEXTURE_BINDING_ARRAY

View File

@ -906,8 +906,8 @@ impl crate::Device<super::Api> for super::Device {
raw_triangle_fill_mode,
raw_front_winding: conv::map_winding(desc.primitive.front_face),
raw_cull_mode: conv::map_cull_mode(desc.primitive.cull_mode),
raw_depth_clip_mode: if self.features.contains(wgt::Features::DEPTH_CLAMPING) {
Some(if desc.primitive.clamp_depth {
raw_depth_clip_mode: if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
Some(if desc.primitive.unclipped_depth {
mtl::MTLDepthClipMode::Clamp
} else {
mtl::MTLDepthClipMode::Clip

View File

@ -222,7 +222,7 @@ struct PrivateCapabilities {
supports_arrays_of_textures: bool,
supports_arrays_of_textures_write: bool,
supports_mutability: bool,
supports_depth_clamping: bool,
supports_depth_clip_control: bool,
}
#[derive(Clone, Debug)]

View File

@ -22,6 +22,7 @@ pub struct PhysicalDeviceFeatures {
timeline_semaphore: Option<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>,
image_robustness: Option<vk::PhysicalDeviceImageRobustnessFeaturesEXT>,
robustness2: Option<vk::PhysicalDeviceRobustness2FeaturesEXT>,
depth_clip_enable: Option<vk::PhysicalDeviceDepthClipEnableFeaturesEXT>,
}
// This is safe because the structs have `p_next: *mut c_void`, which we null out/never read.
@ -53,6 +54,9 @@ impl PhysicalDeviceFeatures {
if let Some(ref mut feature) = self.robustness2 {
info = info.push_next(feature);
}
if let Some(ref mut feature) = self.depth_clip_enable {
info = info.push_next(feature);
}
info
}
@ -102,7 +106,6 @@ impl PhysicalDeviceFeatures {
.multi_draw_indirect(
requested_features.contains(wgt::Features::MULTI_DRAW_INDIRECT),
)
.depth_clamp(requested_features.contains(wgt::Features::DEPTH_CLAMPING))
.fill_mode_non_solid(requested_features.intersects(
wgt::Features::POLYGON_MODE_LINE | wgt::Features::POLYGON_MODE_POINT,
))
@ -281,6 +284,17 @@ impl PhysicalDeviceFeatures {
} else {
None
},
depth_clip_enable: if enabled_extensions.contains(&vk::ExtDepthClipEnableFn::name()) {
Some(
vk::PhysicalDeviceDepthClipEnableFeaturesEXT::builder()
.depth_clip_enable(
requested_features.contains(wgt::Features::DEPTH_CLIP_CONTROL),
)
.build(),
)
} else {
None
},
}
}
@ -307,7 +321,6 @@ impl PhysicalDeviceFeatures {
//if self.core.dual_src_blend != 0
features.set(F::MULTI_DRAW_INDIRECT, self.core.multi_draw_indirect != 0);
features.set(F::DEPTH_CLAMPING, self.core.depth_clamp != 0);
features.set(F::POLYGON_MODE_LINE, self.core.fill_mode_non_solid != 0);
features.set(F::POLYGON_MODE_POINT, self.core.fill_mode_non_solid != 0);
//if self.core.depth_bounds != 0 {
@ -462,6 +475,10 @@ impl PhysicalDeviceFeatures {
}
}
if let Some(ref feature) = self.depth_clip_enable {
features.set(F::DEPTH_CLIP_CONTROL, feature.depth_clip_enable != 0);
}
(features, dl_flags)
}
@ -540,6 +557,10 @@ impl PhysicalDeviceCapabilities {
extensions.push(vk::ExtConservativeRasterizationFn::name());
}
if requested_features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
extensions.push(vk::ExtDepthClipEnableFn::name());
}
extensions
}

View File

@ -1382,7 +1382,6 @@ impl crate::Device<super::Api> for super::Device {
};
let mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::builder()
.depth_clamp_enable(desc.primitive.clamp_depth)
.polygon_mode(conv::map_polygon_mode(desc.primitive.polygon_mode))
.front_face(conv::map_front_face(desc.primitive.front_face))
.line_width(1.0);
@ -1396,6 +1395,13 @@ impl crate::Device<super::Api> for super::Device {
if desc.primitive.conservative {
vk_rasterization = vk_rasterization.push_next(&mut vk_rasterization_conservative_state);
}
let mut vk_depth_clip_state =
vk::PipelineRasterizationDepthClipStateCreateInfoEXT::builder()
.depth_clip_enable(false)
.build();
if desc.primitive.unclipped_depth {
vk_rasterization = vk_rasterization.push_next(&mut vk_depth_clip_state);
}
let mut vk_depth_stencil = vk::PipelineDepthStencilStateCreateInfo::builder();
if let Some(ref ds) = desc.depth_stencil {

View File

@ -163,10 +163,10 @@ bitflags::bitflags! {
#[repr(transparent)]
#[derive(Default)]
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.
/// By default, polygon depth is clipped to 0-1 range before/during rasterization.
/// 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
/// With this extension, we can disabling clipping. That allows
/// shadow map occluders to be rendered into a tighter depth range.
///
/// Supported platforms:
@ -174,7 +174,7 @@ bitflags::bitflags! {
/// - some mobile chips
///
/// This is a web and native feature.
const DEPTH_CLAMPING = 1 << 0;
const DEPTH_CLIP_CONTROL = 1 << 0;
/// Enables BCn family of compressed textures. All BCn textures use 4x4 pixel blocks
/// with 8 or 16 bytes per block.
///
@ -1309,11 +1309,11 @@ pub struct PrimitiveState {
/// The face culling mode.
#[cfg_attr(feature = "serde", serde(default))]
pub cull_mode: Option<Face>,
/// If set to true, the polygon depth is clamped to 0-1 range instead of being clipped.
/// If set to true, the polygon depth is not clipped to 0-1 before rasterization.
///
/// Enabling this requires `Features::DEPTH_CLAMPING` to be enabled.
/// Enabling this requires `Features::DEPTH_CLIP_CONTROL` to be enabled.
#[cfg_attr(feature = "serde", serde(default))]
pub clamp_depth: bool,
pub unclipped_depth: bool,
/// Controls the way each polygon is rasterized. Can be either `Fill` (default), `Line` or `Point`
///
/// Setting this to `Line` requires `Features::POLYGON_MODE_LINE` to be enabled.

View File

@ -210,7 +210,7 @@ impl Example {
impl framework::Example for Example {
fn optional_features() -> wgpu::Features {
wgpu::Features::DEPTH_CLAMPING
wgpu::Features::DEPTH_CLIP_CONTROL
}
fn init(
@ -510,7 +510,9 @@ impl framework::Example for Example {
topology: wgpu::PrimitiveTopology::TriangleList,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
clamp_depth: device.features().contains(wgpu::Features::DEPTH_CLAMPING),
unclipped_depth: device
.features()
.contains(wgpu::Features::DEPTH_CLIP_CONTROL),
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {

View File

@ -604,7 +604,8 @@ fn map_primitive_state(primitive: &wgt::PrimitiveState) -> web_sys::GpuPrimitive
PrimitiveTopology::TriangleStrip => pt::TriangleStrip,
});
//mapped.clamp_depth(primitive.clamp_depth);
//TODO:
//mapped.unclipped_depth(primitive.unclipped_depth);
mapped
}
@ -1026,7 +1027,8 @@ impl crate::Context for Context {
let mut mapped_desc = web_sys::GpuDeviceDescriptor::new();
let possible_features = [
(wgt::Features::DEPTH_CLAMPING, Gfn::DepthClamping),
//TODO: update the name
(wgt::Features::DEPTH_CLIP_CONTROL, Gfn::DepthClamping),
// TODO (_, Gfn::Depth24unormStencil8),
// TODO (_, Gfn::Depth32floatStencil8),
(