<div dir="ltr"><div dir="ltr">This test breaks build for compilers that don't default to C++11+ for cpp sources.<div><br></div><div><a href="https://travis-ci.org/jvesely/piglit/jobs/442796343">https://travis-ci.org/jvesely/piglit/jobs/442796343</a><br></div><div><br></div><div>Jan</div></div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Sep 13, 2018 at 2:11 PM Nicolai Hähnle <<a href="mailto:nhaehnle@gmail.com">nhaehnle@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Nicolai Hähnle <<a href="mailto:nicolai.haehnle@amd.com" target="_blank">nicolai.haehnle@amd.com</a>><br>
<br>
Test extremes of GS amplification under tessellation.<br>
---<br>
 tests/opengl.py                               |   1 +<br>
 .../arb_tessellation_shader/CMakeLists.gl.txt |   1 +<br>
 .../tes-gs-max-output.cpp                     | 817 ++++++++++++++++++<br>
 3 files changed, 819 insertions(+)<br>
 create mode 100644 tests/spec/arb_tessellation_shader/tes-gs-max-output.cpp<br>
<br>
diff --git a/tests/opengl.py b/tests/opengl.py<br>
index 903a95809..3cc25c99c 100644<br>
--- a/tests/opengl.py<br>
+++ b/tests/opengl.py<br>
@@ -1524,20 +1524,21 @@ with profile.test_list.group_manager(<br>
     g(['arb_tessellation_shader-immediate-mode-draw-patches'])<br>
     g(['arb_tessellation_shader-invalid-get-program-params'])<br>
     g(['arb_tessellation_shader-invalid-patch-vertices-range'])<br>
     g(['arb_tessellation_shader-invalid-primitive'])<br>
     g(['built-in-constants',<br>
        os.path.join('spec', 'arb_tessellation_shader', 'minimum-maximums.txt')],<br>
       'built-in-constants',<br>
       override_class=BuiltInConstantsTest)<br>
     g(['arb_tessellation_shader-large-uniforms'])<br>
     g(['arb_tessellation_shader-layout-mismatch'])<br>
+    g(['arb_tessellation_shader-tes-gs-max-output', '-small', '-scan', '1', '50'])<br>
<br>
 # Group ARB_texture_multisample<br>
 with profile.test_list.group_manager(<br>
         PiglitGLTest, grouptools.join('spec', 'ARB_texture_multisample')) as g:<br>
     g(['arb_texture_multisample-large-float-texture'], 'large-float-texture',<br>
       run_concurrent=False)<br>
     g(['arb_texture_multisample-large-float-texture', '--array'],<br>
       'large-float-texture-array', run_concurrent=False)<br>
     g(['arb_texture_multisample-large-float-texture', '--fp16'],<br>
       'large-float-texture-fp16', run_concurrent=False)<br>
diff --git a/tests/spec/arb_tessellation_shader/CMakeLists.gl.txt b/tests/spec/arb_tessellation_shader/CMakeLists.gl.txt<br>
index d70b00f3f..058a1bc49 100644<br>
--- a/tests/spec/arb_tessellation_shader/CMakeLists.gl.txt<br>
+++ b/tests/spec/arb_tessellation_shader/CMakeLists.gl.txt<br>
@@ -11,12 +11,13 @@ link_libraries (<br>
<br>
 piglit_add_executable (arb_tessellation_shader-get-tcs-params get-tcs-params.c)<br>
 piglit_add_executable (arb_tessellation_shader-get-tes-params get-tes-params.c)<br>
 piglit_add_executable (arb_tessellation_shader-immediate-mode-draw-patches immediate-mode-draw-patches.c)<br>
 piglit_add_executable (arb_tessellation_shader-invalid-get-program-params invalid-get-program-params.c)<br>
 piglit_add_executable (arb_tessellation_shader-invalid-patch-vertices-range invalid-patch-vertices-range.c)<br>
 piglit_add_executable (arb_tessellation_shader-invalid-primitive invalid-primitive.c)<br>
 piglit_add_executable (arb_tessellation_shader-minmax minmax.c)<br>
 piglit_add_executable (arb_tessellation_shader-large-uniforms large-uniforms.c)<br>
 piglit_add_executable (arb_tessellation_shader-layout-mismatch layout-mismatch.c)<br>
+piglit_add_executable (arb_tessellation_shader-tes-gs-max-output tes-gs-max-output.cpp)<br>
<br>
 # vim: ft=cmake:<br>
diff --git a/tests/spec/arb_tessellation_shader/tes-gs-max-output.cpp b/tests/spec/arb_tessellation_shader/tes-gs-max-output.cpp<br>
new file mode 100644<br>
index 000000000..de0d2daf1<br>
--- /dev/null<br>
+++ b/tests/spec/arb_tessellation_shader/tes-gs-max-output.cpp<br>
@@ -0,0 +1,817 @@<br>
+/*<br>
+ * Copyright (c) 2018 Advanced Micro Devices<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER<br>
+ * DEALINGS IN THE SOFTWARE.<br>
+ */<br>
+<br>
+/**<br>
+ * \file tes-gs-max-output.cpp<br>
+ *<br>
+ * Stress the limits of what tessellation + geometry shaders can output using<br>
+ * generic shaders with points as input and output primitives, allowing<br>
+ * arbitrary:<br>
+ * - number of input instances (instanced draws)<br>
+ * - number of input patches per instance<br>
+ * - (integer) tessellation factors<br>
+ * - number of invocations (GS instances)<br>
+ * - number of output vertices per invocation<br>
+ * - number of output components per vertex<br>
+ *<br>
+ * Verification works by rendering points and writing to an SSBO from the<br>
+ * fragment shader.<br>
+ */<br>
+<br>
+#include "piglit-util-gl.h"<br>
+<br>
+#include <algorithm><br>
+#include <map><br>
+#include <set><br>
+#include <vector><br>
+<br>
+#define WINDOW_SIZE 256<br>
+<br>
+PIGLIT_GL_TEST_CONFIG_BEGIN<br>
+<br>
+       config.supports_gl_compat_version = 32;<br>
+       config.supports_gl_core_version = 32;<br>
+       config.window_width = WINDOW_SIZE;<br>
+       config.window_height = WINDOW_SIZE;<br>
+       config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;<br>
+       config.khr_no_error_support = PIGLIT_NO_ERRORS;<br>
+<br>
+PIGLIT_GL_TEST_CONFIG_END<br>
+<br>
+#define PASTE(x) #x<br>
+#define STR(x) PASTE(x)<br>
+<br>
+struct testcase {<br>
+       unsigned num_instances; /* draw instances */<br>
+       unsigned num_patches; /* draw size / count */<br>
+       unsigned tessfactor_u;<br>
+       unsigned tessfactor_v;<br>
+       unsigned num_invocations; /* GS invocations / instances */<br>
+       unsigned num_outputs; /* # vertex ouput per GS invocation */<br>
+       unsigned num_extra_components; /* # extra components per GS output vertex */<br>
+<br>
+       bool operator<(const testcase &o) const {<br>
+               return std::make_tuple(num_instances, num_patches, tessfactor_u,<br>
+                                      tessfactor_v, num_invocations, num_outputs,<br>
+                                      num_extra_components)<br>
+                       <<br>
+                      std::make_tuple(o.num_instances, o.num_patches, o.tessfactor_u,<br>
+                                      o.tessfactor_v, o.num_invocations, o.num_outputs,<br>
+                                      o.num_extra_components);<br>
+       }<br>
+};<br>
+<br>
+struct fragmentshaderkey {<br>
+       unsigned num_extra_components;<br>
+<br>
+       bool operator<(const fragmentshaderkey &o) const {<br>
+               return num_extra_components < o.num_extra_components;<br>
+       }<br>
+};<br>
+<br>
+struct geometryshaderkey {<br>
+       unsigned num_invocations;<br>
+       unsigned num_outputs;<br>
+       unsigned num_extra_components;<br>
+<br>
+       bool operator<(const geometryshaderkey &o) const {<br>
+               if (num_invocations < o.num_invocations)<br>
+                       return true;<br>
+               if (num_invocations > o.num_invocations)<br>
+                       return false;<br>
+               if (num_outputs < o.num_outputs)<br>
+                       return true;<br>
+               if (num_outputs > o.num_outputs)<br>
+                       return false;<br>
+               return num_extra_components < o.num_extra_components;<br>
+       }<br>
+};<br>
+<br>
+static std::map<fragmentshaderkey, GLuint> fragmentshaders;<br>
+static std::map<geometryshaderkey, GLuint> testprograms;<br>
+<br>
+static const struct testcase default_testcase = {<br>
+       .num_instances = 1,<br>
+       .num_patches = 1,<br>
+       .tessfactor_u = 1,<br>
+       .tessfactor_v = 1,<br>
+       .num_invocations = 1,<br>
+       .num_outputs = 1,<br>
+       .num_extra_components = 0,<br>
+};<br>
+<br>
+static int32_t *buffer_copy;<br>
+<br>
+static const unsigned max_final_points = 2 * 1024 * 1024; /* requires 16 MiB buffer */<br>
+static bool small = false;<br>
+static GLuint vs_shader;<br>
+static GLuint tcs_shader;<br>
+static GLuint tes_shader;<br>
+static GLuint vao;<br>
+static GLuint ssbo;<br>
+static std::vector<testcase> testcases;<br>
+static std::set<testcase> testcases_set;<br>
+static GLuint max_tessfactor;<br>
+static GLuint max_gs_invocations;<br>
+static GLuint max_gs_out_vertices;<br>
+static GLuint max_gs_total_out_components;<br>
+static GLuint max_gs_out_components;<br>
+static unsigned max_gs_out_vertices_real;<br>
+<br>
+static const char vs_text[] =<br>
+       "#version 150\n"<br>
+       "\n"<br>
+       "uniform int u_verts_per_instance;\n"<br>
+       "\n"<br>
+       "out int vs_tcs_id;\n"<br>
+       "\n"<br>
+       "void main() {\n"<br>
+       "  vs_tcs_id = gl_InstanceID * u_verts_per_instance + gl_VertexID;\n"<br>
+       "}\n";<br>
+<br>
+static const char tcs_text[] =<br>
+       "#version 150\n"<br>
+       "#extension GL_ARB_tessellation_shader : require\n"<br>
+       "layout(vertices = 1) out;\n"<br>
+       "\n"<br>
+       "in int vs_tcs_id[];\n"<br>
+       "\n"<br>
+       "out int tcs_tes_id[];\n"<br>
+       "\n"<br>
+       "uniform int u_tessfactor_u;\n"<br>
+       "uniform int u_tessfactor_v;\n"<br>
+       "\n"<br>
+       "void main() {\n"<br>
+       "  tcs_tes_id[gl_InvocationID] = vs_tcs_id[gl_InvocationID];\n"<br>
+       "  gl_TessLevelOuter[0] = u_tessfactor_v;\n"<br>
+       "  gl_TessLevelOuter[1] = u_tessfactor_u;\n"<br>
+       "}\n";<br>
+<br>
+static const char tes_text[] =<br>
+       "#version 150\n"<br>
+       "#extension GL_ARB_tessellation_shader : require\n"<br>
+       "layout(isolines, equal_spacing) in;\n"<br>
+       "\n"<br>
+       "in int tcs_tes_id[];\n"<br>
+       "\n"<br>
+       "out int tes_gs_id;\n"<br>
+       "\n"<br>
+       "void main() {\n"<br>
+       "  tes_gs_id = tcs_tes_id[0];\n"<br>
+       "  gl_Position.x = gl_TessCoord[0];\n"<br>
+       "  gl_Position.y = gl_TessCoord[1];\n"<br>
+       "}\n";<br>
+<br>
+/* Those numbers really don't matter much for what we're trying to do here. */<br>
+#define GEN_SEQUENCE \<br>
+       "int seq_next(int x) {\n" \<br>
+       "  x = (x + 1) * 709900053;\n" \<br>
+       "  x = x ^ (x >> 17);\n" \<br>
+       "  return x;\n" \<br>
+       "}\n"<br>
+<br>
+static const char gs_text[] =<br>
+       "#version 150\n"<br>
+       "#extension GL_ARB_gpu_shader5 : require\n"<br>
+       "\n"<br>
+       "#define NUM_INVOCATIONS %d\n"<br>
+       "#define NUM_OUT_VERTICES %d\n"<br>
+       "#define NUM_EXTRA_COMPONENTS %d\n"<br>
+       "\n"<br>
+       "layout(lines, invocations = NUM_INVOCATIONS) in;\n"<br>
+       "layout(points, max_vertices = NUM_OUT_VERTICES) out;\n"<br>
+       "\n"<br>
+       "uniform int u_tessfactor_u;\n"<br>
+       "uniform int u_tessfactor_v;\n"<br>
+       "\n"<br>
+       "in int tes_gs_id[];\n"<br>
+       "\n"<br>
+       "flat out int gs_ps_data[1 + NUM_EXTRA_COMPONENTS];\n"<br>
+       "\n"<br>
+       GEN_SEQUENCE<br>
+       "\n"<br>
+       "void main() {\n"<br>
+       "  int in_id = tes_gs_id[0] * u_tessfactor_u * u_tessfactor_v;\n"<br>
+       "  float v = gl_in[0].gl_Position.y;\n"<br>
+       "  in_id += u_tessfactor_u * int(v * u_tessfactor_v + 0.5);\n"<br>
+       "  float u = min(gl_in[0].gl_Position.x, gl_in[1].gl_Position.x);\n"<br>
+       "  in_id += int(u * u_tessfactor_u + 0.5);\n"<br>
+       "\n"<br>
+       "  for (int i = 0; i < NUM_OUT_VERTICES; ++i) {\n"<br>
+       "    uint id = (in_id * NUM_INVOCATIONS + gl_InvocationID) * NUM_OUT_VERTICES + i;\n"<br>
+       "    uint x = id %% " STR(WINDOW_SIZE) "u;\n"<br>
+       "    uint y = (id / " STR(WINDOW_SIZE) "u) %% " STR(WINDOW_SIZE) "u;\n"<br>
+       "    gl_Position.x = (float(x) + 0.5) / " STR(WINDOW_SIZE) " * 2.0 - 1.0;\n"<br>
+       "    gl_Position.y = (float(y) + 0.5) / " STR(WINDOW_SIZE) " * 2.0 - 1.0;\n"<br>
+       "    gl_Position.z = 0.0;\n"<br>
+       "    gl_Position.w = 1.0;\n"<br>
+       "\n"<br>
+       "    int val = int(id);\n"<br>
+       "    for (int j = 0; j <= NUM_EXTRA_COMPONENTS; ++j) {\n"<br>
+       "      gs_ps_data[j] = val;\n"<br>
+       "      val = seq_next(val);\n"<br>
+       "    }\n"<br>
+       "\n"<br>
+       "    EmitVertex();\n"<br>
+       "  }\n"<br>
+       "}\n";<br>
+<br>
+static const char fs_text[] =<br>
+       "#version 150\n"<br>
+       "#extension GL_ARB_shader_storage_buffer_object : require\n"<br>
+       "\n"<br>
+       "#define NUM_EXTRA_COMPONENTS %d\n"<br>
+       "\n"<br>
+       "flat in int gs_ps_data[1 + NUM_EXTRA_COMPONENTS];\n"<br>
+       "out vec4 out_color;\n"<br>
+       "\n"<br>
+       "layout(std430, binding = 0) buffer SSBO {\n"<br>
+       "  ivec2 data[];\n"<br>
+       "} ssbo;\n"<br>
+       "\n"<br>
+       GEN_SEQUENCE<br>
+       "\n"<br>
+       "void main() {\n"<br>
+       "  int id = gs_ps_data[0];\n"<br>
+       "  int screen_id = int(gl_FragCoord.y) * " STR(WINDOW_SIZE) " + int(gl_FragCoord.x);\n"<br>
+       "  if (screen_id != id %% (" STR(WINDOW_SIZE * WINDOW_SIZE) ")) {\n"<br>
+       "    ssbo.data[id].x = 1000;\n"<br>
+       "    ssbo.data[id].y = screen_id;\n"<br>
+       "    out_color = vec4(0.1, 0, 0, 1);\n"<br>
+       "    return;\n"<br>
+       "  }\n"<br>
+       "\n"<br>
+       "  int val = id;\n"<br>
+       "  for (int j = 0; j <= NUM_EXTRA_COMPONENTS; ++j) {\n"<br>
+       "    if (val != gs_ps_data[j]) {\n"<br>
+       "      ssbo.data[id].x = 2000 + j;\n"<br>
+       "      ssbo.data[id].y = gs_ps_data[j];\n"<br>
+       "      out_color = vec4(0, 0.1, 0, 1);\n"<br>
+       "      return;\n"<br>
+       "    }\n"<br>
+       "    val = seq_next(val);\n"<br>
+       "  }\n"<br>
+       "\n"<br>
+       "  ssbo.data[id].x = 1;\n"<br>
+       "  out_color = vec4(0, 0, 0, 1);\n"<br>
+       "}\n";<br>
+<br>
+static void<br>
+print_testcase(const struct testcase *tc)<br>
+{<br>
+       printf("Case: instances = %u patches = %u tessfactor = %u,%u invocations = %u "<br>
+              "outputs = %u extra_components = %u\n",<br>
+              tc->num_instances, tc->num_patches, tc->tessfactor_u, tc->tessfactor_v,<br>
+              tc->num_invocations, tc->num_outputs, tc->num_extra_components);<br>
+}<br>
+<br>
+static void<br>
+add_testcase(const struct testcase *tc)<br>
+{<br>
+       if (!testcases_set.insert(*tc).second)<br>
+               return;<br>
+<br>
+       if (tc->num_instances > 64 * 1024 ||<br>
+           tc->num_patches > 64 * 1024 ||<br>
+           tc->tessfactor_u > 64 * 1024 ||<br>
+           tc->tessfactor_v > 64 * 1024 ||<br>
+           tc->num_invocations > 64 * 1024 ||<br>
+           tc->num_outputs > 64 * 1024 ||<br>
+           tc->num_extra_components > 64 * 1024) {<br>
+               fprintf(stderr, "Excessive test case size. Are you sure?\n");<br>
+               print_testcase(tc);<br>
+               exit(1);<br>
+       }<br>
+<br>
+       /* Multiple separate multiplies to avoid integer wraparound */<br>
+       if ((uint64_t)tc->num_instances * tc->num_patches * tc->tessfactor_u > max_final_points ||<br>
+           (uint64_t)tc->tessfactor_v * tc->num_invocations * tc->num_outputs > max_final_points ||<br>
+           (uint64_t)tc->num_instances * tc->num_patches * tc->tessfactor_u *<br>
+           tc->tessfactor_v * tc->num_invocations * tc->num_outputs > max_final_points) {<br>
+               fprintf(stderr, "Test case has more than %u final points.\n", max_final_points);<br>
+               print_testcase(tc);<br>
+               exit(1);<br>
+       }<br>
+<br>
+       /* Check against implementation-defined limits. */<br>
+       if (tc->tessfactor_u > max_tessfactor || tc->tessfactor_v > max_tessfactor) {<br>
+               fprintf(stderr, "Tessellation factor too high (max: %u)\n",<br>
+                       max_tessfactor);<br>
+               print_testcase(tc);<br>
+               exit(1);<br>
+       }<br>
+       if (tc->num_outputs > max_gs_out_vertices) {<br>
+               fprintf(stderr, "Too many output vertices (max: %d)\n",<br>
+                       max_gs_out_vertices);<br>
+               print_testcase(tc);<br>
+               exit(1);<br>
+       }<br>
+       if (tc->num_outputs * (5 + tc->num_extra_components) > max_gs_total_out_components) {<br>
+               fprintf(stderr, "Too many output components (max: %d)\n",<br>
+                       max_gs_total_out_components);<br>
+               print_testcase(tc);<br>
+               exit(1);<br>
+       }<br>
+       if (tc->num_invocations > max_gs_invocations) {<br>
+               fprintf(stderr, "Too many GS invocations (max: %d)\n",<br>
+                       max_gs_invocations);<br>
+               print_testcase(tc);<br>
+               exit(1);<br>
+       }<br>
+<br>
+       /* Compile GS shader and link program */<br>
+       geometryshaderkey gskey;<br>
+       gskey.num_invocations = tc->num_invocations;<br>
+       gskey.num_outputs = tc->num_outputs;<br>
+       gskey.num_extra_components = tc->num_extra_components;<br>
+       if (testprograms.find(gskey) == testprograms.end()) {<br>
+               char *text;<br>
+<br>
+               fragmentshaderkey fskey;<br>
+               fskey.num_extra_components = tc->num_extra_components;<br>
+               auto fsit = fragmentshaders.find(fskey);<br>
+               if (fsit == fragmentshaders.end()) {<br>
+                       if (asprintf(&text, fs_text, tc->num_extra_components) < 0)<br>
+                               abort();<br>
+                       GLuint fs_shader =<br>
+                               piglit_compile_shader_text(GL_FRAGMENT_SHADER, text);<br>
+                       free(text);<br>
+<br>
+                       fsit = fragmentshaders.insert(std::make_pair(fskey, fs_shader)).first;<br>
+               }<br>
+<br>
+               if (asprintf(&text, gs_text, tc->num_invocations, tc->num_outputs,<br>
+                       tc->num_extra_components) < 0)<br>
+                       abort();<br>
+               GLuint gs_shader =<br>
+                       piglit_compile_shader_text(GL_GEOMETRY_SHADER, text);<br>
+               free(text);<br>
+<br>
+               GLuint prog =  glCreateProgram();<br>
+               glAttachShader(prog, vs_shader);<br>
+               glAttachShader(prog, tcs_shader);<br>
+               glAttachShader(prog, tes_shader);<br>
+               glAttachShader(prog, gs_shader);<br>
+               glAttachShader(prog, fsit->second);<br>
+               glLinkProgram(prog);<br>
+               if (!piglit_link_check_status(prog))<br>
+                       piglit_report_result(PIGLIT_FAIL);<br>
+<br>
+               glDeleteShader(gs_shader);<br>
+<br>
+               testprograms.insert(std::make_pair(gskey, prog));<br>
+       }<br>
+<br>
+       testcases.push_back(*tc);<br>
+}<br>
+<br>
+static bool<br>
+run_testcase(const struct testcase *tc)<br>
+{<br>
+       unsigned final_points = tc->num_instances * tc->num_patches * tc->tessfactor_u *<br>
+                               tc->tessfactor_v * tc->num_invocations * tc->num_outputs;<br>
+       unsigned bufsize = 2 * sizeof(int32_t) * final_points;<br>
+<br>
+       print_testcase(tc);<br>
+<br>
+       glClearColor(0, 0, 0, 1);<br>
+       glClear(GL_COLOR_BUFFER_BIT);<br>
+<br>
+       geometryshaderkey gskey;<br>
+       gskey.num_invocations = tc->num_invocations;<br>
+       gskey.num_outputs = tc->num_outputs;<br>
+       gskey.num_extra_components = tc->num_extra_components;<br>
+       auto progit = testprograms.find(gskey);<br>
+       assert(progit != testprograms.end());<br>
+<br>
+       glUseProgram(progit->second);<br>
+       glPatchParameteri(GL_PATCH_VERTICES, 1);<br>
+       glUniform1i(glGetUniformLocation(progit->second, "u_tessfactor_u"),<br>
+                   tc->tessfactor_u);<br>
+       glUniform1i(glGetUniformLocation(progit->second, "u_tessfactor_v"),<br>
+                   tc->tessfactor_v);<br>
+       glUniform1i(glGetUniformLocation(progit->second, "u_verts_per_instance"),<br>
+                   tc->num_patches);<br>
+<br>
+       glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);<br>
+<br>
+       memset(buffer_copy, 0, bufsize);<br>
+       glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, bufsize, buffer_copy);<br>
+<br>
+       glEnable(GL_BLEND);<br>
+       glBlendFunc(GL_ONE, GL_ONE);<br>
+<br>
+       glDrawArraysInstanced(GL_PATCHES, 0, tc->num_patches, tc->num_instances);<br>
+<br>
+       glDisable(GL_BLEND);<br>
+<br>
+       if (!piglit_check_gl_error(GL_NO_ERROR))<br>
+               return false;<br>
+<br>
+       static const float expected[] = { 0, 0, 0, 1 };<br>
+       bool ok = true;<br>
+<br>
+       if (!piglit_probe_rect_rgba(0, 0, WINDOW_SIZE, WINDOW_SIZE, expected))<br>
+               ok = false;<br>
+<br>
+       glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, bufsize, buffer_copy);<br>
+<br>
+       for (unsigned i = 0; i < final_points; ++i) {<br>
+               if (buffer_copy[2 * i] != 1) {<br>
+                       printf("Error @ %d: %d %d\n", i,<br>
+                              buffer_copy[2 * i], buffer_copy[2 * i + 1]);<br>
+                       ok = false;<br>
+               }<br>
+       }<br>
+<br>
+       return ok;<br>
+}<br>
+<br>
+<br>
+static void<br>
+generate_testcases_max2(const testcase &tc, bool explicit_instances, bool explicit_patches)<br>
+{<br>
+       unsigned amplify = tc.tessfactor_u * tc.tessfactor_v * tc.num_invocations * tc.num_outputs;<br>
+       unsigned target_in = max_final_points / amplify;<br>
+<br>
+       if (small)<br>
+               target_in = MIN2(4, target_in);<br>
+<br>
+       if (!explicit_instances) {<br>
+               testcase tc1 = tc;<br>
+               tc1.num_instances = MAX2(1, target_in / tc1.num_patches);<br>
+               add_testcase(&tc1);<br>
+       }<br>
+<br>
+       if (!explicit_patches) {<br>
+               testcase tc1 = tc;<br>
+               tc1.num_patches = MAX2(1, target_in / tc1.num_instances);<br>
+               add_testcase(&tc1);<br>
+       }<br>
+<br>
+       if (!explicit_instances && !explicit_patches) {<br>
+               testcase tc1 = tc;<br>
+               tc1.num_instances = MAX2(1, (unsigned)sqrt(target_in));<br>
+               tc1.num_patches = MAX2(1, target_in / tc1.num_instances);<br>
+               add_testcase(&tc1);<br>
+       }<br>
+<br>
+       if (explicit_instances && explicit_patches)<br>
+               add_testcase(&tc);<br>
+}<br>
+<br>
+static void<br>
+generate_testcases_max1(const testcase &tc, bool explicit_instances, bool explicit_patches,<br>
+                       bool explicit_tessfactor_u, bool explicit_tessfactor_v,<br>
+                       unsigned tess_out_max)<br>
+{<br>
+       if (!explicit_tessfactor_u) {<br>
+               testcase tc1 = tc;<br>
+               tc1.tessfactor_u = MIN2(MAX2(1, tess_out_max / tc1.tessfactor_v),<br>
+                                       max_tessfactor);<br>
+               generate_testcases_max2(tc1, explicit_instances, explicit_patches);<br>
+       }<br>
+<br>
+       if (!explicit_tessfactor_v) {<br>
+               testcase tc1 = tc;<br>
+               tc1.tessfactor_v = MIN2(MAX2(1, tess_out_max / tc1.tessfactor_u),<br>
+                                       max_tessfactor);<br>
+               generate_testcases_max2(tc1, explicit_instances, explicit_patches);<br>
+       }<br>
+<br>
+       if (!explicit_tessfactor_u && !explicit_tessfactor_v) {<br>
+               testcase tc1 = tc;<br>
+               tc1.tessfactor_u = MIN2(MAX2(1, (unsigned)sqrt(tess_out_max)),<br>
+                                       max_tessfactor);<br>
+               tc1.tessfactor_v = MIN2(MAX2(1, tess_out_max / tc1.tessfactor_u),<br>
+                                       max_tessfactor);<br>
+               generate_testcases_max2(tc1, explicit_instances, explicit_patches);<br>
+       }<br>
+<br>
+       if (explicit_tessfactor_u && explicit_tessfactor_v)<br>
+               generate_testcases_max2(tc, explicit_instances, explicit_patches);<br>
+}<br>
+<br>
+static void<br>
+generate_testcases_max(const testcase &tc, bool explicit_instances, bool explicit_patches,<br>
+                      bool explicit_tessfactor_u, bool explicit_tessfactor_v)<br>
+{<br>
+       unsigned amplify = tc.num_invocations * tc.num_outputs;<br>
+       unsigned tess_out_max = max_final_points / amplify;<br>
+<br>
+       if (small) {<br>
+               generate_testcases_max1(tc, explicit_instances, explicit_patches,<br>
+                                       explicit_tessfactor_u, explicit_tessfactor_v,<br>
+                                       MIN2(4, tess_out_max));<br>
+       } else {<br>
+               generate_testcases_max1(tc, explicit_instances, explicit_patches,<br>
+                                       explicit_tessfactor_u, explicit_tessfactor_v,<br>
+                                       tess_out_max);<br>
+               while (tess_out_max > 4) {<br>
+                       tess_out_max = sqrt(tess_out_max);<br>
+                       generate_testcases_max1(tc, explicit_instances, explicit_patches,<br>
+                                               explicit_tessfactor_u, explicit_tessfactor_v,<br>
+                                               tess_out_max);<br>
+               }<br>
+       }<br>
+}<br>
+<br>
+static float<br>
+rand_subdivide(int partitions)<br>
+{<br>
+       double x = 1.0;<br>
+<br>
+       for (int i = 1; i < partitions; ++i)<br>
+               x = std::min(x, (double)rand() / ((double)RAND_MAX + 1));<br>
+<br>
+       return x;<br>
+}<br>
+<br>
+void<br>
+piglit_init(int argc, char **argv)<br>
+{<br>
+       bool explicit_instances = false;<br>
+       bool explicit_patches = false;<br>
+       bool explicit_tessfactor_u = false;<br>
+       bool explicit_tessfactor_v = false;<br>
+       bool explicit_invocations = false;<br>
+       bool explicit_outputs = false;<br>
+       bool explicit_components = false;<br>
+       bool scan_mode = false;<br>
+       unsigned scan_seed = 0;<br>
+       unsigned scan_count = 0;<br>
+       struct testcase explicit_testcase;<br>
+<br>
+       piglit_require_extension("GL_ARB_tessellation_shader");<br>
+       piglit_require_extension("GL_ARB_shader_storage_buffer_object");<br>
+<br>
+       memcpy(&explicit_testcase, &default_testcase, sizeof(explicit_testcase));<br>
+<br>
+       int i;<br>
+       for (i = 1; i < argc; ++i) {<br>
+               if (!strcmp(argv[i], "-small")) {<br>
+                       small = true;<br>
+               } else {<br>
+                       if (i + 1 >= argc)<br>
+                               break;<br>
+<br>
+                       if (!strcmp(argv[i], "-instances")) {<br>
+                               explicit_testcase.num_instances = atoi(argv[i + 1]);<br>
+                               explicit_instances = true;<br>
+                               i++;<br>
+                       } else if (!strcmp(argv[i], "-patches")) {<br>
+                               explicit_testcase.num_patches = atoi(argv[i + 1]);<br>
+                               explicit_patches = true;<br>
+                               i++;<br>
+                       } else if (!strcmp(argv[i], "-tessfactor_u")) {<br>
+                               explicit_testcase.tessfactor_u = atoi(argv[i + 1]);<br>
+                               explicit_tessfactor_u = true;<br>
+                               i++;<br>
+                       } else if (!strcmp(argv[i], "-tessfactor_v")) {<br>
+                               explicit_testcase.tessfactor_v = atoi(argv[i + 1]);<br>
+                               explicit_tessfactor_v = true;<br>
+                               i++;<br>
+                       } else if (!strcmp(argv[i], "-invocations")) {<br>
+                               explicit_testcase.num_invocations = atoi(argv[i + 1]);<br>
+                               explicit_invocations = true;<br>
+                               i++;<br>
+                       } else if (!strcmp(argv[i], "-outputs")) {<br>
+                               explicit_testcase.num_outputs = atoi(argv[i + 1]);<br>
+                               explicit_outputs = true;<br>
+                               i++;<br>
+                       } else if (!strcmp(argv[i], "-components")) {<br>
+                               explicit_testcase.num_extra_components = atoi(argv[i + 1]);<br>
+                               explicit_components = true;<br>
+                               i++;<br>
+                       } else {<br>
+                               if (i + 2 >= argc)<br>
+                                       break;<br>
+<br>
+                               if (!strcmp(argv[i], "-scan")) {<br>
+                                       scan_seed = atoi(argv[i + 1]);<br>
+                                       scan_count = atoi(argv[i + 2]);<br>
+                                       scan_mode = true;<br>
+                                       i += 2;<br>
+                               } else<br>
+                                       break;<br>
+                       }<br>
+               }<br>
+       }<br>
+       if (i < argc) {<br>
+               fprintf(stderr, "Unknown argument or too few params: %s\n", argv[i]);<br>
+               exit(1);<br>
+       }<br>
+<br>
+       /* Various GL objects needed by the test */<br>
+       vs_shader = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_text);<br>
+       if (!piglit_check_gl_error(GL_NO_ERROR))<br>
+               piglit_report_result(PIGLIT_FAIL);<br>
+<br>
+       tcs_shader = piglit_compile_shader_text(GL_TESS_CONTROL_SHADER, tcs_text);<br>
+       if (!piglit_check_gl_error(GL_NO_ERROR))<br>
+               piglit_report_result(PIGLIT_FAIL);<br>
+<br>
+       tes_shader = piglit_compile_shader_text(GL_TESS_EVALUATION_SHADER, tes_text);<br>
+       if (!piglit_check_gl_error(GL_NO_ERROR))<br>
+               piglit_report_result(PIGLIT_FAIL);<br>
+<br>
+       glGenVertexArrays(1, &vao);<br>
+       glBindVertexArray(vao);<br>
+<br>
+       glGenBuffers(1, &ssbo);<br>
+       glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);<br>
+       glBufferData(GL_SHADER_STORAGE_BUFFER, max_final_points * 8, NULL, GL_DYNAMIC_READ);<br>
+<br>
+       buffer_copy = (int32_t *)calloc(2 * sizeof(int32_t), max_final_points);<br>
+<br>
+       glGetIntegerv(GL_MAX_TESS_GEN_LEVEL, (GLint*)&max_tessfactor);<br>
+       glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, (GLint*)&max_gs_out_vertices);<br>
+       glGetIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,<br>
+                     (GLint*)&max_gs_total_out_components);<br>
+       glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,<br>
+                     (GLint*)&max_gs_out_components);<br>
+       glGetIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, (GLint*)&max_gs_invocations);<br>
+       if (!piglit_check_gl_error(GL_NO_ERROR))<br>
+               piglit_report_result(PIGLIT_FAIL);<br>
+<br>
+       max_gs_out_vertices_real = MIN2(max_gs_out_vertices,<br>
+                                       max_gs_total_out_components / 5);<br>
+<br>
+       if (scan_mode) {<br>
+               srand(scan_seed);<br>
+<br>
+               /* First, generate test cases that max out each of the dimensions */<br>
+               testcase tc0 = explicit_testcase;<br>
+               if (!explicit_invocations)<br>
+                       tc0.num_invocations = max_gs_invocations;<br>
+<br>
+               if (!explicit_outputs) {<br>
+                       testcase tc1 = tc0;<br>
+<br>
+                       if (!explicit_components) {<br>
+                               tc1.num_outputs = max_gs_out_vertices_real;<br>
+                               tc1.num_extra_components =<br>
+                                       MIN2(max_gs_total_out_components / tc1.num_outputs,<br>
+                                            max_gs_out_components) - 5;<br>
+                       } else {<br>
+                               tc1.num_outputs =<br>
+                                       MIN2(max_gs_total_out_components /<br>
+                                            (5 + tc1.num_extra_components),<br>
+                                            max_gs_out_vertices_real);<br>
+                       }<br>
+<br>
+                       generate_testcases_max(tc1, explicit_instances, explicit_patches,<br>
+                                              explicit_tessfactor_u, explicit_tessfactor_v);<br>
+               }<br>
+<br>
+               if (!explicit_components) {<br>
+                       testcase tc1 = tc0;<br>
+<br>
+                       if (!explicit_outputs) {<br>
+                               tc1.num_extra_components = max_gs_out_components - 5;<br>
+                               tc1.num_outputs =<br>
+                                       MIN2(max_gs_total_out_components /<br>
+                                            (5 + tc1.num_extra_components),<br>
+                                            max_gs_out_vertices_real);<br>
+                       } else {<br>
+                               tc1.num_extra_components =<br>
+                                       MIN2(max_gs_total_out_components / tc1.num_outputs,<br>
+                                            max_gs_out_components) - 4;<br>
+                       }<br>
+<br>
+                       generate_testcases_max(tc1, explicit_instances, explicit_patches,<br>
+                                              explicit_tessfactor_u, explicit_tessfactor_v);<br>
+               }<br>
+<br>
+               if (explicit_outputs && explicit_components)<br>
+                       generate_testcases_max(tc0, explicit_instances, explicit_patches,<br>
+                                              explicit_tessfactor_u, explicit_tessfactor_v);<br>
+<br>
+               /* Generate additional tests randomly.<br>
+                *<br>
+                * Attempt to generate a random distribution that isn't too<br>
+                * lop-sided, but admittedly this is all just hand-wavey<br>
+                * heuristics.<br>
+                */<br>
+               while (testcases.size() < scan_count) {<br>
+                       testcase tc = explicit_testcase;<br>
+<br>
+                       if (!explicit_outputs || !explicit_components) {<br>
+                               if (explicit_outputs || rand() & 1) {<br>
+                                       unsigned max_components =<br>
+                                               MIN2(max_gs_total_out_components / tc.num_outputs,<br>
+                                                    max_gs_out_components) - 5;<br>
+                                       tc.num_extra_components = rand() % (max_components + 1);<br>
+<br>
+                                       if (!explicit_outputs) {<br>
+                                               unsigned max_outputs =<br>
+                                                       MIN2(max_gs_total_out_components /<br>
+                                                            (5 + tc.num_extra_components),<br>
+                                                            max_gs_out_vertices_real);<br>
+                                               tc.num_outputs = 1 + rand() % max_outputs;<br>
+                                       }<br>
+                               } else {<br>
+                                       unsigned max_outputs =<br>
+                                               MIN2(max_gs_total_out_components /<br>
+                                                    (5 + tc.num_extra_components),<br>
+                                                    max_gs_out_vertices_real);<br>
+                                       tc.num_outputs = 1 + rand() % max_outputs;<br>
+<br>
+                                       if (!explicit_components) {<br>
+                                               unsigned max_components =<br>
+                                                       MIN2(max_gs_total_out_components / tc.num_outputs,<br>
+                                                            max_gs_out_components) - 5;<br>
+                                               tc.num_extra_components = rand() % (max_components + 1);<br>
+                                       }<br>
+                               }<br>
+                       }<br>
+<br>
+                       unsigned amplify = tc.num_outputs;<br>
+<br>
+                       if (explicit_invocations)<br>
+                               amplify *= tc.num_invocations;<br>
+                       if (explicit_tessfactor_u)<br>
+                               amplify *= tc.tessfactor_u;<br>
+                       if (explicit_tessfactor_v)<br>
+                               amplify *= tc.tessfactor_v;<br>
+                       if (explicit_patches)<br>
+                               amplify *= tc.num_patches;<br>
+                       if (explicit_instances)<br>
+                               amplify *= tc.num_instances;<br>
+<br>
+                       unsigned target = max_final_points / amplify;<br>
+<br>
+                       if (small)<br>
+                               target = MIN2(32, target);<br>
+<br>
+                       if (!explicit_tessfactor_u) {<br>
+                               float tf_log_weight = logf(target) * rand_subdivide(6);<br>
+                               tc.tessfactor_u = MIN2(expf(tf_log_weight), max_tessfactor);<br>
+                               target /= tc.tessfactor_u;<br>
+                       }<br>
+                       if (!explicit_tessfactor_v) {<br>
+                               float tf_log_weight = logf(target) * rand_subdivide(6);<br>
+                               tc.tessfactor_v = MIN2(expf(tf_log_weight), max_tessfactor);<br>
+                               target /= tc.tessfactor_v;<br>
+                       }<br>
+                       if (!explicit_invocations) {<br>
+                               float log_weight = logf(target);<br>
+                               if (!explicit_instances || !explicit_patches)<br>
+                                       log_weight *= rand_subdivide(2);<br>
+                               tc.num_invocations = MIN2(expf(log_weight), max_gs_invocations);<br>
+                               target /= tc.num_invocations;<br>
+                       }<br>
+                       if (!explicit_instances) {<br>
+                               float log_weight = logf(target);<br>
+                               if (!explicit_patches)<br>
+                                       log_weight *= rand_subdivide(2);<br>
+                               tc.num_instances = expf(log_weight);<br>
+                               target /= tc.num_instances;<br>
+                       }<br>
+                       if (!explicit_patches)<br>
+                               tc.num_patches = 1 + rand() % target;<br>
+<br>
+                       add_testcase(&tc);<br>
+               }<br>
+       } else {<br>
+               add_testcase(&explicit_testcase);<br>
+       }<br>
+}<br>
+<br>
+enum piglit_result<br>
+piglit_display(void)<br>
+{<br>
+       bool pass = true;<br>
+<br>
+       for (unsigned i = 0; i < testcases.size(); ++i) {<br>
+               if (!run_testcase(&testcases[i]))<br>
+                       pass = false;<br>
+       }<br>
+<br>
+       if (!piglit_check_gl_error(GL_NO_ERROR))<br>
+               pass = false;<br>
+<br>
+       piglit_present_results();<br>
+<br>
+       return pass ? PIGLIT_PASS : PIGLIT_FAIL;<br>
+}<br>
-- <br>
2.17.1<br>
<br>
_______________________________________________<br>
Piglit mailing list<br>
<a href="mailto:Piglit@lists.freedesktop.org" target="_blank">Piglit@lists.freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/piglit" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/piglit</a><br>
</blockquote></div>