[Piglit] [PATCH] glsl: Add tests for glGetActiveAttrib

Ian Romanick idr at freedesktop.org
Wed Nov 23 13:13:34 PST 2011


From: Ian Romanick <ian.d.romanick at intel.com>

Verify that glGetActiveAttrib and GL_ACTIVE_ATTRIBUTES return sensible
data under a variety of circumstances.  There are checks for all the
types and built-in attributes in GLSL 1.10, 1.20, and 1.30.

All of the subcases pass on NVIDIA's closed-source Linux driver and
AMD's closed-source Linux driver.

These test fails horribly on Mesa 7.11.  Matrix attributes are
reported multiple times (once per column of the matrix) and built-in
attributes are never reported.  Mesa master fixes the matrix issues,
but it still has problems with built-in attributes.  There is a patch
on the mesa-dev mailing list to fix that issue.

Signed-off-by: Ian Romanick <ian.d.romanick at intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=43138
---
 tests/all.tests                 |    9 +
 tests/general/CMakeLists.gl.txt |    1 +
 tests/general/getactiveattrib.c |  552 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 562 insertions(+), 0 deletions(-)
 create mode 100644 tests/general/getactiveattrib.c

diff --git a/tests/all.tests b/tests/all.tests
index da5ac17..36d8bf4 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -828,6 +828,9 @@ for mode in ['fixed', 'pos_clipvert', 'clipvert_pos']:
 	cmdline = 'clip-plane-transformation ' + mode
 	spec['glsl-1.10']['execution']['clipping'][cmdline] = concurrent_test(cmdline)
 
