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}