1 /*
2  * Copyright (C) 2014 Intel Corporation
3  *
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:
10  *
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
13  * Software.
14  *
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 DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 /** @file early-z.c
25  *
26  * Test the interaction between early per-fragment tests, image access
27  * and occlusion queries.  According to the spec:
28  *
29  * "When early per-fragment operations are enabled, the depth bounds
30  *  test, stencil test, depth buffer test, and occlusion query sample
31  *  counting operations are performed prior to fragment shader
32  *  execution, and the stencil buffer, depth buffer, and occlusion
33  *  query sample counts will be updated accordingly."
34  *
35  * "If a fragment is discarded during any of these operations, it will
36  *  not be processed by any subsequent stage, including fragment
37  *  shader execution."
38  *
39  * This checks several consequences of the quoted text, including that
40  * the fragment shader is guaranteed not to be executed if the depth
41  * test fails, that the depth value computed by the fragment shader is
42  * ignored, and that fragments discarded during fragment shader
43  * execution are counted by occlusion queries.  We also check that
44  * when using normal (late) fragment tests image stores have an effect
45  * regardless of the depth test results.
46  */
47 
48 #include "common.h"
49 
50 /** Window width. */
51 #define W 16
52 
53 /** Window height. */
54 #define H 96
55 
56 /** Total number of pixels in the window and image. */
57 #define N (W * H)
58 
59 PIGLIT_GL_TEST_CONFIG_BEGIN
60 
61 config.supports_gl_core_version = 32;
62 
63 config.window_width = W;
64 config.window_height = H;
65 config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;
66 config.khr_no_error_support = PIGLIT_NO_ERRORS;
67 
68 PIGLIT_GL_TEST_CONFIG_END
69 
70 static bool
init_image(const struct image_info img)71 init_image(const struct image_info img)
72 {
73         uint32_t pixels[4 * N];
74 
75         return init_pixels(img, pixels, 1, 0, 0, 1) &&
76                 upload_image(img, 0, pixels);
77 }
78 
79 static bool
check_zb(double z)80 check_zb(double z)
81 {
82         const struct image_info img = image_info(GL_TEXTURE_2D, GL_R32F, W, H);
83         uint32_t pixels[N];
84 
85         glReadPixels(0, 0, W, H, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);
86         if (!piglit_check_gl_error(GL_NO_ERROR))
87                 return false;
88 
89         if (!check_pixels(img, pixels, z, 0, 0, 0)) {
90                 printf("  Source: depth buffer\n");
91                 return false;
92         }
93 
94         return true;
95 }
96 
97 static bool
check_img(const struct image_info img,double r,double g,double b,double a)98 check_img(const struct image_info img, double r, double g, double b, double a)
99 {
100         uint32_t pixels[4 * N];
101 
102         if (!download_image(img, 0, pixels))
103                 return false;
104 
105         if (!check_pixels(img, pixels, r, g, b, a)) {
106                 printf("  Source: image\n");
107                 return false;
108         }
109 
110         return true;
111 }
112 
113 static bool
check_query(GLuint q,int expect)114 check_query(GLuint q, int expect)
115 {
116         int value;
117 
118         glGetQueryObjectiv(q, GL_QUERY_RESULT, &value);
119         if (value != expect) {
120                 printf("Query result\n  Expected: %d\n  Observed: %d\n",
121                        expect, value);
122                 return false;
123         }
124 
125         return piglit_check_gl_error(GL_NO_ERROR);
126 }
127 
128 /**
129  * Write to an image from the fragment shader using early or late
130  * depth tests according to \a input_layout and check the results.
131  */
132 static bool
run_test_image(const char * input_layout,GLenum depth_func,double expect_r,double expect_g,double expect_b,double expect_a,double expect_z)133 run_test_image(const char *input_layout, GLenum depth_func,
134                double expect_r, double expect_g, double expect_b,
135                double expect_a, double expect_z)
136 {
137         const struct grid_info grid =
138                 grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, W, H);
139         const struct image_info img = image_info_for_grid(grid);
140         GLuint prog = generate_program(
141                 grid, GL_FRAGMENT_SHADER,
142                 concat(hunk(input_layout),
143                        image_hunk(img, ""),
144                        hunk("IMAGE_UNIFORM_T img;\n"
145                             "\n"
146                             "GRID_T op(ivec2 idx, GRID_T x) {\n"
147                             "        imageStore(img, IMAGE_ADDR(idx),"
148                             "                   GRID_T(0, 1, 0, 1));\n"
149                             "        gl_FragDepth = 1.0;\n"
150                             "        return GRID_T(0, 1, 0, 1);\n"
151                             "}\n"), NULL));
152         bool ret = prog && init_fb(grid) &&
153                 init_image(img) &&
154                 set_uniform_int(prog, "img", 0);
155 
156         glEnable(GL_DEPTH_TEST);
157         glDepthFunc(depth_func);
158 
159         ret &= draw_grid(grid, prog) &&
160                 check_img(img, expect_r, expect_g, expect_b, expect_a) &&
161                 check_zb(expect_z);
162 
163         glDeleteProgram(prog);
164         return ret;
165 }
166 
167 /**
168  * Draw a grid of conditionally discarded fragments with early or late
169  * depth tests according to \a input_layout and check the resulting
170  * occlusion query sample count.
171  */
172 static bool
run_test_query(const char * input_layout,GLenum depth_func,unsigned expect_samples_passed)173 run_test_query(const char *input_layout, GLenum depth_func,
174                unsigned expect_samples_passed)
175 {
176         const struct grid_info grid =
177                 grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, W, H);
178         GLuint prog = generate_program(
179                 grid, GL_FRAGMENT_SHADER,
180                 concat(hunk(input_layout),
181                        hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
182                             "        if ((idx.x & 1) == 0)\n"
183                             "                discard;\n"
184                             "        gl_FragDepth = 1.0;\n"
185                             "        return GRID_T(0, 1, 0, 1);\n"
186                             "}\n"), NULL));
187         bool ret = prog && init_fb(grid);
188         GLenum q;
189 
190         glEnable(GL_DEPTH_TEST);
191         glDepthFunc(depth_func);
192         glGenQueries(1, &q);
193 
194         glBeginQuery(GL_SAMPLES_PASSED, q);
195         ret &= draw_grid(grid, prog);
196         glEndQuery(GL_SAMPLES_PASSED);
197 
198         ret &= check_query(q, expect_samples_passed);
199 
200         glDeleteQueries(1, &q);
201         glDeleteProgram(prog);
202         return ret;
203 }
204 
205 void
piglit_init(int argc,char ** argv)206 piglit_init(int argc, char **argv)
207 {
208         enum piglit_result status = PIGLIT_PASS;
209 
210         piglit_require_extension("GL_ARB_shader_image_load_store");
211 
212         /*
213          * Image stores should be executed, but the computed depth
214          * value should have no effect if the early depth test
215          * passes.
216          */
217         subtest(&status, true,
218                 run_test_image("layout(early_fragment_tests) in;\n",
219                                GL_LEQUAL,
220                                0.0, 1.0, 0.0, 1.0, 0.5),
221                 "image access test/early-z pass");
222 
223         /*
224          * Image stores should have no effect if the early depth test
225          * fails.
226          */
227         subtest(&status, true,
228                 run_test_image("layout(early_fragment_tests) in;\n",
229                                GL_GREATER,
230                                1.0, 0.0, 0.0, 1.0, 0.5),
231                 "image access test/early-z fail");
232 
233         /*
234          * Image stores should be executed and the computed depth
235          * value should be recorded if the late depth test passes.
236          */
237         subtest(&status, true,
238                 run_test_image("",
239                                GL_GREATER,
240                                0.0, 1.0, 0.0, 1.0, 1.0),
241                 "image access test/late-z pass");
242 
243         /*
244          * Image stores should be executed, but the computed depth
245          * value should have no effect if the late depth test
246          * fails.
247          */
248         subtest(&status, true,
249                 run_test_image("",
250                                GL_LEQUAL,
251                                0.0, 1.0, 0.0, 1.0, 0.5),
252                 "image access test/late-z fail");
253 
254         /*
255          * All fragments should be recorded in the occlusion query
256          * with a passing early depth test even if some are discarded
257          * further down the pipeline.
258          */
259         subtest(&status, true,
260                 run_test_query("layout(early_fragment_tests) in;\n",
261                                GL_LEQUAL, N),
262                 "occlusion query test/early-z pass");
263 
264         /*
265          * No fragments should be recorded in the occlusion query with
266          * a failing early depth test.
267          */
268         subtest(&status, true,
269                 run_test_query("layout(early_fragment_tests) in;\n",
270                                GL_GREATER, 0),
271                 "occlusion query test/early-z fail");
272 
273         /*
274          * Only the fragments that don't call discard should be
275          * recorded in the sample count with a passing late depth
276          * test.
277          */
278         subtest(&status, true,
279                 run_test_query("",
280                                GL_GREATER, N / 2),
281                 "occlusion query test/late-z pass");
282 
283         /*
284          * No fragments should be recorded in the sample count with a
285          * failing late depth test.
286          */
287         subtest(&status, true,
288                 run_test_query("",
289                                GL_LEQUAL, 0),
290                 "occlusion query test/late-z fail");
291 
292         piglit_report_result(status);
293 }
294 
295 enum piglit_result
piglit_display(void)296 piglit_display(void)
297 {
298         return PIGLIT_FAIL;
299 }
300