2 * Copyright Mathias Fröhlich <Mathias.Froehlich@web.de>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Mathias Fröhlich <Mathias.Froehlich@web.de>
27 /** @file clip-control-depth-precision.c
29 * Test for ARB_clip_control.
30 * This is actually the application level use case making use of the
31 * close to logarithmic depth buffer precision available with the
32 * GL_ZERO_TO_ONE depth mode that is newly provided with this extension.
33 * The ARB_clip_control spec gives a set of web references explaining the
35 * In short we set up a projection matrix that maps infinite far away
36 * points to 0 and the near plane to 1. We use a float depth buffer
37 * with a well known accuracy behavior. That together gives a depth
38 * buffer resolution that is about the relative floating point accuracy
39 * relative to the distance from the eye point.
40 * This extension avoids adding a constant number even in an intermediate
41 * step which would destroy the effective depth precision possible with
42 * the floating point depth buffers.
43 * Roughtly in numbers:
44 * Two fragments at 5000001 and 5000000 \about 5000001*(1 - eps) distance
45 * from the eye point should yield to different values in the depth buffer.
46 * The same goes for about any fragment distance x that you should be able
47 * to distinguish this from x*(1 - eps).
48 * And this is exactly what this test checks. We draw two surfaces
49 * a big red one at a distance x and a half that big green one at a distance
50 * x*(1 - 10*eps) to have a security factor of 10 to allow for some roundoff
51 * errors to accumulate. Due to the depth precision we must not get z fighting
52 * between these two and see a nested green solid square inside a bigger red
53 * square really behind it.
56 #include "piglit-util-gl.h"
58 PIGLIT_GL_TEST_CONFIG_BEGIN
60 config
.supports_gl_compat_version
= 20;
62 config
.window_visual
= PIGLIT_GL_VISUAL_RGB
| PIGLIT_GL_VISUAL_DOUBLE
;
63 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
65 PIGLIT_GL_TEST_CONFIG_END
68 piglit_init(int argc
, char **argv
)
70 GLdouble projection
[16] = { 0.0, };
72 piglit_require_extension("GL_ARB_clip_control");
73 piglit_require_extension("GL_ARB_depth_buffer_float");
74 piglit_require_extension("GL_EXT_framebuffer_object");
75 piglit_require_extension("GL_EXT_framebuffer_blit");
77 /* Set up a projection matrix mapping z = -1 to z = 1
78 * and z = -inf to z = 0 in projection space.
79 * Given the clip control setting below, this is just
80 * written as is into the float depth buffer.
82 projection
[0 + 4*0] = 1;
83 projection
[1 + 4*1] = (GLdouble
)piglit_width
/piglit_height
;
84 projection
[2 + 4*3] = 1;
85 projection
[3 + 4*2] = -1;
87 glMatrixMode(GL_PROJECTION
);
88 glLoadMatrixd(projection
);
90 glMatrixMode(GL_MODELVIEW
);
97 GLfloat red
[3] = { 1, 0, 0 };
98 GLfloat green
[3] = { 0, 1, 0 };
99 GLboolean pass
= GL_TRUE
;
104 glGenRenderbuffers(1, &cb
);
105 glBindRenderbuffer(GL_RENDERBUFFER
, cb
);
106 glRenderbufferStorage(GL_RENDERBUFFER
, GL_RGBA
, piglit_width
, piglit_height
);
107 glBindRenderbuffer(GL_RENDERBUFFER
, 0);
109 glGenRenderbuffers(1, &db
);
110 glBindRenderbuffer(GL_RENDERBUFFER
, db
);
111 glRenderbufferStorage(GL_RENDERBUFFER
, GL_DEPTH_COMPONENT32F
, piglit_width
, piglit_height
);
112 glBindRenderbuffer(GL_RENDERBUFFER
, 0);
114 glGenFramebuffers(1, &fb
);
115 glBindFramebuffer(GL_FRAMEBUFFER
, fb
);
116 glFramebufferRenderbuffer(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_RENDERBUFFER
, cb
);
117 glFramebufferRenderbuffer(GL_FRAMEBUFFER
, GL_DEPTH_ATTACHMENT
, GL_RENDERBUFFER
, db
);
119 status
= glCheckFramebufferStatus(GL_FRAMEBUFFER
);
120 if (status
!= GL_FRAMEBUFFER_COMPLETE
) {
121 printf("FBO incomplete status 0x%X\n", status
);
122 piglit_report_result(PIGLIT_FAIL
);
125 glClipControl(GL_LOWER_LEFT
, GL_ZERO_TO_ONE
);
128 glClearColor(0, 0, 0, 1);
129 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
130 glEnable(GL_DEPTH_TEST
);
131 glDepthFunc(GL_GREATER
);
133 for (range10
= 0; range10
< 16; ++range10
) {
134 int width
= piglit_width
/4;
135 int height
= piglit_height
/4;
136 int tilex
= range10
% 4;
137 int tiley
= range10
/ 4;
139 int y
= tiley
*height
;
140 double z
= pow(10, 1 + range10
);
142 /* Set up a new viewport for each depth we want to test */
143 glViewport(x
, y
, width
, height
);
145 /* Draw a red surface at given distance z */
147 piglit_draw_rect_z(-z
, -0.5*z
, -0.5*z
, z
, z
);
149 pass
= piglit_probe_pixel_rgb(x
+ width
/2, y
+ height
/2, red
) && pass
;
151 /* And a green one just close in front of that red one */
153 piglit_draw_rect_z((10*FLT_EPSILON
- 1)*z
, -0.25*z
, -0.25*z
, 0.5*z
, 0.5*z
);
155 pass
= piglit_probe_pixel_rgb(x
+ width
/2, y
+ height
/2, green
) && pass
;
159 /* set viewport to window size */
160 glViewport(0, 0, piglit_width
, piglit_height
);
162 /* copy the result to the back buffer */
163 glBindFramebuffer(GL_READ_FRAMEBUFFER
, fb
);
164 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, 0);
165 glBlitFramebuffer(0, 0, piglit_width
, piglit_height
, 0, 0, piglit_width
, piglit_height
, GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
166 glBindFramebuffer(GL_FRAMEBUFFER
, 0);
168 glDeleteFramebuffers(1, &fb
);
169 glDeleteRenderbuffers(1, &cb
);
170 glDeleteRenderbuffers(1, &db
);
172 piglit_present_results();
174 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;