[Piglit] [PATCH 05/12] generated_tests: Test tessellation evaluation shader input.

Chris Forbes chrisf at ijw.co.nz
Wed Sep 17 00:42:18 PDT 2014


From: Fabian Bieler <fabianbieler at fastmail.fm>

For every GLSL variable type, generate four tests. One passes a per-vertex
and one a per-patch varying of said type as a scalar from the tessellation
control to the tessellation evaluation shader. The two other tests do the same
for a two-element array of that type.

The varying gets filled in the tessellation control shader from a uniform and
compared against the same uniform in the tessellation evaluation shader.

Every test draws 4 patches, each of which gets tessellated into a quad that
fills a quarter of the screen.

Also test core profile built-in varyings in gl_PerVertex.
---
 generated_tests/CMakeLists.txt         |   4 +
 generated_tests/gen_tes_input_tests.py | 330 +++++++++++++++++++++++++++++++++
 2 files changed, 334 insertions(+)
 create mode 100644 generated_tests/gen_tes_input_tests.py

diff --git a/generated_tests/CMakeLists.txt b/generated_tests/CMakeLists.txt
index 6d27b3e..e8129a7 100644
--- a/generated_tests/CMakeLists.txt
+++ b/generated_tests/CMakeLists.txt
@@ -34,6 +34,9 @@ piglit_make_generated_tests(
 	const_builtin_equal_tests.list
 	gen_const_builtin_equal_tests.py)
 piglit_make_generated_tests(
+	tes_input_tests.list
+	gen_tes_input_tests.py)
+piglit_make_generated_tests(
 	interpolation_tests.list
 	gen_interpolation_tests.py)
 piglit_make_generated_tests(
@@ -105,6 +108,7 @@ add_custom_target(gen-tests ALL
 		builtin_cl_math_tests.list
 		builtin_cl_relational_tests.list
 		cl_store_tests.list
+		tes_input_tests.list
 		interpolation_tests.list
 		non-lvalue_tests.list
 		texture_query_lod_tests.list
diff --git a/generated_tests/gen_tes_input_tests.py b/generated_tests/gen_tes_input_tests.py
new file mode 100644
index 0000000..4c6d06d
--- /dev/null
+++ b/generated_tests/gen_tes_input_tests.py
@@ -0,0 +1,330 @@
+#!/usr/bin/env python
+# coding=utf-8
+#
+# Copyright © 2014 The Piglit Project
+#
+# 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.
+
+## Test passing variables from the tessellation control shader to the
+# tessellation evaluation shader.
+#
+# For every combination of varying type as scalar and as two element array and
+# per-vertex or per-patch varying create a test that that passes said variable
+# between the tessellation shader stages.
+#
+# Copy a uniform value to the varying in the tessellation control shader and
+# compare the varying to the same uniform in the tessellation evaluation
+# shader.
+# If the values are equal draw the screen green, red otherwise.
+#
+# Draw for tessellated quads. Each should cover one quarter of the screen.
+#
+# This script outputs, to stdout, the name of each file it generates.
+
+import os, sys, random
+
+
+class Test(object):
+    def __init__(self, type_name, array, patch_in, name):
+        """Creates a test.
+
+        type_name -- varying type to test (e.g.: vec4, mat3x2, int, ...)
+        array -- number of array elements to test, None for no array
+        patch_in -- true for per-patch varying, false for per-vertex varying
+        name -- name of the variable to test
+
+        """
+        self.var_name = name or 'var';
+        self.use_block = 0 if patch_in else 1
+
+        if self.var_name == 'gl_Position':
+            self.var_type = 'vec4'
+            self.var_array = None
+            self.patch_in = False
+        elif self.var_name == 'gl_PointSize':
+            self.var_type = 'float'
+            self.var_array = None
+            self.patch_in = False
+        elif self.var_name == 'gl_ClipDistance':
+            self.var_type = 'float'
+            self.var_array = 8
+            self.patch_in = False
+        else:
+            self.var_type = type_name
+            self.var_array = array
+            self.patch_in = patch_in
+
+        if self.built_in:
+            self.interface_name = 'gl_PerVertex'
+            self.interface_tcs_instance = 'gl_out'
+            self.interface_tes_instance = 'gl_in'
+        else:
+            self.interface_name = 'tc2te_interface'
+            self.interface_tcs_instance = '' if self.patch_in else 'tc2te'
+            self.interface_tes_instance = '' if self.patch_in else 'tc2te'
+
+        if self.var_array:
+            self.var_type_full = self.var_type + '[{0}]'.format(self.var_array)
+        else:
+            self.var_type_full = self.var_type
+
+        if self.patch_in:
+            self.interface_prefix = 'patch '
+            self.interface_postfix = ''
+        else:
+            self.interface_prefix = ''
+            self.interface_postfix = '[]'
+
+    @property
+    def built_in(self):
+        return self.var_name.startswith('gl_')
+
+    @property
+    def tcs_var_ref(self):
+        return '[gl_InvocationID].' + self.var_name if self.interface_tcs_instance else self.var_name
+
+    @property
+    def tes_var_ref(self):
+        return '[i].' + self.var_name if self.interface_tes_instance else self.var_name
+
+    @property
+    def tcs_reference_index(self):
+        return 'gl_PrimitiveID' if self.patch_in else 'gl_PrimitiveID * vertices_in + gl_InvocationID'
+
+    @property
+    def tes_reference_index(self):
+        return 'gl_PrimitiveID' if self.patch_in else 'gl_PrimitiveID * vertices_in + i'
+
+    @property
+    def reference_size(self):
+        return 4 if self.patch_in else 12
+
+    @property
+    def uniform_string(self):
+        """Returns string for loading uniform data by the shader_runner."""
+        data = self.test_data()
+        uniforms = ''
+        if (self.var_array):
+            for i in range(self.reference_size):
+                for j in range(self.var_array):
+                    uniforms += 'uniform {0} reference[{1}].v[{2}] {3}\n'.format(
+                            self.var_type, i, j, data[i*j])
+        else:
+            for i in range(self.reference_size):
+                uniforms += 'uniform {0} reference[{1}].v {2}\n'.format(
+                        self.var_type,
+                        i,
+                        data[i])
+
+        #strip last newline
+        return uniforms[:-1]
+
+    def components(self):
+        """Returns the number of scalar components of the used data type."""
+        n = 1
+
+        if self.var_type.startswith('mat'):
+            if 'x' in self.var_type:
+                n *= int(self.var_type[-1])
+                n *= int(self.var_type[-3])
+            else:
+                n *= int(self.var_type[-1])
+                n *= int(self.var_type[-1])
+        elif 'vec' in self.var_type:
+            n *= int(self.var_type[-1])
+
+        return n
+
+    def test_data(self):
+        """Returns random but deterministic data as a list of strings.
+
+        n strings are returned containing c random values, each.
+        Where n is the number of vertices times the array length and
+        c is the number of components in the tested scalar data type.
+        """
+        random.seed(17)
+
+        if self.var_array:
+            n = self.var_array * self.reference_size
+        else:
+            n = self.reference_size
+
+        if self.var_type.startswith('i'):
+            rand = lambda : random.randint(-0x80000000, 0x7fffffff)
+        elif self.var_type.startswith('u'):
+            rand = lambda : random.randint(0, 0xffffffff)
+        else:
+            rand = lambda : ((-1 + 2 * random.randint(0, 1)) *
+                             random.randint(0, 2**23-1) *
+                             2.0**(random.randint(-126, 127)))
+
+        c = self.components()
+
+        ret = []
+        for i in range(n):
+            ret.append(" ".join([str(rand()) for _ in range(c)]))
+
+        return ret
+
+    def filename(self):
+        """Returns the file name (including path) for the test."""
+        if (self.built_in):
+            name = self.var_name
+        elif (self.var_array):
+            name = self.var_type + '_{0}'.format(self.var_array)
+        else:
+            name = self.var_type
+        if self.patch_in:
+            name = 'patch-' + name
+        return os.path.join('spec',
+                            'arb_tessellation_shader',
+                            'execution',
+                            'tes-input',
+                            'tes-input-{0}.shader_test'.format(name))
+
+    def generate(self):
+        """Generates and writes the test to disc."""
+        test = \
+"""# Test generated by:
+# {generator_command}
+# Test tessellation control shader inputs
+[require]
+GLSL >= 1.50
+GL_ARB_tessellation_shader
+
+[vertex shader]
+void main()
+{{
+	gl_Position = vec4(0);
+}}
+
+[tessellation control shader]
+#extension GL_ARB_tessellation_shader : require
+layout(vertices = 3) out;
+
+uniform struct S0 {{
+	{self.var_type_full} v;
+}} reference[12];
+
+#if {self.use_block}
+{self.interface_prefix}out {self.interface_name} {{
+	{self.var_type_full} {self.var_name};
+}} {self.interface_tcs_instance}{self.interface_postfix};
+#else
+{self.interface_prefix}out {self.var_type_full} {self.var_name};
+#endif
+
+void main()
+{{
+	const int vertices_in = 3;
+	{self.interface_tcs_instance}{self.tcs_var_ref} = reference[{self.tcs_reference_index}].v;
+	gl_TessLevelOuter = float[4](1.0, 1.0, 1.0, 1.0);
+	gl_TessLevelInner = float[2](1.0, 1.0);
+}}
+
+[tessellation evaluation shader]
+#extension GL_ARB_tessellation_shader : require
+layout(quads) in;
+
+uniform struct S0 {{
+	{self.var_type_full} v;
+}} reference[12];
+
+#if {self.use_block}
+{self.interface_prefix}in {self.interface_name} {{
+	{self.var_type_full} {self.var_name};
+}} {self.interface_tes_instance}{self.interface_postfix};
+#else
+{self.interface_prefix}in {self.var_type_full} {self.var_name};
+#endif
+
+out vec4 vert_color;
+
+void main()
+{{
+	const int vertices_in = 3;
+	const vec4 red = vec4(1, 0, 0, 1);
+	const vec4 green = vec4(0, 1, 0, 1);
+	vert_color = green;
+	for (int i = 0; i < vertices_in; ++i)
+		if ({self.interface_tes_instance}{self.tes_var_ref} != reference[{self.tes_reference_index}].v)
+			vert_color = red;
+	vec2[3] position = vec2[3](
+		vec2(float(gl_PrimitiveID / 2) - 1.0, float(gl_PrimitiveID % 2) - 1.0),
+		vec2(float(gl_PrimitiveID / 2) - 0.0, float(gl_PrimitiveID % 2) - 1.0),
+		vec2(float(gl_PrimitiveID / 2) - 1.0, float(gl_PrimitiveID % 2) - 0.0)
+	);
+	gl_Position = vec4(position[0]
+	            + (position[1] - position[0]) * gl_TessCoord[0]
+	            + (position[2] - position[0]) * gl_TessCoord[1], 0.0, 1.0);
+}}
+
+[fragment shader]
+
+in vec4 vert_color;
+
+out vec4 frag_color;
+
+void main()
+{{
+	frag_color = vert_color;
+}}
+
+[test]
+{self.uniform_string}
+draw arrays GL_PATCHES 0 12
+relative probe rgb (0.25, 0.25) (0.0, 1.0, 0.0)
+relative probe rgb (0.75, 0.25) (0.0, 1.0, 0.0)
+relative probe rgb (0.25, 0.75) (0.0, 1.0, 0.0)
+relative probe rgb (0.75, 0.75) (0.0, 1.0, 0.0)
+"""
+
+        test = test.format(self = self,
+            generator_command = " ".join(sys.argv))
+
+        filename = self.filename()
+        dirname = os.path.dirname(filename)
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+        with open(filename, 'w') as f:
+            f.write(test)
+
+
+def all_tests():
+    for type_name in ['float', 'vec2',  'vec3',  'vec4',
+                      'mat2', 'mat3', 'mat4',
+                      'mat2x3', 'mat2x4', 'mat3x2',
+                      'mat3x4', 'mat4x2', 'mat4x3',
+                      'int', 'ivec2', 'ivec3', 'ivec4',
+                      'uint', 'uvec2', 'uvec3', 'uvec4']:
+        for array in [None, 2]:
+            for patch_in in [True, False]:
+                    yield Test(type_name, array, patch_in, name=None)
+    for var in ['gl_Position', 'gl_PointSize', 'gl_ClipDistance']:
+        yield Test(type_name=None, array=None, patch_in=False, name=var);
+
+def main():
+    for test in all_tests():
+        test.generate()
+        print(test.filename())
+
+
+if __name__ == '__main__':
+    main()
-- 
2.1.0



More information about the Piglit mailing list