blob: 84d1e03e0b8a8f459b1aaf3dab0ee20a4b093109 [file] [log] [blame]
// 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.
//! 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<u32>,
/// 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<u32>,
/// 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<u32>,
}
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<StencilOp> 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<StencilFaces> 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<f32>),
/// 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<Compare> for ash::vk::CompareOp {
#[inline]
fn from(val: Compare) -> Self {
Self::from_raw(val as i32)
}
}