[Piglit] [PATCH 4/4] arb_tessellation_shader/tes-gs-max-output: new test for TES/GS amplification
Jan Vesely
jan.vesely at rutgers.edu
Thu Oct 18 20:05:17 UTC 2018
On Thu, 2018-10-18 at 08:30 +0000, Haehnle, Nicolai wrote:
> On 17.10.18 19:57, Jan Vesely wrote:
> > This test breaks build for compilers that don't default to C++11+ for
> > cpp sources.
> >
> > https://travis-ci.org/jvesely/piglit/jobs/442796343
>
> Sorry about that. I just pushed a commit that hopefully fixes this.
It does. thank you.
Jan
>
> Cheers,
> Nicolai
>
>
> >
> > Jan
> >
> > On Thu, Sep 13, 2018 at 2:11 PM Nicolai Hähnle <nhaehnle at gmail.com
> > <mailto:nhaehnle at gmail.com>> wrote:
> >
> > From: Nicolai Hähnle <nicolai.haehnle at amd.com
> > <mailto:nicolai.haehnle at amd.com>>
> >
> > Test extremes of GS amplification under tessellation.
> > ---
> > tests/opengl.py | 1 +
> > .../arb_tessellation_shader/CMakeLists.gl.txt | 1 +
> > .../tes-gs-max-output.cpp | 817 ++++++++++++++++++
> > 3 files changed, 819 insertions(+)
> > create mode 100644
> > tests/spec/arb_tessellation_shader/tes-gs-max-output.cpp
> >
> > diff --git a/tests/opengl.py b/tests/opengl.py
> > index 903a95809..3cc25c99c 100644
> > --- a/tests/opengl.py
> > +++ b/tests/opengl.py
> > @@ -1524,20 +1524,21 @@ with profile.test_list.group_manager(
> > g(['arb_tessellation_shader-immediate-mode-draw-patches'])
> > g(['arb_tessellation_shader-invalid-get-program-params'])
> > g(['arb_tessellation_shader-invalid-patch-vertices-range'])
> > g(['arb_tessellation_shader-invalid-primitive'])
> > g(['built-in-constants',
> > os.path.join('spec', 'arb_tessellation_shader',
> > 'minimum-maximums.txt')],
> > 'built-in-constants',
> > override_class=BuiltInConstantsTest)
> > g(['arb_tessellation_shader-large-uniforms'])
> > g(['arb_tessellation_shader-layout-mismatch'])
> > + g(['arb_tessellation_shader-tes-gs-max-output', '-small',
> > '-scan', '1', '50'])
> >
> > # Group ARB_texture_multisample
> > with profile.test_list.group_manager(
> > PiglitGLTest, grouptools.join('spec',
> > 'ARB_texture_multisample')) as g:
> > g(['arb_texture_multisample-large-float-texture'],
> > 'large-float-texture',
> > run_concurrent=False)
> > g(['arb_texture_multisample-large-float-texture', '--array'],
> > 'large-float-texture-array', run_concurrent=False)
> > g(['arb_texture_multisample-large-float-texture', '--fp16'],
> > 'large-float-texture-fp16', run_concurrent=False)
> > diff --git a/tests/spec/arb_tessellation_shader/CMakeLists.gl.txt
> > b/tests/spec/arb_tessellation_shader/CMakeLists.gl.txt
> > index d70b00f3f..058a1bc49 100644
> > --- a/tests/spec/arb_tessellation_shader/CMakeLists.gl.txt
> > +++ b/tests/spec/arb_tessellation_shader/CMakeLists.gl.txt
> > @@ -11,12 +11,13 @@ link_libraries (
> >
> > piglit_add_executable (arb_tessellation_shader-get-tcs-params
> > get-tcs-params.c)
> > piglit_add_executable (arb_tessellation_shader-get-tes-params
> > get-tes-params.c)
> > piglit_add_executable
> > (arb_tessellation_shader-immediate-mode-draw-patches
> > immediate-mode-draw-patches.c)
> > piglit_add_executable
> > (arb_tessellation_shader-invalid-get-program-params
> > invalid-get-program-params.c)
> > piglit_add_executable
> > (arb_tessellation_shader-invalid-patch-vertices-range
> > invalid-patch-vertices-range.c)
> > piglit_add_executable (arb_tessellation_shader-invalid-primitive
> > invalid-primitive.c)
> > piglit_add_executable (arb_tessellation_shader-minmax minmax.c)
> > piglit_add_executable (arb_tessellation_shader-large-uniforms
> > large-uniforms.c)
> > piglit_add_executable (arb_tessellation_shader-layout-mismatch
> > layout-mismatch.c)
> > +piglit_add_executable (arb_tessellation_shader-tes-gs-max-output
> > tes-gs-max-output.cpp)
> >
> > # vim: ft=cmake:
> > diff --git
> > a/tests/spec/arb_tessellation_shader/tes-gs-max-output.cpp
> > b/tests/spec/arb_tessellation_shader/tes-gs-max-output.cpp
> > new file mode 100644
> > index 000000000..de0d2daf1
> > --- /dev/null
> > +++ b/tests/spec/arb_tessellation_shader/tes-gs-max-output.cpp
> > @@ -0,0 +1,817 @@
> > +/*
> > + * Copyright (c) 2018 Advanced Micro Devices
> > + *
> > + * 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 tes-gs-max-output.cpp
> > + *
> > + * Stress the limits of what tessellation + geometry shaders can
> > output using
> > + * generic shaders with points as input and output primitives, allowing
> > + * arbitrary:
> > + * - number of input instances (instanced draws)
> > + * - number of input patches per instance
> > + * - (integer) tessellation factors
> > + * - number of invocations (GS instances)
> > + * - number of output vertices per invocation
> > + * - number of output components per vertex
> > + *
> > + * Verification works by rendering points and writing to an SSBO
> > from the
> > + * fragment shader.
> > + */
> > +
> > +#include "piglit-util-gl.h"
> > +
> > +#include <algorithm>
> > +#include <map>
> > +#include <set>
> > +#include <vector>
> > +
> > +#define WINDOW_SIZE 256
> > +
> > +PIGLIT_GL_TEST_CONFIG_BEGIN
> > +
> > + config.supports_gl_compat_version = 32;
> > + config.supports_gl_core_version = 32;
> > + config.window_width = WINDOW_SIZE;
> > + config.window_height = WINDOW_SIZE;
> > + config.window_visual = PIGLIT_GL_VISUAL_DOUBLE |
> > PIGLIT_GL_VISUAL_RGBA;
> > + config.khr_no_error_support = PIGLIT_NO_ERRORS;
> > +
> > +PIGLIT_GL_TEST_CONFIG_END
> > +
> > +#define PASTE(x) #x
> > +#define STR(x) PASTE(x)
> > +
> > +struct testcase {
> > + unsigned num_instances; /* draw instances */
> > + unsigned num_patches; /* draw size / count */
> > + unsigned tessfactor_u;
> > + unsigned tessfactor_v;
> > + unsigned num_invocations; /* GS invocations / instances */
> > + unsigned num_outputs; /* # vertex ouput per GS invocation */
> > + unsigned num_extra_components; /* # extra components per GS
> > output vertex */
> > +
> > + bool operator<(const testcase &o) const {
> > + return std::make_tuple(num_instances, num_patches,
> > tessfactor_u,
> > + tessfactor_v,
> > num_invocations, num_outputs,
> > + num_extra_components)
> > + <
> > + std::make_tuple(o.num_instances,
> > o.num_patches, o.tessfactor_u,
> > + o.tessfactor_v,
> > o.num_invocations, o.num_outputs,
> > + o.num_extra_components);
> > + }
> > +};
> > +
> > +struct fragmentshaderkey {
> > + unsigned num_extra_components;
> > +
> > + bool operator<(const fragmentshaderkey &o) const {
> > + return num_extra_components < o.num_extra_components;
> > + }
> > +};
> > +
> > +struct geometryshaderkey {
> > + unsigned num_invocations;
> > + unsigned num_outputs;
> > + unsigned num_extra_components;
> > +
> > + bool operator<(const geometryshaderkey &o) const {
> > + if (num_invocations < o.num_invocations)
> > + return true;
> > + if (num_invocations > o.num_invocations)
> > + return false;
> > + if (num_outputs < o.num_outputs)
> > + return true;
> > + if (num_outputs > o.num_outputs)
> > + return false;
> > + return num_extra_components < o.num_extra_components;
> > + }
> > +};
> > +
> > +static std::map<fragmentshaderkey, GLuint> fragmentshaders;
> > +static std::map<geometryshaderkey, GLuint> testprograms;
> > +
> > +static const struct testcase default_testcase = {
> > + .num_instances = 1,
> > + .num_patches = 1,
> > + .tessfactor_u = 1,
> > + .tessfactor_v = 1,
> > + .num_invocations = 1,
> > + .num_outputs = 1,
> > + .num_extra_components = 0,
> > +};
> > +
> > +static int32_t *buffer_copy;
> > +
> > +static const unsigned max_final_points = 2 * 1024 * 1024; /*
> > requires 16 MiB buffer */
> > +static bool small = false;
> > +static GLuint vs_shader;
> > +static GLuint tcs_shader;
> > +static GLuint tes_shader;
> > +static GLuint vao;
> > +static GLuint ssbo;
> > +static std::vector<testcase> testcases;
> > +static std::set<testcase> testcases_set;
> > +static GLuint max_tessfactor;
> > +static GLuint max_gs_invocations;
> > +static GLuint max_gs_out_vertices;
> > +static GLuint max_gs_total_out_components;
> > +static GLuint max_gs_out_components;
> > +static unsigned max_gs_out_vertices_real;
> > +
> > +static const char vs_text[] =
> > + "#version 150\n"
> > + "\n"
> > + "uniform int u_verts_per_instance;\n"
> > + "\n"
> > + "out int vs_tcs_id;\n"
> > + "\n"
> > + "void main() {\n"
> > + " vs_tcs_id = gl_InstanceID * u_verts_per_instance +
> > gl_VertexID;\n"
> > + "}\n";
> > +
> > +static const char tcs_text[] =
> > + "#version 150\n"
> > + "#extension GL_ARB_tessellation_shader : require\n"
> > + "layout(vertices = 1) out;\n"
> > + "\n"
> > + "in int vs_tcs_id[];\n"
> > + "\n"
> > + "out int tcs_tes_id[];\n"
> > + "\n"
> > + "uniform int u_tessfactor_u;\n"
> > + "uniform int u_tessfactor_v;\n"
> > + "\n"
> > + "void main() {\n"
> > + " tcs_tes_id[gl_InvocationID] = vs_tcs_id[gl_InvocationID];\n"
> > + " gl_TessLevelOuter[0] = u_tessfactor_v;\n"
> > + " gl_TessLevelOuter[1] = u_tessfactor_u;\n"
> > + "}\n";
> > +
> > +static const char tes_text[] =
> > + "#version 150\n"
> > + "#extension GL_ARB_tessellation_shader : require\n"
> > + "layout(isolines, equal_spacing) in;\n"
> > + "\n"
> > + "in int tcs_tes_id[];\n"
> > + "\n"
> > + "out int tes_gs_id;\n"
> > + "\n"
> > + "void main() {\n"
> > + " tes_gs_id = tcs_tes_id[0];\n"
> > + " gl_Position.x = gl_TessCoord[0];\n"
> > + " gl_Position.y = gl_TessCoord[1];\n"
> > + "}\n";
> > +
> > +/* Those numbers really don't matter much for what we're trying to
> > do here. */
> > +#define GEN_SEQUENCE \
> > + "int seq_next(int x) {\n" \
> > + " x = (x + 1) * 709900053;\n" \
> > + " x = x ^ (x >> 17);\n" \
> > + " return x;\n" \
> > + "}\n"
> > +
> > +static const char gs_text[] =
> > + "#version 150\n"
> > + "#extension GL_ARB_gpu_shader5 : require\n"
> > + "\n"
> > + "#define NUM_INVOCATIONS %d\n"
> > + "#define NUM_OUT_VERTICES %d\n"
> > + "#define NUM_EXTRA_COMPONENTS %d\n"
> > + "\n"
> > + "layout(lines, invocations = NUM_INVOCATIONS) in;\n"
> > + "layout(points, max_vertices = NUM_OUT_VERTICES) out;\n"
> > + "\n"
> > + "uniform int u_tessfactor_u;\n"
> > + "uniform int u_tessfactor_v;\n"
> > + "\n"
> > + "in int tes_gs_id[];\n"
> > + "\n"
> > + "flat out int gs_ps_data[1 + NUM_EXTRA_COMPONENTS];\n"
> > + "\n"
> > + GEN_SEQUENCE
> > + "\n"
> > + "void main() {\n"
> > + " int in_id = tes_gs_id[0] * u_tessfactor_u *
> > u_tessfactor_v;\n"
> > + " float v = gl_in[0].gl_Position.y;\n"
> > + " in_id += u_tessfactor_u * int(v * u_tessfactor_v + 0.5);\n"
> > + " float u = min(gl_in[0].gl_Position.x,
> > gl_in[1].gl_Position.x);\n"
> > + " in_id += int(u * u_tessfactor_u + 0.5);\n"
> > + "\n"
> > + " for (int i = 0; i < NUM_OUT_VERTICES; ++i) {\n"
> > + " uint id = (in_id * NUM_INVOCATIONS + gl_InvocationID) *
> > NUM_OUT_VERTICES + i;\n"
> > + " uint x = id %% " STR(WINDOW_SIZE) "u;\n"
> > + " uint y = (id / " STR(WINDOW_SIZE) "u) %% "
> > STR(WINDOW_SIZE) "u;\n"
> > + " gl_Position.x = (float(x) + 0.5) / " STR(WINDOW_SIZE) "
> > * 2.0 - 1.0;\n"
> > + " gl_Position.y = (float(y) + 0.5) / " STR(WINDOW_SIZE) "
> > * 2.0 - 1.0;\n"
> > + " gl_Position.z = 0.0;\n"
> > + " gl_Position.w = 1.0;\n"
> > + "\n"
> > + " int val = int(id);\n"
> > + " for (int j = 0; j <= NUM_EXTRA_COMPONENTS; ++j) {\n"
> > + " gs_ps_data[j] = val;\n"
> > + " val = seq_next(val);\n"
> > + " }\n"
> > + "\n"
> > + " EmitVertex();\n"
> > + " }\n"
> > + "}\n";
> > +
> > +static const char fs_text[] =
> > + "#version 150\n"
> > + "#extension GL_ARB_shader_storage_buffer_object : require\n"
> > + "\n"
> > + "#define NUM_EXTRA_COMPONENTS %d\n"
> > + "\n"
> > + "flat in int gs_ps_data[1 + NUM_EXTRA_COMPONENTS];\n"
> > + "out vec4 out_color;\n"
> > + "\n"
> > + "layout(std430, binding = 0) buffer SSBO {\n"
> > + " ivec2 data[];\n"
> > + "} ssbo;\n"
> > + "\n"
> > + GEN_SEQUENCE
> > + "\n"
> > + "void main() {\n"
> > + " int id = gs_ps_data[0];\n"
> > + " int screen_id = int(gl_FragCoord.y) * " STR(WINDOW_SIZE)
> > " + int(gl_FragCoord.x);\n"
> > + " if (screen_id != id %% (" STR(WINDOW_SIZE * WINDOW_SIZE)
> > ")) {\n"
> > + " ssbo.data[id].x = 1000;\n"
> > + " ssbo.data[id].y = screen_id;\n"
> > + " out_color = vec4(0.1, 0, 0, 1);\n"
> > + " return;\n"
> > + " }\n"
> > + "\n"
> > + " int val = id;\n"
> > + " for (int j = 0; j <= NUM_EXTRA_COMPONENTS; ++j) {\n"
> > + " if (val != gs_ps_data[j]) {\n"
> > + " ssbo.data[id].x = 2000 + j;\n"
> > + " ssbo.data[id].y = gs_ps_data[j];\n"
> > + " out_color = vec4(0, 0.1, 0, 1);\n"
> > + " return;\n"
> > + " }\n"
> > + " val = seq_next(val);\n"
> > + " }\n"
> > + "\n"
> > + " ssbo.data[id].x = 1;\n"
> > + " out_color = vec4(0, 0, 0, 1);\n"
> > + "}\n";
> > +
> > +static void
> > +print_testcase(const struct testcase *tc)
> > +{
> > + printf("Case: instances = %u patches = %u tessfactor = %u,%u
> > invocations = %u "
> > + "outputs = %u extra_components = %u\n",
> > + tc->num_instances, tc->num_patches, tc->tessfactor_u,
> > tc->tessfactor_v,
> > + tc->num_invocations, tc->num_outputs,
> > tc->num_extra_components);
> > +}
> > +
> > +static void
> > +add_testcase(const struct testcase *tc)
> > +{
> > + if (!testcases_set.insert(*tc).second)
> > + return;
> > +
> > + if (tc->num_instances > 64 * 1024 ||
> > + tc->num_patches > 64 * 1024 ||
> > + tc->tessfactor_u > 64 * 1024 ||
> > + tc->tessfactor_v > 64 * 1024 ||
> > + tc->num_invocations > 64 * 1024 ||
> > + tc->num_outputs > 64 * 1024 ||
> > + tc->num_extra_components > 64 * 1024) {
> > + fprintf(stderr, "Excessive test case size. Are you
> > sure?\n");
> > + print_testcase(tc);
> > + exit(1);
> > + }
> > +
> > + /* Multiple separate multiplies to avoid integer wraparound */
> > + if ((uint64_t)tc->num_instances * tc->num_patches *
> > tc->tessfactor_u > max_final_points ||
> > + (uint64_t)tc->tessfactor_v * tc->num_invocations *
> > tc->num_outputs > max_final_points ||
> > + (uint64_t)tc->num_instances * tc->num_patches *
> > tc->tessfactor_u *
> > + tc->tessfactor_v * tc->num_invocations * tc->num_outputs
> > > max_final_points) {
> > + fprintf(stderr, "Test case has more than %u final
> > points.\n", max_final_points);
> > + print_testcase(tc);
> > + exit(1);
> > + }
> > +
> > + /* Check against implementation-defined limits. */
> > + if (tc->tessfactor_u > max_tessfactor || tc->tessfactor_v >
> > max_tessfactor) {
> > + fprintf(stderr, "Tessellation factor too high (max:
> > %u)\n",
> > + max_tessfactor);
> > + print_testcase(tc);
> > + exit(1);
> > + }
> > + if (tc->num_outputs > max_gs_out_vertices) {
> > + fprintf(stderr, "Too many output vertices (max: %d)\n",
> > + max_gs_out_vertices);
> > + print_testcase(tc);
> > + exit(1);
> > + }
> > + if (tc->num_outputs * (5 + tc->num_extra_components) >
> > max_gs_total_out_components) {
> > + fprintf(stderr, "Too many output components (max:
> > %d)\n",
> > + max_gs_total_out_components);
> > + print_testcase(tc);
> > + exit(1);
> > + }
> > + if (tc->num_invocations > max_gs_invocations) {
> > + fprintf(stderr, "Too many GS invocations (max: %d)\n",
> > + max_gs_invocations);
> > + print_testcase(tc);
> > + exit(1);
> > + }
> > +
> > + /* Compile GS shader and link program */
> > + geometryshaderkey gskey;
> > + gskey.num_invocations = tc->num_invocations;
> > + gskey.num_outputs = tc->num_outputs;
> > + gskey.num_extra_components = tc->num_extra_components;
> > + if (testprograms.find(gskey) == testprograms.end()) {
> > + char *text;
> > +
> > + fragmentshaderkey fskey;
> > + fskey.num_extra_components = tc->num_extra_components;
> > + auto fsit = fragmentshaders.find(fskey);
> > + if (fsit == fragmentshaders.end()) {
> > + if (asprintf(&text, fs_text,
> > tc->num_extra_components) < 0)
> > + abort();
> > + GLuint fs_shader =
> > +
> > piglit_compile_shader_text(GL_FRAGMENT_SHADER, text);
> > + free(text);
> > +
> > + fsit =
> > fragmentshaders.insert(std::make_pair(fskey, fs_shader)).first;
> > + }
> > +
> > + if (asprintf(&text, gs_text, tc->num_invocations,
> > tc->num_outputs,
> > + tc->num_extra_components) < 0)
> > + abort();
> > + GLuint gs_shader =
> > +
> > piglit_compile_shader_text(GL_GEOMETRY_SHADER, text);
> > + free(text);
> > +
> > + GLuint prog = glCreateProgram();
> > + glAttachShader(prog, vs_shader);
> > + glAttachShader(prog, tcs_shader);
> > + glAttachShader(prog, tes_shader);
> > + glAttachShader(prog, gs_shader);
> > + glAttachShader(prog, fsit->second);
> > + glLinkProgram(prog);
> > + if (!piglit_link_check_status(prog))
> > + piglit_report_result(PIGLIT_FAIL);
> > +
> > + glDeleteShader(gs_shader);
> > +
> > + testprograms.insert(std::make_pair(gskey, prog));
> > + }
> > +
> > + testcases.push_back(*tc);
> > +}
> > +
> > +static bool
> > +run_testcase(const struct testcase *tc)
> > +{
> > + unsigned final_points = tc->num_instances * tc->num_patches
> > * tc->tessfactor_u *
> > + tc->tessfactor_v *
> > tc->num_invocations * tc->num_outputs;
> > + unsigned bufsize = 2 * sizeof(int32_t) * final_points;
> > +
> > + print_testcase(tc);
> > +
> > + glClearColor(0, 0, 0, 1);
> > + glClear(GL_COLOR_BUFFER_BIT);
> > +
> > + geometryshaderkey gskey;
> > + gskey.num_invocations = tc->num_invocations;
> > + gskey.num_outputs = tc->num_outputs;
> > + gskey.num_extra_components = tc->num_extra_components;
> > + auto progit = testprograms.find(gskey);
> > + assert(progit != testprograms.end());
> > +
> > + glUseProgram(progit->second);
> > + glPatchParameteri(GL_PATCH_VERTICES, 1);
> > + glUniform1i(glGetUniformLocation(progit->second,
> > "u_tessfactor_u"),
> > + tc->tessfactor_u);
> > + glUniform1i(glGetUniformLocation(progit->second,
> > "u_tessfactor_v"),
> > + tc->tessfactor_v);
> > + glUniform1i(glGetUniformLocation(progit->second,
> > "u_verts_per_instance"),
> > + tc->num_patches);
> > +
> > + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
> > +
> > + memset(buffer_copy, 0, bufsize);
> > + glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, bufsize,
> > buffer_copy);
> > +
> > + glEnable(GL_BLEND);
> > + glBlendFunc(GL_ONE, GL_ONE);
> > +
> > + glDrawArraysInstanced(GL_PATCHES, 0, tc->num_patches,
> > tc->num_instances);
> > +
> > + glDisable(GL_BLEND);
> > +
> > + if (!piglit_check_gl_error(GL_NO_ERROR))
> > + return false;
> > +
> > + static const float expected[] = { 0, 0, 0, 1 };
> > + bool ok = true;
> > +
> > + if (!piglit_probe_rect_rgba(0, 0, WINDOW_SIZE, WINDOW_SIZE,
> > expected))
> > + ok = false;
> > +
> > + glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, bufsize,
> > buffer_copy);
> > +
> > + for (unsigned i = 0; i < final_points; ++i) {
> > + if (buffer_copy[2 * i] != 1) {
> > + printf("Error @ %d: %d %d\n", i,
> > + buffer_copy[2 * i], buffer_copy[2 * i
> > + 1]);
> > + ok = false;
> > + }
> > + }
> > +
> > + return ok;
> > +}
> > +
> > +
> > +static void
> > +generate_testcases_max2(const testcase &tc, bool
> > explicit_instances, bool explicit_patches)
> > +{
> > + unsigned amplify = tc.tessfactor_u * tc.tessfactor_v *
> > tc.num_invocations * tc.num_outputs;
> > + unsigned target_in = max_final_points / amplify;
> > +
> > + if (small)
> > + target_in = MIN2(4, target_in);
> > +
> > + if (!explicit_instances) {
> > + testcase tc1 = tc;
> > + tc1.num_instances = MAX2(1, target_in /
> > tc1.num_patches);
> > + add_testcase(&tc1);
> > + }
> > +
> > + if (!explicit_patches) {
> > + testcase tc1 = tc;
> > + tc1.num_patches = MAX2(1, target_in /
> > tc1.num_instances);
> > + add_testcase(&tc1);
> > + }
> > +
> > + if (!explicit_instances && !explicit_patches) {
> > + testcase tc1 = tc;
> > + tc1.num_instances = MAX2(1, (unsigned)sqrt(target_in));
> > + tc1.num_patches = MAX2(1, target_in /
> > tc1.num_instances);
> > + add_testcase(&tc1);
> > + }
> > +
> > + if (explicit_instances && explicit_patches)
> > + add_testcase(&tc);
> > +}
> > +
> > +static void
> > +generate_testcases_max1(const testcase &tc, bool
> > explicit_instances, bool explicit_patches,
> > + bool explicit_tessfactor_u, bool
> > explicit_tessfactor_v,
> > + unsigned tess_out_max)
> > +{
> > + if (!explicit_tessfactor_u) {
> > + testcase tc1 = tc;
> > + tc1.tessfactor_u = MIN2(MAX2(1, tess_out_max /
> > tc1.tessfactor_v),
> > + max_tessfactor);
> > + generate_testcases_max2(tc1, explicit_instances,
> > explicit_patches);
> > + }
> > +
> > + if (!explicit_tessfactor_v) {
> > + testcase tc1 = tc;
> > + tc1.tessfactor_v = MIN2(MAX2(1, tess_out_max /
> > tc1.tessfactor_u),
> > + max_tessfactor);
> > + generate_testcases_max2(tc1, explicit_instances,
> > explicit_patches);
> > + }
> > +
> > + if (!explicit_tessfactor_u && !explicit_tessfactor_v) {
> > + testcase tc1 = tc;
> > + tc1.tessfactor_u = MIN2(MAX2(1,
> > (unsigned)sqrt(tess_out_max)),
> > + max_tessfactor);
> > + tc1.tessfactor_v = MIN2(MAX2(1, tess_out_max /
> > tc1.tessfactor_u),
> > + max_tessfactor);
> > + generate_testcases_max2(tc1, explicit_instances,
> > explicit_patches);
> > + }
> > +
> > + if (explicit_tessfactor_u && explicit_tessfactor_v)
> > + generate_testcases_max2(tc, explicit_instances,
> > explicit_patches);
> > +}
> > +
> > +static void
> > +generate_testcases_max(const testcase &tc, bool explicit_instances,
> > bool explicit_patches,
> > + bool explicit_tessfactor_u, bool
> > explicit_tessfactor_v)
> > +{
> > + unsigned amplify = tc.num_invocations * tc.num_outputs;
> > + unsigned tess_out_max = max_final_points / amplify;
> > +
> > + if (small) {
> > + generate_testcases_max1(tc, explicit_instances,
> > explicit_patches,
> > + explicit_tessfactor_u,
> > explicit_tessfactor_v,
> > + MIN2(4, tess_out_max));
> > + } else {
> > + generate_testcases_max1(tc, explicit_instances,
> > explicit_patches,
> > + explicit_tessfactor_u,
> > explicit_tessfactor_v,
> > + tess_out_max);
> > + while (tess_out_max > 4) {
> > + tess_out_max = sqrt(tess_out_max);
> > + generate_testcases_max1(tc,
> > explicit_instances, explicit_patches,
> > +
> > explicit_tessfactor_u, explicit_tessfactor_v,
> > + tess_out_max);
> > + }
> > + }
> > +}
> > +
> > +static float
> > +rand_subdivide(int partitions)
> > +{
> > + double x = 1.0;
> > +
> > + for (int i = 1; i < partitions; ++i)
> > + x = std::min(x, (double)rand() / ((double)RAND_MAX +
> > 1));
> > +
> > + return x;
> > +}
> > +
> > +void
> > +piglit_init(int argc, char **argv)
> > +{
> > + bool explicit_instances = false;
> > + bool explicit_patches = false;
> > + bool explicit_tessfactor_u = false;
> > + bool explicit_tessfactor_v = false;
> > + bool explicit_invocations = false;
> > + bool explicit_outputs = false;
> > + bool explicit_components = false;
> > + bool scan_mode = false;
> > + unsigned scan_seed = 0;
> > + unsigned scan_count = 0;
> > + struct testcase explicit_testcase;
> > +
> > + piglit_require_extension("GL_ARB_tessellation_shader");
> > + piglit_require_extension("GL_ARB_shader_storage_buffer_object");
> > +
> > + memcpy(&explicit_testcase, &default_testcase,
> > sizeof(explicit_testcase));
> > +
> > + int i;
> > + for (i = 1; i < argc; ++i) {
> > + if (!strcmp(argv[i], "-small")) {
> > + small = true;
> > + } else {
> > + if (i + 1 >= argc)
> > + break;
> > +
> > + if (!strcmp(argv[i], "-instances")) {
> > + explicit_testcase.num_instances =
> > atoi(argv[i + 1]);
> > + explicit_instances = true;
> > + i++;
> > + } else if (!strcmp(argv[i], "-patches")) {
> > + explicit_testcase.num_patches =
> > atoi(argv[i + 1]);
> > + explicit_patches = true;
> > + i++;
> > + } else if (!strcmp(argv[i], "-tessfactor_u")) {
> > + explicit_testcase.tessfactor_u =
> > atoi(argv[i + 1]);
> > + explicit_tessfactor_u = true;
> > + i++;
> > + } else if (!strcmp(argv[i], "-tessfactor_v")) {
> > + explicit_testcase.tessfactor_v =
> > atoi(argv[i + 1]);
> > + explicit_tessfactor_v = true;
> > + i++;
> > + } else if (!strcmp(argv[i], "-invocations")) {
> > + explicit_testcase.num_invocations =
> > atoi(argv[i + 1]);
> > + explicit_invocations = true;
> > + i++;
> > + } else if (!strcmp(argv[i], "-outputs")) {
> > + explicit_testcase.num_outputs =
> > atoi(argv[i + 1]);
> > + explicit_outputs = true;
> > + i++;
> > + } else if (!strcmp(argv[i], "-components")) {
> > +
> > explicit_testcase.num_extra_components = atoi(argv[i + 1]);
> > + explicit_components = true;
> > + i++;
> > + } else {
> > + if (i + 2 >= argc)
> > + break;
> > +
> > + if (!strcmp(argv[i], "-scan")) {
> > + scan_seed = atoi(argv[i + 1]);
> > + scan_count = atoi(argv[i + 2]);
> > + scan_mode = true;
> > + i += 2;
> > + } else
> > + break;
> > + }
> > + }
> > + }
> > + if (i < argc) {
> > + fprintf(stderr, "Unknown argument or too few params:
> > %s\n", argv[i]);
> > + exit(1);
> > + }
> > +
> > + /* Various GL objects needed by the test */
> > + vs_shader = piglit_compile_shader_text(GL_VERTEX_SHADER,
> > vs_text);
> > + if (!piglit_check_gl_error(GL_NO_ERROR))
> > + piglit_report_result(PIGLIT_FAIL);
> > +
> > + tcs_shader =
> > piglit_compile_shader_text(GL_TESS_CONTROL_SHADER, tcs_text);
> > + if (!piglit_check_gl_error(GL_NO_ERROR))
> > + piglit_report_result(PIGLIT_FAIL);
> > +
> > + tes_shader =
> > piglit_compile_shader_text(GL_TESS_EVALUATION_SHADER, tes_text);
> > + if (!piglit_check_gl_error(GL_NO_ERROR))
> > + piglit_report_result(PIGLIT_FAIL);
> > +
> > + glGenVertexArrays(1, &vao);
> > + glBindVertexArray(vao);
> > +
> > + glGenBuffers(1, &ssbo);
> > + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
> > + glBufferData(GL_SHADER_STORAGE_BUFFER, max_final_points * 8,
> > NULL, GL_DYNAMIC_READ);
> > +
> > + buffer_copy = (int32_t *)calloc(2 * sizeof(int32_t),
> > max_final_points);
> > +
> > + glGetIntegerv(GL_MAX_TESS_GEN_LEVEL, (GLint*)&max_tessfactor);
> > + glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES,
> > (GLint*)&max_gs_out_vertices);
> > + glGetIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,
> > + (GLint*)&max_gs_total_out_components);
> > + glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,
> > + (GLint*)&max_gs_out_components);
> > + glGetIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS,
> > (GLint*)&max_gs_invocations);
> > + if (!piglit_check_gl_error(GL_NO_ERROR))
> > + piglit_report_result(PIGLIT_FAIL);
> > +
> > + max_gs_out_vertices_real = MIN2(max_gs_out_vertices,
> > + max_gs_total_out_components
> > / 5);
> > +
> > + if (scan_mode) {
> > + srand(scan_seed);
> > +
> > + /* First, generate test cases that max out each of
> > the dimensions */
> > + testcase tc0 = explicit_testcase;
> > + if (!explicit_invocations)
> > + tc0.num_invocations = max_gs_invocations;
> > +
> > + if (!explicit_outputs) {
> > + testcase tc1 = tc0;
> > +
> > + if (!explicit_components) {
> > + tc1.num_outputs =
> > max_gs_out_vertices_real;
> > + tc1.num_extra_components =
> > +
> > MIN2(max_gs_total_out_components / tc1.num_outputs,
> > + max_gs_out_components) - 5;
> > + } else {
> > + tc1.num_outputs =
> > +
> > MIN2(max_gs_total_out_components /
> > + (5 +
> > tc1.num_extra_components),
> > + max_gs_out_vertices_real);
> > + }
> > +
> > + generate_testcases_max(tc1,
> > explicit_instances, explicit_patches,
> > +
> > explicit_tessfactor_u, explicit_tessfactor_v);
> > + }
> > +
> > + if (!explicit_components) {
> > + testcase tc1 = tc0;
> > +
> > + if (!explicit_outputs) {
> > + tc1.num_extra_components =
> > max_gs_out_components - 5;
> > + tc1.num_outputs =
> > +
> > MIN2(max_gs_total_out_components /
> > + (5 +
> > tc1.num_extra_components),
> > + max_gs_out_vertices_real);
> > + } else {
> > + tc1.num_extra_components =
> > +
> > MIN2(max_gs_total_out_components / tc1.num_outputs,
> > + max_gs_out_components) - 4;
> > + }
> > +
> > + generate_testcases_max(tc1,
> > explicit_instances, explicit_patches,
> > +
> > explicit_tessfactor_u, explicit_tessfactor_v);
> > + }
> > +
> > + if (explicit_outputs && explicit_components)
> > + generate_testcases_max(tc0,
> > explicit_instances, explicit_patches,
> > +
> > explicit_tessfactor_u, explicit_tessfactor_v);
> > +
> > + /* Generate additional tests randomly.
> > + *
> > + * Attempt to generate a random distribution that
> > isn't too
> > + * lop-sided, but admittedly this is all just hand-wavey
> > + * heuristics.
> > + */
> > + while (testcases.size() < scan_count) {
> > + testcase tc = explicit_testcase;
> > +
> > + if (!explicit_outputs || !explicit_components) {
> > + if (explicit_outputs || rand() & 1) {
> > + unsigned max_components =
> > +
> > MIN2(max_gs_total_out_components / tc.num_outputs,
> > +
> > max_gs_out_components) - 5;
> > + tc.num_extra_components =
> > rand() % (max_components + 1);
> > +
> > + if (!explicit_outputs) {
> > + unsigned max_outputs =
> > +
> > MIN2(max_gs_total_out_components /
> > + (5 +
> > tc.num_extra_components),
> > +
> > max_gs_out_vertices_real);
> > + tc.num_outputs = 1 +
> > rand() % max_outputs;
> > + }
> > + } else {
> > + unsigned max_outputs =
> > +
> > MIN2(max_gs_total_out_components /
> > + (5 +
> > tc.num_extra_components),
> > +
> > max_gs_out_vertices_real);
> > + tc.num_outputs = 1 + rand()
> > % max_outputs;
> > +
> > + if (!explicit_components) {
> > + unsigned
> > max_components =
> > +
> > MIN2(max_gs_total_out_components / tc.num_outputs,
> > +
> > max_gs_out_components) - 5;
> > +
> > tc.num_extra_components = rand() % (max_components + 1);
> > + }
> > + }
> > + }
> > +
> > + unsigned amplify = tc.num_outputs;
> > +
> > + if (explicit_invocations)
> > + amplify *= tc.num_invocations;
> > + if (explicit_tessfactor_u)
> > + amplify *= tc.tessfactor_u;
> > + if (explicit_tessfactor_v)
> > + amplify *= tc.tessfactor_v;
> > + if (explicit_patches)
> > + amplify *= tc.num_patches;
> > + if (explicit_instances)
> > + amplify *= tc.num_instances;
> > +
> > + unsigned target = max_final_points / amplify;
> > +
> > + if (small)
> > + target = MIN2(32, target);
> > +
> > + if (!explicit_tessfactor_u) {
> > + float tf_log_weight = logf(target) *
> > rand_subdivide(6);
> > + tc.tessfactor_u =
> > MIN2(expf(tf_log_weight), max_tessfactor);
> > + target /= tc.tessfactor_u;
> > + }
> > + if (!explicit_tessfactor_v) {
> > + float tf_log_weight = logf(target) *
> > rand_subdivide(6);
> > + tc.tessfactor_v =
> > MIN2(expf(tf_log_weight), max_tessfactor);
> > + target /= tc.tessfactor_v;
> > + }
> > + if (!explicit_invocations) {
> > + float log_weight = logf(target);
> > + if (!explicit_instances ||
> > !explicit_patches)
> > + log_weight *= rand_subdivide(2);
> > + tc.num_invocations =
> > MIN2(expf(log_weight), max_gs_invocations);
> > + target /= tc.num_invocations;
> > + }
> > + if (!explicit_instances) {
> > + float log_weight = logf(target);
> > + if (!explicit_patches)
> > + log_weight *= rand_subdivide(2);
> > + tc.num_instances = expf(log_weight);
> > + target /= tc.num_instances;
> > + }
> > + if (!explicit_patches)
> > + tc.num_patches = 1 + rand() % target;
> > +
> > + add_testcase(&tc);
> > + }
> > + } else {
> > + add_testcase(&explicit_testcase);
> > + }
> > +}
> > +
> > +enum piglit_result
> > +piglit_display(void)
> > +{
> > + bool pass = true;
> > +
> > + for (unsigned i = 0; i < testcases.size(); ++i) {
> > + if (!run_testcase(&testcases[i]))
> > + pass = false;
> > + }
> > +
> > + if (!piglit_check_gl_error(GL_NO_ERROR))
> > + pass = false;
> > +
> > + piglit_present_results();
> > +
> > + return pass ? PIGLIT_PASS : PIGLIT_FAIL;
> > +}
> > --
> > 2.17.1
> >
> > _______________________________________________
> > Piglit mailing list
> > Piglit at lists.freedesktop.org <mailto:Piglit at lists.freedesktop.org>
> > https://lists.freedesktop.org/mailman/listinfo/piglit
> >
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part
URL: <https://lists.freedesktop.org/archives/piglit/attachments/20181018/2c3a0e75/attachment-0001.sig>
More information about the Piglit
mailing list