/* * Copyright © 2013 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 max-counters.c * * Test that using more than the maximum number of suported atomic * counters, buffers or bindings fails with a linking error. */ #include "common.h" PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_core_version = 31; config.window_width = 1; config.window_height = 1; 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 char * iterate_template(const char *template, unsigned n) { char *ss; int i, ret; ss = strdup(""); assert(ss); for (i = 0; i < n; ++i) { char *s, *tmp = ss; ret = asprintf(&s, template, i); assert(ret >= 0); ret = asprintf(&ss, "%s%s", tmp, s); assert(ret >= 0); free(tmp); free(s); } return ss; } /** * Generate source code by substituting the first occurrence of "%s" * in \a src_template with \a n copies of \a decl_template and the * second occurrence of "%s" with \a n copies of \a insn_template. */ static char * generate_source(const char *src_template, const char *decl_template, const char *insn_template, unsigned n) { char *decls = iterate_template(decl_template, n); char *insns = iterate_template(insn_template, n); char *src; int ret; ret = asprintf(&src, src_template, decls, insns); assert(ret); free(decls); free(insns); return src; } static bool run_test_vertex_max_counters(unsigned num_counters) { /* Generate a shader with 'num_counters' counters. */ char *vs_source = generate_source( "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "\n" "%s\n" "\n" "in vec4 position;\n" "flat out ivec4 vcolor;\n" "\n" "void main() {\n" " uint y = 0u;\n" " %s\n" " vcolor.x = int(y);\n" " gl_Position = position;\n" "}\n", "layout(binding=0) uniform atomic_uint x%d;\n", " y += atomicCounterDecrement(x%d);\n", num_counters); GLuint prog = glCreateProgram(); bool ret = atomic_counters_compile(prog, GL_VERTEX_SHADER, vs_source) && atomic_counters_link(prog); glDeleteProgram(prog); free(vs_source); return ret; } static bool run_test_fragment_max_counters(unsigned num_counters) { /* Generate a shader with 'num_counters' counters. */ char *fs_source = generate_source( "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "\n" "%s\n" "\n" "out ivec4 fcolor;\n" "\n" "void main() {\n" " uint y = 0u;\n" " %s\n" " fcolor.x = int(y);\n" "}\n", "layout(binding=0) uniform atomic_uint x%d;\n", " y += atomicCounterDecrement(x%d);\n", num_counters); GLuint prog = glCreateProgram(); bool ret = atomic_counters_compile(prog, GL_FRAGMENT_SHADER, fs_source) && atomic_counters_link(prog); glDeleteProgram(prog); free(fs_source); return ret; } static bool run_test_combined_max_counters(unsigned num_fragment_counters, unsigned num_vertex_counters) { /* Generate a shader with 'num_fragment_counters' counters. */ char *fs_source = generate_source( "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "\n" "%s\n" "\n" "flat in ivec4 vcolor;\n" "out ivec4 fcolor;\n" "\n" "void main() {\n" " uint y = uint(vcolor.x);\n" " %s\n" " fcolor.x = int(y);\n" "}\n", "layout(binding=0) uniform atomic_uint fx%d;\n", " y += atomicCounterDecrement(fx%d);\n", num_fragment_counters); /* Generate a shader with 'num_vertex_counters' counters. */ char *vs_source = generate_source( "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "\n" "%s\n" "\n" "in vec4 position;\n" "flat out ivec4 vcolor;\n" "\n" "void main() {\n" " uint y = 0u;\n" " %s\n" " vcolor.x = int(y);\n" " gl_Position = position;\n" "}\n", "layout(binding=1) uniform atomic_uint vx%d;\n", " y += atomicCounterDecrement(vx%d);\n", num_vertex_counters); GLuint prog = glCreateProgram(); bool ret = atomic_counters_compile(prog, GL_FRAGMENT_SHADER, fs_source) && atomic_counters_compile(prog, GL_VERTEX_SHADER, vs_source) && atomic_counters_link(prog); glDeleteProgram(prog); free(fs_source); free(vs_source); return ret; } static bool run_test_fragment_max_buffers(unsigned num_buffers) { /* Generate a shader with 'num_buffers' buffers. */ char *src = generate_source( "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "#define PASTE(A,B) A ## B\n" "#define Y(I) PASTE(y, I)\n" "\n" "out ivec4 fcolor;\n" "\n" "%s" "\n" "void main() {\n" " uint x = 0u;\n" " %s\n" " fcolor.x = int(x);\n" "}\n", "#define I %d\n" "layout(binding=I, offset=0) uniform atomic_uint Y(I);\n" "#undef I\n", " x += atomicCounterDecrement(y%d);\n", num_buffers); GLuint prog = glCreateProgram(); bool ret = atomic_counters_compile(prog, GL_FRAGMENT_SHADER, src) && atomic_counters_link(prog); glDeleteProgram(prog); free(src); return ret; } static bool run_test_vertex_max_buffers(unsigned num_buffers) { /* Generate a shader with 'num_buffers' buffers. */ char *src = generate_source( "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "#define PASTE(A,B) A ## B\n" "#define X(I) PASTE(x, I)\n" "\n" "in vec4 position;\n" "flat out ivec4 vcolor;\n" "\n" "%s" "\n" "void main() {\n" " uint x = 0u;\n" " %s\n" " vcolor.x = int(x);\n" " gl_Position = position;\n" "}\n", "#define I %d\n" "layout(binding=I, offset=0) uniform atomic_uint X(I);\n" "#undef I\n", " x += atomicCounterDecrement(x%d);\n", num_buffers); GLuint prog = glCreateProgram(); bool ret = atomic_counters_compile(prog, GL_VERTEX_SHADER, src) && atomic_counters_link(prog); glDeleteProgram(prog); free(src); return ret; } static bool run_test_combined_max_buffers(unsigned num_fragment_buffers, unsigned num_vertex_buffers) { /* Generate a shader with 'num_fragment_buffers' buffers. */ char *fs_source = generate_source( "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "#define PASTE(A,B) A ## B\n" "#define Y(I) PASTE(y, I)\n" "\n" "out ivec4 fcolor;\n" "\n" "%s" "\n" "void main() {\n" " uint x = 0u;\n" " %s\n" " fcolor.x = int(x);\n" "}\n", "#define I %d\n" "layout(binding=I, offset=0) uniform atomic_uint Y(I);\n" "#undef I\n", " x += atomicCounterDecrement(y%d);\n", num_fragment_buffers); /* Generate a shader with 'num_vertex_buffers' buffers. */ char *vs_source = generate_source( "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "#define PASTE(A,B) A ## B\n" "#define X(I) PASTE(x, I)\n" "\n" "in vec4 position;\n" "flat out ivec4 vcolor;\n" "\n" "%s" "\n" "void main() {\n" " uint x = 0u;\n" " %s\n" " vcolor.x = int(x);\n" " gl_Position = position;\n" "}\n", "#define I %d\n" "layout(binding=I, offset=4) uniform atomic_uint X(I);\n" "#undef I\n", " x += atomicCounterDecrement(x%d);\n", num_vertex_buffers); GLuint prog = glCreateProgram(); bool ret = atomic_counters_compile(prog, GL_FRAGMENT_SHADER, fs_source) && atomic_counters_compile(prog, GL_VERTEX_SHADER, vs_source) && atomic_counters_link(prog); glDeleteProgram(prog); free(fs_source); free(vs_source); return ret; } static bool run_test_fragment_max_bindings(unsigned binding) { const char *src_template = "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "\n" "layout(binding=%d) uniform atomic_uint x;" "\n" "void main() {\n" "}\n"; char *src; GLuint prog = glCreateProgram(); int ret; ret = asprintf(&src, src_template, binding); assert(ret); ret = atomic_counters_compile(prog, GL_FRAGMENT_SHADER, src); glDeleteProgram(prog); free(src); return ret; } static bool run_test_vertex_max_bindings(unsigned binding) { const char *src_template = "#version 140\n" "#extension GL_ARB_shader_atomic_counters : enable\n" "\n" "in vec4 position;\n" "layout(binding=%d) uniform atomic_uint x;" "\n" "void main() {\n" " gl_Position = position;\n" "}\n"; char *src; GLuint prog = glCreateProgram(); int ret; ret = asprintf(&src, src_template, binding); assert(ret); ret = atomic_counters_compile(prog, GL_VERTEX_SHADER, src); glDeleteProgram(prog); free(src); return ret; } void piglit_init(int argc, char **argv) { enum piglit_result status = PIGLIT_PASS; struct atomic_counters_limits ls = atomic_counters_get_limits(); piglit_require_gl_version(31); piglit_require_extension("GL_ARB_shader_atomic_counters"); printf("Max combined: %d\n", ls.combined_counters); printf("Max VS: %d\n", ls.vertex_counters); printf("Max FS: %d\n", ls.fragment_counters); atomic_counters_subtest(&status, GL_VERTEX_SHADER, "Vertex shader test above maximum " "number of atomic counters", !run_test_vertex_max_counters, ls.vertex_counters + 1); atomic_counters_subtest(&status, GL_FRAGMENT_SHADER, "Fragment shader test above maximum " "number of atomic counters", !run_test_fragment_max_counters, ls.fragment_counters + 1); if (ls.vertex_counters + ls.fragment_counters > ls.combined_counters) { atomic_counters_subtest(&status, GL_NONE, "Combined test above maximum number " "of atomic counters", !run_test_combined_max_counters, ls.fragment_counters, ls.combined_counters - ls.fragment_counters + 1); } else { piglit_report_subtest_result( PIGLIT_SKIP, "Combined test above maximum number " "of atomic counters"); } atomic_counters_subtest(&status, GL_FRAGMENT_SHADER, "Fragment shader test under maximum " "number of atomic counter buffers", run_test_fragment_max_buffers, ls.fragment_buffers); atomic_counters_subtest(&status, GL_FRAGMENT_SHADER, "Fragment shader test above maximum " "number of atomic counter buffers", !run_test_fragment_max_buffers, ls.fragment_buffers + 1); atomic_counters_subtest(&status, GL_VERTEX_SHADER, "Vertex shader test under maximum " "number of atomic counter buffers", run_test_vertex_max_buffers, ls.vertex_buffers); atomic_counters_subtest(&status, GL_VERTEX_SHADER, "Vertex shader test above maximum " "number of atomic counter buffers", !run_test_vertex_max_buffers, ls.vertex_buffers + 1); const int combined_test_max_vs_bufs = MIN2(ls.vertex_buffers, ls.combined_buffers - ls.fragment_buffers); if (combined_test_max_vs_bufs > 0) { atomic_counters_subtest(&status, GL_NONE, "Combined test under maximum " "number of atomic counter buffers", run_test_combined_max_buffers, ls.fragment_buffers, combined_test_max_vs_bufs); } else { piglit_report_subtest_result( PIGLIT_SKIP, "Combined test under maximum " "number of atomic counter buffers"); } if (combined_test_max_vs_bufs < ls.vertex_buffers) { atomic_counters_subtest(&status, GL_NONE, "Combined test above maximum " "number of atomic counter buffers", !run_test_combined_max_buffers, ls.fragment_buffers, combined_test_max_vs_bufs + 1); } else { piglit_report_subtest_result( PIGLIT_SKIP, "Combined test above maximum " "number of atomic counter buffers"); } atomic_counters_subtest(&status, GL_FRAGMENT_SHADER, "Fragment shader test above maximum " "number of atomic counter bindings", !run_test_fragment_max_bindings, ls.bindings + 1); atomic_counters_subtest(&status, GL_VERTEX_SHADER, "Vertex shader test above maximum " "number of atomic counter bindings", !run_test_vertex_max_bindings, ls.bindings + 1); piglit_report_result(status); } enum piglit_result piglit_display(void) { return PIGLIT_PASS; }