[Piglit] [v4 11/11] arb_transform_feedback3: add test for re-drawing multiple streams

Topi Pohjolainen topi.pohjolainen at intel.com
Thu Nov 14 04:20:34 PST 2013


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.
+ */
+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
+
+/**
+ * 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;
+}
-- 
1.8.3.1



More information about the Piglit mailing list