glium/draw_parameters/
depth.rs

1use crate::context::CommandContext;
2use crate::version::Api;
3use crate::version::Version;
4
5use crate::DrawError;
6use crate::gl;
7
8/// Represents the depth parameters of a draw command.
9#[derive(Debug, Copy, Clone)]
10pub struct Depth {
11    /// The function that the GPU will use to determine whether to write over an existing pixel
12    /// on the target. Don't forget to set `depth_write` appropriately if you use a depth test.
13    ///
14    /// See the `DepthTest` documentation for more details.
15    ///
16    /// The default is `Overwrite`.
17    pub test: DepthTest,
18
19    /// Sets whether the GPU will write the depth values on the depth buffer if they pass the
20    /// depth test.
21    ///
22    /// The default is `false`. You most likely want `true` if you're doing depth testing.
23    ///
24    /// If you pass `true` but don't have a depth buffer available, drawing will produce
25    /// a `NoDepthBuffer` error.
26    pub write: bool,
27
28    /// The range of possible Z values in surface coordinates.
29    ///
30    /// Just like OpenGL turns X and Y coordinates between `-1.0` and `1.0` into surface
31    /// coordinates, it will also map your Z coordinates to a certain range which you can
32    /// specify here.
33    ///
34    /// The two values must be between `0.0` and `1.0`, anything outside this range will result
35    /// in a panic. By default the depth range is `(0.0, 1.0)`.
36    ///
37    /// The first value of the tuple must be the "near" value, where `-1.0` will be mapped.
38    /// The second value must be the "far" value, where `1.0` will be mapped.
39    /// It is possible for the "near" value to be greater than the "far" value.
40    pub range: (f32, f32),
41
42    /// Sets whether the depth values of samples should be clamped to `0.0` and `1.0`.
43    ///
44    /// The default value is `NoClamp`.
45    pub clamp: DepthClamp,
46}
47
48impl Default for Depth {
49    #[inline]
50    fn default() -> Depth {
51        Depth {
52            test: DepthTest::Overwrite,
53            write: false,
54            range: (0.0, 1.0),
55            clamp: DepthClamp::NoClamp,
56        }
57    }
58}
59
60/// The function that the GPU will use to determine whether to write over an existing pixel
61/// on the target.
62///
63/// # Depth buffers
64///
65/// After the fragment shader has been run, the GPU maps the output Z coordinates to the depth
66/// range (which you can specify in the draw parameters) in order to obtain the depth value in
67/// in window coordinates. This depth value is always between `0.0` and `1.0`.
68///
69/// In addition to the buffer where pixel colors are stored, you can also have a buffer
70/// which contains the depth value of each pixel. Whenever the GPU tries to write a pixel,
71/// it will first compare the depth value of the pixel to be written with the depth value that
72/// is stored at this location. If `depth_write` is set to `true` in the draw parameters, it will
73/// then write the depth value in the buffer.
74///
75/// The most common value for depth testing is to set `depth_test` to `IfLess`, and `depth_write`
76/// to `true`.
77///
78/// If you don't have a depth buffer available, you can only pass `Overwrite`. Glium detects if
79/// you pass any other value and reports an error.
80#[derive(Clone, Copy, Debug, PartialEq, Eq)]
81pub enum DepthTest {
82    /// Never replace the target pixel.
83    ///
84    /// This option doesn't really make sense, but is here for completeness.
85    Ignore,
86
87    /// Always replace the target pixel.
88    ///
89    /// This is the default mode.
90    Overwrite,
91
92    /// Replace if the z-value of the source is equal to the destination.
93    IfEqual,
94
95    /// Replace if the z-value of the source is different than the destination.
96    IfNotEqual,
97
98    /// Replace if the z-value of the source is more than the destination.
99    IfMore,
100
101    /// Replace if the z-value of the source is more than, or equal to the destination.
102    IfMoreOrEqual,
103
104    /// Replace if the z-value of the source is less than the destination.
105    IfLess,
106
107    /// Replace if the z-value of the source is less than, or equal to the destination.
108    IfLessOrEqual
109}
110
111impl DepthTest {
112    /// Returns true if the function requires a depth buffer to be used.
113    #[inline]
114    pub fn requires_depth_buffer(&self) -> bool {
115        match *self {
116            DepthTest::Ignore => true,
117            DepthTest::Overwrite => false,
118            DepthTest::IfEqual => true,
119            DepthTest::IfNotEqual => true,
120            DepthTest::IfMore => true,
121            DepthTest::IfMoreOrEqual => true,
122            DepthTest::IfLess => true,
123            DepthTest::IfLessOrEqual => true,
124        }
125    }
126
127    #[inline]
128    fn to_glenum(&self) -> gl::types::GLenum {
129        match *self {
130            DepthTest::Ignore => gl::NEVER,
131            DepthTest::Overwrite => gl::ALWAYS,
132            DepthTest::IfEqual => gl::EQUAL,
133            DepthTest::IfNotEqual => gl::NOTEQUAL,
134            DepthTest::IfMore => gl::GREATER,
135            DepthTest::IfMoreOrEqual => gl::GEQUAL,
136            DepthTest::IfLess => gl::LESS,
137            DepthTest::IfLessOrEqual => gl::LEQUAL,
138        }
139    }
140}
141
142/// Specifies whether the depth value of samples should be clamped to `0.0` or `1.0`.
143#[derive(Clone, Copy, Debug, PartialEq, Eq)]
144pub enum DepthClamp {
145    /// Do not clamp. Samples with values outside of the `[0.0, 1.0]` range will be discarded.
146    ///
147    /// This is the default value and is supported everywhere.
148    NoClamp,
149
150    /// Clamp the depth values. All samples will always be drawn.
151    ///
152    /// This value is only supported on OpenGL.
153    Clamp,
154
155    /// Depth values inferior to `0.0` will be clamped to `0.0`.
156    ///
157    /// **This option is supported only by very few OpenGL devices**.
158    ClampNear,
159
160    /// Depth values superior to `1.0` will be clamped to `1.0`.
161    ///
162    /// **This option is supported only by very few OpenGL devices**.
163    ClampFar,
164}
165
166pub fn sync_depth(ctxt: &mut CommandContext<'_>, depth: &Depth) -> Result<(), DrawError> {
167    // depth clamp
168    {
169        let state = &mut *ctxt.state;
170        match (depth.clamp, &mut state.enabled_depth_clamp_near,
171               &mut state.enabled_depth_clamp_far)
172        {
173            (DepthClamp::NoClamp, &mut false, &mut false) => (),
174            (DepthClamp::Clamp, &mut true, &mut true) => (),
175
176            (DepthClamp::NoClamp, near, far) => {
177                if ctxt.version >= &Version(Api::Gl, 3, 0) || ctxt.extensions.gl_arb_depth_clamp ||
178                   ctxt.extensions.gl_nv_depth_clamp
179                {
180                    unsafe { ctxt.gl.Disable(gl::DEPTH_CLAMP) };
181                    *near = false;
182                    *far = false;
183                } else {
184                    return Err(DrawError::DepthClampNotSupported);
185                }
186            },
187
188            (DepthClamp::Clamp, near, far) => {
189                if ctxt.version >= &Version(Api::Gl, 3, 0) || ctxt.extensions.gl_arb_depth_clamp ||
190                   ctxt.extensions.gl_nv_depth_clamp
191                {
192                    unsafe { ctxt.gl.Enable(gl::DEPTH_CLAMP) };
193                    *near = true;
194                    *far = true;
195                } else {
196                    return Err(DrawError::DepthClampNotSupported);
197                }
198            },
199
200            (DepthClamp::ClampNear, &mut true, &mut false) => (),
201            (DepthClamp::ClampFar, &mut false, &mut true) => (),
202
203            (DepthClamp::ClampNear, &mut true, far) => {
204                if ctxt.extensions.gl_amd_depth_clamp_separate {
205                    unsafe { ctxt.gl.Disable(gl::DEPTH_CLAMP_FAR_AMD) };
206                    *far = false;
207                } else {
208                    return Err(DrawError::DepthClampNotSupported);
209                }
210
211            },
212
213            (DepthClamp::ClampNear, near @ &mut false, far) => {
214                if ctxt.extensions.gl_amd_depth_clamp_separate {
215                    unsafe { ctxt.gl.Enable(gl::DEPTH_CLAMP_NEAR_AMD) };
216                    if *far { unsafe { ctxt.gl.Disable(gl::DEPTH_CLAMP_FAR_AMD); } }
217                    *near = true;
218                    *far = false;
219                } else {
220                    return Err(DrawError::DepthClampNotSupported);
221                }
222            },
223
224            (DepthClamp::ClampFar, near, &mut true) => {
225                if ctxt.extensions.gl_amd_depth_clamp_separate {
226                    unsafe { ctxt.gl.Disable(gl::DEPTH_CLAMP_NEAR_AMD) };
227                    *near = false;
228                } else {
229                    return Err(DrawError::DepthClampNotSupported);
230                }
231            },
232
233            (DepthClamp::ClampFar, near, far @ &mut false) => {
234                if ctxt.extensions.gl_amd_depth_clamp_separate {
235                    unsafe { ctxt.gl.Enable(gl::DEPTH_CLAMP_FAR_AMD) };
236                    if *near { unsafe { ctxt.gl.Disable(gl::DEPTH_CLAMP_NEAR_AMD); } }
237                    *near = false;
238                    *far = true;
239                } else {
240                    return Err(DrawError::DepthClampNotSupported);
241                }
242            },
243        }
244    }
245
246    // depth range
247    if depth.range.0 < 0.0 || depth.range.0 > 1.0 ||
248       depth.range.1 < 0.0 || depth.range.1 > 1.0
249    {
250        return Err(DrawError::InvalidDepthRange);
251    }
252
253    if depth.range != ctxt.state.depth_range {
254        // TODO: WebGL requires depth.range.1 > depth.range.0
255        unsafe {
256            ctxt.gl.DepthRange(depth.range.0 as f64, depth.range.1 as f64);
257        }
258        ctxt.state.depth_range = depth.range;
259    }
260
261    if depth.test == DepthTest::Overwrite && !depth.write {
262        // simply disabling GL_DEPTH_TEST
263        if ctxt.state.enabled_depth_test {
264            unsafe { ctxt.gl.Disable(gl::DEPTH_TEST) };
265            ctxt.state.enabled_depth_test = false;
266        }
267        return Ok(());
268
269    } else if !ctxt.state.enabled_depth_test {
270        unsafe { ctxt.gl.Enable(gl::DEPTH_TEST) };
271        ctxt.state.enabled_depth_test = true;
272    }
273
274    // depth test
275    unsafe {
276        let depth_test = depth.test.to_glenum();
277        if ctxt.state.depth_func != depth_test {
278            ctxt.gl.DepthFunc(depth_test);
279            ctxt.state.depth_func = depth_test;
280        }
281    }
282
283    // depth mask
284    if depth.write != ctxt.state.depth_mask {
285        unsafe {
286            ctxt.gl.DepthMask(if depth.write { gl::TRUE } else { gl::FALSE });
287        }
288        ctxt.state.depth_mask = depth.write;
289    }
290
291    Ok(())
292}