use crate::{
device::Device,
macros::{vulkan_bitflags, vulkan_enum},
Requires, RequiresAllOf, RequiresOneOf, ValidationError,
};
use std::ops::RangeInclusive;
#[derive(Clone, Debug)]
pub struct DepthStencilState {
pub flags: DepthStencilStateFlags,
pub depth: Option<DepthState>,
pub depth_bounds: Option<RangeInclusive<f32>>,
pub stencil: Option<StencilState>,
pub _ne: crate::NonExhaustive,
}
impl Default for DepthStencilState {
#[inline]
fn default() -> Self {
Self {
flags: DepthStencilStateFlags::empty(),
depth: Default::default(),
depth_bounds: Default::default(),
stencil: Default::default(),
_ne: crate::NonExhaustive(()),
}
}
}
impl DepthStencilState {
#[inline]
#[deprecated(since = "0.34.0", note = "use `DepthStencilState::default` instead")]
pub fn disabled() -> Self {
Self::default()
}
#[inline]
#[deprecated(since = "0.34.0", note = "use `DepthState::simple` instead")]
pub fn simple_depth_test() -> Self {
Self {
flags: DepthStencilStateFlags::empty(),
depth: Some(DepthState::simple()),
depth_bounds: Default::default(),
stencil: Default::default(),
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
flags,
ref depth,
ref depth_bounds,
ref stencil,
_ne: _,
} = self;
flags.validate_device(device).map_err(|err| {
err.add_context("flags")
.set_vuids(&["VUID-VkPipelineDepthStencilStateCreateInfo-flags-parameter"])
})?;
if let Some(depth_state) = depth {
depth_state
.validate(device)
.map_err(|err| err.add_context("depth"))?;
}
if let Some(depth_bounds) = depth_bounds {
if !device.enabled_features().depth_bounds {
return Err(Box::new(ValidationError {
context: "depth_bounds".into(),
problem: "is `Some`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
"depth_bounds",
)])]),
vuids: &[
"VUID-VkPipelineDepthStencilStateCreateInfo-depthBoundsTestEnable-00598",
],
}));
}
if !device.enabled_extensions().ext_depth_range_unrestricted {
if !(0.0..1.0).contains(depth_bounds.start()) {
return Err(Box::new(ValidationError {
context: "depth_bounds.start".into(),
problem: "is not between 0.0 and 1.0 inclusive".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceExtension("ext_depth_range_unrestricted"),
])]),
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510"],
}));
}
if !(0.0..1.0).contains(depth_bounds.end()) {
return Err(Box::new(ValidationError {
context: "depth_bounds.end".into(),
problem: "is not between 0.0 and 1.0 inclusive".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceExtension("ext_depth_range_unrestricted"),
])]),
vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510"],
}));
}
}
}
if let Some(stencil_state) = stencil {
stencil_state
.validate(device)
.map_err(|err| err.add_context("stencil"))?;
}
Ok(())
}
}
vulkan_bitflags! {
#[non_exhaustive]
DepthStencilStateFlags = PipelineDepthStencilStateCreateFlags(u32);
}
#[derive(Clone, Copy, Debug)]
pub struct DepthState {
pub write_enable: bool,
pub compare_op: CompareOp,
}
impl Default for DepthState {
#[inline]
fn default() -> Self {
Self {
write_enable: false,
compare_op: CompareOp::Always,
}
}
}
impl DepthState {
#[inline]
pub fn simple() -> Self {
Self {
compare_op: CompareOp::Less,
write_enable: true,
}
}
pub(crate) fn validate(self, device: &Device) -> Result<(), Box<ValidationError>> {
let Self {
write_enable: _,
compare_op,
} = self;
compare_op.validate_device(device).map_err(|err| {
err.add_context("compare_op")
.set_vuids(&["VUID-VkPipelineDepthStencilStateCreateInfo-depthCompareOp-parameter"])
})?;
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct StencilState {
pub front: StencilOpState,
pub back: StencilOpState,
}
impl Default for StencilState {
#[inline]
fn default() -> Self {
Self {
front: Default::default(),
back: Default::default(),
}
}
}
impl StencilState {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &StencilState {
ref front,
ref back,
} = self;
front
.ops
.validate(device)
.map_err(|err| err.add_context("front.ops"))?;
back.ops
.validate(device)
.map_err(|err| err.add_context("back.ops"))?;
Ok(())
}
}
#[derive(Clone, Copy, Debug)]
pub struct StencilOpState {
pub ops: StencilOps,
pub compare_mask: u32,
pub write_mask: u32,
pub reference: u32,
}
impl Default for StencilOpState {
#[inline]
fn default() -> StencilOpState {
StencilOpState {
ops: Default::default(),
compare_mask: u32::MAX,
write_mask: u32::MAX,
reference: u32::MAX,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct StencilOps {
pub fail_op: StencilOp,
pub pass_op: StencilOp,
pub depth_fail_op: StencilOp,
pub compare_op: CompareOp,
}
impl Default for StencilOps {
#[inline]
fn default() -> Self {
Self {
pass_op: StencilOp::Keep,
fail_op: StencilOp::Keep,
depth_fail_op: StencilOp::Keep,
compare_op: CompareOp::Never,
}
}
}
impl StencilOps {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
fail_op,
pass_op,
depth_fail_op,
compare_op,
} = self;
fail_op.validate_device(device).map_err(|err| {
err.add_context("fail_op")
.set_vuids(&["VUID-VkStencilOpState-failOp-parameter"])
})?;
pass_op.validate_device(device).map_err(|err| {
err.add_context("pass_op")
.set_vuids(&["VUID-VkStencilOpState-passOp-parameter"])
})?;
depth_fail_op.validate_device(device).map_err(|err| {
err.add_context("depth_fail_op")
.set_vuids(&["VUID-VkStencilOpState-depthFailOp-parameter"])
})?;
compare_op.validate_device(device).map_err(|err| {
err.add_context("compare_op")
.set_vuids(&["VUID-VkStencilOpState-compareOp-parameter"])
})?;
Ok(())
}
}
vulkan_enum! {
#[non_exhaustive]
StencilOp = StencilOp(i32);
Keep = KEEP,
Zero = ZERO,
Replace = REPLACE,
IncrementAndClamp = INCREMENT_AND_CLAMP,
DecrementAndClamp = DECREMENT_AND_CLAMP,
Invert = INVERT,
IncrementAndWrap = INCREMENT_AND_WRAP,
DecrementAndWrap = DECREMENT_AND_WRAP,
}
vulkan_enum! {
#[non_exhaustive]
StencilFaces = StencilFaceFlags(u32);
Front = FRONT,
Back = BACK,
FrontAndBack = FRONT_AND_BACK,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct DynamicStencilValue {
pub front: u32,
pub back: u32,
}
vulkan_enum! {
#[non_exhaustive]
CompareOp = CompareOp(i32);
Never = NEVER,
Less = LESS,
Equal = EQUAL,
LessOrEqual = LESS_OR_EQUAL,
Greater = GREATER,
NotEqual = NOT_EQUAL,
GreaterOrEqual = GREATER_OR_EQUAL,
Always = ALWAYS,
}