/* * 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; config.khr_no_error_support = PIGLIT_NO_ERRORS; 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("IMAGE_UNIFORM_T img;\n" "IMAGE_UNIFORM_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; }