[Piglit] [PATCH] gs: Test interaction between gl_PrimitiveIDIn and primitive restart.

Paul Berry stereotype441 at gmail.com
Mon Aug 26 21:38:59 PDT 2013


Verified using the NVIDIA proprietary driver for linux.
---
 tests/all.tests                                    |   9 +
 .../glsl-1.50/execution/geometry/CMakeLists.gl.txt |   1 +
 .../execution/geometry/primitive-id-restart.c      | 265 +++++++++++++++++++++
 3 files changed, 275 insertions(+)
 create mode 100644 tests/spec/glsl-1.50/execution/geometry/primitive-id-restart.c

diff --git a/tests/all.tests b/tests/all.tests
index 7c1503a..a8c0f76 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -947,6 +947,15 @@ for i in [31, 32, 33, 34, 127, 128, 129, 130, 0]:
     add_concurrent_test(spec['glsl-1.50'],
                         'glsl-1.50-geometry-end-primitive {0}'.format(i))
 
+for prim_type in ['GL_POINTS', 'GL_LINE_LOOP', 'GL_LINE_STRIP', 'GL_LINES',
+                  'GL_TRIANGLES', 'GL_TRIANGLE_STRIP', 'GL_TRIANGLE_FAN',
+                  'GL_LINES_ADJACENCY', 'GL_LINE_STRIP_ADJACENCY',
+                  'GL_TRIANGLES_ADJACENCY', 'GL_TRIANGLE_STRIP_ADJACENCY']:
+    for restart_index in ['ffs', 'other']:
+        add_concurrent_test(spec['glsl-1.50'],
+                            'glsl-1.50-geometry-primitive-id-restart {0} {1}'.format(
+                                prim_type, restart_index))
+
 spec['glsl-3.30'] = Group()
 import_glsl_parser_tests(spec['glsl-3.30'],
 			 os.path.join(testsDir, 'spec', 'glsl-3.30'),
diff --git a/tests/spec/glsl-1.50/execution/geometry/CMakeLists.gl.txt b/tests/spec/glsl-1.50/execution/geometry/CMakeLists.gl.txt
index d4becb7..aa61f6c 100644
--- a/tests/spec/glsl-1.50/execution/geometry/CMakeLists.gl.txt
+++ b/tests/spec/glsl-1.50/execution/geometry/CMakeLists.gl.txt
@@ -11,3 +11,4 @@ ${OPENGL_glu_LIBRARY}
 )
 
 piglit_add_executable (glsl-1.50-geometry-end-primitive end-primitive.c)
