[Piglit] [v4 11/11] arb_transform_feedback3: add test for re-drawing multiple streams
Ian Romanick
idr at freedesktop.org
Fri Nov 22 13:47:18 PST 2013
On 11/14/2013 04:20 AM, Topi Pohjolainen wrote:
> Passes on NVIDIA (304.88 on GTX 660).
>
> v2:
> - dropped unnecessary requirement for 1.50 glsl - test
> requires GL version 3.2 already
> - use fragment shader in re-drawing also instead of using
> deprecated vertex shader alone (gl_FrontColor)
>
> Signed-off-by: Topi Pohjolainen <topi.pohjolainen at intel.com>
> ---
> tests/all.tests | 1 +
> .../spec/arb_transform_feedback3/CMakeLists.gl.txt | 1 +
> .../ext_interleaved_draw_streams.c | 399 +++++++++++++++++++++
> 3 files changed, 401 insertions(+)
> create mode 100644 tests/spec/arb_transform_feedback3/ext_interleaved_draw_streams.c
>
> diff --git a/tests/all.tests b/tests/all.tests
> index 1cc318f..7fc8870 100644
> --- a/tests/all.tests
> +++ b/tests/all.tests
> @@ -2493,6 +2493,7 @@ arb_transform_feedback3['arb_transform_feedback3-set_invalid_varyings'] = PlainE
> arb_transform_feedback3['arb_transform_feedback3-ext_interleaved_max_buffers_and_varyings_vs'] = PlainExecTest(['arb_transform_feedback3-ext_interleaved_max_buffers_and_varyings', '-auto', 'vs'])
> arb_transform_feedback3['arb_transform_feedback3-ext_interleaved_max_buffers_and_varyings_gs'] = PlainExecTest(['arb_transform_feedback3-ext_interleaved_max_buffers_and_varyings', '-auto', 'gs'])
> arb_transform_feedback3['arb_transform_feedback3-ext_interleaved_max_streams'] = PlainExecTest(['arb_transform_feedback3-ext_interleaved_max_streams', '-auto'])
> +arb_transform_feedback3['arb_transform_feedback3-ext_interleaved_draw_streams'] = PlainExecTest(['arb_transform_feedback3-ext_interleaved_draw_streams', '-auto'])
>
> arb_transform_feedback3['arb_transform_feedback3-ext_interleaved_two_bufs_vs'] = PlainExecTest(['arb_transform_feedback3-ext_interleaved_two_bufs', '-auto', 'vs'])
> arb_transform_feedback3['arb_transform_feedback3-ext_interleaved_two_bufs_gs'] = PlainExecTest(['arb_transform_feedback3-ext_interleaved_two_bufs', '-auto', 'gs'])
> diff --git a/tests/spec/arb_transform_feedback3/CMakeLists.gl.txt b/tests/spec/arb_transform_feedback3/CMakeLists.gl.txt
> index d786f4b..9bbd024 100644
> --- a/tests/spec/arb_transform_feedback3/CMakeLists.gl.txt
> +++ b/tests/spec/arb_transform_feedback3/CMakeLists.gl.txt
> @@ -17,5 +17,6 @@ piglit_add_executable (arb_transform_feedback3-set_invalid_varyings set_invalid_
> piglit_add_executable (arb_transform_feedback3-ext_interleaved_max_buffers_and_varyings ext_interleaved_max_buffers_and_varyings.c xfb3_common.c)
> piglit_add_executable (arb_transform_feedback3-ext_interleaved_max_streams ext_interleaved_max_streams.c xfb3_common.c)
> piglit_add_executable (arb_transform_feedback3-ext_interleaved_two_bufs ext_interleaved_two_bufs.c)
> +piglit_add_executable (arb_transform_feedback3-ext_interleaved_draw_streams ext_interleaved_draw_streams.c)
>
> # vim: ft=cmake:
> diff --git a/tests/spec/arb_transform_feedback3/ext_interleaved_draw_streams.c b/tests/spec/arb_transform_feedback3/ext_interleaved_draw_streams.c
> new file mode 100644
> index 0000000..7e7888f
> --- /dev/null
> +++ b/tests/spec/arb_transform_feedback3/ext_interleaved_draw_streams.c
> @@ -0,0 +1,399 @@
> +/*
> + * 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.
> + */
> +
> +#include "piglit-util-gl-common.h"
> +
> +/**
> + * @file ext_interleaved_draw_streams.c
> + *
> + * Records three separate vertex streams and re-draws two of them. This test is
> + * based on the tf2-draw-auto test which draws three rectangles but records
> + * only the first and the third. Here the primitives are instead recorded into
> + * separate vertex streams (and hence into a separate buffers).
> + *
> + * The first round emits nine point primitives through the vertex stage to the
> + * geometry stage. First four are recorded in one stream, the fifth in another
> + * and finally the last four in third. The geometry program takes advantage of
> + * the builtin primitive counter (gl_PrimitiveID) when distributing the vertices
> + * into the streams.
> + * The first and the second stream represent four points with color values each.
> + * These are re-drawn as two separate rectangles and the results are checked
> + * between and after the two re-draw rounds.
> + *
> + * The rectangles represent the first quarter and the second half of the
> + * framebuffer. The fifth point is given to the second stream and does not take
> + * part in the re-drawing. The resulted framebuffer should hence have color
> + * values as depicted below:
> + *
> + * 0 +-------------------+ 2
> + * | red |
> + * 1 +-------------------+ 3
> + * | clear color |
> + * 5 +-------------------+ 7
> + * | |
> + * | blue |
> + * 6 +-------------------+ 8
> + */
> +
> +PIGLIT_GL_TEST_CONFIG_BEGIN
> +
> + config.supports_gl_compat_version = 32;
> + config.supports_gl_core_version = 32;
> +
> + config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;
> +
> +PIGLIT_GL_TEST_CONFIG_END
> +
> +static const char vstext_tf[] =
> + "#version 150\n"
> + "attribute vec2 in_pos;\n"
> + "void main() {"
> + " gl_Position = vec4(in_pos.x, in_pos.y, 0.0, 1.0);\n"
> + "}\n";
> +
> +/**
> + * First four point primitives are emitted in stream zero, the fifth into
> + * stream one, six to eight are skipped, and finally the last four are emitted
> + * into stream two.
The code I see in the shader doesn't seem to match this comment. It
looks like a primitives > 4 are sent to stream two. It also doesn't
match the description above.
> + */
> +static const char gs_text[] =
> + "#version 150\n"
> + "#extension GL_ARB_gpu_shader5 : enable\n"
> + "layout(points) in;\n"
> + "layout(points, max_vertices = 1) out;\n"
> + "in int gl_PrimitiveID;\n"
> + "\n"
> + "layout(points, stream = 0) out;\n"
> + "out vec4 col_0;\n"
> + "out vec4 pos_0;\n"
> + "layout(points, stream = 1) out;\n"
> + "out vec4 col_1;\n"
> + "out vec4 pos_1;\n"
> + "layout(points, stream = 2) out;\n"
> + "out vec4 col_2;\n"
> + "out vec4 pos_2;\n"
> + "\n"
> + "void main() {\n"
> + " if (gl_PrimitiveID < 4) {\n"
> + " pos_0 = gl_in[0].gl_Position;\n"
> + " col_0 = vec4(1.0, 0.0, 0.0, 1.0);\n"
> + " EmitStreamVertex(0);\n"
> + " }\n"
> + "\n"
> + " if (gl_PrimitiveID == 4) {\n"
> + " pos_1 = gl_in[0].gl_Position;\n"
> + " col_1 = vec4(0.0, 1.0, 0.0, 1.0);\n"
> + " EmitStreamVertex(1);\n"
> + " }\n"
> + "\n"
> + " if (gl_PrimitiveID > 4) {\n"
> + " pos_2 = gl_in[0].gl_Position;\n"
> + " col_2 = vec4(0.0, 0.0, 1.0, 1.0);\n"
> + " EmitStreamVertex(2);\n"
> + " }\n"
> + "}\n";
> +
> +static const char vs_text_redraw[] =
> + "#version 150\n"
> + "attribute vec4 in_pos;\n"
> + "attribute vec4 in_col;\n"
> + "out vec4 color;\n"
> + "void main() {"
> + " gl_Position = in_pos;\n"
> + " color = in_col;\n"
> + "}\n";
> +
> +static const char fs_text_redraw[] =
> + "#version 150\n"
> + "in vec4 color;\n"
> + "void main() {\n"
> + " gl_FragColor = color;\n"
> + "}\n";
> +
> +/**
> + * The spec for ARB_transform_feedback3 says:
> + *
> + * If a string in <varyings> is "gl_NextBuffer", it does not identify a varying
> + * variable, but instead serves as a buffer separator value to direct subsequent
> + * varyings at the next transform feedback binding point.
> + */
> +static const char *varyings[] = {
> + "col_0", "pos_0", "gl_NextBuffer",
> + "col_1", "pos_1", "gl_NextBuffer",
> + "col_2", "pos_2"
> +};
> +
> +#define STREAM_N 3
This works, and I'm not going to ask you to change it. But... the way
we usually do this is declare one of the arrays with a literal size
(e.g., static GLuint xfb[3]), then use the ARRAY_SIZE() macro to re-use
that size.
Assuming the comment is just stale, with the comment fixed, the patch is
Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>
> +
> +/**
> + * Single transform feedback object can track multiple vertex streams, i.e.,
> + * the individual amount of vertices emitted in each stream. Later on calling
> + * 'DrawTransformFeedbackStream()' additionally designates the stream to be
> + * replayed.
> + */
> +GLuint tfb;
> +static GLuint xfb[STREAM_N];
> +static const unsigned tf_vertex_n[] = { 4, 1, 4 };
> +
> +/**
> + * Each stream tracks color (copy of 'gl_FrontColor') and position (copy of
> + * 'gl_Position') both consisting of four floats.
> + */
> +#define N_FLOATS_PER_VERTEX (4 + 4)
> +
> +static void
> +check_driver(void)
> +{
> + GLint streams, comps;
> +
> + piglit_require_extension("GL_ARB_transform_feedback3");
> + piglit_require_extension("GL_ARB_gpu_shader5");
> +
> + glGetIntegerv(GL_MAX_VERTEX_STREAMS, &streams);
> + if (streams < STREAM_N) {
> + printf("Test requires %d(%d) vertex streams\n",
> + STREAM_N, streams);
> + piglit_report_result(PIGLIT_SKIP);
> + }
> +
> + glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &comps);
> + if (comps < 4 * N_FLOATS_PER_VERTEX) {
> + printf("Test requires space for %u components per three "
> + "streams each\n", 4 * N_FLOATS_PER_VERTEX);
> + piglit_report_result(PIGLIT_SKIP);
> + }
> +}
> +
> +static void
> +build_and_setup_tf_program(void)
> +{
> + GLuint prog = piglit_build_simple_program_multiple_shaders(
> + GL_VERTEX_SHADER, vstext_tf,
> + GL_GEOMETRY_SHADER, gs_text, 0);
> +
> + glBindAttribLocation(prog, 0, "in_pos");
> +
> + /**
> + * In the EXT style feedback gathering the varyings to be tracked need
> + * to be specified after the program is compiled but before linking.
> + *
> + * It should be noticed that when mixed mode is used, i.e., where
> + * one records multiple attributes per buffer but also uses separate
> + * buffers, the mode must be set to interleaved.
> + */
> + glTransformFeedbackVaryings(prog, ARRAY_SIZE(varyings), varyings,
> + GL_INTERLEAVED_ATTRIBS);
> +
> + if (!piglit_check_gl_error(GL_NO_ERROR))
> + piglit_report_result(PIGLIT_FAIL);
> +
> + glLinkProgram(prog);
> + if (!piglit_link_check_status(prog))
> + piglit_report_result(PIGLIT_FAIL);
> + if (!piglit_check_gl_error(GL_NO_ERROR))
> + piglit_report_result(PIGLIT_FAIL);
> +
> + glUseProgram(prog);
> +}
> +
> +static void
> +setup_tf_bufs_and_queries(GLuint *generated_queries, GLuint *written_queries)
> +{
> + unsigned i;
> +
> + glGenBuffers(STREAM_N, xfb);
> + glGenQueries(STREAM_N, generated_queries);
> + glGenQueries(STREAM_N, written_queries);
> + for (i = 0; i < STREAM_N; ++i) {
> + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, xfb[i]);
> + glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
> + tf_vertex_n[i] * N_FLOATS_PER_VERTEX * sizeof(float),
> + NULL, GL_STREAM_READ);
> +
> + glBeginQueryIndexed(GL_PRIMITIVES_GENERATED, i,
> + generated_queries[i]);
> + glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, i,
> + written_queries[i]);
> + }
> +}
> +
> +static void
> +check_tf_counters(GLuint *generated_queries, GLuint *written_queries)
> +{
> + unsigned i;
> +
> + for (i = 0; i < STREAM_N; ++i) {
> + GLuint query_result;
> +
> + glEndQueryIndexed(GL_PRIMITIVES_GENERATED, i);
> + glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, i);
> +
> + glGetQueryObjectuiv(generated_queries[i], GL_QUERY_RESULT,
> + &query_result);
> + if (query_result != tf_vertex_n[i]) {
> + printf("Expected %u primitives generated for stream %u,"
> + " got %u\n", tf_vertex_n[i], i, query_result);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> +
> + glGetQueryObjectuiv(written_queries[i], GL_QUERY_RESULT,
> + &query_result);
> + if (query_result != tf_vertex_n[i]) {
> + printf("Expected %u primitives written for stream %u,"
> + " got %u\n", tf_vertex_n[i], i, query_result);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + }
> +}
> +
> +static void
> +setup_vertices(void)
> +{
> + /* First quarter, one vertex to be discarded, second half */
> + static const float verts[] = {
> + -1.0f, 0.5f,
> + 1.0f, 0.5f,
> + -1.0f, 1.0f,
> + 1.0f, 1.0f,
> +
> + 0.5f, 0.5f,
> +
> + -1.0f, -1.0f,
> + 1.0f, -1.0f,
> + -1.0f, 0.0f,
> + 1.0f, 0.0f,
> + };
> + GLuint vao, buf;
> +
> + /* Test is run under desktop OpenGL 3.2 -> use of VAOs is required */
> + glGenVertexArrays(1, &vao);
> + glBindVertexArray(vao);
> +
> + glGenBuffers(1, &buf);
> + glBindBuffer(GL_ARRAY_BUFFER, buf);
> + glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
> + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
> + glEnableVertexAttribArray(0);
> +}
> +
> +void
> +piglit_init(int argc, char **argv)
> +{
> + GLuint generated_queries[STREAM_N];
> + GLuint written_queries[STREAM_N];
> +
> + check_driver();
> +
> + build_and_setup_tf_program();
> +
> + /**
> + * The feedback object is used to store internally the number of
> + * vertices recorded. This is used internally when the streams are
> + * re-drawn.
> + */
> + glGenTransformFeedbacks(1, &tfb);
> + glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb);
> +
> + setup_tf_bufs_and_queries(generated_queries, written_queries);
> +
> + if (!piglit_check_gl_error(GL_NO_ERROR))
> + piglit_report_result(PIGLIT_FAIL);
> +
> + setup_vertices();
> +
> + /* Draw into tfb */
> + glBeginTransformFeedback(GL_POINTS);
> + glDrawArrays(GL_POINTS, 0, 4 + 1 + 4);
> + glEndTransformFeedback();
> + glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
> +
> + if (!piglit_check_gl_error(GL_NO_ERROR))
> + piglit_report_result(PIGLIT_FAIL);
> +
> + check_tf_counters(generated_queries, written_queries);
> +}
> +
> +/**
> + * Draw one rectangle from feedback stream 'i' and check the first and second
> + * quarter and second half colors.
> + */
> +static bool
> +redraw_and_check(unsigned i, const float *quarter_1_col,
> + const float *quarter_2_col, const float *second_half_col)
> +{
> + bool pass = true;
> +
> + glBindBuffer(GL_ARRAY_BUFFER, xfb[i]);
> + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE,
> + N_FLOATS_PER_VERTEX * sizeof(float),
> + (void *)(intptr_t)(4 * sizeof(float)));
> + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE,
> + N_FLOATS_PER_VERTEX * sizeof(float), NULL);
> + glDrawTransformFeedbackStream(GL_TRIANGLE_STRIP, tfb, i);
> +
> + if (!piglit_check_gl_error(GL_NO_ERROR))
> + piglit_report_result(PIGLIT_FAIL);
> +
> + pass = piglit_probe_pixel_rgba(piglit_width / 2, 7 * piglit_height / 8,
> + quarter_1_col) && pass;
> + pass = piglit_probe_pixel_rgba(piglit_width / 2, 5 * piglit_height / 8,
> + quarter_2_col) && pass;
> + pass = piglit_probe_pixel_rgba(piglit_width / 2, 3 * piglit_height / 8,
> + second_half_col) && pass;
> +
> + return pass;
> +}
> +
> +enum piglit_result
> +piglit_display(void)
> +{
> + bool pass = true;
> + GLuint prog;
> + static const float red[] = {1.0, 0.0, 0.0, 1.0};
> + static const float blue[] = {0.0, 0.0, 1.0, 1.0};
> + static const float clearcolor[] = {0.2, 0.2, 0.2, 1.0};
> +
> + glClearColor(0.2, 0.2, 0.2, 1.0);
> + glClear(GL_COLOR_BUFFER_BIT);
> +
> + prog = piglit_build_simple_program(vs_text_redraw, fs_text_redraw);
> +
> + glBindAttribLocation(prog, 0, "in_pos");
> + glBindAttribLocation(prog, 1, "in_col");
> +
> + glUseProgram(prog);
> +
> + /**
> + * Initial recording round already provided coordinates in attribute
> + * position zero. Here the colors are additionally provided in position
> + * one which needs to be activated as well.
> + */
> + glEnableVertexAttribArray(1);
> +
> + pass = redraw_and_check(0, red, clearcolor, clearcolor) && pass;
> + pass = redraw_and_check(2, red, clearcolor, blue) && pass;
> +
> + glDeleteTransformFeedbacks(1, &tfb);
> +
> + return pass ? PIGLIT_PASS : PIGLIT_FAIL;
> +}
>
More information about the Piglit
mailing list