summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/all.py1
-rw-r--r--tests/quick.py2
-rw-r--r--tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt1
-rw-r--r--tests/spec/arb_shader_image_load_store/host-mem-barrier.c1063
4 files changed, 1067 insertions, 0 deletions
diff --git a/tests/all.py b/tests/all.py
index 7444b1530..a0a68acc6 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -4431,6 +4431,7 @@ arb_shader_image_load_store['bitcast'] = PiglitGLTest(['arb_shader_image_load_st
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)
arb_shader_image_load_store['early-z'] = PiglitGLTest(['arb_shader_image_load_store-early-z'], run_concurrent=True)
+arb_shader_image_load_store['host-mem-barrier'] = PiglitGLTest(['arb_shader_image_load_store-host-mem-barrier'], 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 10333965d..d82410068 100644
--- a/tests/quick.py
+++ b/tests/quick.py
@@ -15,3 +15,5 @@ del profile.tests['shaders']['glsl-vs-unroll-explosion']
profile.tests['spec']['ARB_shader_image_load_store']['coherency'] = PiglitGLTest(
['arb_shader_image_load_store-coherency', '--quick'], run_concurrent=True)
+profile.tests['spec']['ARB_shader_image_load_store']['host-mem-barrier'] = PiglitGLTest(
+ ['arb_shader_image_load_store-host-mem-barrier', '--quick'], run_concurrent=True)
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 874afac5a..814a58554 100644
--- a/tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt
+++ b/tests/spec/arb_shader_image_load_store/CMakeLists.gl.txt
@@ -17,5 +17,6 @@ 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})
piglit_add_executable(arb_shader_image_load_store-early-z early-z.c ${depends})
+piglit_add_executable(arb_shader_image_load_store-host-mem-barrier host-mem-barrier.c ${depends})
# vim: ft=cmake:
diff --git a/tests/spec/arb_shader_image_load_store/host-mem-barrier.c b/tests/spec/arb_shader_image_load_store/host-mem-barrier.c
new file mode 100644
index 000000000..ee0d650fc
--- /dev/null
+++ b/tests/spec/arb_shader_image_load_store/host-mem-barrier.c
@@ -0,0 +1,1063 @@
+/*
+ * 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 host-mem-barrier.c
+ *
+ * Unlike other GL API objects, images are not implicitly synchronized
+ * with subsequent GL operations. The glMemoryBarrier() API is provided
+ * to serialize shader memory transactions issued by previous drawing
+ * commands with respect to a given set of subsequent GL commands
+ * specified as a bit set.
+ *
+ * This test should cause several kinds of data hazard situations
+ * deliberately (RaW, WaR, WaW) between image loads and stores and other
+ * parts of the pipeline including vertex, element and indirect command
+ * fetch, shader uniform buffer, image and atomic counter access, texture
+ * sampling, pixel transfer operations, texture and buffer update
+ * commands, framebuffer writes and reads and transform feedback output.
+ *
+ * The test is repeated for different execution sizes to account for
+ * implementations with varying levels of parallelism and with caches
+ * of different sizes. Unless running in "quick" mode a series of
+ * control tests is executed which inhibits all glMemoryBarrier()
+ * calls in order to make sure that the test is leading to data
+ * hazards, since otherwise the main test is not meaningful. The
+ * control test always passes as it is expected to misrender.
+ */
+
+#include "common.h"
+
+/** Maximum image width. */
+#define L 64
+
+/** Maximum number of pixels. */
+#define N (L * L)
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+config.supports_gl_core_version = 32;
+
+config.window_width = L;
+config.window_height = L;
+config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+static char *
+common_hunk(const struct image_info img)
+{
+ return concat(hunk("#extension GL_ARB_shader_atomic_counters : enable\n"),
+ image_hunk(img, ""),
+ hunk("#define RED DATA_T(1, 0, 0, 1)\n"
+ "#define GREEN DATA_T(0, 1, 0, 1)\n"
+ "\n"
+ "uniform IMAGE_T src_img;\n"
+ "uniform IMAGE_T dst_img;\n"
+ "uniform int pass;\n"), NULL);
+}
+
+struct image_barrier_info {
+ /** Test name. */
+ const char *name;
+
+ /** Invoke a memory barrier affecting the specified units. */
+ bool (*run_barrier)(GLbitfield barriers);
+
+ /** Informative "control" test with no barriers whose result
+ * is ignored. */
+ bool control_test;
+};
+
+static bool
+run_barrier_none(GLbitfield barriers)
+{
+ return true;
+}
+
+static bool
+run_barrier_one(GLbitfield barriers)
+{
+ glMemoryBarrier(barriers);
+ return piglit_check_gl_error(GL_NO_ERROR);
+}
+
+static bool
+run_barrier_full(GLbitfield barriers)
+{
+ glMemoryBarrier(GL_ALL_BARRIER_BITS);
+ return piglit_check_gl_error(GL_NO_ERROR);
+}
+
+const struct image_barrier_info image_barriers[] = {
+ { "control", run_barrier_none, true },
+ { "one bit", run_barrier_one, false },
+ { "full", run_barrier_full, false },
+ { 0 }
+};
+
+static bool
+check_fb_green(const struct grid_info grid)
+{
+ uint32_t pixels[N][4];
+
+ return download_result(grid, pixels[0]) &&
+ check_pixels(image_info_for_grid(grid),
+ pixels[0], 0, 1, 0, 1);
+}
+
+static bool
+check_img_green(const struct image_info img)
+{
+ uint32_t pixels[N][4];
+
+ return download_image(img, 1, pixels[0]) &&
+ check_pixels(img, pixels[0], 0, 1, 0, 1);
+}
+
+static bool
+init_common(const struct grid_info grid, const struct image_info img,
+ GLuint prog)
+{
+ uint32_t pixels[N][4];
+
+ if (!init_pixels(img, pixels[0], 0, 1, 0, 1) ||
+ !upload_image(img, 0, pixels[0]) ||
+ !init_pixels(img, pixels[0], 66, 66, 66, 66) ||
+ !upload_image(img, 1, pixels[0]))
+ return false;
+
+ set_uniform_int(prog, "src_img", 0);
+ set_uniform_int(prog, "dst_img", 1);
+ set_uniform_int(prog, "pass", 0);
+
+ return init_fb(grid);
+}
+
+static bool
+run_test_vertex_array_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_VERTEX_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32F, l, l);
+ static GLuint vao, vbo;
+ GLuint prog = generate_program(
+ grid, GL_VERTEX_SHADER,
+ concat(common_hunk(img),
+ hunk("in vec4 piglit_texcoord;\n"
+ "\n"
+ "GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " return piglit_texcoord;\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), GREEN);\n"
+ " return x;\n"
+ " }\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog) &&
+ generate_grid_arrays(&vao, &vbo,
+ 1.0 / l - 1.0, 1.0 / l - 1.0,
+ 2.0 / l, 2.0 / l, l, l);
+
+ /* Bind the image as texcoord vbo simultaneously. */
+ glBindBuffer(GL_ARRAY_BUFFER, get_buffer(1));
+ glVertexAttribPointer(PIGLIT_ATTRIB_TEX, 4, GL_FLOAT, GL_FALSE,
+ 0, 0);
+ glEnableVertexAttribArray(PIGLIT_ATTRIB_TEX);
+
+ /* First pass: render green to the vbo. */
+ glDrawArrays(GL_POINTS, 0, l * l);
+
+ /* Barrier. */
+ bar->run_barrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
+
+ /* Second pass: check that the texcoords are all green
+ * (read-after-write). */
+ set_uniform_int(prog, "pass", 1);
+ glDrawArrays(GL_POINTS, 0, l * l);
+
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_fb_green(grid);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_element_array_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_R32UI, l, l);
+ static GLuint vao, vbo;
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " return GRID_T(GREEN);\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx),"
+ " DATA_T(IMAGE_ADDR(idx)));\n"
+ " return x;\n"
+ " }\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog) &&
+ generate_grid_arrays(&vao, &vbo,
+ 1.0 / l - 1.0, 1.0 / l - 1.0,
+ 2.0 / l, 2.0 / l, l, l);
+
+ /* Bind the image as element buffer simultaneously. */
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, get_buffer(1));
+
+ /* First pass: write sequential indices to the element buffer. */
+ glDrawArrays(GL_POINTS, 0, l * l);
+
+ /* Barrier. */
+ bar->run_barrier(GL_ELEMENT_ARRAY_BARRIER_BIT);
+
+ /* Second pass: render the generated element buffer
+ * (read-after-write). */
+ set_uniform_int(prog, "pass", 1);
+ glDrawElements(GL_POINTS, l * l, GL_UNSIGNED_INT, 0);
+
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_fb_green(grid);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_ubo_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("layout(std140) uniform u {\n"
+ " vec4 xs[N];\n"
+ "};\n"
+ "\n"
+ "GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " return xs[IMAGE_ADDR(idx)];\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), GREEN);\n"
+ " return x;\n"
+ " }\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+
+ /* Bind the image as uniform buffer simultaneously. */
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, get_buffer(1));
+
+ /* First pass: render green to the uniform buffer. */
+ ret &= draw_grid(grid, prog) &&
+
+ /* Barrier. */
+ bar->run_barrier(GL_UNIFORM_BARRIER_BIT) &&
+
+ /* Second pass: check that the uniforms are all green
+ * (read-after-write). */
+ set_uniform_int(prog, "pass", 1) &&
+ draw_grid(grid, prog) &&
+ check_fb_green(grid);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_tex_fetch_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_2D, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("uniform sampler2D tex;\n"
+ "\n"
+ "GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " return texelFetch(tex, idx, 0);\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), GREEN);\n"
+ " return x;\n"
+ " }\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+
+ /* Bind the image as texture simultaneously. */
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, get_texture(1));
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ /* First pass: render green to the uniform buffer. */
+ ret &= draw_grid(grid, prog) &&
+
+ /* Barrier. */
+ bar->run_barrier(GL_TEXTURE_FETCH_BARRIER_BIT) &&
+ set_uniform_int(prog, "pass", 1) &&
+
+ /* Second pass: check that the texture is green
+ * (read-after-write). */
+ draw_grid(grid, prog) &&
+ check_fb_green(grid);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_image_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_2D, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " return imageLoad(dst_img, IMAGE_ADDR(idx));\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), GREEN);\n"
+ " return x;\n"
+ " }\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog) &&
+
+ /* First pass: render green to the image. */
+ draw_grid(grid, prog) &&
+
+ /* Barrier. */
+ bar->run_barrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) &&
+
+ /* Second pass: check that the image is green
+ * (read-after-write). */
+ set_uniform_int(prog, "pass", 1) &&
+ draw_grid(grid, prog) &&
+ check_fb_green(grid);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_image_war(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_2D, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " imageStore(src_img, IMAGE_ADDR(idx), RED);\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx),"
+ " imageLoad(src_img, IMAGE_ADDR(idx)));\n"
+ " }\n"
+ " return x;\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog) &&
+
+ /* First pass: read back the source image. */
+ draw_grid(grid, prog) &&
+
+ /* Barrier. */
+ bar->run_barrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) &&
+
+ /* Second pass: render red to the source image
+ * (write-after-read). */
+ set_uniform_int(prog, "pass", 1) &&
+ draw_grid(grid, prog) &&
+
+ /* Check that the read-back results from the first
+ * pass are green. */
+ check_img_green(img);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_indirect_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_VERTEX_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32UI, l, l);
+ static GLuint vao, vbo;
+ GLuint prog = generate_program(
+ grid, GL_VERTEX_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " return GRID_T(gl_InstanceID == 2 ? GREEN : RED);\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx),"
+ " DATA_T(1, 3, IMAGE_ADDR(idx), 0));\n"
+ " return x;\n"
+ " }\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog) &&
+ generate_grid_arrays(&vao, &vbo,
+ 1.0 / l - 1.0, 1.0 / l - 1.0,
+ 2.0 / l, 2.0 / l, l, l);
+
+ /* Bind the image as indirect command buffer
+ * simultaneously. */
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, get_buffer(1));
+
+ /* First pass: Render instanced draw commands to the indirect
+ * buffer. */
+ glDrawArrays(GL_POINTS, 0, l * l);
+
+ /* Barrier. */
+ bar->run_barrier(GL_COMMAND_BARRIER_BIT);
+
+ /* Second pass: render the generated indirect buffer
+ * (read-after-write). */
+ set_uniform_int(prog, "pass", 1);
+ glMultiDrawArraysIndirect(GL_POINTS, 0, l * l, 0);
+
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_fb_green(grid);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_pixel_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), GREEN);\n"
+ " return x;\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+ uint32_t pixels[N][4];
+ GLuint tex;
+
+ /* Bind the image as pixel unpack buffer simultaneously. */
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, get_buffer(1));
+
+ /* First pass: render green to the image. */
+ draw_grid(grid, prog);
+
+ /* Barrier. */
+ bar->run_barrier(GL_PIXEL_BUFFER_BARRIER_BIT);
+
+ /* Second pass: use the result as pixel source
+ * (read-after-write). */
+ glTexImage2D(GL_TEXTURE_2D, 0, img.format->format,
+ l, l, 0, img.format->pixel_format,
+ img.format->pixel_type, 0);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ /* Check that the resulting texture is green. */
+ glGetTexImage(GL_TEXTURE_2D, 0, img.format->pixel_format,
+ image_base_type(img.format), pixels);
+
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_pixels(img, pixels[0], 0, 1, 0, 1);
+
+ glDeleteTextures(1, &tex);
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_pixel_waw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), RED);\n"
+ " return x;\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+ uint32_t pixels[N][4];
+ GLuint tex;
+
+ init_pixels(img, pixels[0], 0, 1, 0, 1);
+
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, img.format->format,
+ l, l, 0, img.format->pixel_format,
+ image_base_type(img.format), pixels);
+
+ /* Bind the image as pixel pack buffer simultaneously. */
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, get_buffer(1));
+
+ /* First pass: render red to the image. */
+ draw_grid(grid, prog);
+
+ /* Barrier. */
+ bar->run_barrier(GL_PIXEL_BUFFER_BARRIER_BIT);
+
+ /* Second pass: use the image as pixel destination filling it
+ * with green (write-after-write). */
+ glGetTexImage(GL_TEXTURE_2D, 0, img.format->pixel_format,
+ img.format->pixel_type, 0);
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+
+ /* Check that the resulting image is green. */
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_img_green(img);
+
+ glDeleteTextures(1, &tex);
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_tex_update_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_2D, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), GREEN);\n"
+ " return x;\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+ uint32_t pixels[N][4];
+
+ glBindTexture(GL_TEXTURE_2D, get_texture(1));
+
+ /* First pass: render green to the image. */
+ draw_grid(grid, prog);
+
+ /* Barrier. */
+ bar->run_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
+
+ /* Read back the result (read-after-write). */
+ glGetTexImage(GL_TEXTURE_2D, 0, img.format->pixel_format,
+ image_base_type(img.format), pixels);
+
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_pixels(img, pixels[0], 0, 1, 0, 1);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_tex_update_waw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_2D, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx),"
+ " (idx.y >= H / 2 ? GREEN : RED));\n"
+ " return x;\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+ uint32_t pixels[N][4];
+
+ init_pixels(set_image_size(img, l, l / 2, 1, 1),
+ pixels[0], 0, 1, 0, 1);
+
+ glBindTexture(GL_TEXTURE_2D, get_texture(1));
+
+ /* First pass: render red to the first half of the image,
+ * green to the second half. */
+ draw_grid(grid, prog);
+
+ /* Barrier. */
+ bar->run_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
+
+ /* Fill the first half with green (write-after-write). */
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, l, l / 2,
+ img.format->pixel_format, image_base_type(img.format),
+ pixels);
+
+ /* Check that the resulting image is green. */
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_img_green(img);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_buf_update_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), GREEN);\n"
+ " return x;\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+ uint32_t pixels[N][4];
+
+ glBindBuffer(GL_TEXTURE_BUFFER, get_buffer(1));
+
+ /* First pass: render green to the image. */
+ draw_grid(grid, prog);
+
+ /* Barrier. */
+ bar->run_barrier(GL_BUFFER_UPDATE_BARRIER_BIT);
+
+ /* Read back the result (read-after-write). */
+ glGetBufferSubData(GL_TEXTURE_BUFFER, 0,
+ 4 * l * l * sizeof(uint32_t), pixels[0]);
+
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_pixels(img, pixels[0], 0, 1, 0, 1);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_buf_update_waw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx),"
+ " (idx.y >= H / 2 ? GREEN : RED));\n"
+ " return x;\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+ uint32_t pixels[N][4];
+
+ init_pixels(set_image_size(img, l * l / 2, 1, 1, 1),
+ pixels[0], 0, 1, 0, 1);
+ glBindBuffer(GL_TEXTURE_BUFFER, get_buffer(1));
+
+ /* First pass: render red to the first half of the image,
+ * green to the second half. */
+ draw_grid(grid, prog);
+
+ /* Barrier. */
+ bar->run_barrier(GL_BUFFER_UPDATE_BARRIER_BIT);
+
+ /* Fill the first half with green (write-after-write). */
+ glBufferSubData(GL_TEXTURE_BUFFER, 0, 4 * l * l / 2 * sizeof(uint32_t),
+ pixels);
+
+ /* Check that the resulting image is green. */
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_img_green(img);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_fb_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_2D, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), GREEN);\n"
+ " return x;\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+ uint32_t pixels[N][4];
+ GLuint fb;
+
+ glGenFramebuffers(1, &fb);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fb);
+
+ /* Bind the image as color attachment of the read framebuffer
+ * simultaneously. */
+ glFramebufferTexture(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ get_texture(1), 0);
+
+ /* First pass: render green to the image. */
+ draw_grid(grid, prog);
+
+ /* Barrier. */
+ bar->run_barrier(GL_FRAMEBUFFER_BARRIER_BIT);
+
+ /* Read back and check the result from the read
+ * framebuffer (read-after-write). */
+ glReadPixels(0, 0, l, l, img.format->pixel_format,
+ image_base_type(img.format), pixels);
+
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_pixels(img, pixels[0], 0, 1, 0, 1);
+
+ glDeleteFramebuffers(1, &fb);
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_fb_waw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_2D, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " return GREEN;"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), RED);\n"
+ " return RED;\n"
+ " }\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+ GLuint fb;
+
+ glGenFramebuffers(1, &fb);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb);
+
+ /* Bind the image as color attachment of the framebuffer
+ * simultaneously. */
+ glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ get_texture(1), 0);
+
+ /* First pass: render red to the image. */
+ ret &= draw_grid(grid, prog) &&
+
+ /* Barrier. */
+ bar->run_barrier(GL_FRAMEBUFFER_BARRIER_BIT) &&
+
+ /* Second pass: render green to the framebuffer
+ * (write-after-write). */
+ set_uniform_int(prog, "pass", 1) &&
+ draw_grid(grid, prog) &&
+
+ /* Check that the resulting image is green. */
+ check_img_green(img);
+
+ glDeleteFramebuffers(1, &fb);
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+setup_xfb_varying(GLuint prog, const char *varying)
+{
+ glTransformFeedbackVaryings(prog, 1, &varying, GL_INTERLEAVED_ATTRIBS);
+ glLinkProgram(prog);
+
+ return piglit_check_gl_error(GL_NO_ERROR);
+}
+
+static bool
+run_test_xfb_waw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_VERTEX_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32F, l, l);
+ GLuint prog = generate_program(
+ grid, GL_VERTEX_SHADER,
+ concat(common_hunk(img),
+ hunk("GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " return GREEN;\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), RED);\n"
+ " return x;\n"
+ " }\n"
+ "}\n"), NULL));
+ bool ret = prog && setup_xfb_varying(prog, "vcolor") &&
+ init_common(grid, img, prog);
+ GLuint xfb;
+
+ glGenTransformFeedbacks(1, &xfb);
+ glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb);
+
+ /* Bind the image as transform feedback buffer
+ * simultaneously. */
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, get_buffer(1));
+ glBeginTransformFeedback(GL_POINTS);
+ glPauseTransformFeedback();
+
+ /* First pass: render red to the image. */
+ draw_grid(grid, prog);
+
+ /* Barrier. */
+ bar->run_barrier(GL_TRANSFORM_FEEDBACK_BARRIER_BIT);
+
+ /* Second pass: Write out the vcolor output to the transform
+ * feedback buffer (write-after-write). */
+ set_uniform_int(prog, "pass", 1);
+ glResumeTransformFeedback();
+ draw_grid(grid, prog);
+ glEndTransformFeedback();
+
+ /* Check that the resulting image is green. */
+ ret &= piglit_check_gl_error(GL_NO_ERROR) &&
+ check_img_green(img);
+
+ glDeleteTransformFeedbacks(1, &xfb);
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_atom_raw(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32UI, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("layout(binding=0, offset=0) uniform atomic_uint c[4];\n"
+ "\n"
+ "GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " return GRID_T(atomicCounter(c[0]),"
+ " atomicCounter(c[1]),"
+ " atomicCounter(c[2]),"
+ " atomicCounter(c[3]));\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx), GREEN);\n"
+ " return x;\n"
+ " }\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+
+ /* Bind the image as atomic counter buffer simultaneously. */
+ glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, get_buffer(1));
+
+ /* First pass: render green to the image. */
+ ret &= draw_grid(grid, prog) &&
+
+ /* Barrier. */
+ bar->run_barrier(GL_ATOMIC_COUNTER_BARRIER_BIT) &&
+
+ /* Second pass: Check that the atomic counters read
+ * back green (read-after-write). */
+ set_uniform_int(prog, "pass", 1) &&
+ draw_grid(grid, prog) &&
+ check_fb_green(grid);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static bool
+run_test_atom_war(const struct image_barrier_info *bar, unsigned l)
+{
+ const struct grid_info grid =
+ grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, l, l);
+ const struct image_info img =
+ image_info(GL_TEXTURE_BUFFER, GL_RGBA32UI, l, l);
+ GLuint prog = generate_program(
+ grid, GL_FRAGMENT_SHADER,
+ concat(common_hunk(img),
+ hunk("layout(binding=0, offset=0) uniform atomic_uint c[4];\n"
+ "\n"
+ "GRID_T op(ivec2 idx, GRID_T x) {\n"
+ " if (pass == 1) {\n"
+ " atomicCounterIncrement(c[0]);"
+ " atomicCounterIncrement(c[1]);"
+ " atomicCounterIncrement(c[2]);"
+ " atomicCounterIncrement(c[3]);\n"
+ " } else {\n"
+ " imageStore(dst_img, IMAGE_ADDR(idx),"
+ " imageLoad(src_img, IMAGE_ADDR(idx)));\n"
+ " }\n"
+ " return x;\n"
+ "}\n"), NULL));
+ bool ret = prog && init_common(grid, img, prog);
+
+ /* Bind the image as atomic counter buffer simultaneously. */
+ glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, get_buffer(0));
+
+ /* First pass: read back the source image. */
+ ret &= draw_grid(grid, prog) &&
+
+ /* Barrier. */
+ bar->run_barrier(GL_ATOMIC_COUNTER_BARRIER_BIT) &&
+
+ /* Second pass: Modify the source image using atomic
+ * counter increments (write-after-read). */
+ set_uniform_int(prog, "pass", 1) &&
+ draw_grid(grid, prog) &&
+
+ /* Check that the read-back results from the first
+ * pass are green. */
+ check_img_green(img);
+
+ glDeleteProgram(prog);
+ return ret;
+}
+
+static void
+barrier_subtest(enum piglit_result *status, bool guard,
+ bool (*run)(const struct image_barrier_info *, unsigned),
+ const char *name, const struct image_barrier_info *bar,
+ unsigned l)
+{
+ subtest(status, guard, run(bar, l) || bar->control_test,
+ "%s/%s barrier test/%dx%d", name, bar->name, l, l);
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+ const bool quick = (argc >= 2 && !strcmp(argv[1], "--quick"));
+ const struct image_barrier_info *bar;
+ enum piglit_result status = PIGLIT_PASS;
+ unsigned l;
+
+ piglit_require_extension("GL_ARB_shader_image_load_store");
+ piglit_require_extension("GL_ARB_shader_atomic_counters");
+
+ for (l = 4; l <= L; l *= 4) {
+ for (bar = image_barriers; bar->name; ++bar) {
+ if (quick && bar->control_test)
+ continue;
+
+ barrier_subtest(&status,
+ get_image_stage(GL_VERTEX_SHADER),
+ run_test_vertex_array_raw,
+ "Vertex array/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_element_array_raw,
+ "Element array/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_ubo_raw,
+ "Uniform buffer/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_tex_fetch_raw,
+ "Texture fetch/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_image_raw,
+ "Image/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_image_war,
+ "Image/WaR", bar, l);
+
+ barrier_subtest(&status,
+ (get_image_stage(GL_VERTEX_SHADER) &&
+ piglit_is_extension_supported(
+ "GL_ARB_draw_indirect")),
+ run_test_indirect_raw,
+ "Indirect/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_pixel_raw,
+ "Pixel/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_pixel_waw,
+ "Pixel/WaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_tex_update_raw,
+ "Texture update/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_tex_update_waw,
+ "Texture update/WaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_buf_update_raw,
+ "Buffer update/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_buf_update_waw,
+ "Buffer update/WaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_fb_raw,
+ "Framebuffer/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_fb_waw,
+ "Framebuffer/WaW", bar, l);
+
+ barrier_subtest(&status,
+ (get_image_stage(GL_VERTEX_SHADER) &&
+ piglit_is_extension_supported(
+ "GL_ARB_transform_feedback2")),
+ run_test_xfb_waw,
+ "Transform feedback/WaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_atom_raw,
+ "Atomic counter/RaW", bar, l);
+
+ barrier_subtest(&status, true, run_test_atom_war,
+ "Atomic counter/WaR", bar, l);
+ }
+ }
+
+ piglit_report_result(status);
+}
+
+enum piglit_result
+piglit_display(void)
+{
+ return PIGLIT_FAIL;
+}