+piglit_add_executable (glsl-1.50-geometry-primitive-id-restart primitive-id-restart.c)
diff --git a/tests/spec/glsl-1.50/execution/geometry/primitive-id-restart.c b/tests/spec/glsl-1.50/execution/geometry/primitive-id-restart.c
new file mode 100644
index 0000000..72f024d
--- /dev/null
+++ b/tests/spec/glsl-1.50/execution/geometry/primitive-id-restart.c
@@ -0,0 +1,265 @@
+/*
+ * 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.
+ */
+
+/**
+ * \file primitive-id-restart.c
+ *
+ * Verify that the use of primitive restart does not reset the
+ * geometry shader's gl_PrimitiveID counter.
+ *
+ * From the GL 3.2 core spec, section 2.12.4 (Geometry Shader
+ * Execution Environment):
+ *
+ *     Restarting a primitive topology using the primitive restart
+ *     index has no effect on the primitive ID counter.
+ *
+ * This test uses a simple geometry shader that copies
+ * gl_PrimitiveIDIn to a single output, which is captured using
+ * transform feedback.
+ *
+ * The test operates by specifying a sequence of:
+ *
+ * - One vertex followed by primitive restart
+ * - Two vertices followed by primitive restart
+ * - Three vertices followed by primitive restart
+ *
+ * And so on up to twelve.  The resulting transform feedback output is
+ * checked to verify that the primitive ID's received by the geometry
+ * shaders count upwards from 0, without restarting anywhere.
+ *
+ * Note: some generations of Intel hardware require primitive restart
+ * to be emulated in software when either:
+ *
+ * - certain primitive types are used, or
+ *
+ * - the primitive restart index is not all 0xff's.
+ *
+ * To make sure that both the hardware and software primitive restart
+ * codepaths are tested, this test accepts command line options to
+ * control (a) which primitive type to use, and (b) whether the
+ * primitive restart index should be all 0xff's.
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 32;
+	config.supports_gl_core_version = 32;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+
+#define LONGEST_INPUT_SEQUENCE 12
+#define NUM_INPUT_ELEMENTS \
+	(LONGEST_INPUT_SEQUENCE * (LONGEST_INPUT_SEQUENCE + 3) / 2)
+#define MAX_TOTAL_PRIMS \
+	(LONGEST_INPUT_SEQUENCE * (LONGEST_INPUT_SEQUENCE + 1) / 2)
+
+
+static const char *vs_text =
+	"#version 150\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"}\n";
+
+static const char *gs_template =
+	"#version 150\n"
+	"#define INPUT_LAYOUT %s\n"
+	"layout(INPUT_LAYOUT) in;\n"
+	"layout(points, max_vertices = 1) out;\n"
+	"\n"
+	"out int primitive_id;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  primitive_id = gl_PrimitiveIDIn;\n"
+	"  EmitVertex();\n"
+	"}\n";
+
+static const char *varyings[] = { "primitive_id" };
+
+
+struct prim_type_info
+{
+	const char *name;
+	GLenum prim_type;
+	const char *input_layout;
+} prim_types[] = {
+#define PRIM_TYPE(prim_type, input_layout) \
+	{ #prim_type, prim_type, input_layout }
+	PRIM_TYPE(GL_POINTS, "points"),
+	PRIM_TYPE(GL_LINE_LOOP, "lines"),
+	PRIM_TYPE(GL_LINE_STRIP, "lines"),
+	PRIM_TYPE(GL_LINES, "lines"),
+	PRIM_TYPE(GL_TRIANGLES, "triangles"),
+	PRIM_TYPE(GL_TRIANGLE_STRIP, "triangles"),
+	PRIM_TYPE(GL_TRIANGLE_FAN, "triangles"),
+	PRIM_TYPE(GL_LINES_ADJACENCY, "lines_adjacency"),
+	PRIM_TYPE(GL_LINE_STRIP_ADJACENCY, "lines_adjacency"),
+	PRIM_TYPE(GL_TRIANGLES_ADJACENCY, "triangles_adjacency"),
+	PRIM_TYPE(GL_TRIANGLE_STRIP_ADJACENCY, "triangles_adjacency"),
+#undef PRIM_TYPE
+};
+
+
+static void
+print_usage_and_exit(const char *prog_name)
+{
+	int i;
+	printf("Usage: %s <primitive> <restart-index>\n"
+	       "  where <primitive> is one of the following:\n", prog_name);
+	for(i = 0; i < ARRAY_SIZE(prim_types); i++)
+		printf("    %s\n", prim_types[i].name);
+	printf("  and <restart-index> is one of the following:\n"
+	       "    ffs - use a primitive restart index that is all 0xffs\n"
+	       "    other - use a different primitive restart index\n");
+	piglit_report_result(PIGLIT_FAIL);
+}
+
+
+void
+piglit_init(int argc, char **argv)
+{
+	GLenum prim_type = 0;
+	const char *input_layout = NULL;
+	GLubyte prim_restart_index;
+	char *gs_text;
+	GLuint prog, vs, gs, vao, xfb_buf, element_buf, generated_query,
+		primitives_generated;
+	GLubyte *elements;
+	int i, j;
+	GLsizei num_elements;
+	bool pass = true;
+	GLuint *readback;
+
+	/* Parse params */
+	if (argc != 3)
+		print_usage_and_exit(argv[0]);
+	for (i = 0; i < ARRAY_SIZE(prim_types); i++) {
+		if (strcmp(argv[1], prim_types[i].name) == 0) {
+			prim_type = prim_types[i].prim_type;
+			input_layout = prim_types[i].input_layout;
+			break;
+		}
+	}
+	if (input_layout == NULL)
+		print_usage_and_exit(argv[0]);
+	if (strcmp(argv[2], "ffs") == 0)
+		prim_restart_index = 0xff;
+	else if (strcmp(argv[2], "other") == 0)
+		prim_restart_index = 1;
+	else
+		print_usage_and_exit(argv[0]);
+
+	/* Compile shaders */
+	prog = glCreateProgram();
+	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_text);
+	glAttachShader(prog, vs);
+	asprintf(&gs_text, gs_template, input_layout);
+	gs = piglit_compile_shader_text(GL_GEOMETRY_SHADER, gs_text);
+	free(gs_text);
+	glAttachShader(prog, gs);
+	glTransformFeedbackVaryings(prog, 1, varyings, GL_INTERLEAVED_ATTRIBS);
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog))
+		piglit_report_result(PIGLIT_FAIL);
+	glUseProgram(prog);
+
+	/* Set up other GL state */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+	glGenBuffers(1, &xfb_buf);
+	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buf);
+	glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
+		     MAX_TOTAL_PRIMS * sizeof(GLint), NULL,
+		     GL_STREAM_READ);
+	glGenQueries(1, &generated_query);
+	glEnable(GL_RASTERIZER_DISCARD);
+	glEnable(GL_PRIMITIVE_RESTART);
+	glPrimitiveRestartIndex(prim_restart_index);
+
+	/* Set up element buffer */
+	glGenBuffers(1, &element_buf);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buf);
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+		     sizeof(GLubyte) * NUM_INPUT_ELEMENTS, NULL,
+		     GL_STATIC_DRAW);
+	elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_WRITE);
+	num_elements = 0;
+	for (i = 1; i <= LONGEST_INPUT_SEQUENCE; i++) {
+		for (j = 0; j < i; j++) {
+			/* Every element that isn't the primitive
+			 * restart index can just be element 0, since
+			 * we don't care about the actual vertex data.
+			 */
+			elements[num_elements++] = 0;
+		}
+		elements[num_elements++] = prim_restart_index;
+	}
+	glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+	/* Run vertices through the pipeline */
+	glBeginQuery(GL_PRIMITIVES_GENERATED, generated_query);
+	glBeginTransformFeedback(GL_POINTS);
+	glDrawElements(prim_type, num_elements, GL_UNSIGNED_BYTE, NULL);
+	glEndTransformFeedback();
+	glEndQuery(GL_PRIMITIVES_GENERATED);
+
+	/* Find out how many times the GS got invoked so we'll know
+	 * how many transform feedback outputs to examine.
+	 */
+	glGetQueryObjectuiv(generated_query, GL_QUERY_RESULT,
+			    &primitives_generated);
+	if (primitives_generated > MAX_TOTAL_PRIMS) {
+		printf("Expected no more than %d primitives, got %d\n",
+		       MAX_TOTAL_PRIMS, primitives_generated);
+		pass = false;
+
+		/* Set primitives_generated to MAX_TOTAL_PRIMS so that
+		 * we don't overflow the buffer in the loop below.
+		 */
+	}
+
+	/* Check transform feedback outputs. */
+	readback = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
+	for (i = 0; i < primitives_generated; i++) {
+		if (readback[i] != i) {
+			printf("Expected primitive %d to have gl_PrimitiveIDIn"
+			       " = %d, got %d instead\n", i, i, readback[i]);
+			pass = false;
+		}
+	}
+	glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
+
+	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
+}
+
+
+enum piglit_result
+piglit_display(void)
+{
+	/* Should never be reached */
+	return PIGLIT_FAIL;
+}
-- 
1.8.4



More information about the Piglit mailing list