2 * Copyright (C) 2014 Intel Corporation
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 DEALINGS
24 /** @file dead-fragments.c
26 * Quoting the ARB_shader_image_load_store extension:
27 * "If a fragment shader is invoked to process fragments or samples
28 * not covered by a primitive being rasterized to facilitate the
29 * approximation of derivatives for texture lookups, stores and
30 * atomics have no effect."
32 * The purpose of this test is to check this assertion, as well as
33 * that image stores and atomics have no effect after a fragment is
34 * discarded. Both tests are repeated for a few different built-in
46 /** Total number of pixels in the window and image. */
49 PIGLIT_GL_TEST_CONFIG_BEGIN
51 config
.supports_gl_core_version
= 32;
53 config
.window_width
= W
;
54 config
.window_height
= H
;
55 config
.window_visual
= PIGLIT_GL_VISUAL_DOUBLE
| PIGLIT_GL_VISUAL_RGBA
;
56 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
58 PIGLIT_GL_TEST_CONFIG_END
60 struct image_op_info
{
61 /** Image built-in name. */
64 /** GLSL statement that invokes this image built-in. */
68 static const struct image_op_info image_ops
[] = {
71 "void inc(ivec2 idx) {\n"
72 " imageStore(img, IMAGE_ADDR(idx),"
73 " imageLoad(img, IMAGE_ADDR(idx)) + BASE_T(1));\n"
78 "void inc(ivec2 idx) {\n"
79 " imageAtomicAdd(img, IMAGE_ADDR(idx), BASE_T(1));\n"
84 "void inc(ivec2 idx) {\n"
85 " imageAtomicMax(img, IMAGE_ADDR(idx),"
86 " imageLoad(img, IMAGE_ADDR(idx)).x + BASE_T(1));\n"
90 "imageAtomicExchange",
91 "void inc(ivec2 idx) {\n"
92 " imageAtomicExchange(img, IMAGE_ADDR(idx),"
93 " imageLoad(img, IMAGE_ADDR(idx)).x + BASE_T(1));\n"
97 "imageAtomicCompSwap",
98 "void inc(ivec2 idx) {\n"
99 " imageAtomicCompSwap(img, IMAGE_ADDR(idx),"
100 " imageLoad(img, IMAGE_ADDR(idx)).x,"
101 " imageLoad(img, IMAGE_ADDR(idx)).x + BASE_T(1));\n"
108 init_image(const struct image_info img
)
113 for (i
= 0; i
< N
; ++i
)
116 return upload_image(img
, 0, pixels
);
120 check_discard(const struct grid_info grid
, const struct image_info img
,
121 unsigned w
, unsigned h
)
123 uint32_t pixels
[H
][W
], expect
[H
][W
];
126 for (i
= 0; i
< W
; ++i
)
127 for (j
= 0; j
< H
; ++j
)
128 expect
[j
][i
] = (i
% 5 == 0 ? 0 : 1) + j
;
130 return download_image(img
, 0, pixels
[0]) &&
131 check_pixels_v(img
, pixels
[0], expect
[0]);
135 check_derivative(const struct grid_info grid
, const struct image_info img
,
136 unsigned w
, unsigned h
)
138 uint32_t pixels_fb
[H
][W
], expect_fb
[H
][W
];
139 uint32_t pixels_img
[H
][W
], expect_img
[H
][W
];
142 for (i
= 0; i
< W
; ++i
) {
143 for (j
= 0; j
< H
; ++j
) {
144 expect_fb
[j
][i
] = (j
< h
&& i
< w
? 1000 :
145 encode(get_image_format(GL_R32F
), 0.5));
146 expect_img
[j
][i
] = (j
< h
&& i
< w
? 1 : 0) + j
;
150 if (!download_result(grid
, pixels_fb
[0]) ||
151 !download_image(img
, 0, pixels_img
[0]))
154 if (!check_pixels_v(img
, pixels_fb
[0], expect_fb
[0])) {
155 printf(" Source: framebuffer\n");
157 * Purely informational check, we don't care what the
158 * result is as long as derivatives are being
159 * calculated, don't fail if the result doesn't equal
160 * the expected value as it's most likely an accuracy
165 if (!check_pixels_v(img
, pixels_img
[0], expect_img
[0])) {
166 printf(" Source: image\n");
174 run_test(const struct image_op_info
*op
,
175 unsigned w
, unsigned h
,
176 bool (*check
)(const struct grid_info grid
,
177 const struct image_info img
,
178 unsigned w
, unsigned h
),
181 const struct grid_info grid
=
182 grid_info(GL_FRAGMENT_SHADER
, GL_R32UI
, W
, H
);
183 const struct image_info img
= image_info_for_grid(grid
);
184 GLuint prog
= generate_program(
185 grid
, GL_FRAGMENT_SHADER
,
186 concat(image_hunk(img
, ""),
187 hunk("IMAGE_UNIFORM_T img;\n"),
193 set_uniform_int(prog
, "img", 0) &&
194 draw_grid(set_grid_size(grid
, w
, h
), prog
) &&
195 check(grid
, img
, w
, h
);
197 glDeleteProgram(prog
);
202 piglit_init(int argc
, char **argv
)
204 enum piglit_result status
= PIGLIT_PASS
;
205 const struct image_op_info
*op
;
207 piglit_require_extension("GL_ARB_shader_image_load_store");
209 for (op
= image_ops
; op
->name
; ++op
) {
211 * Draw a rectangle discarding a subset of the
212 * fragments before inc() is run, then make sure that
213 * it had no effect for those fragments.
215 subtest(&status
, true,
216 run_test(op
, W
, H
, check_discard
,
217 "GRID_T op(ivec2 idx, GRID_T x) {\n"
218 " if (idx.x % 5 == 0)\n"
223 "%s/discard test", op
->name
);
226 * Draw a 1-pixel wide rectangle and make a derivative
227 * computation in the orthogonal direction to get the
228 * GPU to run fragment shader invocations located
229 * outside the primitive, then make sure that inc()
230 * had no effect for those fragments.
232 subtest(&status
, true,
233 run_test(op
, W
- 3, 1, check_derivative
,
234 "GRID_T op(ivec2 idx, GRID_T x) {\n"
235 " x = uvec4(1000 * dFdy(vec4("
236 " imageLoad(img, IMAGE_ADDR(idx)))));"
240 "%s/derivative test", op
->name
);
243 piglit_report_result(status
);