+spec['glsl-1.10']['api'] = Group()
+add_concurrent_test(spec['glsl-1.10']['api'], 'getactiveattrib 110');
+
 # Group spec/glsl-1.20
 spec['glsl-1.20'] = Group()
 import_glsl_parser_tests(spec['glsl-1.20'],
@@ -867,6 +870,9 @@ add_recursion_test(rec, 'indirect-separate')
 add_recursion_test(rec, 'indirect-complex')
 add_recursion_test(rec, 'indirect-complex-separate')
 
+spec['glsl-1.20']['api'] = Group()
+add_concurrent_test(spec['glsl-1.20']['api'], 'getactiveattrib 120');
+
 
 # Group spec/glsl-1.30
 spec['glsl-1.30'] = Group()
@@ -900,6 +906,9 @@ add_concurrent_test(spec['glsl-1.30']['execution'], 'vertexid-beginend')
 add_concurrent_test(spec['glsl-1.30']['execution'], 'vertexid-drawarrays')
 add_concurrent_test(spec['glsl-1.30']['execution'], 'vertexid-drawelements')
 
+spec['glsl-1.30']['api'] = Group()
+add_concurrent_test(spec['glsl-1.30']['api'], 'getactiveattrib 130');
+
 # Group AMD_conservative_depth
 spec['AMD_conservative_depth'] = Group()
 import_glsl_parser_tests(spec['AMD_conservative_depth'],
diff --git a/tests/general/CMakeLists.gl.txt b/tests/general/CMakeLists.gl.txt
index 2cfc7be..9c59f22 100644
--- a/tests/general/CMakeLists.gl.txt
+++ b/tests/general/CMakeLists.gl.txt
@@ -54,6 +54,7 @@ add_executable (framebuffer-srgb framebuffer-srgb.c)
 IF (UNIX)
 	target_link_libraries (framebuffer-srgb m)
 ENDIF (UNIX)
+add_executable (getactiveattrib getactiveattrib.c)
 add_executable (geterror-inside-begin geterror-inside-begin.c)
 add_executable (geterror-invalid-enum geterror-invalid-enum.c)
 add_executable (gl30basic gl30basic.c)
diff --git a/tests/general/getactiveattrib.c b/tests/general/getactiveattrib.c
new file mode 100644
index 0000000..7c01da1
--- /dev/null
+++ b/tests/general/getactiveattrib.c
@@ -0,0 +1,552 @@
+/*
+ * 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 getactiveattrib.c
+ * Verify that glGetActiveAttrib and GL_ACTIVE_ATTRIBUTES return the expected
+ * values for a variety of shaders.
+ *
+ * \author Ian Romanick
+ */
+
+#include "piglit-util.h"
+
+int piglit_width = 100, piglit_height = 100;
+int piglit_window_mode = GLUT_RGB | GLUT_DOUBLE;
+
+struct attribute {
+	/** Name of the attribute. */
+	const char *name;
+
+	/**
+	 * This attribute must be active in the linked shader.
+	 *
+	 * Some attributes must be active and some may or may not be active
+	 * (becuase a clever compiler could optimize them away.  Attributes
+	 * that must not be active should not be listed in
+	 * \c test::attributes.
+	 */
+	bool must_be_active;
+
+	/**
+	 * Expected (array) size of the attribute.
+	 *
+	 * \note
+	 * Attribute arrays aren't added until GLSL 1.50.
+	 */
+	GLint size;
+
+	/** Expected GLSL type of the attribute. */
+	GLenum type;
+};
+
+struct test {
+	const char *code;
+
+	unsigned num_attributes;
+
+	struct attribute attributes[16];
+};
+
+static const struct test glsl110_tests[] = {
+	/* The first group of tests tries all the possible types for vertex
+	 * shader inputs.
+	 */
+	{
+		"attribute float vertex;\n"
+		"void main() { gl_Position = vec4(vertex); }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT },
+		}
+	},
+	{
+		"attribute vec2 vertex;\n"
+		"void main() { gl_Position = vertex.xyxy; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_VEC2 },
+		}
+	},
+	{
+		"attribute vec3 vertex;\n"
+		"void main() { gl_Position = vertex.xyzx; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_VEC3 },
+		}
+	},
+	{
+		"attribute vec4 vertex;\n"
+		"void main() { gl_Position = vertex; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_VEC4 },
+		}
+	},
+	{
+		"attribute mat2 vertex;\n"
+		"void main() { gl_Position = vertex[0].xyxy; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_MAT2 },
+		}
+	},
+	{
+		"attribute mat3 vertex;\n"
+		"void main() { gl_Position = vertex[0].xyzx; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_MAT3 },
+		}
+	},
+	{
+		"attribute mat4 vertex;\n"
+		"void main() { gl_Position = vertex[0]; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_MAT4 },
+		}
+	},
+
+
+	/* Try using each of the built-in attributes one at a time.  Only the
+	 * first two glMultiTexCoord attributes are checked because that's all
+	 * an implementation is required to support.
+	 */
+	{
+		"void main() { gl_Position = gl_Color; }",
+		1,
+		{
+			{ "gl_Color",  true,  1, GL_FLOAT_VEC4 },
+		}
+	},
+	{
+		"void main() { gl_Position = gl_SecondaryColor; }",
+		1,
+		{
+			{ "gl_SecondaryColor", true,  1, GL_FLOAT_VEC4 },
+		}
+	},
+	{
+		"void main() { gl_Position = gl_Normal.xyzx; }",
+		1,
+		{
+			{ "gl_Normal", true,  1, GL_FLOAT_VEC3 },
+		}
+	},
+	{
+		"void main() { gl_Position = gl_Vertex; }",
+		1,
+		{
+			{ "gl_Vertex", true,  1, GL_FLOAT_VEC4 },
+		}
+	},
+	{
+		"void main() { gl_Position = gl_MultiTexCoord0; }",
+		1,
+		{
+			{ "gl_MultiTexCoord0", true,  1, GL_FLOAT_VEC4 },
+		}
+	},
+	{
+		"void main() { gl_Position = gl_MultiTexCoord1; }",
+		1,
+		{
+			{ "gl_MultiTexCoord1", true,  1, GL_FLOAT_VEC4 },
+		}
+	},
+	{
+		"void main() { gl_Position = vec4(gl_FogCoord); }",
+		1,
+		{
+			{ "gl_FogCoord", true,  1, GL_FLOAT },
+		}
+	},
+
+	/* Try various cases of using / not using some user-defined attributes
+	 * and some built-in attributes.
+	 */
+	{
+		"attribute vec4 not_used;\n"
+		"void main() { gl_Position = gl_Vertex; }",
+		1,
+		{
+			{ "gl_Vertex", true,  1, GL_FLOAT_VEC4 },
+		}
+	},
+	{
+		"attribute vec4 vertex;\n"
+		"void main() { gl_Position = vertex + gl_Vertex; }",
+		2,
+		{
+			{ "gl_Vertex", true,  1, GL_FLOAT_VEC4 },
+			{ "vertex",    true,  1, GL_FLOAT_VEC4 },
+		}
+	},
+	{
+		"attribute vec4 vertex;\n"
+		"void main() {\n"
+		"    gl_Position = vertex;\n"
+		"    if (false) gl_Position = gl_Vertex;\n"
+		"}",
+		2,
+		{
+			{ "gl_Vertex", false, 1, GL_FLOAT_VEC4 },
+			{ "vertex",    true,  1, GL_FLOAT_VEC4 },
+		}
+	},
+	{
+		"attribute vec4 vertex;\n"
+		"attribute vec2 alternate;\n"
+		"uniform bool use_alternate;\n"
+		"void main() {\n"
+		"    gl_Position = vertex;\n"
+		"    if (use_alternate) gl_Position = alternate.xyxy;\n"
+		"}",
+		2,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_VEC4 },
+			{ "alternate", true,  1, GL_FLOAT_VEC2 },
+		}
+	},
+};
+
+static const struct test glsl120_tests[] = {
+	/* Try all the possible types for vertex shader inputs.  Note that
+	 * this only checks the types that were added in GLSL 1.20.
+	 *
+	 * Since GLSL 1.20 doesn't add any new built-in attributes, there are
+	 * no other tests added in the GLSL 1.20 group.
+	 */
+	{
+		"#version 120\n"
+		"attribute mat2x3 vertex;\n"
+		"void main() { gl_Position = vertex[0].xxxx; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_MAT2x3 },
+		}
+	},
+	{
+		"#version 120\n"
+		"attribute mat2x4 vertex;\n"
+		"void main() { gl_Position = vertex[0].xxxx; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_MAT2x4 },
+		}
+	},
+	{
+		"#version 120\n"
+		"attribute mat3x2 vertex;\n"
+		"void main() { gl_Position = vertex[0].xxxx; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_MAT3x2 },
+		}
+	},
+	{
+		"#version 120\n"
+		"attribute mat3x4 vertex;\n"
+		"void main() { gl_Position = vertex[0].xxxx; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_MAT3x4 },
+		}
+	},
+	{
+		"#version 120\n"
+		"attribute mat4x2 vertex;\n"
+		"void main() { gl_Position = vertex[0].xxxx; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_MAT4x2 },
+		}
+	},
+	{
+		"#version 120\n"
+		"attribute mat4x3 vertex;\n"
+		"void main() { gl_Position = vertex[0].xxxx; }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_FLOAT_MAT4x3 },
+		}
+	},
+};
+
+static const struct test glsl130_tests[] = {
+	/* Try all the possible types for vertex shader inputs.  Note that
+	 * this only checks the types that were added in GLSL 1.30.
+	 *
+	 * Since GLSL 1.30 doesn't add any new built-in attributes, there are
+	 * no other tests added in the GLSL 1.30 group.
+	 */
+	{
+		"#version 130\n"
+		"in int vertex;\n"
+		"void main() { gl_Position = vec4(vertex); }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_INT },
+		}
+	},
+	{
+		"#version 130\n"
+		"in uint vertex;\n"
+		"void main() { gl_Position = vec4(vertex); }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_UNSIGNED_INT },
+		}
+	},
+	{
+		"#version 130\n"
+		"in ivec2 vertex;\n"
+		"void main() { gl_Position = vec4(vertex.x); }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_INT_VEC2 },
+		}
+	},
+	{
+		"#version 130\n"
+		"in uvec2 vertex;\n"
+		"void main() { gl_Position = vec4(vertex.x); }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_UNSIGNED_INT_VEC2 },
+		}
+	},
+	{
+		"#version 130\n"
+		"in ivec3 vertex;\n"
+		"void main() { gl_Position = vec4(vertex.x); }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_INT_VEC3 },
+		}
+	},
+	{
+		"#version 130\n"
+		"in uvec3 vertex;\n"
+		"void main() { gl_Position = vec4(vertex.x); }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_UNSIGNED_INT_VEC3 },
+		}
+	},
+	{
+		"#version 130\n"
+		"in ivec4 vertex;\n"
+		"void main() { gl_Position = vec4(vertex.x); }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_INT_VEC4 },
+		}
+	},
+	{
+		"#version 130\n"
+		"in uvec4 vertex;\n"
+		"void main() { gl_Position = vec4(vertex.x); }",
+		1,
+		{
+			{ "vertex",    true,  1, GL_UNSIGNED_INT_VEC4 },
+		}
+	},
+};
+
+enum piglit_result
+piglit_display(void)
+{
+	return PIGLIT_FAIL;
+}
+
+int
+find_attrib(const struct attribute *attribs, unsigned num_attribs,
+	    const char *name)
+{
+	unsigned i;
+
+	for (i = 0; i < num_attribs; i++) {
+		if (strcmp(attribs[i].name, name) == 0)
+			return (int) i;
+	}
+
+	return -1;
+}
+
+#define DUMP_SHADER(code)						\
+	do {								\
+		if (!shader_dumped) {					\
+			fprintf(stderr, "\nFailing shader:\n%s\n\n",	\
+				code);					\
+			shader_dumped = true;				\
+		}							\
+	} while (false)
+
+bool
+do_test(const struct test *tests, unsigned num_tests)
+{
+	bool pass = true;
+	unsigned i;
+
+	for (i = 0; i < num_tests; i++) {
+		GLint vert =
+			piglit_compile_shader_text(GL_VERTEX_SHADER,
+						   tests[i].code);
+		GLint prog = piglit_link_simple_program(vert, 0);
+		GLint num_attr;
+		unsigned visited_count[64];
+		unsigned j;
+		bool shader_dumped = false;
+
+		assert(tests[i].num_attributes <= ARRAY_SIZE(visited_count));
+
+		memset(visited_count, 0, sizeof(visited_count));
+
+		/* From page 93 (page 109 of the PDF) says:
+		 *
+		 *     "An attribute variable (either conventional or generic)
+		 *     is considered active if it is determined by the
+		 *     compiler and linker that the attribute may be accessed
+		 *     when the shader is executed. Attribute variables that
+		 *     are declared in a vertex shader but never used will not
+		 *     count against the limit. In cases where the compiler
+		 *     and linker cannot make a conclusive determination, an
+		 *     attribute will be considered active."
+		 *
+		 * Compare the set of active attributes against the list of
+		 * expected active attributes.
+		 */
+		piglit_GetProgramiv(prog, GL_ACTIVE_ATTRIBUTES, &num_attr);
+
+		for (j = 0; j < num_attr; j++) {
+			const struct attribute *attr;
+			char name_buf[256];
+			int attr_idx;
+			GLsizei name_len;
+			GLint size;
+			GLenum type;
+
+			glGetActiveAttrib(prog, j,
+					  sizeof(name_buf),
+					  &name_len,
+					  &size,
+					  &type,
+					  name_buf);
+			attr_idx = find_attrib(tests[i].attributes,
+					       tests[i].num_attributes,
+					       name_buf);
+
+			/* If the named attribute is not in the list for the
+			 * test, then it must not be active.
+			 */
+			if (attr_idx < 0) {
+				DUMP_SHADER(tests[i].code);
+				fprintf(stderr,
+					"Attribute `%s' should not be active "
+					"but is.\n", name_buf);
+				pass = false;
+				continue;
+			}
+
+			attr = &tests[i].attributes[attr_idx];
+			if (visited_count[attr_idx] != 0) {
+				DUMP_SHADER(tests[i].code);
+				fprintf(stderr,
+					"Attribute `%s' listed multiple times "
+					"in active list.\n", name_buf);
+				pass = false;
+			} else if (attr->size != size) {
+				DUMP_SHADER(tests[i].code);
+				fprintf(stderr,
+					"Attribute `%s' should have size %d, "
+					"but had size %d.\n",
+					name_buf, attr->size, size);
+				pass = false;
+			} else if (attr->type != type) {
+				DUMP_SHADER(tests[i].code);
+				fprintf(stderr,
+					"Attribute `%s' should have type "
+					"0x%04x, but had type 0x%04x.\n",
+					name_buf, attr->type, type);
+				pass = false;
+			}
+
+			visited_count[attr_idx]++;
+		}
+
+		for (j = 0; j < tests[i].num_attributes; j++) {
+			if (tests[i].attributes[j].must_be_active
+			    && visited_count[j] == 0) {
+				DUMP_SHADER(tests[i].code);
+				fprintf(stderr,
+					"Attribute `%s' should have been "
+					"active but wasn't.\n",
+					tests[i].attributes[j].name);
+				pass = false;
+			}
+		}
+	}
+
+	return pass;
+}
+
+void usage_and_fail(const char *name)
+{
+	fprintf(stderr, "Usage: %s [110|120|130]\n", name);
+	piglit_report_result(PIGLIT_FAIL);
+}
+
+void piglit_init(int argc, char **argv)
+{
+	bool pass = true;
+	unsigned i;
+
+	if (argc == 1) {
+		usage_and_fail(argv[0]);
+	}
+
+	for (i = 1; i < argc; i++) {
+		if (strcmp("110", argv[i]) == 0) {
+			pass = do_test(glsl110_tests,
+				       ARRAY_SIZE(glsl110_tests))
+				&& pass;
+		} else if (strcmp("120", argv[i]) == 0) {
+			piglit_require_GLSL_version(120);
+			pass = do_test(glsl120_tests,
+				       ARRAY_SIZE(glsl120_tests))
+				&& pass;
+		} else if (strcmp("130", argv[i]) == 0) {
+			piglit_require_GLSL_version(130);
+			pass = do_test(glsl130_tests,
+				       ARRAY_SIZE(glsl130_tests))
+				&& pass;
+		} else {
+			usage_and_fail(argv[0]);
+		}
+	}
+
+	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
+}
-- 
1.7.6.4



More information about the Piglit mailing list