// Copyright (c) 2016 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. //! Depth and stencil operations description. //! //! After the fragment shader has finished running, each fragment goes through the depth //! and stencil 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 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 std::ops::Range; use std::u32; /// Configuration of the depth and stencil tests. #[derive(Debug, Clone)] pub struct DepthStencil { /// Comparison to use between the depth value of each fragment and the depth value currently /// in the depth buffer. pub depth_compare: Compare, /// If `true`, then the value in the depth buffer will be updated when the depth test succeeds. pub depth_write: bool, /// 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. pub depth_bounds_test: DepthBounds, /// Stencil operations to use for points, lines and triangles whose front is facing the user. pub stencil_front: Stencil, /// Stencil operations to use for triangles whose back is facing the user. pub stencil_back: Stencil, } impl DepthStencil { /// Creates a `DepthStencil` where both the depth and stencil tests are disabled and have /// no effect. #[inline] pub fn disabled() -> DepthStencil { DepthStencil { depth_write: false, depth_compare: Compare::Always, depth_bounds_test: DepthBounds::Disabled, stencil_front: Default::default(), stencil_back: Default::default(), } } /// Creates a `DepthStencil` with a `Less` depth test, `depth_write` set to true, and stencil /// testing disabled. #[inline] pub fn simple_depth_test() -> DepthStencil { DepthStencil { depth_write: true, depth_compare: Compare::Less, depth_bounds_test: DepthBounds::Disabled, stencil_front: Default::default(), stencil_back: Default::default(), } } } impl Default for DepthStencil { #[inline] fn default() -> DepthStencil { DepthStencil::disabled() } } /// Configuration of a stencil test. #[derive(Debug, Copy, Clone)] pub struct Stencil { /// The comparison to perform between the existing stencil value in the stencil buffer, and /// the reference value (given by `reference`). pub compare: Compare, /// 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 failed. pub fail_op: StencilOp, /// The operation to perform when the stencil test passed but the depth test failed. pub depth_fail_op: StencilOp, /// Selects the bits of the unsigned integer stencil values participating in the stencil test. /// /// Ignored if `compare` is `Never` or `Always`. /// /// If `None`, then this value is dynamic and will need to be set when drawing. Doesn't apply /// if `compare` is `Never` or `Always`. /// /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in /// `stencil_back` (but the content can be different). If this value is `None` in /// `stencil_front`, then it must also be `None` in `stencil_back`. This rule doesn't apply /// if `compare` is `Never` or `Always`. pub compare_mask: Option, /// Selects the bits of the unsigned integer stencil values updated by the stencil test in the /// stencil framebuffer attachment. /// /// If `None`, then this value is dynamic and will need to be set when drawing. /// /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in /// `stencil_back` (but the content can be different). If this value is `None` in /// `stencil_front`, then it must also be `None` in `stencil_back`. pub write_mask: Option, /// Reference value that is used in the unsigned stencil comparison. /// /// If `None`, then this value is dynamic and will need to be set when drawing. /// /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in /// `stencil_back` (but the content can be different). If this value is `None` in /// `stencil_front`, then it must also be `None` in `stencil_back`. pub reference: Option, } impl Stencil { /// Returns true if the stencil operation will always result in `Keep`. #[inline] pub fn always_keep(&self) -> bool { match self.compare { Compare::Always => { self.pass_op == StencilOp::Keep && self.depth_fail_op == StencilOp::Keep } Compare::Never => self.fail_op == StencilOp::Keep, _ => { self.pass_op == StencilOp::Keep && self.fail_op == StencilOp::Keep && self.depth_fail_op == StencilOp::Keep } } } } impl Default for Stencil { #[inline] fn default() -> Stencil { Stencil { compare: Compare::Never, pass_op: StencilOp::Keep, fail_op: StencilOp::Keep, depth_fail_op: StencilOp::Keep, compare_mask: Some(u32::MAX), write_mask: Some(u32::MAX), reference: Some(u32::MAX), } } } /// Operation to perform after the depth and stencil tests. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(i32)] pub enum StencilOp { Keep = ash::vk::StencilOp::KEEP.as_raw(), Zero = ash::vk::StencilOp::ZERO.as_raw(), Replace = ash::vk::StencilOp::REPLACE.as_raw(), IncrementAndClamp = ash::vk::StencilOp::INCREMENT_AND_CLAMP.as_raw(), DecrementAndClamp = ash::vk::StencilOp::DECREMENT_AND_CLAMP.as_raw(), Invert = ash::vk::StencilOp::INVERT.as_raw(), IncrementAndWrap = ash::vk::StencilOp::INCREMENT_AND_WRAP.as_raw(), DecrementAndWrap = ash::vk::StencilOp::DECREMENT_AND_WRAP.as_raw(), } impl From for ash::vk::StencilOp { #[inline] fn from(val: StencilOp) -> Self { Self::from_raw(val as i32) } } /// Specifies a face for stencil operations. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(u32)] pub enum StencilFaces { Front = ash::vk::StencilFaceFlags::FRONT.as_raw(), Back = ash::vk::StencilFaceFlags::BACK.as_raw(), FrontAndBack = ash::vk::StencilFaceFlags::FRONT_AND_BACK.as_raw(), } impl From for ash::vk::StencilFaceFlags { #[inline] fn from(val: StencilFaces) -> Self { Self::from_raw(val as u32) } } /// 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, } /// Allows you to ask the GPU to exclude fragments that are outside of a certain range. #[derive(Debug, Clone, PartialEq)] pub enum DepthBounds { /// The test is disabled. All fragments pass the depth bounds test. Disabled, /// Fragments that are within the given range do pass the test. Values are depth values /// between 0.0 and 1.0. Fixed(Range), /// The depth bounds test is enabled, but the range will need to specified when you submit /// a draw command. Dynamic, } impl DepthBounds { /// Returns true if equal to `DepthBounds::Dynamic`. #[inline] pub fn is_dynamic(&self) -> bool { match self { &DepthBounds::Dynamic => true, _ => false, } } } /// Specifies how two values should be compared to decide whether a test passes or fails. /// /// Used for both depth testing and stencil testing. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(i32)] pub enum Compare { /// The test never passes. Never = ash::vk::CompareOp::NEVER.as_raw(), /// The test passes if `value < reference_value`. Less = ash::vk::CompareOp::LESS.as_raw(), /// The test passes if `value == reference_value`. Equal = ash::vk::CompareOp::EQUAL.as_raw(), /// The test passes if `value <= reference_value`. LessOrEqual = ash::vk::CompareOp::LESS_OR_EQUAL.as_raw(), /// The test passes if `value > reference_value`. Greater = ash::vk::CompareOp::GREATER.as_raw(), /// The test passes if `value != reference_value`. NotEqual = ash::vk::CompareOp::NOT_EQUAL.as_raw(), /// The test passes if `value >= reference_value`. GreaterOrEqual = ash::vk::CompareOp::GREATER_OR_EQUAL.as_raw(), /// The test always passes. Always = ash::vk::CompareOp::ALWAYS.as_raw(), } impl From for ash::vk::CompareOp { #[inline] fn from(val: Compare) -> Self { Self::from_raw(val as i32) } }