[Piglit] [v4 09/11] arb_transform_feedback3: add test for recording max streams

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


Passes on NVIDIA (304.88 on GTX 660).

I realized by through trial-and-error that the global
declaration in the geometry shader of the form:

  layout(points, max_vertices = 4) out;

says that there are in total four vertices output for _all_
the vertex streams and that the subsequent declaration for
the default stream just simply do not need to say anything
about how many vertices each outputs. It is enough that the
total for each gs invocation does not exceed the amout set
in the global declaration.

  layout(points, stream = 1) out;

This is probably all said in the documentation somewhere -
I just haven't found it yet.

v2:
  - fixed indentation: spaces -> tabs (Ian)
  - require core/compatibility version 3.2 instead of
    ARB_geometry_shader4 which is not going to be supported by
    mesa (Ian)
  - drop _EXT, use core names instead (Ian)
  - now using piglit_build_simple_program_multiple_shaders()

v3:
  - added calls to glDeleteBuffers(), glDeleteQueries() and
    glDeleteVertexArrays()
  - simplified the dynamic generation of varyings for the gs
    program and for the corresponding array given to
    TransformFeedbackVaryings()
  - renamed into 'ext_interleaved_max_streams'
  - dropped unnecessary requirement for 1.50 glsl - test
    requires GL version 3.2 already

Signed-off-by: Topi Pohjolainen <topi.pohjolainen at intel.com>
---
 tests/all.tests                                    |   1 +
 .../spec/arb_transform_feedback3/CMakeLists.gl.txt |   1 +
 .../ext_interleaved_max_streams.c                  | 249 +++++++++++++++++++++
 tests/spec/arb_transform_feedback3/xfb3_common.c   |  87 +++++++
 tests/spec/arb_transform_feedback3/xfb3_common.h   |   9 +
 5 files changed, 347 insertions(+)
 create mode 100644 tests/spec/arb_transform_feedback3/ext_interleaved_max_streams.c

