[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