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
26 * The ARB_shader_image_load_store extension defines an image access
27 * to be invalid when certain conditions are met, in which case image
28 * stores and atomics are defined to have no effect and image loads
29 * and atomics give zero as result. This test causes such invalid
30 * accesses and checks that the result is as expected and that no data
31 * is accidentally overwritten.
33 * The spec describes other conditions that cause an image access to
34 * have undefined results. In those cases we simply check that the
35 * undefined access didn't lead to program termination.
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 /** Allowed image formats. */
65 const struct image_format_info
*formats
;
67 /** GLSL statement that invokes this image built-in. */
71 static const struct image_op_info image_ops
[] = {
73 "imageLoad", image_formats_load_store
,
74 "GRID_T op(ivec2 idx, GRID_T x) {\n"
75 " return imageLoad(imgs[u], off + IMAGE_ADDR(idx));\n"
79 "imageStore", image_formats_load_store
,
80 "GRID_T op(ivec2 idx, GRID_T x) {\n"
81 " imageStore(imgs[u], off + IMAGE_ADDR(idx), DATA_T(33));\n"
82 " return GRID_T(0, 0, 0, SCALE.w == 0 ? 1 : 0);"
86 "imageAtomicAdd", image_formats_atomic
,
87 "GRID_T op(ivec2 idx, GRID_T x) {\n"
88 " return GRID_T(imageAtomicAdd(imgs[u],"
89 " off + IMAGE_ADDR(idx),"
95 "imageAtomicMin", image_formats_atomic
,
96 "GRID_T op(ivec2 idx, GRID_T x) {\n"
97 " return GRID_T(imageAtomicMin(imgs[u],"
98 " off + IMAGE_ADDR(idx),"
104 "imageAtomicMax", image_formats_atomic
,
105 "GRID_T op(ivec2 idx, GRID_T x) {\n"
106 " return GRID_T(imageAtomicMax(imgs[u],"
107 " off + IMAGE_ADDR(idx),"
113 "imageAtomicAnd", image_formats_atomic
,
114 "GRID_T op(ivec2 idx, GRID_T x) {\n"
115 " return GRID_T(imageAtomicAnd(imgs[u],"
116 " off + IMAGE_ADDR(idx),"
122 "imageAtomicOr", image_formats_atomic
,
123 "GRID_T op(ivec2 idx, GRID_T x) {\n"
124 " return GRID_T(imageAtomicOr(imgs[u],"
125 " off + IMAGE_ADDR(idx),"
131 "imageAtomicXor", image_formats_atomic
,
132 "GRID_T op(ivec2 idx, GRID_T x) {\n"
133 " return GRID_T(imageAtomicXor(imgs[u],"
134 " off + IMAGE_ADDR(idx),"
140 "imageAtomicExchange", image_formats_atomic
,
141 "GRID_T op(ivec2 idx, GRID_T x) {\n"
142 " return GRID_T(imageAtomicExchange(imgs[u],"
143 " off + IMAGE_ADDR(idx),"
149 "imageAtomicCompSwap", image_formats_atomic
,
150 "GRID_T op(ivec2 idx, GRID_T x) {\n"
151 " return GRID_T(imageAtomicCompSwap(imgs[u],"
152 " off + IMAGE_ADDR(idx),"
153 " BASE_T(0), BASE_T(33)),"
161 init_image(const struct image_info img
, GLuint prog
)
163 uint32_t pixels
[4 * N
];
165 return init_pixels(img
, pixels
, 1, 1, 1, 1) &&
166 upload_image(img
, 0, pixels
) &&
167 set_uniform_int(prog
, "imgs[0]", 0);
171 init_level(const struct image_info img
, unsigned level
,
172 GLenum format
, unsigned w
, unsigned h
)
174 uint32_t pixels
[4 * N
];
176 init_pixels(img
, pixels
, 1, 1, 1, 1);
177 glBindTexture(GL_TEXTURE_2D
, get_texture(0));
178 glTexImage2D(GL_TEXTURE_2D
, level
, format
,
179 w
, h
, 0, img
.format
->pixel_format
,
180 image_base_type(img
.format
), pixels
);
182 return piglit_check_gl_error(GL_NO_ERROR
);
186 check(const struct grid_info grid
, const struct image_info img
)
188 uint32_t pixels_fb
[4 * N
], pixels_img
[4 * N
];
190 if (!download_result(grid
, pixels_fb
) ||
191 !download_image(img
, 0, pixels_img
))
194 /* Check that the built-in return value is zero (nonexisting texel). */
195 if (!check_pixels(image_info_for_grid(grid
), pixels_fb
, 0, 0, 0,
196 (image_num_components(img
.format
) < 4 ? 1 : 0))) {
197 printf(" Source: framebuffer\n");
201 /* Check that the image wasn't modified. */
202 if (!check_pixels(img
, pixels_img
, 1, 1, 1, 1)) {
203 printf(" Source: image\n");
211 invalidate_unbound(const struct image_info img
, GLuint prog
)
213 glBindImageTexture(0, 0, 0, GL_FALSE
, 0, GL_READ_ONLY
,
216 return piglit_check_gl_error(GL_NO_ERROR
);
220 invalidate_incomplete(const struct image_info img
, GLuint prog
)
222 /* Bind a mipmap level with incorrect dimensions so the
223 * texture becomes incomplete. */
224 bool ret
= init_level(img
, 1, img
.format
->format
, W
, H
);
226 glBindImageTexture(0, get_texture(0), 1, GL_TRUE
, 0, GL_READ_WRITE
,
229 return ret
&& piglit_check_gl_error(GL_NO_ERROR
);
233 invalidate_level_bounds(const struct image_info img
, GLuint prog
)
236 const struct image_extent size
= image_level_size(img
, level
);
237 /* Create a second mipmap level */
238 bool ret
= init_level(img
, level
, img
.format
->format
, size
.x
, size
.y
);
240 /* and set it as base level, */
241 glTexParameteriv(GL_TEXTURE_2D
, GL_TEXTURE_BASE_LEVEL
, &level
);
243 /* but keep the the first level bound. */
244 glBindImageTexture(0, get_texture(0), 0, GL_TRUE
, 0, GL_READ_WRITE
,
247 return ret
&& piglit_check_gl_error(GL_NO_ERROR
);
251 invalidate_invalid_format(const struct image_info img
, GLuint prog
)
253 const GLenum base_format
= image_base_internal_format(img
.format
);
254 /* Pick an invalid texture format with a compatible base
256 bool ret
= init_level(img
, 0, (base_format
== GL_RGBA32F
?
257 GL_RGB5_A1
: GL_RGB8UI
), W
, H
);
259 glBindImageTexture(0, get_texture(0), 0, GL_TRUE
, 0,
260 GL_READ_WRITE
, img
.format
->format
);
262 return ret
&& piglit_check_gl_error(GL_NO_ERROR
);
266 invalidate_incompatible_format(const struct image_info img
, GLuint prog
)
268 GLenum base_format
= image_base_internal_format(img
.format
);
269 /* Pick an incompatible texture format with a compatible base
271 glBindImageTexture(0, get_texture(0), 0, GL_TRUE
, 0,
272 GL_READ_WRITE
, (base_format
== GL_RGBA32F
?
273 GL_RGBA8
: GL_RG32UI
));
275 return piglit_check_gl_error(GL_NO_ERROR
);
279 invalidate_layer_bounds(const struct image_info img
, GLuint prog
)
281 glBindImageTexture(0, get_texture(0), 0, GL_FALSE
, N
,
282 GL_READ_WRITE
, img
.format
->format
);
284 return piglit_check_gl_error(GL_NO_ERROR
);
288 invalidate_address_bounds(const struct image_info img
, GLuint prog
)
290 return set_uniform_int(prog
, "off", N
);
294 invalidate_index_bounds(const struct image_info img
, GLuint prog
)
296 return set_uniform_int(prog
, "u", 0xdeadcafe);
300 invalidate_nop(const struct image_info img
, GLuint prog
)
306 run_test(const struct image_op_info
*op
,
307 const struct image_info real_img
,
308 const struct image_info prog_img
,
309 bool (*invalidate
)(const struct image_info
, GLuint
),
312 const struct grid_info grid
=
313 grid_info(GL_FRAGMENT_SHADER
,
314 image_base_internal_format(real_img
.format
), W
, H
);
315 GLuint prog
= generate_program(
316 grid
, GL_FRAGMENT_SHADER
,
317 concat(image_hunk(prog_img
, ""),
318 hunk("IMAGE_UNIFORM_T imgs[1];\n"
320 "uniform int off;\n"),
325 init_image(real_img
, prog
) &&
326 invalidate(real_img
, prog
) &&
327 draw_grid(grid
, prog
) &&
328 (check(grid
, real_img
) || control_test
);
330 glDeleteProgram(prog
);
335 piglit_init(int argc
, char **argv
)
337 enum piglit_result status
= PIGLIT_PASS
;
338 const struct image_op_info
*op
;
339 const struct image_format_info
*format
;
340 const struct image_target_info
*target
;
342 piglit_require_extension("GL_ARB_shader_image_load_store");
344 for (op
= image_ops
; op
->name
; ++op
) {
345 const struct image_info def_img
= image_info(
346 GL_TEXTURE_2D
, op
->formats
[0].format
, W
, H
);
347 const struct image_info def_img_buffer
= image_info(
348 GL_TEXTURE_BUFFER
, op
->formats
[0].format
, W
, H
);
351 * According to the spec, an access is considered
352 * invalid in the following cases, in which image
353 * stores and atomics should have no effect, and image
354 * loads should return zero:
356 * " * no texture is bound to the selected image unit;
359 subtest(&status
, true,
360 run_test(op
, def_img
, def_img
,
361 invalidate_unbound
, false),
362 "%s/unbound image test", op
->name
);
365 * " * the texture bound to the selected image unit is
368 subtest(&status
, true,
369 run_test(op
, def_img
, def_img
,
370 invalidate_incomplete
, false),
371 "%s/incomplete image test", op
->name
);
374 * " * the texture level bound to the image unit is
375 * less than the base level or greater than the
376 * maximum level of the texture; [...]"
378 subtest(&status
, true,
379 run_test(op
, def_img
, def_img
,
380 invalidate_level_bounds
, false),
381 "%s/level bounds test", op
->name
);
384 * " * the internal format of the texture bound to the
385 * image unit is not found in Table X.2; [...]"
387 subtest(&status
, true,
388 run_test(op
, def_img
, def_img
,
389 invalidate_invalid_format
, false),
390 "%s/invalid format test", op
->name
);
393 * " * the internal format of the texture bound to the
394 * image unit is incompatible with the specified
395 * <format> according to Table X.3; [...]"
397 subtest(&status
, true,
398 run_test(op
, def_img
, def_img
,
399 invalidate_incompatible_format
, false),
400 "%s/incompatible format test", op
->name
);
402 /* Test for the regression which happened when
403 * GL_TEXTURE_BUFFER was allowed to have incompatible format.
405 subtest(&status
, true,
406 run_test(op
, def_img_buffer
, def_img_buffer
,
407 invalidate_incompatible_format
, false),
408 "%s/incompatible format test/image%s",
409 op
->name
, def_img_buffer
.target
->name
);
412 * " * the texture bound to the image unit has layers,
413 * and the selected layer or cube map face doesn't
416 subtest(&status
, true,
418 image_info(GL_TEXTURE_2D_ARRAY
,
419 op
->formats
[0].format
, W
, H
),
420 def_img
, invalidate_layer_bounds
, false),
421 "%s/layer bounds test", op
->name
);
424 * " * the selected texel tau_i, tau_i_j, or tau_i_j_k
425 * doesn't exist; [...]"
427 for (target
= image_targets(); target
->name
; ++target
) {
428 const struct image_info img
= image_info(
429 target
->target
, op
->formats
[0].format
, W
, H
);
431 subtest(&status
, true,
432 run_test(op
, img
, img
,
433 invalidate_address_bounds
, false),
434 "%s/address bounds test/image%s/%s",
435 op
->name
, img
.target
->name
, img
.format
->name
);
438 for (format
= &op
->formats
[1]; format
->name
; ++format
) {
439 const struct image_info img
= image_info(
440 GL_TEXTURE_2D
, format
->format
, W
, H
);
442 subtest(&status
, true,
443 run_test(op
, img
, img
,
444 invalidate_address_bounds
, false),
445 "%s/address bounds test/image%s/%s",
446 op
->name
, img
.target
->name
, img
.format
->name
);
450 * The following cases have undefined results, but may
451 * not lead to program termination:
453 * "If the index used to select an individual [array]
454 * element is negative or greater than or equal to
455 * the size of the array [...]"
457 subtest(&status
, true,
458 run_test(op
, def_img
, def_img
,
459 invalidate_index_bounds
, true),
460 "%s/index bounds test", op
->name
);
463 * "the type of image variable used to access the
464 * image unit does not match the target of a texture
465 * bound to the image unit [...]"
467 subtest(&status
, true,
468 run_test(op
, def_img
,
469 image_info(GL_TEXTURE_3D
,
470 op
->formats
[0].format
, W
, H
),
471 invalidate_nop
, true),
472 "%s/target mismatch test", op
->name
);
475 * "the format layout qualifier for an image variable
476 * used for an image load or atomic operation does
477 * not match the format of the image unit [...]"
479 subtest(&status
, true,
481 image_info(GL_TEXTURE_2D
,
482 GL_R11F_G11F_B10F
, W
, H
),
483 def_img
, invalidate_nop
, true),
484 "%s/format mismatch test", op
->name
);
488 piglit_report_result(status
);