diff options
author | Francisco Jerez <currojerez@riseup.net> | 2014-12-04 12:49:16 +0200 |
---|---|---|
committer | Francisco Jerez <currojerez@riseup.net> | 2015-01-31 18:28:49 +0200 |
commit | ae9e89c75102beebb71180fd7cd4218a61b3a6e4 (patch) | |
tree | 57292471df809b76398bca7d83c89ca4643074f8 | |
parent | aed992baacccbc0b47fc29ceabf78cebfbf66b23 (diff) |
arb_shader_image_load_store: Import dead fragments test.
Test that image stores and atomics have no effect when called from
fragment shader invocations that aren't covered by a primitive or have
been discarded.
-rw-r--r-- | tests/all.py | 1 | ||||
-rw-r--r-- | tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt | 1 | ||||
-rw-r--r-- | tests/spec/arb_shader_image_load_store/dead-fragments.c | 249 |
3 files changed, 251 insertions, 0 deletions
diff --git a/tests/all.py b/tests/all.py index e4bdc1786..a21ff5eb0 100644 --- a/tests/all.py +++ b/tests/all.py @@ -4429,6 +4429,7 @@ import_glsl_parser_tests(spec['ARB_shader_image_load_store'], arb_shader_image_load_store['atomicity'] = PiglitGLTest(['arb_shader_image_load_store-atomicity'], run_concurrent=True) arb_shader_image_load_store['bitcast'] = PiglitGLTest(['arb_shader_image_load_store-bitcast'], run_concurrent=True) arb_shader_image_load_store['coherency'] = PiglitGLTest(['arb_shader_image_load_store-coherency'], run_concurrent=True) +arb_shader_image_load_store['dead-fragments'] = PiglitGLTest(['arb_shader_image_load_store-dead-fragments'], run_concurrent=True) profile.tests['hiz'] = hiz profile.tests['fast_color_clear'] = fast_color_clear diff --git a/tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt b/tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt index 6a6aa25d9..af8d85b5d 100644 --- a/tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt +++ b/tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt @@ -15,5 +15,6 @@ set(depends image.c grid.c common.c) piglit_add_executable(arb_shader_image_load_store-atomicity atomicity.c ${depends}) piglit_add_executable(arb_shader_image_load_store-bitcast bitcast.c ${depends}) piglit_add_executable(arb_shader_image_load_store-coherency coherency.c ${depends}) +piglit_add_executable(arb_shader_image_load_store-dead-fragments dead-fragments.c ${depends}) # vim: ft=cmake: diff --git a/tests/spec/arb_shader_image_load_store/dead-fragments.c b/tests/spec/arb_shader_image_load_store/dead-fragments.c new file mode 100644 index 000000000..d33fa02b9 --- /dev/null +++ b/tests/spec/arb_shader_image_load_store/dead-fragments.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** @file dead-fragments.c + * + * Quoting the ARB_shader_image_load_store extension: + * "If a fragment shader is invoked to process fragments or samples + * not covered by a primitive being rasterized to facilitate the + * approximation of derivatives for texture lookups, stores and + * atomics have no effect." + * + * The purpose of this test is to check this assertion, as well as + * that image stores and atomics have no effect after a fragment is + * discarded. Both tests are repeated for a few different built-in + * functions. + */ + +#include "common.h" + +/** Window width. */ +#define W 16 + +/** Window height. */ +#define H 96 + +/** Total number of pixels in the window and image. */ +#define N (W * H) + +PIGLIT_GL_TEST_CONFIG_BEGIN + +config.supports_gl_core_version = 32; + +config.window_width = W; +config.window_height = H; +config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA; + +PIGLIT_GL_TEST_CONFIG_END + +struct image_op_info { + /** Image built-in name. */ + const char *name; + + /** GLSL statement that invokes this image built-in. */ + const char *hunk; +}; + +static const struct image_op_info image_ops[] = { + { + "imageStore", + "void inc(ivec2 idx) {\n" + " imageStore(img, IMAGE_ADDR(idx)," + " imageLoad(img, IMAGE_ADDR(idx)) + BASE_T(1));\n" + "}\n" + }, + { + "imageAtomicAdd", + "void inc(ivec2 idx) {\n" + " imageAtomicAdd(img, IMAGE_ADDR(idx), BASE_T(1));\n" + "}\n" + }, + { + "imageAtomicMax", + "void inc(ivec2 idx) {\n" + " imageAtomicMax(img, IMAGE_ADDR(idx)," + " imageLoad(img, IMAGE_ADDR(idx)).x + BASE_T(1));\n" + "}\n" + }, + { + "imageAtomicExchange", + "void inc(ivec2 idx) {\n" + " imageAtomicExchange(img, IMAGE_ADDR(idx)," + " imageLoad(img, IMAGE_ADDR(idx)).x + BASE_T(1));\n" + "}\n" + }, + { + "imageAtomicCompSwap", + "void inc(ivec2 idx) {\n" + " imageAtomicCompSwap(img, IMAGE_ADDR(idx)," + " imageLoad(img, IMAGE_ADDR(idx)).x," + " imageLoad(img, IMAGE_ADDR(idx)).x + BASE_T(1));\n" + "}\n" + }, + { 0 } +}; + +static bool +init_image(const struct image_info img) +{ + uint32_t pixels[N]; + int i; + + for (i = 0; i < N; ++i) + pixels[i] = i / W; + + return upload_image(img, 0, pixels); +} + +static bool +check_discard(const struct grid_info grid, const struct image_info img, + unsigned w, unsigned h) +{ + uint32_t pixels[H][W], expect[H][W]; + int i, j; + + for (i = 0; i < W; ++i) + for (j = 0; j < H; ++j) + expect[j][i] = (i % 5 == 0 ? 0 : 1) + j; + + return download_image(img, 0, pixels[0]) && + check_pixels_v(img, pixels[0], expect[0]); +} + +static bool +check_derivative(const struct grid_info grid, const struct image_info img, + unsigned w, unsigned h) +{ + uint32_t pixels_fb[H][W], expect_fb[H][W]; + uint32_t pixels_img[H][W], expect_img[H][W]; + int i, j; + + for (i = 0; i < W; ++i) { + for (j = 0; j < H; ++j) { + expect_fb[j][i] = (j < h && i < w ? 1000 : + encode(get_image_format(GL_R32F), 0.5)); + expect_img[j][i] = (j < h && i < w ? 1 : 0) + j; + } + } + + if (!download_result(grid, pixels_fb[0]) || + !download_image(img, 0, pixels_img[0])) + return false; + + if (!check_pixels_v(img, pixels_fb[0], expect_fb[0])) { + printf(" Source: framebuffer\n"); + /* + * Purely informational check, we don't care what the + * result is as long as derivatives are being + * calculated, don't fail if the result doesn't equal + * the expected value as it's most likely an accuracy + * issue. + */ + } + + if (!check_pixels_v(img, pixels_img[0], expect_img[0])) { + printf(" Source: image\n"); + return false; + } + + return true; +} + +static bool +run_test(const struct image_op_info *op, + unsigned w, unsigned h, + bool (*check)(const struct grid_info grid, + const struct image_info img, + unsigned w, unsigned h), + const char *body) +{ + const struct grid_info grid = + grid_info(GL_FRAGMENT_SHADER, GL_R32UI, W, H); + const struct image_info img = image_info_for_grid(grid); + GLuint prog = generate_program( + grid, GL_FRAGMENT_SHADER, + concat(image_hunk(img, ""), + hunk("uniform IMAGE_T img;\n"), + hunk(op->hunk), + hunk(body), NULL)); + bool ret = prog && + init_fb(grid) && + init_image(img) && + set_uniform_int(prog, "img", 0) && + draw_grid(set_grid_size(grid, w, h), prog) && + check(grid, img, w, h); + + glDeleteProgram(prog); + return ret; +} + +void +piglit_init(int argc, char **argv) +{ + enum piglit_result status = PIGLIT_PASS; + const struct image_op_info *op; + + piglit_require_extension("GL_ARB_shader_image_load_store"); + + for (op = image_ops; op->name; ++op) { + /* + * Draw a rectangle discarding a subset of the + * fragments before inc() is run, then make sure that + * it had no effect for those fragments. + */ + subtest(&status, true, + run_test(op, W, H, check_discard, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " if (idx.x % 5 == 0)\n" + " discard;\n" + " inc(idx);\n" + " return x;\n" + "}\n"), + "%s/discard test", op->name); + + /* + * Draw a 1-pixel wide rectangle and make a derivative + * computation in the orthogonal direction to get the + * GPU to run fragment shader invocations located + * outside the primitive, then make sure that inc() + * had no effect for those fragments. + */ + subtest(&status, true, + run_test(op, W - 3, 1, check_derivative, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " x = uvec4(1000 * dFdy(vec4(" + " imageLoad(img, IMAGE_ADDR(idx)))));" + " inc(idx);\n" + " return x;\n" + "}\n"), + "%s/derivative test", op->name); + } + + piglit_report_result(status); +} + +enum piglit_result +piglit_display(void) +{ + return PIGLIT_FAIL; +} |