/* * 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 layer.c * * The spec defines two different image unit binding modes for * textures with multiple layers, depending on the "layered" parameter * of glBindImageTexture(): * * "If is TRUE, the entire level is bound. If is * FALSE, only the single layer identified by will be bound. * When is FALSE, the single bound layer is treated as a * different texture target for image accesses: * * * one-dimensional array texture layers are treated as one-dimensional * textures; * * * two-dimensional array, three-dimensional, cube map, cube map array * texture layers are treated as two-dimensional textures; and * * * two-dimensional multisample array textures are treated as * two-dimensional multisample textures." * * We check that this is the case by binding a texture of each target * in layered or unlayered mode and then dumping all the accessible * contents of the texture to the framebuffer from a fragment shader. * After each individual texel is read its old contents are * overwritten by the shader. * * For textures that don't have multiple layers we check that the * described process reads and subsequently overwrites the full * texture contents regardless of the values of the layered and layer * parameters, since according to the spec: * * "If the texture identified by does not have multiple * layers or faces, the entire texture level is bound, regardless of * the values specified by and ." */ #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; config.khr_no_error_support = PIGLIT_NO_ERRORS; PIGLIT_GL_TEST_CONFIG_END static bool init_image(const struct image_info img, bool layered, unsigned l) { uint32_t pixels[4 * N]; unsigned i; bool ret; for (i = 0; i < 4 * N; ++i) pixels[i] = encode(img.format, i); ret = upload_image(img, 0, pixels); glBindImageTexture(0, get_texture(0), 0, layered, l, GL_READ_WRITE, img.format->format); return ret && piglit_check_gl_error(GL_NO_ERROR); } static bool check(const struct grid_info grid, const struct image_info img, unsigned l) { const unsigned layer_sz = 4 * product(grid.size); uint32_t pixels_fb[4 * N], expect_fb[4 * N]; uint32_t pixels_img[4 * N], expect_img[4 * N]; unsigned i; if (!download_result(grid, pixels_fb) || !download_image(img, 0, pixels_img)) return false; for (i = 0; i < layer_sz; ++i) { /* * The framebuffer contents should reflect layer l of * the image which is bound to the image unit. */ expect_fb[i] = encode(grid.format, layer_sz * l + i); } for (i = 0; i < 4 * N; ++i) { if (i / layer_sz == l) { /* * Layer l should have been modified by the * shader. */ expect_img[i] = encode(img.format, 33); } else { /* * Other layers should have remained * unchanged. */ expect_img[i] = encode(img.format, i); } } if (!check_pixels_v(image_info_for_grid(grid), 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; } /** * If \a layered is false, bind an individual layer of a texture to an * image unit, read its contents and write back a different value to * the same location. If \a layered is true or the texture has a * single layer, the whole texture will be read and written back. * * For textures with a single layer, the arguments \a layered and \a * layer which are passed to the same arguments of * glBindImageTexture() should have no effect as required by the spec. */ static bool run_test(const struct image_target_info *target, bool layered, unsigned layer) { const struct image_info real_img = image_info( target->target, GL_RGBA32F, W, H); const unsigned slices = (layered ? 1 : image_num_layers(real_img)); /* * "Slice" of the image that will be bound to the pipeline. */ const struct image_info slice_img = image_info( (layered ? target->target : image_layer_target(target)), GL_RGBA32F, W, H / slices); /* * Grid with as many elements as the slice. */ const struct grid_info grid = grid_info( GL_FRAGMENT_SHADER, GL_RGBA32F, W, H / slices); GLuint prog = generate_program( grid, GL_FRAGMENT_SHADER, concat(image_hunk(slice_img, ""), hunk("IMAGE_UNIFORM_T img;\n" "\n" "GRID_T op(ivec2 idx, GRID_T x) {\n" " GRID_T v = imageLoad(img, IMAGE_ADDR(idx));\n" " imageStore(img, IMAGE_ADDR(idx), DATA_T(33));\n" " return v;\n" "}\n"), NULL)); bool ret = prog && init_fb(grid) && init_image(real_img, layered, layer) && set_uniform_int(prog, "img", 0) && draw_grid(grid, prog) && check(grid, real_img, (slices == 1 ? 0 : layer)); glDeleteProgram(prog); return ret; } void piglit_init(int argc, char **argv) { enum piglit_result status = PIGLIT_PASS; const struct image_target_info *target; piglit_require_extension("GL_ARB_shader_image_load_store"); for (target = image_targets(); target->name; ++target) { subtest(&status, true, run_test(target, false, 5), "image%s/non-layered binding test", target->name); subtest(&status, true, run_test(target, true, 5), "image%s/layered binding test", target->name); } piglit_report_result(status); } enum piglit_result piglit_display(void) { return PIGLIT_FAIL; }