aboutsummaryrefslogtreecommitdiff
path: root/src/pipeline/graphics/depth_stencil.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/pipeline/graphics/depth_stencil.rs')
-rw-r--r--src/pipeline/graphics/depth_stencil.rs338
1 files changed, 338 insertions, 0 deletions
diff --git a/src/pipeline/graphics/depth_stencil.rs b/src/pipeline/graphics/depth_stencil.rs
new file mode 100644
index 0000000..650be60
--- /dev/null
+++ b/src/pipeline/graphics/depth_stencil.rs
@@ -0,0 +1,338 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Configures the operation of the depth, stencil and depth bounds tests.
+//!
+//! The depth test passes of fails depending on how the depth value of each fragment compares
+//! to the existing depth value in the depth buffer at that fragment's location. Depth values
+//! are always between 0.0 and 1.0.
+//!
+//! The depth bounds test allows you to ask the GPU to exclude fragments that are outside of a
+//! certain range. This is done in addition to the regular depth test.
+//!
+//! The stencil test passes or fails depending on how a reference value compares to the existing
+//! value in the stencil buffer at each fragment's location. Depending on the outcome of the
+//! depth and stencil tests, the value of the stencil buffer at that location can be updated.
+
+use crate::{macros::vulkan_enum, pipeline::StateMode};
+use std::ops::RangeInclusive;
+
+/// The state in a graphics pipeline describing how the depth, depth bounds and stencil tests
+/// should behave.
+#[derive(Clone, Debug)]
+pub struct DepthStencilState {
+ /// The state of the depth test.
+ ///
+ /// If set to `None`, the depth test is disabled, all fragments will pass and no depth writes
+ /// are performed.
+ pub depth: Option<DepthState>,
+
+ /// The state of the depth bounds test.
+ ///
+ /// If set to `None`, the depth bounds test is disabled, all fragments will pass.
+ pub depth_bounds: Option<DepthBoundsState>,
+
+ /// The state of the stencil test.
+ ///
+ /// If set to `None`, the stencil test is disabled, all fragments will pass and no stencil
+ /// writes are performed.
+ pub stencil: Option<StencilState>,
+}
+
+impl DepthStencilState {
+ /// Creates a `DepthStencilState` where all tests are disabled and have no effect.
+ #[inline]
+ pub fn disabled() -> Self {
+ Self {
+ depth: Default::default(),
+ depth_bounds: Default::default(),
+ stencil: Default::default(),
+ }
+ }
+
+ /// Creates a `DepthStencilState` with a `Less` depth test, `depth_write` set to true, and other
+ /// tests disabled.
+ #[inline]
+ pub fn simple_depth_test() -> Self {
+ Self {
+ depth: Some(DepthState {
+ enable_dynamic: false,
+ compare_op: StateMode::Fixed(CompareOp::Less),
+ write_enable: StateMode::Fixed(true),
+ }),
+ depth_bounds: Default::default(),
+ stencil: Default::default(),
+ }
+ }
+}
+
+impl Default for DepthStencilState {
+ /// Returns [`DepthStencilState::disabled()`].
+ #[inline]
+ fn default() -> Self {
+ DepthStencilState::disabled()
+ }
+}
+
+/// The state in a graphics pipeline describing how the depth test should behave when enabled.
+#[derive(Clone, Copy, Debug)]
+pub struct DepthState {
+ /// Sets whether depth testing should be enabled and disabled dynamically. If set to `false`,
+ /// depth testing is always enabled.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub enable_dynamic: bool,
+
+ /// Sets whether the value in the depth buffer will be updated when the depth test succeeds.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub write_enable: StateMode<bool>,
+
+ /// Comparison operation to use between the depth value of each incoming fragment and the depth
+ /// value currently in the depth buffer.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub compare_op: StateMode<CompareOp>,
+}
+
+impl Default for DepthState {
+ /// Creates a `DepthState` with no dynamic state, depth writes disabled and `compare_op` set
+ /// to always pass.
+ #[inline]
+ fn default() -> Self {
+ Self {
+ enable_dynamic: false,
+ write_enable: StateMode::Fixed(false),
+ compare_op: StateMode::Fixed(CompareOp::Always),
+ }
+ }
+}
+
+/// The state in a graphics pipeline describing how the depth bounds test should behave when
+/// enabled.
+#[derive(Clone, Debug)]
+pub struct DepthBoundsState {
+ /// Sets whether depth bounds testing should be enabled and disabled dynamically. If set to
+ /// `false`, depth bounds testing is always enabled.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub enable_dynamic: bool,
+
+ /// The minimum and maximum depth values to use for the test. Fragments with values outside this
+ /// range are discarded.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub bounds: StateMode<RangeInclusive<f32>>,
+}
+
+impl Default for DepthBoundsState {
+ /// Creates a `DepthBoundsState` with no dynamic state and the bounds set to `0.0..=1.0`.
+ #[inline]
+ fn default() -> Self {
+ Self {
+ enable_dynamic: false,
+ bounds: StateMode::Fixed(0.0..=1.0),
+ }
+ }
+}
+
+/// The state in a graphics pipeline describing how the stencil test should behave when enabled.
+///
+/// Dynamic state can only be enabled or disabled for both faces at once. Therefore, the dynamic
+/// state values in `StencilOpState`, must match: the values for `front` and `back` must either both
+/// be `Fixed` or both be `Dynamic`.
+#[derive(Clone, Debug)]
+pub struct StencilState {
+ /// Sets whether stencil testing should be enabled and disabled dynamically. If set to
+ /// `false`, stencil testing is always enabled.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub enable_dynamic: bool,
+
+ /// The stencil operation state to use for points and lines, and for triangles whose front is
+ /// facing the user.
+ pub front: StencilOpState,
+
+ /// The stencil operation state to use for triangles whose back is facing the user.
+ pub back: StencilOpState,
+}
+
+/// Stencil test operations for a single face.
+#[derive(Clone, Copy, Debug)]
+pub struct StencilOpState {
+ /// The stencil operations to perform.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub ops: StateMode<StencilOps>,
+
+ /// A bitmask that selects the bits of the unsigned integer stencil values participating in the
+ /// stencil test. Ignored if `compare_op` is `Never` or `Always`.
+ pub compare_mask: StateMode<u32>,
+
+ /// A bitmask that selects the bits of the unsigned integer stencil values updated by the
+ /// stencil test in the stencil framebuffer attachment. Ignored if the relevant operation is
+ /// `Keep`.
+ pub write_mask: StateMode<u32>,
+
+ /// Reference value that is used in the unsigned stencil comparison. The stencil test is
+ /// considered to pass if the `compare_op` between the stencil buffer value and this reference
+ /// value yields true.
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if culling is disabled, and the `reference` values of the front and back face
+ /// are not equal, then the
+ /// [`separate_stencil_mask_ref`](crate::device::Features::separate_stencil_mask_ref)
+ /// feature must be enabled on the device.
+ pub reference: StateMode<u32>,
+}
+
+impl Default for StencilOpState {
+ /// Creates a `StencilOpState` with no dynamic state, `compare_op` set to `Never`, the stencil
+ /// operations set to `Keep`, and the masks and reference values set to `u32::MAX`.
+ #[inline]
+ fn default() -> StencilOpState {
+ StencilOpState {
+ ops: StateMode::Fixed(Default::default()),
+ compare_mask: StateMode::Fixed(u32::MAX),
+ write_mask: StateMode::Fixed(u32::MAX),
+ reference: StateMode::Fixed(u32::MAX),
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct StencilOps {
+ /// The operation to perform when the stencil test failed.
+ pub fail_op: StencilOp,
+
+ /// The operation to perform when both the depth test and the stencil test passed.
+ pub pass_op: StencilOp,
+
+ /// The operation to perform when the stencil test passed but the depth test failed.
+ pub depth_fail_op: StencilOp,
+
+ /// The comparison to perform between the existing stencil value in the stencil buffer, and
+ /// the reference value (given by `reference`).
+ pub compare_op: CompareOp,
+}
+
+impl Default for StencilOps {
+ /// Creates a `StencilOps` with no dynamic state, `compare_op` set to `Never` and the stencil
+ /// operations set to `Keep`.
+ #[inline]
+ fn default() -> Self {
+ Self {
+ pass_op: StencilOp::Keep,
+ fail_op: StencilOp::Keep,
+ depth_fail_op: StencilOp::Keep,
+ compare_op: CompareOp::Never,
+ }
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Operation to perform after the depth and stencil tests.
+ StencilOp = StencilOp(i32);
+
+ // TODO: document
+ Keep = KEEP,
+
+ // TODO: document
+ Zero = ZERO,
+
+ // TODO: document
+ Replace = REPLACE,
+
+ // TODO: document
+ IncrementAndClamp = INCREMENT_AND_CLAMP,
+
+ // TODO: document
+ DecrementAndClamp = DECREMENT_AND_CLAMP,
+
+ // TODO: document
+ Invert = INVERT,
+
+ // TODO: document
+ IncrementAndWrap = INCREMENT_AND_WRAP,
+
+ // TODO: document
+ DecrementAndWrap = DECREMENT_AND_WRAP,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Specifies a face for stencil operations.
+ StencilFaces = StencilFaceFlags(u32);
+
+ // TODO: document
+ Front = FRONT,
+
+ // TODO: document
+ Back = BACK,
+
+ // TODO: document
+ FrontAndBack = FRONT_AND_BACK,
+}
+
+/// Specifies a dynamic state value for the front and back faces.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct DynamicStencilValue {
+ pub front: u32,
+ pub back: u32,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Specifies how two values should be compared to decide whether a test passes or fails.
+ ///
+ /// Used for both depth testing and stencil testing.
+ CompareOp = CompareOp(i32);
+
+ /// The test never passes.
+ Never = NEVER,
+
+ /// The test passes if `value < reference_value`.
+ Less = LESS,
+
+ /// The test passes if `value == reference_value`.
+ Equal = EQUAL,
+
+ /// The test passes if `value <= reference_value`.
+ LessOrEqual = LESS_OR_EQUAL,
+
+ /// The test passes if `value > reference_value`.
+ Greater = GREATER,
+
+ /// The test passes if `value != reference_value`.
+ NotEqual = NOT_EQUAL,
+
+ /// The test passes if `value >= reference_value`.
+ GreaterOrEqual = GREATER_OR_EQUAL,
+
+ /// The test always passes.
+ Always = ALWAYS,
+}