[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