Test that image built-in functions do what they are supposed to do by comparing their results with a simulation run on the CPU with similar inputs. The test is repeated for all built-ins, shader stages, formats and texture targets either sequentially or combinatorially depending on the --quick flag. --- tests/all.py | 1 + tests/quick.py | 1 + .../arb_shader_image_load_store/CMakeLists.gl.txt | 1 + tests/spec/arb_shader_image_load_store/semantics.c | 397 +++++++++++++++++++++ 4 files changed, 400 insertions(+) create mode 100644 tests/spec/arb_shader_image_load_store/semantics.c
diff --git a/tests/all.py b/tests/all.py index 3f95600..56852ad 100644 --- a/tests/all.py +++ b/tests/all.py @@ -4441,6 +4441,7 @@ arb_shader_image_load_store['max-size'] = PiglitGLTest('arb_shader_image_load_st arb_shader_image_load_store['minmax'] = PiglitGLTest('arb_shader_image_load_store-minmax', run_concurrent=True) arb_shader_image_load_store['qualifiers'] = PiglitGLTest('arb_shader_image_load_store-qualifiers', run_concurrent=True) arb_shader_image_load_store['restrict'] = PiglitGLTest('arb_shader_image_load_store-restrict', run_concurrent=True) +arb_shader_image_load_store['semantics'] = PiglitGLTest('arb_shader_image_load_store-semantics', run_concurrent=True) profile.tests['hiz'] = hiz profile.tests['fast_color_clear'] = fast_color_clear diff --git a/tests/quick.py b/tests/quick.py index 77cbefb..aa20059 100644 --- a/tests/quick.py +++ b/tests/quick.py @@ -16,3 +16,4 @@ del profile.tests['shaders']['glsl-vs-unroll-explosion'] profile.tests['spec']['ARB_shader_image_load_store']['coherency'].command += ["--quick"] profile.tests['spec']['ARB_shader_image_load_store']['host-mem-barrier'].command += ["--quick"] profile.tests['spec']['ARB_shader_image_load_store']['max-size'].command += ["--quick"] +profile.tests['spec']['ARB_shader_image_load_store']['semantics'].command += ["--quick"] 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 bf202e4..f03b4af 100644 --- a/tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt +++ b/tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt @@ -27,5 +27,6 @@ piglit_add_executable(arb_shader_image_load_store-max-size max-size.c ${depends} piglit_add_executable(arb_shader_image_load_store-minmax minmax.c ${depends}) piglit_add_executable(arb_shader_image_load_store-qualifiers qualifiers.c ${depends}) piglit_add_executable(arb_shader_image_load_store-restrict restrict.c ${depends}) +piglit_add_executable(arb_shader_image_load_store-semantics semantics.c ${depends}) # vim: ft=cmake: diff --git a/tests/spec/arb_shader_image_load_store/semantics.c b/tests/spec/arb_shader_image_load_store/semantics.c new file mode 100644 index 0000000..122e490 --- /dev/null +++ b/tests/spec/arb_shader_image_load_store/semantics.c @@ -0,0 +1,397 @@ +/* + * 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 semantics.c + * + * Test all allowed combinations of image targets, formats, built-in + * functions and shader stages. The test initializes an image to some + * arbitrary pattern and runs N invocations of a shader that calls the + * built-in function once on the corresponding location of the image. + * Then the same operation is simulated on the CPU and the results are + * compared with each other. + */ + +#include "common.h" + +/** Window width. The actual width of the image varies with the image + * dimensionality, but the total number of pixels \a N remains + * invariant. */ +#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; + + /** Allowed image formats. */ + const struct image_format_info *formats; + + /** Execute this image built-in on the CPU. */ + void (*exec)(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret); + + /** GLSL statement that invokes this image built-in. */ + const char *hunk; +}; + +static void +image_exec_load(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + int i; + + for (i = 0; i < image_num_components(format); ++i) + ret[i] = img[i]; +} + +static void +image_exec_store(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + int i; + + for (i = 0; i < image_num_components(format); ++i) + img[i] = arg[i]; + + for (i = 0; i < 4; ++i) + ret[i] = 0; +} + +static void +image_exec_add(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + ret[0] = img[0]; + img[0] = encode(format, (decode(format, img[0]) + + decode(format, arg[0]))); +} + +static void +image_exec_min(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + ret[0] = img[0]; + img[0] = encode(format, MIN2(decode(format, img[0]), + decode(format, arg[0]))); +} + +static void +image_exec_max(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + ret[0] = img[0]; + img[0] = encode(format, MAX2(decode(format, img[0]), + decode(format, arg[0]))); +} + +static void +image_exec_and(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + ret[0] = img[0]; + img[0] = img[0] & arg[0]; +} + +static void +image_exec_or(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + ret[0] = img[0]; + img[0] = img[0] | arg[0]; +} + +static void +image_exec_xor(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + ret[0] = img[0]; + img[0] = img[0] ^ arg[0]; +} + +static void +image_exec_exchange(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + ret[0] = img[0]; + img[0] = arg[0]; +} + +static void +image_exec_comp_swap(const struct image_format_info *format, + const uint32_t *arg, uint32_t *img, uint32_t *ret) +{ + ret[0] = img[0]; + img[0] = (img[0] == encode(format, image_format_scale(format).x / N) ? + arg[0] : img[0]); +} + +static const struct image_op_info image_ops[] = { + { + "imageLoad", image_formats_load_store, image_exec_load, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " return imageLoad(img, IMAGE_ADDR(idx));\n" + "}\n" + }, + { + "imageStore", image_formats_load_store, image_exec_store, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " imageStore(img, IMAGE_ADDR(idx), arg(idx));\n" + " return GRID_T(0);" + "}\n" + }, + { + "imageAtomicAdd", image_formats_atomic, image_exec_add, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " return GRID_T(imageAtomicAdd(img, IMAGE_ADDR(idx)," + " arg(idx).x)," + " 0, 0, 1);\n" + "}\n" + }, + { + "imageAtomicMin", image_formats_atomic, image_exec_min, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " return GRID_T(imageAtomicMin(img, IMAGE_ADDR(idx)," + " arg(idx).x)," + " 0, 0, 1);\n" + "}\n" + }, + { + "imageAtomicMax", image_formats_atomic, image_exec_max, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " return GRID_T(imageAtomicMax(img, IMAGE_ADDR(idx)," + " arg(idx).x)," + " 0, 0, 1);\n" + "}\n" + }, + { + "imageAtomicAnd", image_formats_atomic, image_exec_and, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " return GRID_T(imageAtomicAnd(img, IMAGE_ADDR(idx)," + " arg(idx).x)," + " 0, 0, 1);\n" + "}\n" + }, + { + "imageAtomicOr", image_formats_atomic, image_exec_or, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " return GRID_T(imageAtomicOr(img, IMAGE_ADDR(idx)," + " arg(idx).x)," + " 0, 0, 1);\n" + "}\n" + }, + { + "imageAtomicXor", image_formats_atomic, image_exec_xor, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " return GRID_T(imageAtomicXor(img, IMAGE_ADDR(idx)," + " arg(idx).x)," + " 0, 0, 1);\n" + "}\n" + }, + { + "imageAtomicExchange", image_formats_atomic, image_exec_exchange, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " return GRID_T(imageAtomicExchange(img, IMAGE_ADDR(idx)," + " arg(idx).x)," + " 0, 0, 1);\n" + "}\n" + }, + { + "imageAtomicCompSwap", image_formats_atomic, image_exec_comp_swap, + "GRID_T op(ivec2 idx, GRID_T x) {\n" + " return GRID_T(imageAtomicCompSwap(img, IMAGE_ADDR(idx)," + " BASE_T(SCALE.x / N)," + " arg(idx).x)," + " 0, 0, 1);\n" + "}\n" + }, + { 0 } +}; + +static bool +init_image_pixels(const struct image_info img, unsigned unit, + uint32_t *r_pixels) +{ + const unsigned m = image_num_components(img.format); + unsigned i; + + for (i = 0; i < m * N; ++i) + r_pixels[i] = encode(img.format, + get_idx(image_format_scale(img.format), i % m) + * (unit == 0 ? i : m * N - i) / (m * N)); + + return true; +} + +static bool +init_image(const struct image_info img, unsigned unit) +{ + uint32_t pixels[4 * N]; + + return init_image_pixels(img, unit, pixels) && + upload_image(img, unit, pixels); +} + +static bool +check(const struct image_op_info *op, + const struct grid_info grid, + const struct image_info img) +{ + const struct image_info grid_img = { + get_image_target(GL_TEXTURE_2D), + grid.format, grid.size, img.epsilon + }; + const unsigned m = image_num_components(img.format); + uint32_t pixels_fb[4 * N], expect_fb[4 * N]; + uint32_t pixels_img[4 * N], expect_img[4 * N]; + uint32_t arg[4 * N]; + int i; + + if (!download_result(grid, pixels_fb) || + !download_image(img, 0, pixels_img)) + return false; + + /* Initialize the image and argument to the known state. */ + init_image_pixels(img, 0, expect_img); + init_image_pixels(img, 1, arg); + init_pixels(grid_img, expect_fb, 0, 0, 0, 1); + + /* Calculate the result of the image built-in. */ + for (i = 0; i < N; ++i) + op->exec(img.format, &arg[m * i], &expect_img[m * i], + &expect_fb[4 * i]); + + /* Check that the shader gave the same result. */ + if (!check_pixels_v(grid_img, pixels_fb, expect_fb)) { + printf(" Source: framebuffer\n"); + return false; + } + + if (!check_pixels_v(img, pixels_img, expect_img)) { + printf(" Source: image\n"); + return false; + } + + return true; +} + +static bool +run_test(const struct image_op_info *op, + const struct image_stage_info *stage, + const struct image_format_info *format, + const struct image_target_info *target) +{ + const struct grid_info grid = grid_info( + stage->stage, image_base_internal_format(format), W, H); + const struct image_info img = image_info( + target->target, format->format, W, H); + GLuint prog = generate_program( + grid, stage->stage, + concat(image_hunk(img, ""), + hunk("uniform IMAGE_T img;\n" + "uniform IMAGE_T arg_img;\n" + "\n" + "GRID_T arg(ivec2 idx) {\n" + " return imageLoad(arg_img, IMAGE_ADDR(idx));\n" + "}\n"), + hunk(op->hunk), NULL)); + bool ret = prog && init_fb(grid) && + init_image(img, 0) && + init_image(img, 1) && + set_uniform_int(prog, "img", 0) && + set_uniform_int(prog, "arg_img", 1) && + draw_grid(grid, prog) && + check(op, grid, img); + + glDeleteProgram(prog); + return ret; +} + +void +piglit_init(int argc, char **argv) +{ + /* + * If quick is enabled traverse each variable (stage, op, + * format and target) in sequence leaving the other ones fixed + * instead of going through the cartesian product of the four + * variables. + */ + const bool quick = (argc >= 2 && !strcmp(argv[1], "--quick")); + enum piglit_result status = PIGLIT_PASS; + const struct image_stage_info *stage; + const struct image_op_info *op; + const struct image_format_info *format; + const struct image_target_info *target; + unsigned m = 0; + + piglit_require_extension("GL_ARB_shader_image_load_store"); + piglit_require_extension("GL_ARB_texture_cube_map_array"); + + for (op = image_ops; op->name; ++op) { + for (stage = image_stages(); stage->name; ++stage) { + for (format = op->formats; format->name; ++format) { + for (target = image_targets(); target->name; ++target) { + subtest(&status, true, + run_test(op, stage, format, target), + "%s/%s shader/%s/image%s test", + op->name, stage->name, + format->name, target->name); + + if (quick && (m & 1)) + break; + } + + if (quick && ((m |= 1) & 2)) + break; + } + + if (quick && ((m |= 2) & 4)) + break; + } + + if (quick) + m |= 4; + } + + piglit_report_result(status); +} + +enum piglit_result +piglit_display(void) +{ + return PIGLIT_FAIL; +} -- 2.1.3 _______________________________________________ Piglit mailing list Piglit@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/piglit