[Piglit] [PATCH] Test transform feedback with intervening glReadPixels.

Paul Berry stereotype441 at gmail.com
Fri Dec 23 13:54:57 PST 2011


This test verifies that transform feedback continues to work correctly
if glReadPixels is executed while it is in progress.

This is an important case to test on Mesa's i965 driver, because
glReadPixels forces the driver to start a new batch buffer, and at the
beginning of each batch buffer the driver needs to update the
transform feedback buffer pointers (in case they were used by another
process in between the two batches).
---
 tests/all.tests                                    |    4 +
 .../spec/ext_transform_feedback/CMakeLists.gl.txt  |    1 +
 .../spec/ext_transform_feedback/intervening-read.c |  266 ++++++++++++++++++++
 3 files changed, 271 insertions(+), 0 deletions(-)
 create mode 100644 tests/spec/ext_transform_feedback/intervening-read.c

diff --git a/tests/all.tests b/tests/all.tests
index 5ec532e..0a353d1 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -1382,6 +1382,10 @@ ext_transform_feedback['discard-copypixels'] = concurrent_test('ext_transform_fe
 ext_transform_feedback['discard-drawarrays'] = concurrent_test('ext_transform_feedback-discard-drawarrays')
 ext_transform_feedback['discard-drawpixels'] = concurrent_test('ext_transform_feedback-discard-drawpixels')
 ext_transform_feedback['immediate-reuse'] = concurrent_test('ext_transform_feedback-immediate-reuse')
+for mode in ['output', 'prims_generated', 'prims_written']:
+        test_name = 'intervening-read {0}'.format(mode)
+        ext_transform_feedback[test_name] = PlainExecTest(
+                'ext_transform_feedback-{0} -auto'.format(test_name))
 ext_transform_feedback['position-readback-bufferbase'] = 		PlainExecTest(['ext_transform_feedback-position', '-auto'])
 ext_transform_feedback['position-readback-bufferbase-discard'] = 	PlainExecTest(['ext_transform_feedback-position', '-auto', 'discard'])
 ext_transform_feedback['position-readback-bufferoffset'] = 		PlainExecTest(['ext_transform_feedback-position', '-auto', 'offset'])
diff --git a/tests/spec/ext_transform_feedback/CMakeLists.gl.txt b/tests/spec/ext_transform_feedback/CMakeLists.gl.txt
index 8582ef0..8334274 100644
--- a/tests/spec/ext_transform_feedback/CMakeLists.gl.txt
+++ b/tests/spec/ext_transform_feedback/CMakeLists.gl.txt
@@ -23,6 +23,7 @@ add_executable (ext_transform_feedback-generatemipmap generatemipmap.c)
 add_executable (ext_transform_feedback-position position.c)
 add_executable (ext_transform_feedback-immediate-reuse immediate-reuse.c)
 add_executable (ext_transform_feedback-interleaved interleaved.c)
+add_executable (ext_transform_feedback-intervening-read intervening-read.c)
 add_executable (ext_transform_feedback-separate separate.c)
 add_executable (ext_transform_feedback-output-type output-type.c)
 add_executable (ext_transform_feedback-order order.c)
diff --git a/tests/spec/ext_transform_feedback/intervening-read.c b/tests/spec/ext_transform_feedback/intervening-read.c
new file mode 100644
index 0000000..c441df2
--- /dev/null
+++ b/tests/spec/ext_transform_feedback/intervening-read.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright © 2011 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 intervening-read.c
+ *
+ * Verify that transform feedback continues to work correctly if
+ * glReadPixels is executed while it is in progress.
+ *
+ * This test accepts a single command-line argument which determines
+ * what aspect of transform feedback is tested:
+ *
+ * - output: Verifies that correct transform feedback output is generated.
+ *
+ * - prims_generated: Verifies that the PRIMITIVES_GENERATED counter
+ *   is updated correctly.
+ *
+ * - prims_written: Verifies that the PRIMITIVES_WRITTEN counter is
+ *   updated correctly.
+ *
+ * The test draws two triangles before executing glReadPixels, and two
+ * triangles after executing glReadPixels.  It uses a transform
+ * feedback buffer that is large enough to accommodate 12 vertices,
+ * but it requests that no more than 9 vertices be written to it.
+ * This allows us to verify that the intervening glReadPixels call
+ * doesn't interfere with overflow checking.
+ */
+
+#include "piglit-util.h"
+
+int piglit_width = 64;
+int piglit_height = 32;
+int piglit_window_mode = GLUT_DOUBLE | GLUT_RGB;
+
+static enum test_mode {
+	TEST_MODE_OUTPUT,
+	TEST_MODE_PRIMS_GENERATED,
+	TEST_MODE_PRIMS_WRITTEN
+} test_mode;
+
+static const char *vstext =
+	"attribute vec4 in_position;\n"
+	"attribute vec4 in_color;\n"
+	"varying vec4 out_position;\n"
+	"varying vec4 out_color;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  gl_Position = in_position;\n"
+	"  out_position = in_position;\n"
+	"  out_color = in_color;\n"
+	"}\n";
+
+static const char *fstext =
+	"varying vec4 out_color;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = out_color;\n"
+	"}\n";
+
+static const char *varyings[] = { "out_position", "out_color" };
+
+static GLuint xfb_buf;
+static GLuint prog;
+static GLuint query;
+
+static void
+print_usage_and_exit(char *prog_name)
+{
+	printf("Usage: %s <mode>\n"
+	       "  where <mode> is one of:\n"
+	       "    output\n"
+	       "    prims_generated\n"
+	       "    prims_written\n", prog_name);
+	exit(1);
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	GLuint vs, fs;
+
+	/* Interpret command line args */
+	if (argc != 2)
+		print_usage_and_exit(argv[0]);
+	if (strcmp(argv[1], "output") == 0)
+		test_mode = TEST_MODE_OUTPUT;
+	else if (strcmp(argv[1], "prims_generated") == 0)
+		test_mode = TEST_MODE_PRIMS_GENERATED;
+	else if (strcmp(argv[1], "prims_written") == 0)
+		test_mode = TEST_MODE_PRIMS_WRITTEN;
+	else
+		print_usage_and_exit(argv[0]);
+
+	piglit_require_GLSL();
+	piglit_require_transform_feedback();
+
+	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vstext);
+	fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fstext);
+	prog = piglit_CreateProgram();
+	piglit_AttachShader(prog, vs);
+	piglit_AttachShader(prog, fs);
+	piglit_BindAttribLocation(prog, 0, "in_position");
+	piglit_BindAttribLocation(prog, 1, "in_color");
+	piglit_TransformFeedbackVaryings(prog, 2, varyings, GL_INTERLEAVED_ATTRIBS);
+	piglit_LinkProgram(prog);
+	if (!piglit_link_check_status(prog)) {
+		piglit_DeleteProgram(prog);
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	glGenBuffers(1, &xfb_buf);
+	glGenQueries(1, &query);
+}
+
+struct vertex_data {
+	float position[4];
+	float color[4];
+};
+
+void
+dump_vertex_data(const struct vertex_data *data)
+{
+	printf("position=(%f, %f, %f, %f), color=(%f, %f, %f, %f)",
+	       data->position[0], data->position[1], data->position[2], data->position[3],
+	       data->color[0], data->color[1], data->color[2], data->color[3]);
+}
+
+enum piglit_result
+piglit_display(void)
+{
+	int i, j;
+	GLboolean pass = GL_TRUE;
+	static const struct vertex_data vertex_input[12] = {
+		/*  position XYZW             color RGBA */
+		{ { -1.0, -1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
+		{ {  0.0, -1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
+		{ { -1.0,  1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
+		{ { -1.0,  1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
+		{ {  0.0, -1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
+		{ {  0.0,  1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
+		{ {  0.0, -1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
+		{ {  1.0, -1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
+		{ {  0.0,  1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
+		{ {  0.0,  1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
+		{ {  1.0, -1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
+		{ {  1.0,  1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } }
+	};
+	static struct vertex_data initial_xfb_data[12];
+	const struct vertex_data *readback;
+	GLuint query_result;
+
+	glUseProgram(prog);
+
+	/* Setup inputs */
+	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE,
+			      sizeof(struct vertex_data),
+			      &vertex_input[0].position);
+	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE,
+			      sizeof(struct vertex_data),
+			      &vertex_input[0].color);
+	glEnableVertexAttribArray(0);
+	glEnableVertexAttribArray(1);
+
+	/* Setup transform feedback */
+	for (i = 0; i < ARRAY_SIZE(initial_xfb_data); ++i) {
+		for (j = 0; j < 4; ++j) {
+			initial_xfb_data[i].position[j] = 12345.0;
+			initial_xfb_data[i].color[j] = 12345.0;
+		}
+	}
+	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf);
+	glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(initial_xfb_data),
+		     initial_xfb_data, GL_STREAM_READ);
+	piglit_BindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buf, 0,
+			       sizeof(float[9][8]));
+	piglit_BeginTransformFeedback(GL_TRIANGLES);
+	switch (test_mode) {
+	case TEST_MODE_PRIMS_GENERATED:
+		glBeginQuery(GL_PRIMITIVES_GENERATED, query);
+		break;
+	case TEST_MODE_PRIMS_WRITTEN:
+		glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
+		break;
+	default:
+		break;
+	}
+
+	/* First draw call */
+	glDrawArrays(GL_TRIANGLES, 0, 6);
+
+	/* Read pixels */
+	pass = piglit_probe_rect_rgba(0, 0, piglit_width / 2, piglit_height,
+				      vertex_input[0].color) && pass;
+
+	/* Second draw call */
+	glDrawArrays(GL_TRIANGLES, 6, 6);
+
+	/* Finish transform feedback and test correct behavior. */
+	piglit_EndTransformFeedback();
+	switch (test_mode) {
+	case TEST_MODE_OUTPUT:
+		readback = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER,
+				       GL_READ_ONLY);
+		for (i = 0; i < 12; ++i) {
+			const struct vertex_data *expected = i < 9
+				? &vertex_input[i] : &initial_xfb_data[i];
+			if (memcmp(&readback[i], expected,
+				   sizeof(struct vertex_data)) != 0) {
+				printf("Read incorrect data for vertex %i.\n",
+				       i);
+				printf("Readback: ");
+				dump_vertex_data(&readback[i]);
+				printf("\nExpected: ");
+				dump_vertex_data(expected);
+				printf("\n");
+				pass = GL_FALSE;
+			}
+		}
+		glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
+		break;
+	case TEST_MODE_PRIMS_GENERATED:
+		glEndQuery(GL_PRIMITIVES_GENERATED);
+		glGetQueryObjectuiv(query, GL_QUERY_RESULT, &query_result);
+		if (query_result != 4) {
+			printf("Expected 4 primitives generated, got %u\n",
+			       query_result);
+			pass = GL_FALSE;
+		}
+		break;
+	case TEST_MODE_PRIMS_WRITTEN:
+		glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
+		glGetQueryObjectuiv(query, GL_QUERY_RESULT, &query_result);
+		if (query_result != 3) {
+			printf("Expected 3 primitives written, got %u\n",
+			       query_result);
+			pass = GL_FALSE;
+		}
+		break;
+	}
+
+	piglit_present_results();
+
+	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+}
-- 
1.7.6.4



More information about the Piglit mailing list