diff --git a/tests/all.tests b/tests/all.tests
index 2769877..01747a6 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -2492,6 +2492,7 @@ arb_transform_feedback3['arb_transform_feedback3-set_varyings_with_invalid_args'
 arb_transform_feedback3['arb_transform_feedback3-set_invalid_varyings'] = PlainExecTest(['arb_transform_feedback3-set_invalid_varyings', '-auto'])
 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_uniform_buffer_object = Group()
 spec['ARB_uniform_buffer_object'] = arb_uniform_buffer_object
diff --git a/tests/spec/arb_transform_feedback3/CMakeLists.gl.txt b/tests/spec/arb_transform_feedback3/CMakeLists.gl.txt
index 2f1515b..7807d61 100644
--- a/tests/spec/arb_transform_feedback3/CMakeLists.gl.txt
+++ b/tests/spec/arb_transform_feedback3/CMakeLists.gl.txt
@@ -15,5 +15,6 @@ piglit_add_executable (arb_transform_feedback3-draw_using_invalid_stream_index d
 piglit_add_executable (arb_transform_feedback3-set_varyings_with_invalid_args set_varyings_with_invalid_args.c)
 piglit_add_executable (arb_transform_feedback3-set_invalid_varyings set_invalid_varyings.c)
 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)
 
 # vim: ft=cmake:
diff --git a/tests/spec/arb_transform_feedback3/ext_interleaved_max_streams.c b/tests/spec/arb_transform_feedback3/ext_interleaved_max_streams.c
new file mode 100644
index 0000000..4a3df05
--- /dev/null
+++ b/tests/spec/arb_transform_feedback3/ext_interleaved_max_streams.c
@@ -0,0 +1,249 @@
+/*
+ * 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"
+#include "xfb3_common.h"
+
+/**
+ * @file ext_interleaved_single_gs_many_streams.c 
+ *
+ * Record varyings using multiple vertex streams originating from the same
+ * geometry shader instance. The test uses the maximum amount of streams
+ * supported by the implementation. Each stream records an interleaved set of
+ * two attributes into its own transform feedback buffer - the spec does not
+ * allow one to record multiple streams into one single buffer:
+ *
+ * "All varyings assigned to a given binding point are required to come from a
+ *  single vertex stream."
+ *
+ * This test uses the "EXT"-style GLSL transform feedback.
+ */
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 32;
+	config.supports_gl_core_version = 32;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+/**
+ * Generate a geometry program source that outputs vertices into 'stream_n'
+ * separate streams each tracking two varyings:
+ *
+ *   layout(points, stream = 0) out;
+ *   out float x_00000000;
+ *   out vec2 x_00000001;
+ *   layout(points, stream = 1) out;
+ *   out float x_0000002;
+ *   out vec2 x_00000003;
+ *   ...
+ *   layout(points, stream = (stream_n - 1)) out;
+ *   out float x_0..(2 * stream_n - 2);
+ *   out vec2 x_0..(2 * stream_n - 1);
+ *
+ * Hexadecimal formatting is chosen to simplify the handling of varyings in the
+ * test - each string representing a varying is of equal length.
+ */
+static char *
+generate_geometry_shader(unsigned stream_n)
+{
+	unsigned i;
+	char *res;
+	char *curr;
+	static const char prologue[] =
+		"#version 150\n"
+		"#extension GL_ARB_gpu_shader5 : enable\n"
+		"layout(points) in;\n"
+		"layout(points, max_vertices = 0x%08x) out;\n";
+	static const char output_per_stream[] =
+		"layout(points, stream = 0x%08x) out;\n"
+		"out float x_%08x;\n"
+		"out vec2 x_%08x;\n";
+	static const char main_opening[] =
+		"float tmp;\n"
+		"void main() {\n";
+	static const char vertex_emission_per_stream[] =
+		"  gl_Position = gl_in[0].gl_Position;\n"
+		"  tmp = 0x%08x;\n"
+		"  x_%08x = tmp + 1.0;\n"
+		"  x_%08x = vec2(tmp + 2.0, tmp + 3.0);\n"
+		"  EmitStreamVertex(0x%08x);\n";
+	static const char main_closing[] = "}\n";
+	/*
+	 * Prepare space for ascii running number having eight hex-digits,
+	 * format used subsequently contains four (%08x) -> add four.
+	 */
+	static const unsigned int_extra = 4;
+
+	curr = res = malloc(sizeof(prologue) + int_extra +
+			sizeof(main_opening) +
+			stream_n * (sizeof(vertex_emission_per_stream) +
+				     4 * int_extra +
+				     sizeof(output_per_stream) +
+				     3 * int_extra) +
+			sizeof(main_closing));
+
+	curr += sprintf(curr, prologue, stream_n);
+
+	for (i = 0; i < stream_n; ++i)
+		curr += sprintf(curr, output_per_stream, i, i * 2, i * 2 + 1);
+
+	curr += sprintf(curr, main_opening);
+
+	/*
+	 * Generate vertex emission for each stream explicitly. The argument
+	 * for 'EmitStreamVertex()' cannot be simply a loop variable. The spec
+	 * for GL_ARB_gpu_shader5 says:
+	 *
+	 *   "The argument <stream> must be a constant integral expression."
+	 */
+	for (i = 0; i < stream_n; ++i)
+		curr += sprintf(curr, vertex_emission_per_stream,
+				i * 2, i * 2, i * 2 + 1, i);
+
+	curr += sprintf(curr, main_closing);
+
+	return res;
+}
+
+static void
+build_and_use_program(unsigned max_streams)
+{
+	char *gs_text = generate_geometry_shader(max_streams);
+
+	GLuint prog = piglit_build_simple_program_multiple_shaders(
+				GL_VERTEX_SHADER, vs_pass_thru_text,
+				GL_GEOMETRY_SHADER, gs_text, 0);
+	free(gs_text);
+
+	/* In EXT-style the recorded varyings need to be set before linking. */
+	setup_varyings(prog, max_streams, 2);
+
+	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
+probe_buffers(unsigned max_streams)
+{
+	unsigned i;
+	float expected[1 + 2];
+	bool pass = true;
+
+	/* Check the recordings against expectations */
+	for (i = 0; i < max_streams; ++i) {
+		expected[0] = 2 * i + 1; /* x1[0] */
+		expected[1] = 2 * i + 2; /* x2[0] */
+		expected[2] = 2 * i + 3; /* x2[1] */
+
+		pass = probe_tfb(i, expected, ARRAY_SIZE(expected)) && pass;
+	}
+
+	cleanup_tfb(max_streams);
+
+	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
+}
+
+static void
+check_driver(GLint *max_streams, GLint *max_comps)
+{
+	piglit_require_extension("GL_ARB_transform_feedback3");
+	piglit_require_extension("GL_ARB_gpu_shader5");
+
+	glGetIntegerv(GL_MAX_VERTEX_STREAMS, max_streams);
+	if (!*max_streams) {
+		printf("Number of vertex streams supported is zero\n");
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
+		max_comps);
+	if (!*max_comps) {
+		printf("Number of interleaved components is zero\n");
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	/* Get the number of varyings - each consumes four components */
+	*max_comps /= 4;
+
+	if ((1 + 2) * *max_streams > *max_comps) {
+		printf("Test uses three floats/stream - only %u(%u streams) "
+			"attributes supported by the stack\n",
+			*max_comps, *max_streams);
+		piglit_report_result(PIGLIT_FAIL);
+	}
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	int i;
+	GLint max_streams, max_comps;
+	GLuint vao;
+
+	check_driver(&max_streams, &max_comps);
+
+	build_and_use_program(max_streams);
+
+	setup_tfb(max_streams, 1 + 2);
+
+	/* Test only records using transform feedback. */
+	glEnable(GL_RASTERIZER_DISCARD);
+
+	/* Test is run under desktop OpenGL 3.2 -> use of VAOs is required */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	/* Draw and record */
+	glBeginTransformFeedback(GL_POINTS);
+	glDrawArrays(GL_POINTS, 0, 1);
+	glEndTransformFeedback();
+	glDeleteVertexArrays(1, &vao);
+
+	for (i = 0; i < max_streams; ++i) {
+		glEndQueryIndexed(GL_PRIMITIVES_GENERATED, i);
+		glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, i);
+	}
+
+	if (!piglit_check_gl_error(GL_NO_ERROR)) {
+		cleanup_tfb(max_streams);
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	probe_buffers(max_streams);
+}
+
+enum piglit_result
+piglit_display(void)
+{
+	/* Should never be reached */
+	return PIGLIT_FAIL;
+}
diff --git a/tests/spec/arb_transform_feedback3/xfb3_common.c b/tests/spec/arb_transform_feedback3/xfb3_common.c
index 22918e1..5de8dfb 100644
--- a/tests/spec/arb_transform_feedback3/xfb3_common.c
+++ b/tests/spec/arb_transform_feedback3/xfb3_common.c
@@ -23,6 +23,17 @@
 
 #include "xfb3_common.h"
 
+/*
+ * 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.
+ */
+static GLuint tfb = 0;
+static GLuint *xfb = NULL;
+static GLuint *generated_queries = NULL;
+static GLuint *written_queries = NULL;
+
 void
 setup_varyings(GLuint prog, unsigned n, unsigned m)
 {
@@ -58,3 +69,79 @@ setup_varyings(GLuint prog, unsigned n, unsigned m)
 
 	free(vars);
 }
+
+void
+cleanup_tfb(unsigned stream_n)
+{
+	glDeleteBuffers(stream_n, xfb);
+	glDeleteQueries(stream_n, generated_queries);
+	glDeleteQueries(stream_n, written_queries);
+	free(xfb);
+	free(generated_queries);
+	free(written_queries);
+}
+
+void
+setup_tfb(unsigned stream_n, unsigned floats_per_buf)
+{
+	int i;
+
+	/*
+	 * 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);
+
+	xfb = malloc(stream_n * sizeof(GLuint));
+	generated_queries = malloc(stream_n * sizeof(GLuint));
+	written_queries = malloc(stream_n * sizeof(GLuint));
+
+	/* Set up the transform feedback buffers and queries. */
+	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,
+			floats_per_buf * sizeof(float), NULL, GL_STREAM_READ);
+
+		glBeginQueryIndexed(GL_PRIMITIVES_GENERATED, i,
+			generated_queries[i]);
+		glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, i,
+			written_queries[i]);
+	}
+
+	if (!piglit_check_gl_error(GL_NO_ERROR)) {
+		cleanup_tfb(stream_n);
+		piglit_report_result(PIGLIT_FAIL);
+	}
+}
+
+bool
+probe_tfb(unsigned stream_i, const float *expected, unsigned expected_n)
+{
+	char label[32];
+	GLuint res;
+
+	glGetQueryObjectuiv(generated_queries[stream_i], GL_QUERY_RESULT, &res);
+	if (res != 1) {
+		printf("Expected one primitive generated, got %u for "
+			"stream %u\n", res, stream_i);
+		return false;
+	}
+
+	glGetQueryObjectuiv(written_queries[stream_i], GL_QUERY_RESULT, &res);
+	if (res != 1) {
+		printf("Expected one primitive written, got %u for "
+			"stream %u\n", res, stream_i);
+		return false;
+	}
+
+	sprintf(label, "stream[%u]", stream_i);
+
+	return piglit_probe_buffer(xfb[stream_i], GL_TRANSFORM_FEEDBACK_BUFFER,
+			label, 1, expected_n, expected);
+}
diff --git a/tests/spec/arb_transform_feedback3/xfb3_common.h b/tests/spec/arb_transform_feedback3/xfb3_common.h
index 5211080..277c1f9 100644
--- a/tests/spec/arb_transform_feedback3/xfb3_common.h
+++ b/tests/spec/arb_transform_feedback3/xfb3_common.h
@@ -52,4 +52,13 @@ static const char vs_pass_thru_text[] =
 void
 setup_varyings(GLuint prog, unsigned n, unsigned m);
 
+void
+cleanup_tfb(unsigned stream_n);
+
+void
+setup_tfb(unsigned stream_n, unsigned floats_per_buf);
+
+bool
+probe_tfb(unsigned stream_i, const float *expected, unsigned expected_n);
+
 #endif /* XFB3_COMMON_H */
-- 
1.8.3.1



More information about the Piglit mailing list