[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