[Piglit] [PATCH 3/3] sso: Combine 20 vertex shaders and 20 fragment shaders in various ways.

Ian Romanick idr at freedesktop.org
Mon Oct 14 11:33:01 PDT 2013


On 10/14/2013 11:20 AM, Paul Berry wrote:
> On 1 October 2013 18:22, Ian Romanick <idr at freedesktop.org
> <mailto:idr at freedesktop.org>> wrote:
> 
>     From: Ian Romanick <ian.d.romanick at intel.com
>     <mailto:ian.d.romanick at intel.com>>
> 
>     Verify that the right shaders are used in the right combinations several
>     ways.
> 
>     * The vertex shader has information baked-in that determines the X
>     position
>       of the block on the screen.
> 
>     * The fragment shader has information baked-in that determines how the
>       block is colored.  This is combined with data passed from the vertex
>       shader.
> 
>     Since data is passed from the vertex shader to the fragment shader, the
>     test can use either rendezvous-by-name (default) or
>     rendezvous-by-location
>     (with --by-location command line parameter).
> 
>     This test passes in both modes on NVIDIA (304.64 on GTX 260).
> 
>     Signed-off-by: Ian Romanick <ian.d.romanick at intel.com
>     <mailto:ian.d.romanick at intel.com>>
>     ---
>      tests/all.tests                                    |   2 +
>      .../arb_separate_shader_objects/400-combinations.c | 377
>     +++++++++++++++++++++
>      .../arb_separate_shader_objects/CMakeLists.gl.txt  |   1 +
>      3 files changed, 380 insertions(+)
>      create mode 100644
>     tests/spec/arb_separate_shader_objects/400-combinations.c
> 
>     diff --git a/tests/all.tests b/tests/all.tests
>     index 33556af..1e79514 100644
>     --- a/tests/all.tests
>     +++ b/tests/all.tests
>     @@ -1279,6 +1279,8 @@ arb_separate_shader_objects['Mix
>     BindProgramPipeline and UseProgram'] = concurre
>      arb_separate_shader_objects['ProgramUniform coverage'] =
>     concurrent_test('arb_separate_shader_object-ProgramUniform-coverage')
>      arb_separate_shader_objects['Rendezvous by location'] =
>     plain_test('arb_separate_shader_object-rendezvous_by_location -fbo')
>      arb_separate_shader_objects['ValidateProgramPipeline'] =
>     concurrent_test('arb_separate_shader_object-ValidateProgramPipeline')
>     +arb_separate_shader_objects['400 combinations by location'] =
>     plain_test('arb_separate_shader_object-400-combinations -fbo
>     --by-location')
>     +arb_separate_shader_objects['400 combinations by name'] =
>     plain_test('arb_separate_shader_object-400-combinations -fbo')
> 
>      # Group ARB_sampler_objects
>      arb_sampler_objects = Group()
>     diff --git
>     a/tests/spec/arb_separate_shader_objects/400-combinations.c
>     b/tests/spec/arb_separate_shader_objects/400-combinations.c
>     new file mode 100644
>     index 0000000..8593b6e
>     --- /dev/null
>     +++ b/tests/spec/arb_separate_shader_objects/400-combinations.c
>     @@ -0,0 +1,377 @@
>     +/*
>     + * 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 400-combinations.c
>     + * Combine 20 vertex shaders and 20 fragment shaders in various ways.
>     + *
>     + * Verify that the right shaders are used in the right combinations
>     several
>     + * ways.
>     + *
>     + * * The vertex shader has information baked-in that determines the
>     X position
>     + *   of the block on the screen.
>     + *
>     + * * The fragment shader has information baked-in that determines
>     how the
>     + *   block is colored.  This is combined with data passed from the
>     vertex
>     + *   shader.
>     + *
>     + * Since data is passed from the vertex shader to the fragment
>     shader, the
>     + * test can use either rendezvous-by-name (default) or
>     rendezvous-by-location
>     + * (with --by-location command line parameter).
>     + */
>     +#include "piglit-util-gl-common.h"
>     +
>     +PIGLIT_GL_TEST_CONFIG_BEGIN
>     +
>     +       config.supports_gl_compat_version = 10;
>     +       config.supports_gl_core_version = 31;
>     +       config.window_visual = PIGLIT_GL_VISUAL_RGB |
>     PIGLIT_GL_VISUAL_DOUBLE;
> 
> 
> I'd feel more comfortable if we added:
> 
> config.window_width = (tile_size + border_size) * ARRAY_SIZE(vs_programs);
> config.window_height = (tile_size + border_size) * ARRAY_SIZE(fs_programs);
> 
> That way (a) the fact that this test requires a sufficiently large
> window is explicit, and (b) if we try to run this test with a different
> default piglit window size (as we often do when running piglit with a
> hardware simulator) it won't fail.

Good call!  I like that.  I feel like we should collect some of these
tricks into an "Effective piglit" wiki or something....

>     +
>     +PIGLIT_GL_TEST_CONFIG_END
>     +
>     +/**
>     + * Size of each square that will be drawn.
>     + */
>     +static const unsigned tile_size = 5;
>     +
>     +/**
>     + * Size of the gap between the squares.
>     + */
>     +static const unsigned border_size = 2;
>     +
>     +static GLuint vs_programs[20];
>     +static GLuint fs_programs[20];
>     +
>     +static GLuint pipe;
>     +
>     +static GLuint vao = 0;
>     +static GLuint bo = 0;
>     +
>     +struct combination {
>     +       unsigned char row;
>     +       unsigned char col;
>     +};
>     +
>     +static struct combination combinations[ARRAY_SIZE(vs_programs)
>     +                                      * ARRAY_SIZE(fs_programs)];
>     +
>     +static const char *vs_code =
>     +       "#version %d\n"
>     +       "#extension GL_ARB_separate_shader_objects: require\n"
>     +       "#extension GL_ARB_explicit_attrib_location: require\n"
>     +       "\n"
>     +       "layout(location = 0) in vec4 piglit_vertex;\n"
>     +       "layout(location = 1) in vec3 vertex_color;\n"
>     +       "\n"
>     +       "%s out vec3 %s;\n"
>     +       "\n"
>     +       "const vec4 offset = vec4(%d, 0, 0, 0);\n"
>     +       "\n"
>     +       "uniform mat4 transform;\n"
>     +       "\n"
>     +       "void main()\n"
>     +       "{\n"
>     +       "    gl_Position = transform * (piglit_vertex + offset);\n"
>     +       "    %s = vertex_color;\n"
>     +       "}\n"
>     +       ;
>     +
>     +static const char *fs_code =
>     +       "#version %d\n"
>     +       "#extension GL_ARB_separate_shader_objects: require\n"
>     +       "#extension GL_ARB_explicit_attrib_location: enable\n"
>     +       "\n"
>     +       "#if __VERSION__ >= 130\n"
>     +       "layout(location = 0) out vec4 out_color;\n"
>     +       "#else\n"
>     +       "#define out_color gl_FragColor\n"
>     +       "#endif\n"
>     +       "\n"
>     +       "%s in vec3 %s;\n"
>     +       "\n"
>     +       "const vec3 color_offset = vec3(%d, %d, %d);\n"
>     +       "\n"
>     +       "void main()\n"
>     +       "{\n"
>     +       "    out_color = vec4(%s + color_offset, 1.);\n"
>     +       "}\n"
>     +       ;
>     +
>     +enum piglit_result
>     +piglit_display(void)
>     +{
>     +       unsigned i;
>     +       unsigned j;
>     +
>     +       static const float expected[] = {
>     +               0.0f, 1.0f, 0.0f, 1.0f
>     +       };
>     +
>     +       /* This is stored in row-major order.  Note the GL_TRUE
>     parameter to
>     +        * the glProgramUniformMatrix4fv call below.
>     +        */
>     +       const float transform[16] = {
>     +               2.f / piglit_width, 0.0f, 0.0f, -1.0f,
>     +               0.0f, 2.f / piglit_height, 0.0f, -1.0f,
>     +               0.0f, 0.0f, 0.0f,  0.0f,
>     +               0.0f, 0.0f, 0.0f, 1.0f,
>     +       };
>     +
>     +       bool pass = true;
>     +
>     +       glClearColor(.5f, .5f, .5f, 1.f);
>     +       glClear(GL_COLOR_BUFFER_BIT);
>     +
>     +       for (i = 0; i < ARRAY_SIZE(vs_programs); i++) {
>     +               const GLint loc =
>     +                       glGetUniformLocation(vs_programs[i],
>     "transform");
>     +
>     +               glProgramUniformMatrix4fv(vs_programs[i], loc, 1,
>     GL_TRUE,
>     +                                         transform);
>     +       }
>     +
>     +       glBindProgramPipeline(pipe);
>     +
>     +       for (i = 0; i < ARRAY_SIZE(combinations); i++) {
>     +               const unsigned row = combinations[i].row;
>     +               const unsigned col = combinations[i].col;
>     +
>     +               glUseProgramStages(pipe, GL_VERTEX_SHADER_BIT,
>     +                                  vs_programs[col]);
>     +               glUseProgramStages(pipe, GL_FRAGMENT_SHADER_BIT,
>     +                                  fs_programs[row]);
>     +               glDrawArrays(GL_TRIANGLE_FAN, row * 4, 4);
>     +       }
>     +
>     +       glBindProgramPipeline(0);
>     +
>     +       for (i = 0; i < ARRAY_SIZE(vs_programs); i++) {
>     +               for (j = 0; j < ARRAY_SIZE(fs_programs); j++) {
>     +                       const unsigned x = (i * tile_size)
>     +                               + ((i + 1) * border_size);
>     +                       const unsigned y = (j * tile_size)
>     +                               + ((j + 1) * border_size);
>     +
>     +                       pass = piglit_probe_rect_rgba(x, y,
>     +                                                     tile_size,
>     tile_size,
>     +                                                     expected)
>     +                               && pass;
>     +               }
>     +       }
>     +
>     +       piglit_present_results();
>     +       return pass ? PIGLIT_PASS : PIGLIT_FAIL;
>     +}
>     +
>     +#define RED(x)    ((int) (x / 2))
>     +#define GREEN(x)  (-(int) x)
>     +#define BLUE(x)   ((int) (x * 7))
>     +
>     +void
>     +piglit_init(int argc, char **argv)
>     +{
>     +       unsigned glsl_version;
>     +       unsigned i;
>     +       unsigned j;
>     +       unsigned idx;
>     +       bool es;
>     +       int glsl_major;
>     +       int glsl_minor;
>     +       const char *location;
>     +       const char *vertex_name;
>     +       const char *fragment_name;
>     +
>     +       struct vertex {
>     +               float x;
>     +               float y;
>     +               float r;
>     +               float g;
>     +               float b;
>     +       } *vert;
>     +
>     +       piglit_require_extension("GL_ARB_separate_shader_objects");
>     +       piglit_require_extension("GL_ARB_explicit_attrib_location");
>     +
>     +       if (argc > 1 && strcmp(argv[1], "--by-location") == 0) {
>     +               location = "layout(location = 3)";
>     +               vertex_name = "a";
>     +               fragment_name = "b";
>     +       } else {
>     +               location = "";
>     +               vertex_name = "in_color";
>     +               fragment_name = "in_color";
>     +       }
>     +
>     +       /* Some NVIDIA drivers have issues with layout qualifiers, 'in'
>     +        * keywords, and 'out' keywords in "lower" GLSL versions.
>      If the
>     +        * driver supports GLSL >= 1.40, use 1.40.  Otherwise, pick the
>     +        * highest version that the driver supports.
>     +        */
>     +       piglit_get_glsl_version(&es, &glsl_major, &glsl_minor);
>     +       glsl_version = ((glsl_major * 100) + glsl_minor) >= 140
>     +               ? 140 : ((glsl_major * 100) + glsl_minor);
>     +
>     +       /* Generate the vertex shader programs.  Each vertex shader is
>     +        * hardcoded to select a specific column on the display.
>     +        */
>     +       printf("Generating vertex shaders...\n");
>     +       for (i = 0; i < ARRAY_SIZE(vs_programs); i++) {
>     +               const unsigned base_x = (i * tile_size)
>     +                       + ((i + 1) * border_size);
>     +
>     +               char *source = NULL;
>     +
>     +               asprintf(&source, vs_code,
>     +                        glsl_version,
>     +                        location,
>     +                        vertex_name,
>     +                        base_x,
>     +                        vertex_name);
>     +
>     +               vs_programs[i] =
>     +                       glCreateShaderProgramv(GL_VERTEX_SHADER, 1,
>     +                                              (const GLchar *const
>     *) &source);
>     +               piglit_link_check_status(vs_programs[i]);
>     +
>     +               if (i == 0)
>     +                       puts(source);
>     +
>     +               free(source);
>     +       }
>     +
>     +       printf("Generating fragment shaders...\n");
>     +       for (i = 0; i < ARRAY_SIZE(fs_programs); i++) {
>     +               char *source = NULL;
>     +
>     +               asprintf(&source, fs_code,
>     +                        glsl_version,
>     +                        location,
>     +                        fragment_name,
>     +                        RED(i), GREEN(i), BLUE(i),
>     +                        fragment_name);
>     +
>     +               fs_programs[i] =
>     +                       glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1,
>     +                                              (const GLchar *const
>     *) &source);
>     +               piglit_link_check_status(fs_programs[i]);
>     +
>     +               if (i == 3)
>     +                       puts(source);
>     +
>     +               free(source);
>     +       }
>     +
>     +       glGenProgramPipelines(1, &pipe);
>     +
>     +       /* Generate vertex data for the tests.  The row of each block is
>     +        * determined by the vertex data.  The color data for the
>     block comes
>     +        * from the vertex data and the data baked into the fragment
>     shader.
>     +        */
>     +       if (piglit_get_gl_version() >= 30
>     +           ||
>     piglit_is_extension_supported("GL_ARB_vertex_array_object")) {
>     +               glGenVertexArrays(1, &vao);
>     +               glBindVertexArray(vao);
>     +       }
>     +
>     +       glGenBuffers(1, &bo);
>     +       glBindBuffer(GL_ARRAY_BUFFER, bo);
>     +       glBufferData(GL_ARRAY_BUFFER,
>     +                    sizeof(vert[0]) * 4 * ARRAY_SIZE(fs_programs),
>     +                    NULL, GL_STATIC_DRAW);
>     +
>     +       vert = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
>     +
>     +       for (i = 0; i < ARRAY_SIZE(fs_programs); i++) {
>     +               const unsigned base_y = (i * tile_size)
>     +                       + ((i + 1) * border_size);
>     +
>     +               vert[(i * 4) + 0].x = 0.f;
>     +               vert[(i * 4) + 0].y = (float) base_y;
>     +               vert[(i * 4) + 0].r = (float) -RED(i);
>     +               vert[(i * 4) + 0].g = (float) 1 - GREEN(i);
>     +               vert[(i * 4) + 0].b = (float) -BLUE(i);
>     +
>     +               vert[(i * 4) + 1].x = (float) tile_size;
>     +               vert[(i * 4) + 1].y = (float) base_y;
>     +               vert[(i * 4) + 1].r = (float) -RED(i);
>     +               vert[(i * 4) + 1].g = (float) 1 - GREEN(i);
>     +               vert[(i * 4) + 1].b = (float) -BLUE(i);
>     +
>     +               vert[(i * 4) + 2].x = (float) tile_size;
>     +               vert[(i * 4) + 2].y = (float) (base_y + tile_size);
>     +               vert[(i * 4) + 2].r = (float) -RED(i);
>     +               vert[(i * 4) + 2].g = (float) 1 - GREEN(i);
>     +               vert[(i * 4) + 2].b = (float) -BLUE(i);
>     +
>     +               vert[(i * 4) + 3].x = 0.f;
>     +               vert[(i * 4) + 3].y = (float) (base_y + tile_size);
>     +               vert[(i * 4) + 3].r = (float) -RED(i);
>     +               vert[(i * 4) + 3].g = (float) 1 - GREEN(i);
>     +               vert[(i * 4) + 3].b = (float) -BLUE(i);
>     +       }
>     +
>     +       glUnmapBuffer(GL_ARRAY_BUFFER);
>     +
>     +       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vert[0]),
>     +                             (void *)(intptr_t) offsetof(struct
>     vertex, x));
>     +       glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vert[0]),
>     +                             (void *)(intptr_t) offsetof(struct
>     vertex, r));
>     +       glEnableVertexAttribArray(0);
>     +       glEnableVertexAttribArray(1);
>     +
>     +       /* Generate the set of combinations of vertex shader
>     programs and
>     +        * fragment shader programs that will be used together.
>      This is all
>     +        * the possible combinations.  The next step is to shuffle
>     list so
>     +        * that there's (hopefully) no pattern to the access
>     combination... to
>     +        * uncover driver bugs.
>     +        */
>     +       idx = 0;
>     +       for (i = 0; i < ARRAY_SIZE(vs_programs); i++) {
>     +               for (j = 0; j < ARRAY_SIZE(fs_programs); j++) {
>     +                       combinations[idx].row = j;
>     +                       combinations[idx].col = i;
>     +                       idx++;
>     +               }
>     +       }
>     +
>     +       for (i = 0; i < (5 * ARRAY_SIZE(combinations)); i++) {
>     +               /* Pick a random element from the array.
>     +                */
>     +               const unsigned src = rand() % ARRAY_SIZE(combinations);
>     +
>     +               /* Pick a random element from the array that is not
>     the same
>     +                * as the previous element.  This is done by picking
>     a second
>     +                * number on the range [1, ARRAY_SIZE(combinations)
>     - 2] and
>     +                * adding it (using modular addition) to the first.
>     +                */
>     +               const unsigned delta =
>     +                       (rand() % (ARRAY_SIZE(combinations) - 1)) + 1;
>     +               const unsigned dst = (src + delta) %
>     ARRAY_SIZE(combinations);
>     +
>     +               /* Exchange the two selected elements.
>     +                */
>     +               const struct combination temp = combinations[dst];
>     +               combinations[dst] = combinations[src];
>     +               combinations[src] = temp;
>     +       }
> 
>  
> A less ad-hoc algorithm for shuffling an array is:
> 
> for (i = ARRAY_SIZE(combinations); i > 1; i--) {
>    j = rand() % i;
>    if (j != i - 1)
>       swap elements j and i - 1
> }
> 
> Neglecting deficiencies in rand(), this algorithm produces all possible
> permutations with equal probability.

