[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