1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! Configures the operation of the depth, stencil and depth bounds tests.
11 //!
12 //! The depth test passes of fails depending on how the depth value of each fragment compares
13 //! to the existing depth value in the depth buffer at that fragment's location. Depth values
14 //! are always between 0.0 and 1.0.
15 //!
16 //! The depth bounds test allows you to ask the GPU to exclude fragments that are outside of a
17 //! certain range. This is done in addition to the regular depth test.
18 //!
19 //! The stencil test passes or fails depending on how a reference value compares to the existing
20 //! value in the stencil buffer at each fragment's location. Depending on the outcome of the
21 //! depth and stencil tests, the value of the stencil buffer at that location can be updated.
22 
23 use crate::{macros::vulkan_enum, pipeline::StateMode};
24 use std::ops::RangeInclusive;
25 
26 /// The state in a graphics pipeline describing how the depth, depth bounds and stencil tests
27 /// should behave.
28 #[derive(Clone, Debug)]
29 pub struct DepthStencilState {
30     /// The state of the depth test.
31     ///
32     /// If set to `None`, the depth test is disabled, all fragments will pass and no depth writes
33     /// are performed.
34     pub depth: Option<DepthState>,
35 
36     /// The state of the depth bounds test.
37     ///
38     /// If set to `None`, the depth bounds test is disabled, all fragments will pass.
39     pub depth_bounds: Option<DepthBoundsState>,
40 
41     /// The state of the stencil test.
42     ///
43     /// If set to `None`, the stencil test is disabled, all fragments will pass and no stencil
44     /// writes are performed.
45     pub stencil: Option<StencilState>,
46 }
47 
48 impl DepthStencilState {
49     /// Creates a `DepthStencilState` where all tests are disabled and have no effect.
50     #[inline]
disabled() -> Self51     pub fn disabled() -> Self {
52         Self {
53             depth: Default::default(),
54             depth_bounds: Default::default(),
55             stencil: Default::default(),
56         }
57     }
58 
59     /// Creates a `DepthStencilState` with a `Less` depth test, `depth_write` set to true, and other
60     /// tests disabled.
61     #[inline]
simple_depth_test() -> Self62     pub fn simple_depth_test() -> Self {
63         Self {
64             depth: Some(DepthState {
65                 enable_dynamic: false,
66                 compare_op: StateMode::Fixed(CompareOp::Less),
67                 write_enable: StateMode::Fixed(true),
68             }),
69             depth_bounds: Default::default(),
70             stencil: Default::default(),
71         }
72     }
73 }
74 
75 impl Default for DepthStencilState {
76     /// Returns [`DepthStencilState::disabled()`].
77     #[inline]
default() -> Self78     fn default() -> Self {
79         DepthStencilState::disabled()
80     }
81 }
82 
83 /// The state in a graphics pipeline describing how the depth test should behave when enabled.
84 #[derive(Clone, Copy, Debug)]
85 pub struct DepthState {
86     /// Sets whether depth testing should be enabled and disabled dynamically. If set to `false`,
87     /// depth testing is always enabled.
88     ///
89     /// If set to `true`, the device API version must be at least 1.3, or the
90     /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
91     /// enabled on the device.
92     pub enable_dynamic: bool,
93 
94     /// Sets whether the value in the depth buffer will be updated when the depth test succeeds.
95     ///
96     /// If set to `Dynamic`, the device API version must be at least 1.3, or the
97     /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
98     /// enabled on the device.
99     pub write_enable: StateMode<bool>,
100 
101     /// Comparison operation to use between the depth value of each incoming fragment and the depth
102     /// value currently in the depth buffer.
103     ///
104     /// If set to `Dynamic`, the device API version must be at least 1.3, or the
105     /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
106     /// enabled on the device.
107     pub compare_op: StateMode<CompareOp>,
108 }
109 
110 impl Default for DepthState {
111     /// Creates a `DepthState` with no dynamic state, depth writes disabled and `compare_op` set
112     /// to always pass.
113     #[inline]
default() -> Self114     fn default() -> Self {
115         Self {
116             enable_dynamic: false,
117             write_enable: StateMode::Fixed(false),
118             compare_op: StateMode::Fixed(CompareOp::Always),
119         }
120     }
121 }
122 
123 /// The state in a graphics pipeline describing how the depth bounds test should behave when
124 /// enabled.
125 #[derive(Clone, Debug)]
126 pub struct DepthBoundsState {
127     /// Sets whether depth bounds testing should be enabled and disabled dynamically. If set to
128     /// `false`, depth bounds testing is always enabled.
129     ///
130     /// If set to `true`, the device API version must be at least 1.3, or the
131     /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
132     /// enabled on the device.
133     pub enable_dynamic: bool,
134 
135     /// The minimum and maximum depth values to use for the test. Fragments with values outside this
136     /// range are discarded.
137     ///
138     /// If set to `Dynamic`, the device API version must be at least 1.3, or the
139     /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
140     /// enabled on the device.
141     pub bounds: StateMode<RangeInclusive<f32>>,
142 }
143 
144 impl Default for DepthBoundsState {
145     /// Creates a `DepthBoundsState` with no dynamic state and the bounds set to `0.0..=1.0`.
146     #[inline]
default() -> Self147     fn default() -> Self {
148         Self {
149             enable_dynamic: false,
150             bounds: StateMode::Fixed(0.0..=1.0),
151         }
152     }
153 }
154 
155 /// The state in a graphics pipeline describing how the stencil test should behave when enabled.
156 ///
157 /// Dynamic state can only be enabled or disabled for both faces at once. Therefore, the dynamic
158 /// state values in `StencilOpState`, must match: the values for `front` and `back` must either both
159 /// be `Fixed` or both be `Dynamic`.
160 #[derive(Clone, Debug)]
161 pub struct StencilState {
162     /// Sets whether stencil testing should be enabled and disabled dynamically. If set to
163     /// `false`, stencil testing is always enabled.
164     ///
165     /// If set to `true`, the device API version must be at least 1.3, or the
166     /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
167     /// enabled on the device.
168     pub enable_dynamic: bool,
169 
170     /// The stencil operation state to use for points and lines, and for triangles whose front is
171     /// facing the user.
172     pub front: StencilOpState,
173 
174     /// The stencil operation state to use for triangles whose back is facing the user.
175     pub back: StencilOpState,
176 }
177 
178 /// Stencil test operations for a single face.
179 #[derive(Clone, Copy, Debug)]
180 pub struct StencilOpState {
181     /// The stencil operations to perform.
182     ///
183     /// If set to `Dynamic`, the device API version must be at least 1.3, or the
184     /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
185     /// enabled on the device.
186     pub ops: StateMode<StencilOps>,
187 
188     /// A bitmask that selects the bits of the unsigned integer stencil values participating in the
189     /// stencil test. Ignored if `compare_op` is `Never` or `Always`.
190     pub compare_mask: StateMode<u32>,
191 
192     /// A bitmask that selects the bits of the unsigned integer stencil values updated by the
193     /// stencil test in the stencil framebuffer attachment. Ignored if the relevant operation is
194     /// `Keep`.
195     pub write_mask: StateMode<u32>,
196 
197     /// Reference value that is used in the unsigned stencil comparison. The stencil test is
198     /// considered to pass if the `compare_op` between the stencil buffer value and this reference
199     /// value yields true.
200     ///
201     /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
202     /// devices, if culling is disabled, and the `reference` values of the front and back face
203     /// are not equal, then the
204     /// [`separate_stencil_mask_ref`](crate::device::Features::separate_stencil_mask_ref)
205     /// feature must be enabled on the device.
206     pub reference: StateMode<u32>,
207 }
208 
209 impl Default for StencilOpState {
210     /// Creates a `StencilOpState` with no dynamic state, `compare_op` set to `Never`, the stencil
211     /// operations set to `Keep`, and the masks and reference values set to `u32::MAX`.
212     #[inline]
default() -> StencilOpState213     fn default() -> StencilOpState {
214         StencilOpState {
215             ops: StateMode::Fixed(Default::default()),
216             compare_mask: StateMode::Fixed(u32::MAX),
217             write_mask: StateMode::Fixed(u32::MAX),
218             reference: StateMode::Fixed(u32::MAX),
219         }
220     }
221 }
222 
223 #[derive(Clone, Copy, Debug)]
224 pub struct StencilOps {
225     /// The operation to perform when the stencil test failed.
226     pub fail_op: StencilOp,
227 
228     /// The operation to perform when both the depth test and the stencil test passed.
229     pub pass_op: StencilOp,
230 
231     /// The operation to perform when the stencil test passed but the depth test failed.
232     pub depth_fail_op: StencilOp,
233 
234     /// The comparison to perform between the existing stencil value in the stencil buffer, and
235     /// the reference value (given by `reference`).
236     pub compare_op: CompareOp,
237 }
238 
239 impl Default for StencilOps {
240     /// Creates a `StencilOps` with no dynamic state, `compare_op` set to `Never` and the stencil
241     /// operations set to `Keep`.
242     #[inline]
default() -> Self243     fn default() -> Self {
244         Self {
245             pass_op: StencilOp::Keep,
246             fail_op: StencilOp::Keep,
247             depth_fail_op: StencilOp::Keep,
248             compare_op: CompareOp::Never,
249         }
250     }
251 }
252 
253 vulkan_enum! {
254     #[non_exhaustive]
255 
256     /// Operation to perform after the depth and stencil tests.
257     StencilOp = StencilOp(i32);
258 
259     // TODO: document
260     Keep = KEEP,
261 
262     // TODO: document
263     Zero = ZERO,
264 
265     // TODO: document
266     Replace = REPLACE,
267 
268     // TODO: document
269     IncrementAndClamp = INCREMENT_AND_CLAMP,
270 
271     // TODO: document
272     DecrementAndClamp = DECREMENT_AND_CLAMP,
273 
274     // TODO: document
275     Invert = INVERT,
276 
277     // TODO: document
278     IncrementAndWrap = INCREMENT_AND_WRAP,
279 
280     // TODO: document
281     DecrementAndWrap = DECREMENT_AND_WRAP,
282 }
283 
284 vulkan_enum! {
285     #[non_exhaustive]
286 
287     /// Specifies a face for stencil operations.
288     StencilFaces = StencilFaceFlags(u32);
289 
290     // TODO: document
291     Front = FRONT,
292 
293     // TODO: document
294     Back = BACK,
295 
296     // TODO: document
297     FrontAndBack = FRONT_AND_BACK,
298 }
299 
300 /// Specifies a dynamic state value for the front and back faces.
301 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
302 pub struct DynamicStencilValue {
303     pub front: u32,
304     pub back: u32,
305 }
306 
307 vulkan_enum! {
308     #[non_exhaustive]
309 
310     /// Specifies how two values should be compared to decide whether a test passes or fails.
311     ///
312     /// Used for both depth testing and stencil testing.
313     CompareOp = CompareOp(i32);
314 
315     /// The test never passes.
316     Never = NEVER,
317 
318     /// The test passes if `value < reference_value`.
319     Less = LESS,
320 
321     /// The test passes if `value == reference_value`.
322     Equal = EQUAL,
323 
324     /// The test passes if `value <= reference_value`.
325     LessOrEqual = LESS_OR_EQUAL,
326 
327     /// The test passes if `value > reference_value`.
328     Greater = GREATER,
329 
330     /// The test passes if `value != reference_value`.
331     NotEqual = NOT_EQUAL,
332 
333     /// The test passes if `value >= reference_value`.
334     GreaterOrEqual = GREATER_OR_EQUAL,
335 
336     /// The test always passes.
337     Always = ALWAYS,
338 }
339