Okay... I like not having to rand() twice.

I understand (and empathize) your reservations about using rand.  I
think we can cope with them in a couple ways.

1. Implement a piglit_rand.  This guarantees that we'll have the same
generator on all platforms, compilers, etc.  This doesn't even have to
be a great generator... a dumb LFSR should do it.  Most tests that want
random numbers just want a shuffled sequence or some non-sequential data
values.

2. Implement some standard piglit options for controlling the generator.
 These options would be parsed by the piglit framework code.  I'm
thinking --random-seed-clock and --random-seed=<some value>.

3. Make the random number generator log the seed used when it is first
called.

4. Have a default seed that can be overridden with one of the previously
mentioned command line options.

Thoughts?

> With the above two changes, this patch is:
> 
> Reviewed-by: Paul Berry <stereotype441 at gmail.com
> <mailto:stereotype441 at gmail.com>>
>  
> 
>     +}
>     diff --git
>     a/tests/spec/arb_separate_shader_objects/CMakeLists.gl.txt
>     b/tests/spec/arb_separate_shader_objects/CMakeLists.gl.txt
>     index 32a28ba..2e2e1b8 100644
>     --- a/tests/spec/arb_separate_shader_objects/CMakeLists.gl.txt
>     +++ b/tests/spec/arb_separate_shader_objects/CMakeLists.gl.txt
>     @@ -9,6 +9,7 @@ link_libraries (
>             ${OPENGL_glu_LIBRARY}
>      )
> 
>     +piglit_add_executable (arb_separate_shader_object-400-combinations
>     400-combinations.c)
>      piglit_add_executable
>     (arb_separate_shader_object-GetProgramPipelineiv GetProgramPipelineiv.c)
>      piglit_add_executable (arb_separate_shader_object-IsProgramPipeline
>     IsProgramPipeline.c)
>      piglit_add_executable
>     (arb_separate_shader_object-mix_pipeline_useprogram
>     mix_pipeline_useprogram.c)
>     --
>     1.8.1.4
> 
>     _______________________________________________
>     Piglit mailing list
>     Piglit at lists.freedesktop.org <mailto:Piglit at lists.freedesktop.org>
>     http://lists.freedesktop.org/mailman/listinfo/piglit



More information about the Piglit mailing list