[Piglit] [PATCH] gs: test all input primitive types.
Paul Berry
stereotype441 at gmail.com
Tue Aug 20 15:32:03 PDT 2013
Verified using the NVIDIA proprietary driver for Linux.
---
tests/all.tests | 8 +
.../glsl-1.50/execution/geometry/CMakeLists.gl.txt | 1 +
.../glsl-1.50/execution/geometry/primitive-types.c | 435 +++++++++++++++++++++
3 files changed, 444 insertions(+)
create mode 100644 tests/spec/glsl-1.50/execution/geometry/primitive-types.c
diff --git a/tests/all.tests b/tests/all.tests
index c1e01bc..4532413 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -947,6 +947,14 @@ 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']:
+ add_concurrent_test(spec['glsl-1.50'],
+ 'glsl-1.50-geometry-primitive-types {0}'.format(
+ prim_type))
+
# Group spec/glsl-es-3.00
spec['glsl-es-3.00'] = Group()
import_glsl_parser_tests(spec['glsl-es-3.00'],
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..202fcd2 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-types primitive-types.c)
diff --git a/tests/spec/glsl-1.50/execution/geometry/primitive-types.c b/tests/spec/glsl-1.50/execution/geometry/primitive-types.c
new file mode 100644
index 0000000..f813e01
--- /dev/null
+++ b/tests/spec/glsl-1.50/execution/geometry/primitive-types.c
@@ -0,0 +1,435 @@
+/*
+ * 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-types.c
+ *
+ * Verify that the geometry shader is invoked the proper number of
+ * times, and input vertices are delivered in the proper order, for
+ * all input primitive types.
+ *
+ * This test uses a simple geometry shader that copies the gl_VertexID
+ * + 1 from each of its inputs to an output array, and then captures
+ * the result using transform feedback (gl_VertexID + 1 is used
+ * because this corresponds to the 1-based numbering used in the
+ * OpenGL spec: see section 2.6.1 (Primitive Types) of the GL 3.2 core
+ * spec). The resulting data is checked in C to make sure it matches
+ * the expected sequence of vertices.
+ *
+ * As an incidental side effect, this test verifies that the
+ * implementation assigns the correct input array size for each input
+ * primitive type (since geometry shader compilation would fail if it
+ * didn't).
+ */
+
+
+#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 MAX_OUTPUT_VERTICES 24
+
+
+static const char *vs_text =
+ "#version 150\n"
+ "\n"
+ "out int vertex_id;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " vertex_id = gl_VertexID;\n"
+ "}\n";
+
+static const char *gs_template =
+ "#version 150\n"
+ "#define INPUT_LAYOUT %s\n"
+ "#define VERTICES_PER_PRIM %d\n"
+ "layout(INPUT_LAYOUT) in;\n"
+ "layout(points, max_vertices = VERTICES_PER_PRIM) out;\n"
+ "\n"
+ "in int vertex_id[VERTICES_PER_PRIM];\n"
+ "out int vertex_out[VERTICES_PER_PRIM];\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " for (int i = 0; i < VERTICES_PER_PRIM; i++) {\n"
+ " vertex_out[i] = vertex_id[i] + 1;\n"
+ " }\n"
+ " EmitVertex();\n"
+ "}\n";
+
+
+static const char *varyings[] = {
+ "vertex_out[0]",
+ "vertex_out[1]",
+ "vertex_out[2]",
+ "vertex_out[3]",
+ "vertex_out[4]",
+ "vertex_out[5]",
+};
+
+
+struct test_vector
+{
+ /** Number of vertices to send down the pipeline */
+ unsigned num_input_vertices;
+
+ /** Number of GS invocations expected */
+ unsigned expected_gs_invocations;
+
+ /**
+ * Vertices that each GS invocation is expected to see.
+ */
+ GLint expected_results[MAX_OUTPUT_VERTICES];
+};
+
+static const struct test_vector points_tests[] = {
+ { 0, 0, { } },
+ { 1, 1, { 1 } },
+ { 2, 2, { 1, 2 } },
+};
+
+static const struct test_vector line_loop_tests[] = {
+ { 1, 0, { } },
+ { 2, 2, { 1, 2,
+ 2, 1 } },
+ { 3, 3, { 1, 2,
+ 2, 3,
+ 3, 1 } },
+ { 4, 4, { 1, 2,
+ 2, 3,
+ 3, 4,
+ 4, 1 } },
+};
+
+static const struct test_vector line_strip_tests[] = {
+ { 1, 0, { } },
+ { 2, 1, { 1, 2 } },
+ { 3, 2, { 1, 2,
+ 2, 3 } },
+ { 4, 3, { 1, 2,
+ 2, 3,
+ 3, 4 } },
+};
+
+static const struct test_vector lines_tests[] = {
+ { 1, 0, { } },
+ { 2, 1, { 1, 2 } },
+ { 3, 1, { 1, 2 } },
+ { 4, 2, { 1, 2,
+ 3, 4 } },
+};
+
+static const struct test_vector triangles_tests[] = {
+ { 2, 0, { } },
+ { 3, 1, { 1, 2, 3 } },
+ { 5, 1, { 1, 2, 3 } },
+ { 6, 2, { 1, 2, 3,
+ 4, 5, 6 } },
+};
+
+static const struct test_vector triangle_strip_tests[] = {
+ { 2, 0, { } },
+ { 3, 1, { 1, 2, 3 } },
+ { 4, 2, { 1, 2, 3,
+ 3, 2, 4 } },
+ { 5, 3, { 1, 2, 3,
+ 3, 2, 4,
+ 3, 4, 5 } },
+};
+
+static const struct test_vector triangle_fan_tests[] = {
+ { 2, 0, { } },
+ { 3, 1, { 1, 2, 3 } },
+ { 4, 2, { 1, 2, 3,
+ 1, 3, 4 } },
+ { 5, 3, { 1, 2, 3,
+ 1, 3, 4,
+ 1, 4, 5 } },
+};
+
+static const struct test_vector lines_adjacency_tests[] = {
+ { 3, 0, { } },
+ { 4, 1, { 1, 2, 3, 4 } },
+ { 7, 1, { 1, 2, 3, 4 } },
+ { 8, 2, { 1, 2, 3, 4,
+ 5, 6, 7, 8 } },
+};
+
+static const struct test_vector line_strip_adjacency_tests[] = {
+ { 3, 0, { } },
+ { 4, 1, { 1, 2, 3, 4 } },
+ { 5, 2, { 1, 2, 3, 4,
+ 2, 3, 4, 5 } },
+ { 6, 3, { 1, 2, 3, 4,
+ 2, 3, 4, 5,
+ 3, 4, 5, 6 } },
+};
+
+static const struct test_vector triangles_adjacency_tests[] = {
+ { 5, 0, { } },
+ { 6, 1, { 1, 2, 3, 4, 5, 6 } },
+ { 11, 1, { 1, 2, 3, 4, 5, 6 } },
+ { 12, 2, { 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12 } },
+};
+
+/* Note: the required vertex order is surprisingly non-obvious for
+ * GL_TRIANGLE_STRIP_ADJACENCY.
+ *
+ * Table 2.4 in the GL 3.2 core spec (Triangles generated by triangle
+ * strips with adjacency) defines how the vertices in the triangle
+ * strip are to be interpreted:
+ *
+ * Primitive Vertices Adjacent Vertices
+ * Primitive 1st 2nd 3rd 1/2 2/3 3/1
+ * only (i = 0, n = 1) 1 3 5 2 6 4
+ * first (i = 0) 1 3 5 2 7 4
+ * middle (i odd) 2i+3 2i+1 2i+5 2i-1 2i+4 2i+7
+ * middle (i even) 2i+1 2i+3 2i+5 2i-1 2i+7 2i+4
+ * last (i = n - 1, i odd) 2i+3 2i+1 2i+5 2i-1 2i+4 2i+6
+ * last (i = n - 1, i even) 2i+1 2i+3 2i+5 2i-1 2i+6 2i+4
+ *
+ * But it does not define the order in which these vertices should be
+ * delivered to the geometry shader. That's defined in section 2.12.1
+ * of the GL 3.2 core spec (Geometry Shader Input Primitives):
+ *
+ * Geometry shaders that operate on triangles with adjacent
+ * vertices are valid for the TRIANGLES_ADJACENCY and
+ * TRIANGLE_STRIP_ADJACENCY primitive types. There are six
+ * vertices available for each program invocation. The first,
+ * third and fifth vertices refer to attributes of the first,
+ * second and third vertex of the triangle, respectively. The
+ * second, fourth and sixth vertices refer to attributes of the
+ * vertices adjacent to the edges from the first to the second
+ * vertex, from the second to the third vertex, and from the third
+ * to the first vertex, respectively.
+ *
+ * Therefore the order in which the columns of table 2.4 should be
+ * read is 1st, 1/2, 2nd, 2/3, 3rd, 3/1.
+ *
+ * So, for example, in the case where there is just a single triangle
+ * delivered to the pipeline, we consult the first row of table 2.4 to
+ * find:
+ *
+ * Primitive Vertices Adjacent Vertices
+ * 1st 2nd 3rd 1/2 2/3 3/1
+ * 1 3 5 2 6 4
+ *
+ * Rearranging into the order that should be delivered to the geometry
+ * shader, we get:
+ *
+ * 1st 1/2 2nd 2/3 3rd 3/1
+ * 1 2 3 6 5 4
+ */
+static const struct test_vector triangle_strip_adjacency_tests[] = {
+ { 5, 0, { } },
+ { 6, 1, { 1, 2, 3, 6, 5, 4 } },
+ { 7, 1, { 1, 2, 3, 6, 5, 4 } },
+ { 8, 2, { 1, 2, 3, 7, 5, 4,
+ 5, 1, 3, 6, 7, 8 } },
+ { 9, 2, { 1, 2, 3, 7, 5, 4,
+ 5, 1, 3, 6, 7, 8 } },
+ { 10, 3, { 1, 2, 3, 7, 5, 4,
+ 5, 1, 3, 6, 7, 9,
+ 5, 3, 7, 10, 9, 8 } },
+ { 11, 3, { 1, 2, 3, 7, 5, 4,
+ 5, 1, 3, 6, 7, 9,
+ 5, 3, 7, 10, 9, 8 } },
+ { 12, 4, { 1, 2, 3, 7, 5, 4,
+ 5, 1, 3, 6, 7, 9,
+ 5, 3, 7, 11, 9, 8,
+ 9, 5, 7, 10, 11, 12 } },
+};
+
+
+static const struct test_set
+{
+ const char *name;
+ GLenum prim_type;
+ const char *input_layout;
+ unsigned vertices_per_prim;
+ unsigned num_test_vectors;
+ const struct test_vector *test_vectors;
+} tests[] = {
+#define TEST(prim_type, input_layout, vertices_per_prim, test_array) \
+ { #prim_type, prim_type, input_layout, vertices_per_prim, \
+ ARRAY_SIZE(test_array), test_array }
+ TEST(GL_POINTS, "points", 1, points_tests),
+ TEST(GL_LINE_LOOP, "lines", 2, line_loop_tests),
+ TEST(GL_LINE_STRIP, "lines", 2, line_strip_tests),
+ TEST(GL_LINES, "lines", 2, lines_tests),
+ TEST(GL_TRIANGLES, "triangles", 3, triangles_tests),
+ TEST(GL_TRIANGLE_STRIP, "triangles", 3, triangle_strip_tests),
+ TEST(GL_TRIANGLE_FAN, "triangles", 3, triangle_fan_tests),
+ TEST(GL_LINES_ADJACENCY, "lines_adjacency", 4, lines_adjacency_tests),
+ TEST(GL_LINE_STRIP_ADJACENCY, "lines_adjacency", 4,
+ line_strip_adjacency_tests),
+ TEST(GL_TRIANGLES_ADJACENCY, "triangles_adjacency", 6,
+ triangles_adjacency_tests),
+ TEST(GL_TRIANGLE_STRIP_ADJACENCY, "triangles_adjacency", 6,
+ triangle_strip_adjacency_tests),
+#undef TEST
+};
+
+
+static GLuint generated_query;
+
+
+static void
+print_usage_and_exit(const char *prog_name)
+{
+ int i;
+ printf("Usage: %s <primitive>\n"
+ " where <primitive> is one of the following:\n", prog_name);
+ for (i = 0; i < ARRAY_SIZE(tests); i++)
+ printf(" %s\n", tests[i].name);
+ piglit_report_result(PIGLIT_FAIL);
+}
+
+
+static bool
+do_test_vector(const struct test_set *test, const struct test_vector *vector)
+{
+ GLuint primitives_generated;
+ int i;
+ const GLint *readback;
+ unsigned expected_output_points;
+ unsigned actual_output_points;
+ bool pass = true;
+
+ printf("Testing %s(%d vertices)\n", test->name,
+ vector->num_input_vertices);
+
+ /* Run vertices through the pipeline */
+ glBeginQuery(GL_PRIMITIVES_GENERATED, generated_query);
+ glBeginTransformFeedback(GL_POINTS);
+ glDrawArrays(test->prim_type, 0, vector->num_input_vertices);
+ glEndTransformFeedback();
+ glEndQuery(GL_PRIMITIVES_GENERATED);
+
+ /* Check that the GS got invoked the right number of times */
+ glGetQueryObjectuiv(generated_query, GL_QUERY_RESULT,
+ &primitives_generated);
+ if (primitives_generated != vector->expected_gs_invocations) {
+ printf(" Expected %d GS invocations, got %d\n",
+ vector->expected_gs_invocations, primitives_generated);
+ pass = false;
+ }
+ expected_output_points =
+ vector->expected_gs_invocations * test->vertices_per_prim;
+ actual_output_points = primitives_generated * test->vertices_per_prim;
+
+ /* Check the data output by the GS */
+ readback = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
+ if (memcmp(readback, vector->expected_results,
+ expected_output_points * sizeof(GLint)) != 0) {
+ pass = false;
+ }
+
+ /* Output details if the result was wrong */
+ if (!pass) {
+ printf(" Expected vertex IDs:");
+ for (i = 0; i < expected_output_points; i++)
+ printf(" %d", vector->expected_results[i]);
+ printf("\n");
+ printf(" Actual vertex IDs: ");
+ for (i = 0; i < actual_output_points; i++)
+ printf(" %d", readback[i]);
+ printf("\n");
+ }
+
+ glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
+
+ return pass;
+}
+
+
+void
+piglit_init(int argc, char **argv)
+{
+ int i;
+ const struct test_set *test = NULL;
+ GLuint prog, vs, gs, vao, xfb_buf;
+ char *gs_text;
+ bool pass = true;
+
+ /* Parse params */
+ if (argc != 2)
+ print_usage_and_exit(argv[0]);
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ if (strcmp(argv[1], tests[i].name) == 0) {
+ test = &tests[i];
+ break;
+ }
+ }
+ if (test == NULL)
+ 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, test->input_layout,
+ test->vertices_per_prim);
+ gs = piglit_compile_shader_text(GL_GEOMETRY_SHADER, gs_text);
+ free(gs_text);
+ glAttachShader(prog, gs);
+ glTransformFeedbackVaryings(prog, test->vertices_per_prim, 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_OUTPUT_VERTICES * sizeof(GLint), NULL,
+ GL_STREAM_READ);
+ glGenQueries(1, &generated_query);
+ glEnable(GL_RASTERIZER_DISCARD);
+
+ for (i = 0; i < test->num_test_vectors; i++) {
+ pass = do_test_vector(test, &test->test_vectors[i]) && pass;
+ }
+
+ piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
+}
+
+
+enum piglit_result
+piglit_display(void)
+{
+ /* Should never be reached */
+ return PIGLIT_FAIL;
+}
--
1.8.3.4
More information about the Piglit
mailing list