[Piglit] [RFC 09/12] gen_builtin_uniform_tests.py: Use mako to generate tests

Dylan Baker baker.dylan.c at gmail.com
Mon Dec 8 17:11:30 PST 2014


This patch changes gen_builtin_uniform_tests to use mako to generate
tests, rather than direct string concatenation.

Signed-off-by: Dylan Baker <dylanx.c.baker at intel.com>
---
 generated_tests/CMakeLists.txt                     |   5 +
 generated_tests/builtins/glsl_types.py             |  21 +
 generated_tests/gen_builtin_uniform_tests.py       | 712 ++-------------------
 .../gen_builtin_uniform_tests/cs.shader_test.mako  |  41 ++
 .../gen_builtin_uniform_tests/fs.shader_test.mako  |  48 ++
 .../gen_builtin_uniform_tests/gs.shader_test.mako  |  59 ++
 .../templates/gen_builtin_uniform_tests/utils.mako | 211 ++++++
 .../gen_builtin_uniform_tests/vs.shader_test.mako  |  52 ++
 8 files changed, 505 insertions(+), 644 deletions(-)
 create mode 100644 generated_tests/templates/gen_builtin_uniform_tests/cs.shader_test.mako
 create mode 100644 generated_tests/templates/gen_builtin_uniform_tests/fs.shader_test.mako
 create mode 100644 generated_tests/templates/gen_builtin_uniform_tests/gs.shader_test.mako
 create mode 100644 generated_tests/templates/gen_builtin_uniform_tests/utils.mako
 create mode 100644 generated_tests/templates/gen_builtin_uniform_tests/vs.shader_test.mako

diff --git a/generated_tests/CMakeLists.txt b/generated_tests/CMakeLists.txt
index 98379c5..1f50318 100644
--- a/generated_tests/CMakeLists.txt
+++ b/generated_tests/CMakeLists.txt
@@ -36,6 +36,11 @@ piglit_make_generated_tests(
 	builtins/glsl_types.py
 	builtins/generators.py
 	builtins/math.py
+	templates/gen_builtin_uniform_tests/utils.mako
+	templates/gen_builtin_uniform_tests/vs.shader_test.mako
+	templates/gen_builtin_uniform_tests/fs.shader_test.mako
+	templates/gen_builtin_uniform_tests/gs.shader_test.mako
+	templates/gen_builtin_uniform_tests/cs.shader_test.mako
 	)
 piglit_make_generated_tests(
 	constant_array_size_tests.list
diff --git a/generated_tests/builtins/glsl_types.py b/generated_tests/builtins/glsl_types.py
index 084dcda..038fcd7 100644
--- a/generated_tests/builtins/glsl_types.py
+++ b/generated_tests/builtins/glsl_types.py
@@ -97,6 +97,27 @@ class GlslBuiltinType(object):
         """
         return self.__version_introduced
 
+    @property
+    def as_shader_runner_uniform(self):
+        """Return this glsl_type as expected by shader_runner.
+
+        Specifically this is the format expected by shader_runner for it's
+        uniform command.
+
+        Boolans and vectors are converted to ints, square matricies are
+        rendered in matNxN, everything else is just self.__str__.
+
+        """
+        if self.base_type is GLSL_BOOL:
+            if self.is_scalar:
+                return 'int'
+            else:
+                return 'ivec{}'.format(self.num_rows)
+        elif self.is_matrix:
+            return 'mat{0}x{1}'.format(self.num_cols, self.num_rows)
+        else:
+            return str(self)
+
     def __str__(self):
         return self.__name
 
diff --git a/generated_tests/gen_builtin_uniform_tests.py b/generated_tests/gen_builtin_uniform_tests.py
index 4e83bb6..05e16e2 100644
--- a/generated_tests/gen_builtin_uniform_tests.py
+++ b/generated_tests/gen_builtin_uniform_tests.py
@@ -43,674 +43,98 @@ doesn't generate them.
 
 """
 
-from __future__ import absolute_import
-import abc
-import optparse
+from __future__ import absolute_import, print_function
 import os
 
-import numpy as np
-
-from builtins import glsl_types, generators
 import builtin_function
+from builtins import glsl_types
+from templates import template_dir
 
+TEMPLATES = template_dir(os.path.basename(os.path.splitext(__file__)[0]))
 
-def compute_offset_and_scale(test_vectors):
-    """Compute scale and offset values such that for each result in
-    test_vectors, (result - offset) * scale is in the range [0.25,
-    0.75], and scale is less than or equal to 1.0.  These values are
-    used to transform the test vectors so that their outputs can be
-    stored in gl_FragColor without overflow.
-    """
-    low = min(np.min(tv.result) for tv in test_vectors)
-    hi = max(np.max(tv.result) for tv in test_vectors)
-    span = hi - low
-    center = (hi + low)/2.0
-    span *= 2.0
-    if span < 1.0:
-        span = 1.0
-    offset = center - span/2.0
-    scale = 1.0/span
-    return offset, scale
-
-
-def shader_runner_format(values):
-    """Format the given values for use in a shader_runner "uniform" or
-    "probe rgba" command.  Bools are converted to 0's and 1's, and
-    values are separated by spaces.
-    """
-    transformed_values = []
-    for value in values:
-        if isinstance(value, (bool, np.bool_)):
-            transformed_values.append(int(value))
-        else:
-            transformed_values.append(value)
-    return ' '.join(repr(x) for x in transformed_values)
-
-
-def shader_runner_type(glsl_type):
-    """Return the appropriate type name necessary for binding a
-    uniform of the given type using shader_runner's "uniform" command.
-    Boolean values and vectors are converted to ints, and square
-    matrices are written in "matNxN" form.
-    """
-    if glsl_type.base_type == glsl_types.GLSL_BOOL:
-        if glsl_type.is_scalar:
-            return 'int'
-        else:
-            return 'ivec{0}'.format(glsl_type.num_rows)
-    elif glsl_type.is_matrix:
-        return 'mat{0}x{1}'.format(glsl_type.num_cols, glsl_type.num_rows)
-    else:
-        return str(glsl_type)
-
-
-class Comparator(object):
-    """Base class which abstracts how we compare expected and actual
-    values.
-    """
-    __metaclass__ = abc.ABCMeta
-
-    def make_additional_declarations(self):
-        """Return additional declarations, if any, that are needed in
-        the shader program.
-        """
-        return ''
-
-    @abc.abstractmethod
-    def make_result_handler(self, invocation, output_var):
-        """Return the shader code that is needed to produce the result
-        and store it in output_var.
-
-        invocation is the GLSL code to compute the output of the
-        built-in function.
-        """
-
-    @abc.abstractmethod
-    def make_result_test(self, test_num, test_vector):
-        """Return the shader_runner test code that is needed to test a
-        single test vector.
-        """
-
-    def testname_suffix(self):
-        """Return a string to be used as a suffix on the test name to
-        distinguish it from tests using other comparators."""
-        return ''
-
-
-class BoolComparator(Comparator):
-    """Comparator that tests functions returning bools and bvecs by
-    converting them to floats.
-
-    This comparator causes code to be generated in the following form:
-
-        rettype result = func(args);
-        output_var = vec4(result, 0.0, ...);
-    """
-    def __init__(self, signature):
-        assert not signature.rettype.is_matrix
-        self.__signature = signature
-        self.__padding = 4 - signature.rettype.num_rows
-
-    def make_result_handler(self, invocation, output_var):
-        statements = '  {0} result = {1};\n'.format(
-            self.__signature.rettype, invocation)
-        statements += '  {0} = vec4(result{1});\n'.format(
-            output_var, ', 0.0' * self.__padding)
-        return statements
-
-    def convert_to_float(self, value):
-        """Convert the given vector or scalar value to a list of
-        floats representing the expected color produced by the test.
-        """
-        value = value*1.0  # convert bools to floats
-        value = generators.column_major_values(value)
-        value += [0.0] * self.__padding
-        return value
-
-    def make_result_test(self, test_num, test_vector, draw):
-        test = draw
-        test += 'probe rgba {0} 0 {1}\n'.format(
-            test_num,
-            shader_runner_format(self.convert_to_float(test_vector.result)))
-        return test
-
-
-class BoolIfComparator(Comparator):
-    """Comparator that tests functions returning bools by evaluating
-    them inside an if statement.
-
-    This comparator causes code to be generated in the following form:
-
-        if (func(args))
-          output_var = vec4(1.0, 1.0, 0.0, 1.0);
-        else
-          output_var = vecp(0.0, 0.0, 1.0, 1.0);
-    """
-    def __init__(self, signature):
-        assert signature.rettype == glsl_types.GLSL_BOOL
-        self.__padding = 4 - signature.rettype.num_rows
-
-    def make_result_handler(self, invocation, output_var):
-        statements = '  if({0})\n'.format(invocation)
-        statements += '    {0} = vec4(1.0, 1.0, 0.0, 1.0);\n'.format(
-            output_var)
-        statements += '  else\n'
-        statements += '    {0} = vec4(0.0, 0.0, 1.0, 1.0);\n'.format(
-            output_var)
-        return statements
-
-    def convert_to_float(self, value):
-        """Convert the given vector or scalar value to a list of
-        floats representing the expected color produced by the test.
-        """
-        if value:
-            return [1.0, 1.0, 0.0, 1.0]
-        else:
-            return [0.0, 0.0, 1.0, 1.0]
-
-    def make_result_test(self, test_num, test_vector, draw):
-        test = draw
-        test += 'probe rgba {0} 0 {1}\n'.format(
-            test_num,
-            shader_runner_format(self.convert_to_float(test_vector.result)))
-        return test
-
-    def testname_suffix(self):
-        return '-using-if'
-
-
-class IntComparator(Comparator):
-    """Comparator that tests functions returning ints or ivecs using a
-    strict equality test.
-
-    This comparator causes code to be generated in the following form:
-
-        rettype result = func(args);
-        output_var = result == expected ? vec4(0.0, 1.0, 0.0, 1.0)
-                                        : vec4(1.0, 0.0, 0.0, 1.0);
-    """
-    def __init__(self, signature):
-        self.__signature = signature
-
-    def make_additional_declarations(self):
-        return 'uniform {0} expected;\n'.format(self.__signature.rettype)
-
-    def make_result_handler(self, invocation, output_var):
-        statements = '  {0} result = {1};\n'.format(
-            self.__signature.rettype, invocation)
-        statements += '  {v} = {cond} ? {green} : {red};\n'.format(
-            v=output_var, cond='result == expected',
-            green='vec4(0.0, 1.0, 0.0, 1.0)',
-            red='vec4(1.0, 0.0, 0.0, 1.0)')
-        return statements
-
-    def make_result_test(self, test_num, test_vector, draw):
-        test = 'uniform {0} expected {1}\n'.format(
-            shader_runner_type(self.__signature.rettype),
-            shader_runner_format(generators.column_major_values(
-                test_vector.result)))
-        test += draw
-        test += 'probe rgba {0} 0 0.0 1.0 0.0 1.0\n'.format(test_num)
-        return test
-
-
-class FloatComparator(Comparator):
-    """Comparator that tests functions returning floats or vecs using a
-    strict equality test.
-
-    This comparator causes code to be generated in the following form:
-
-        rettype result = func(args);
-        output_var = distance(result, expected) <= tolerance
-                     ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
-    """
-    def __init__(self, signature):
-        self.__signature = signature
-
-    def make_additional_declarations(self):
-        decls = 'uniform float tolerance;\n'
-        decls += 'uniform {0} expected;\n'.format(self.__signature.rettype)
-        return decls
-
-    def make_indexers(self):
-        """Build a list of strings which index into every possible
-        value of the result.  For example, if the result is a vec2,
-        then build the indexers ['[0]', '[1]'].
-        """
-        if self.__signature.rettype.num_cols == 1:
-            col_indexers = ['']
-        else:
-            col_indexers = ['[{0}]'.format(i)
-                            for i in xrange(self.__signature.rettype.num_cols)]
-        if self.__signature.rettype.num_rows == 1:
-            row_indexers = ['']
-        else:
-            row_indexers = ['[{0}]'.format(i)
-                            for i in xrange(self.__signature.rettype.num_rows)]
-        return [col_indexer + row_indexer
-                for col_indexer in col_indexers
-                for row_indexer in row_indexers]
-
-    def make_result_handler(self, invocation, output_var):
-        statements = '  {0} result = {1};\n'.format(
-            self.__signature.rettype, invocation)
-        # Can't use distance when testing itself, or when the rettype
-        # is a matrix.
-        if self.__signature.name == 'distance' or \
-                self.__signature.rettype.is_matrix:
-            statements += '  {0} residual = result - expected;\n'.format(
-                self.__signature.rettype)
-            statements += '  float error_sq = {0};\n'.format(
-                ' + '.join(
-                    'residual{0} * residual{0}'.format(indexer)
-                    for indexer in self.make_indexers()))
-            condition = 'error_sq <= tolerance * tolerance'
-        else:
-            condition = 'distance(result, expected) <= tolerance'
-        statements += '  {v} = {cond} ? {green} : {red};\n'.format(
-            v=output_var, cond=condition, green='vec4(0.0, 1.0, 0.0, 1.0)',
-            red='vec4(1.0, 0.0, 0.0, 1.0)')
-        return statements
-
-    def make_result_test(self, test_num, test_vector, draw):
-        test = 'uniform {0} expected {1}\n'.format(
-            shader_runner_type(self.__signature.rettype),
-            shader_runner_format(generators.column_major_values(
-                test_vector.result)))
-        test += 'uniform float tolerance {0}\n'.format(
-            shader_runner_format([test_vector.tolerance]))
-        test += draw
-        test += 'probe rgba {0} 0 0.0 1.0 0.0 1.0\n'.format(test_num)
-        return test
-
-
-class ShaderTest(object):
-    """Class used to build a test of a single built-in.  This is an
-    abstract base class--derived types should override test_prefix(),
-    make_vertex_shader(), make_fragment_shader(), and other functions
-    if necessary.
-    """
-    __metaclass__ = abc.ABCMeta
-
-    def __init__(self, signature, test_vectors, use_if):
-        """Prepare to build a test for a single built-in.  signature
-        is the signature of the built-in (a key from the
-        glsl_types_function.test_suite dict), and test_vectors is the
-        list of test vectors for testing the given glsl_types (the
-        corresponding value from the glsl_types_function.test_suite
-        dict).
-
-        If use_if is True, then the generated test checks the result
-        by using it in an if statement--this only works for glsl_typess
-        returning bool.
-        """
-        self._signature = signature
-        self._test_vectors = test_vectors
-        if use_if:
-            self._comparator = BoolIfComparator(signature)
-        elif signature.rettype.base_type == glsl_types.GLSL_BOOL:
-            self._comparator = BoolComparator(signature)
-        elif signature.rettype.base_type == glsl_types.GLSL_FLOAT:
-            self._comparator = FloatComparator(signature)
-        elif signature.rettype.base_type in (glsl_types.GLSL_INT,
-                                             glsl_types.GLSL_UINT):
-            self._comparator = IntComparator(signature)
-        else:
-            raise Exception('Unexpected rettype {0}'.format(signature.rettype))
-
-    def glsl_version(self):
-        return self._signature.version_introduced
-
-    def draw_command(self):
-        if self.glsl_version() >= 140:
-            return 'draw arrays GL_TRIANGLE_FAN 0 4\n'
-        else:
-            return 'draw rect -1 -1 2 2\n'
-
-    def make_additional_requirements(self):
-        """Return a string that should be included in the test's
-        [require] section.
-        """
-        return ''
-
-    @abc.abstractmethod
-    def test_prefix(self):
-        """Return the prefix that should be used in the test file name
-        to identify the type of test, e.g. "vs" for a vertex shader
-        test.
-        """
-
-    def make_vertex_shader(self):
-        """Return the vertex shader for this test (or None if this
-        test doesn't require a vertex shader).  No need to
-        reimplement this function in classes that don't use vertex
-        shaders.
-        """
-        return None
-
-    def make_geometry_shader(self):
-        """Return the geometry shader for this test (or None if this
-        test doesn't require a geometry shader).  No need to
-        reimplement this function in classes that don't use geometry
-        shaders.
-        """
-        return None
-
-    def make_geometry_layout(self):
-        """Return the geometry layout for this test (or None if this
-        test doesn't require a geometry layout section).  No need to
-        reimplement this function in classes that don't use geometry
-        shaders.
-        """
-        return None
-
-    def make_fragment_shader(self):
-        """Return the fragment shader for this test (or None if this
-        test doesn't require a fragment shader).  No need to
-        reimplement this function in classes that don't use fragment
-        shaders.
-        """
-        return None
-
-    def make_compute_shader(self):
-        """Return the compute shader for this test (or None if this test
-        doesn't require a compute shader).  No need to reimplement
-        this function in classes that don't use compute shaders.
-        """
-        return None
-
-    def make_test_shader(self, additional_declarations, prefix_statements,
-                         output_var, suffix_statements):
-        """Generate the shader code necessary to test the built-in.
-        additional_declarations is a string containing any
-        declarations that need to be before the main() function of the
-        shader.  prefix_statements is a string containing any
-        additional statements than need to be inside the main()
-        function of the shader, before the built-in function is
-        called.  output_var is the variable that the result of the
-        built-in function should be assigned to, after conversion to a
-        vec4.  suffix_statements is a string containing any additional
-        statements that need to be inside the main() funciton of the
-        shader, after the built-in function is called.
-        """
-        shader = ''
-        if self._signature.extension:
-            shader += '#extension GL_{0} : require\n'.format(self._signature.extension)
-        shader += additional_declarations
-        for i in xrange(len(self._signature.argtypes)):
-            shader += 'uniform {0} arg{1};\n'.format(
-                self._signature.argtypes[i], i)
-        shader += self._comparator.make_additional_declarations()
-        shader += '\n'
-        shader += 'void main()\n'
-        shader += '{\n'
-        shader += prefix_statements
-        invocation = self._signature.template.format(
-            *['arg{0}'.format(i)
-              for i in xrange(len(self._signature.argtypes))])
-        shader += self._comparator.make_result_handler(invocation, output_var)
-        shader += suffix_statements
-        shader += '}\n'
-        return shader
-
-    def make_test_init(self):
-        """Generate initialization for the test.
-        """
-        return ''
-
-    def make_test(self):
-        """Make the complete shader_runner test file, and return it as
-        a string.
-        """
-        test = self.make_test_init()
-        for test_num, test_vector in enumerate(self._test_vectors):
-            for i in xrange(len(test_vector.arguments)):
-                test += 'uniform {0} arg{1} {2}\n'.format(
-                    shader_runner_type(self._signature.argtypes[i]),
-                    i,
-                    shader_runner_format(generators.column_major_values(
-                        test_vector.arguments[i])))
-            # Note: shader_runner uses a 250x250 window so we must
-            # ensure that test_num <= 250.
-            test += self._comparator.make_result_test(
-                test_num % 250, test_vector, self.draw_command())
-        return test
-
-    def make_vbo_data(self):
-        # Starting with GLSL 1.40/GL 3.1, we need to use VBOs and
-        # vertex shader input bindings for our vertex data instead of
-        # the piglit drawing utilities and gl_Vertex.
-        if self.glsl_version() < 140:
-            return ""
-        vbo = '[vertex data]\n'
-        vbo += 'vertex/float/2\n'
-        vbo += '-1.0 -1.0\n'
-        vbo += ' 1.0 -1.0\n'
-        vbo += ' 1.0  1.0\n'
-        vbo += '-1.0  1.0\n'
-        vbo += '\n'
-        return vbo
 
-    def filename(self):
-        argtype_names = '-'.join(
-            str(argtype) for argtype in self._signature.argtypes)
-        if self._signature.extension:
-            subdir = self._signature.extension.lower()
-        else:
-            subdir = 'glsl-{0:1.2f}'.format(float(self.glsl_version()) / 100)
-        return os.path.join(
-            'spec', subdir, 'execution', 'built-in-functions',
-            '{0}-{1}-{2}{3}.shader_test'.format(
-                self.test_prefix(), self._signature.name, argtype_names,
-                self._comparator.testname_suffix()))
+def _select_comparator(signature, use_if):
+    """Select the apropriate comparison function."""
+    if use_if:
+        return 'boolif'
+    elif signature.rettype.base_type == glsl_types.GLSL_BOOL:
+        return 'bool'
+    elif signature.rettype.base_type == glsl_types.GLSL_FLOAT:
+        return 'float'
+    elif signature.rettype.base_type in (glsl_types.GLSL_INT,
+                                         glsl_types.GLSL_UINT):
+        return 'int'
 
-    def generate_shader_test(self):
-        """Generate the test and write it to the output file."""
-        shader_test = '[require]\n'
-        shader_test += 'GLSL >= {0:1.2f}\n'.format(
-            float(self.glsl_version()) / 100)
-        shader_test += self.make_additional_requirements()
-        shader_test += '\n'
-        vs = self.make_vertex_shader()
-        if vs:
-            shader_test += '[vertex shader]\n'
-            shader_test += vs
-            shader_test += '\n'
-        gs = self.make_geometry_shader()
-        if gs:
-            shader_test += '[geometry shader]\n'
-            shader_test += gs
-            shader_test += '\n'
-        gl = self.make_geometry_layout()
-        if gl:
-            shader_test += '[geometry layout]\n'
-            shader_test += gl
-            shader_test += '\n'
-        fs = self.make_fragment_shader()
-        if fs:
-            shader_test += '[fragment shader]\n'
-            shader_test += fs
-            shader_test += '\n'
-        cs = self.make_compute_shader()
-        if cs:
-            shader_test += '[compute shader]\n'
-            shader_test += cs
-            shader_test += '\n'
-        if vs:
-            shader_test += self.make_vbo_data()
-        shader_test += '[test]\n'
-        shader_test += self.make_test()
-        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(shader_test)
 
+def _get_glsl_version(signature, stage):
+    """Set the apropriate version.
 
-class VertexShaderTest(ShaderTest):
-    """Derived class for tests that exercise the built-in in a vertex
-    shader.
-    """
-    def test_prefix(self):
-        return 'vs'
-
-    def make_vertex_shader(self):
-        if self.glsl_version() >= 140:
-            return self.make_test_shader(
-                'in vec4 vertex;\n' +
-                'out vec4 color;\n',
-                '  gl_Position = vertex;\n',
-                'color', '')
-        else:
-            return self.make_test_shader(
-                'varying vec4 color;\n',
-                '  gl_Position = gl_Vertex;\n',
-                'color', '')
-
-    def make_fragment_shader(self):
-        shader = '''varying vec4 color;
+    normally signature introduced is the correct value, but for some stages
+    that isn't correct.
 
-void main()
-{
-  gl_FragColor = color;
-}
-'''
-        return shader
-
-
-class GeometryShaderTest(ShaderTest):
-    """Derived class for tests that exercise the built-in in a
-    geometry shader.
     """
-    def test_prefix(self):
-        return 'gs'
-
-    def glsl_version(self):
-        return max(150, ShaderTest.glsl_version(self))
-
-    def make_vertex_shader(self):
-        shader = ''
-        shader += "in vec4 vertex;\n"
-        shader += "out vec4 vertex_to_gs;\n"
-
-        shader += "void main()\n"
-        shader += "{\n"
-        shader += "     vertex_to_gs = vertex;\n"
-        shader += "}\n"
-
-        return shader
-
-    def make_geometry_shader(self):
-        additional_declarations = ''
-        additional_declarations += 'layout(triangles) in;\n'
-        additional_declarations \
-            += 'layout(triangle_strip, max_vertices = 3) out;\n'
-        additional_declarations += 'in vec4 vertex_to_gs[3];\n'
-        additional_declarations += 'out vec4 color;\n'
-        return self.make_test_shader(
-            additional_declarations,
-            '  vec4 tmp_color;\n',
-            'tmp_color',
-            '  for (int i = 0; i < 3; i++) {\n'
-            '    gl_Position = vertex_to_gs[i];\n'
-            '    color = tmp_color;\n'
-            '    EmitVertex();\n'
-            '  }\n')
-
-    def make_fragment_shader(self):
-        shader = '''varying vec4 color;
-
-void main()
-{
-  gl_FragColor = color;
-}
-'''
-        return shader
-
-
-class FragmentShaderTest(ShaderTest):
-    """Derived class for tests that exercise the built-in in a
-    fragment shader.
-    """
-    def test_prefix(self):
-        return 'fs'
-
-    def make_vertex_shader(self):
-        shader = ""
-        if self.glsl_version() >= 140:
-            shader += "in vec4 vertex;\n"
-
-        shader += "void main()\n"
-        shader += "{\n"
-        if self.glsl_version() >= 140:
-            shader += "        gl_Position = vertex;\n"
-        else:
-            shader += "        gl_Position = gl_Vertex;\n"
-        shader += "}\n"
-
-        return shader
+    if stage == 'gs':
+        return max(150, signature.version_introduced)
+    elif stage == 'cs':
+        return max(430, signature.version_introduced)
+    return signature.version_introduced
+
+
+def _filename(signature, version, use_if, stage):
+    """Generate the filename."""
+    argtype_names = '-'.join(str(s) for s in signature.argtypes)
+    if signature.extension:
+        subdir = signature.extension.lower()
+    else:
+        subdir = 'glsl-{0:1.2f}'.format(float(version) / 100)
+    return os.path.join(
+        'spec', subdir, 'execution', 'built-in-functions',
+        '{0}-{1}-{2}{3}.shader_test'.format(
+            stage, signature.name, argtype_names,
+            '-using-if' if use_if else ''))
 
-    def make_fragment_shader(self):
-        return self.make_test_shader('', '', 'gl_FragColor', '')
 
+def _get_draw(stage, version):
+    """get the draw function."""
+    if stage == 'cs':
+        return 'compute 1 1 1\n'
+    if version >= 140:
+        return 'draw arrays GL_TRIANGLE_FAN 0 4\n'
+    else:
+        return 'draw rect -1 -1 2 2\n'
 
-class ComputeShaderTest(ShaderTest):
-    """Derived class for tests that exercise the built-in in a
-    compute shader.
-    """
-    def test_prefix(self):
-        return 'cs'
 
-    def glsl_version(self):
-        return max(430, ShaderTest.glsl_version(self))
+def generate(signature, vectors, use_if, stage):
+    """Create a test with the given inputs."""
+    template = TEMPLATES.get_template('{}.shader_test.mako'.format(stage))
+    version = _get_glsl_version(signature, stage)
+    filename = _filename(signature, version, use_if, stage)
 
-    def make_compute_shader(self):
-        additional_declarations = 'writeonly uniform image2D tex;\n'
-        additional_declarations += 'layout(local_size_x = 16, local_size_y = 16) in;\n'
-        return self.make_test_shader(
-            additional_declarations,
-            '  vec4 tmp_color;\n',
-            'tmp_color',
-            '  ivec2 coord = ivec2(gl_GlobalInvocationID.xy);\n'
-            '  imageStore(tex, coord, tmp_color);\n')
+    if not os.path.exists(os.path.dirname(filename)):
+        os.makedirs(os.path.dirname(filename))
 
-    def make_test_init(self):
-        return '''uniform int tex 0
-texture rgbw 0 (16, 16)
-image texture 0
-fb tex 2d 0
-'''
+    print(filename)
 
+    with open(filename, 'w') as f:
+        f.write(template.render(
+            draw=_get_draw(stage, version),
+            comparator=_select_comparator(signature, use_if),
+            signature=signature,
+            vectors=vectors,
+            glsl_version=version))
 
-    def draw_command(self):
-        return 'compute 1 1 1\n'
 
 def all_tests():
-    for use_if in [False, True]:
-        for signature, test_vectors in sorted(builtin_function.test_suite.items()):
-            if use_if and signature.rettype != glsl_types.GLSL_BOOL:
-                continue
-            yield VertexShaderTest(signature, test_vectors, use_if)
-            yield GeometryShaderTest(signature, test_vectors, use_if)
-            yield FragmentShaderTest(signature, test_vectors, use_if)
-            yield ComputeShaderTest(signature, test_vectors, use_if)
+    for signature, test_vectors in builtin_function.test_suite.iteritems():
+        yield signature, test_vectors, False
+        if signature.rettype == glsl_types.GLSL_BOOL:
+            yield signature, test_vectors, True
 
 
 def main():
-    desc = 'Generate shader tests that test built-in functions using uniforms'
-    usage = 'usage: %prog [-h] [--names-only]'
-    parser = optparse.OptionParser(description=desc, usage=usage)
-    parser.add_option(
-        '--names-only',
-        dest='names_only',
-        action='store_true',
-        help="Don't output files, just generate a list of filenames to stdout")
-    options, args = parser.parse_args()
-    for test in all_tests():
-        if not options.names_only:
-            test.generate_shader_test()
-        print test.filename()
+    for sig, vecs, use_if in all_tests():
+        for stage in ['vs', 'fs', 'gs', 'cs']:
+            generate(sig, vecs, use_if, stage)
 
 
 if __name__ == '__main__':
diff --git a/generated_tests/templates/gen_builtin_uniform_tests/cs.shader_test.mako b/generated_tests/templates/gen_builtin_uniform_tests/cs.shader_test.mako
new file mode 100644
index 0000000..60b4df1
--- /dev/null
+++ b/generated_tests/templates/gen_builtin_uniform_tests/cs.shader_test.mako
@@ -0,0 +1,41 @@
+## Copyright (C) 2014 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 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.
+##
+## Create a vertex shader test.
+##
+<%namespace name="utils" file="utils.mako"/>
+
+[require]
+GLSL >= ${'{:1.2f}'.format(float(glsl_version) / 100)}
+
+[compute shader]
+% if signature.extension:
+#extension GL_${signature.extension} : require
+% endif
+writeonly uniform image2D tex;
+layout(local_size_x = 16, local_size_y = 16) in;
+${utils.make_shader(signature, comparator, 'tmp_color', prefix=['vec4 tmp_color;'], suffix=['ivec2 coord = ivec2(gl_GlobalInvocationID.xy);', 'imageStore(tex, coord, tmp_color);'], extension=False)}
+
+[test]
+uniform int tex 0
+texture rgbw 0 (16, 16)
+image texture 0
+fb tex 2d 0
+${utils.make_test(vectors, signature, draw, comparator)}
diff --git a/generated_tests/templates/gen_builtin_uniform_tests/fs.shader_test.mako b/generated_tests/templates/gen_builtin_uniform_tests/fs.shader_test.mako
new file mode 100644
index 0000000..75935f1
--- /dev/null
+++ b/generated_tests/templates/gen_builtin_uniform_tests/fs.shader_test.mako
@@ -0,0 +1,48 @@
+## Copyright (C) 2014 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 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.
+##
+## Create a vertex shader test.
+##
+<%namespace name="utils" file="utils.mako"/>
+
+[require]
+GLSL >= ${'{:1.2f}'.format(float(glsl_version) / 100)}
+
+[vertex shader]
+% if glsl_version >= 140:
+in vec4 vertex;
+% endif
+
+void main()
+{
+% if glsl_version >= 140:
+  gl_Position = vertex;
+% else:
+  gl_Position = gl_Vertex;
+% endif
+}
+
+[fragment shader]
+${utils.make_shader(signature, comparator, 'gl_FragColor')}
+
+${utils.make_vertex_data(glsl_version)}
+
+[test]
+${utils.make_test(vectors, signature, draw, comparator)}
diff --git a/generated_tests/templates/gen_builtin_uniform_tests/gs.shader_test.mako b/generated_tests/templates/gen_builtin_uniform_tests/gs.shader_test.mako
new file mode 100644
index 0000000..81ed1b8
--- /dev/null
+++ b/generated_tests/templates/gen_builtin_uniform_tests/gs.shader_test.mako
@@ -0,0 +1,59 @@
+## Copyright (C) 2014 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 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.
+##
+## Create a vertex shader test.
+##
+<%namespace name="utils" file="utils.mako"/>
+
+[require]
+GLSL >= ${'{:1.2f}'.format(float(glsl_version) / 100)}
+
+[vertex shader]
+in vec4 vertex;
+out vec4 vertex_to_gs;
+
+void main()
+{
+  vertex_to_gs = vertex;
+}
+
+[geometry shader]
+% if signature.extension:
+#extension GL_${signature.extension} : require
+% endif
+layout(triangles) in;
+layout(triangle_strip, max_vertices = 3) out;
+in vec4 vertex_to_gs[3];
+out vec4 color;
+
+${utils.make_shader(signature, comparator, 'tmp_color', prefix=['vec4 tmp_color;'], suffix=['for (int i = 0; i < 3; i++) {', 'gl_Position = vertex_to_gs[i];', 'color = tmp_color;', 'EmitVertex();', '}'], extension=False)}
+
+[fragment shader]
+varying vec4 color;
+
+void main()
+{
+  gl_FragColor = color;
+}
+
+${utils.make_vertex_data(glsl_version)}
+
+[test]
+${utils.make_test(vectors, signature, draw, comparator)}
diff --git a/generated_tests/templates/gen_builtin_uniform_tests/utils.mako b/generated_tests/templates/gen_builtin_uniform_tests/utils.mako
new file mode 100644
index 0000000..742a703
--- /dev/null
+++ b/generated_tests/templates/gen_builtin_uniform_tests/utils.mako
@@ -0,0 +1,211 @@
+## Copyright (C) 2014 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 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.
+
+## Provides shared helper function written in mako for generating tests.
+##
+## These function are shared across the different shader stages, and allow
+## for clear focuses templates for each stage without the need to to
+## reimplement the same functionality multiple times
+
+<%!
+    # Ideally this would all be in a python module, but I can't figure out
+    # how to get a mako template to import a python module that isn't already
+    # in the sys.path, the normal sys.path.append trick doesn't seem to work
+    
+    import numpy as np
+
+
+    def column_major_values(value):
+        """Ripped straight out of builtins.generators."""
+        if isinstance(value, np.ndarray):
+            return list(np.reshape(value, -1, 'F'))
+        else:
+            return [value]
+
+
+    def shader_runner_format(values):
+        """Transform a list of values for shader_runner 'uniform' and 'probe'.
+
+        Shader_runner requires that bools be converted to 0 or 1 and seperated by
+        spaces. This function produces a string formatted as such
+
+        """
+        def gen():
+            for value in values:
+                if isinstance(value, (bool, np.bool_)):
+                    yield int(value)
+                else:
+                    yield value
+
+        return ' '.join(repr(x) for x in gen())
+
+
+    def bool_to_float(value, signature):
+        v = column_major_values(value * 1.0)
+        v.extend([0.0] * (4 - signature.rettype.num_rows))
+        return v
+
+
+    def make_indexer(signature):
+        if signature.rettype.num_cols == 1:
+            col_indexers = ['']
+        else:
+            col_indexers = ['[{}]'.format(i) for i in xrange(signature.rettype.num_cols)]
+
+        if signature.rettype.num_rows == 1:
+            row_indexers = ['']
+        else:
+            row_indexers = ['[{}]'.format(i) for i in xrange(signature.rettype.num_rows)]
+
+        return [c + r for c in col_indexers for r in row_indexers]
+
+
+    def invocation(signature):
+        return signature.template.format(
+            *['arg{0}'.format(i)for i in xrange(len(signature.argtypes))])
+%>
+
+<%def name="make_test(vectors, signature, draw, comparator)" filter='trim'>
+  ## XXX: make test init needs to be handled by the individual generators
+  % for n, vector in enumerate(vectors):
+    % for i in xrange(len(vector.arguments)):
+      uniform ${signature.argtypes[i].as_shader_runner_uniform} arg${i} ${shader_runner_format(column_major_values(vector.arguments[i]))}
+    % endfor
+
+    % if comparator == 'boolif':
+      ${test_bool_if(n, vector, draw, signature)}
+    % elif comparator == 'bool':
+      ${test_bool(n, vector, draw, signature)}
+    % elif comparator == 'int':
+      ${test_int(n, vector, draw, signature)}
+    % elif comparator == 'float':
+      ${test_float(n, vector, draw, signature)}
+    % endif
+  % endfor
+</%def>
+
+<%def name="test_bool(test_num, vector, draw, signature)" filter='trim'>
+  ${draw}
+  probe rgba ${test_num % 250} 0 ${shader_runner_format(bool_to_float(vector.result, signature))}
+</%def>
+
+<%def name="test_bool_if(test_num, vector, draw, signature)" filter='trim'>
+  ${draw}
+  probe rgba ${test_num % 250} 0 ${shader_runner_format([1.0, 1.0, 0.0, 1.0] if vector.result else [0.0, 0.0, 1.0, 1.0])}
+</%def>
+
+<%def name="test_int(test_num, vector, draw, signature)" filter='trim'>
+  uniform ${signature.rettype.as_shader_runner_uniform} expected ${shader_runner_format(column_major_values(vector.result))}
+  ${draw}
+  probe rgba ${test_num % 250} 0 0.0 1.0 0.0 1.0
+</%def>
+
+<%def name="test_float(test_num, vector, draw, signature)" filter='trim'>
+  uniform ${signature.rettype.as_shader_runner_uniform} expected ${shader_runner_format(column_major_values(vector.result))}
+  uniform float tolerance ${shader_runner_format([vector.tolerance])}
+  ${draw}
+  probe rgba ${test_num % 250} 0 0.0 1.0 0.0 1.0
+</%def>
+
+## XXX: original signature (additional_declarations, prefix_statements, output_var, suffix_statement)
+##      additional_declarations -> declarations (originally string, now list)
+##      prefix_statements -> prefix
+##      suffix_statements -> suffix
+##      output_var -> output
+## TODO: Kill declarations, just handle those in the individual templates
+## TODO: convert prefix and suffix to lists
+<%def name="make_shader(signature, comparator, output, prefix=[], suffix=[], extension=True)" filter='trim'>
+  % if extension and signature.extension:
+    #extension GL_${signature.extension} : require
+  % endif
+
+  % for i in xrange(len(signature.argtypes)):
+    uniform ${signature.argtypes[i]} arg${i};
+  % endfor
+
+  % if comparator == 'int':
+    uniform ${signature.rettype} expected;
+  % elif comparator == 'float':
+    uniform float tolerance;
+    uniform ${signature.rettype} expected;
+  % endif
+
+  void main()
+  {
+    % for line in prefix:
+      ${line}
+    % endfor
+    % if comparator == 'boolif':
+      ${result_bool_if(output, signature)}
+    % elif comparator == 'bool':
+      ${result_bool(output, signature)}
+    % elif comparator == 'int':
+      ${result_int(output, signature)}
+    % elif comparator == 'float':
+      ${result_float(output, signature)}
+    % endif
+    % for line in suffix:
+      ${line}
+    % endfor
+  }
+</%def>
+
+<%def name="result_bool(output, signature)" filter='trim'>
+  ${signature.rettype} result = ${invocation(signature)};
+  % if signature.rettype.num_rows != 4:
+    ${output} = vec4(result, ${', '.join(['0.0'] * (4 - signature.rettype.num_rows))});
+  % else:
+    ${output} = vec4(result);
+  % endif
+</%def>
+
+<%def name="result_bool_if(output, signature)" filter='trim'>
+  if (${invocation(signature)})
+    ${output} = vec4(1.0, 1.0, 0.0, 1.0);
+  else
+    ${output} = vec4(0.0, 0.0, 1.0, 1.0);
+</%def>
+
+<%def name="result_int(output, signature)" filter='trim'>
+  ${signature.rettype} result = ${invocation(signature)};
+  ${output} = result == expected ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
+</%def>
+
+<%def name="result_float(output, signature)" filter='trim'>
+  ${signature.rettype} result = ${invocation(signature)};
+  % if signature.name == 'distance' or signature.rettype.is_matrix:
+    ${signature.rettype} residual = result - expected;
+    float error_sq = ${' + '.join('residual{0} * residual{0}'.format(i) for i in make_indexer(signature))};
+    ${output} = error_sq <= tolerance * tolerance ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
+  % else:
+    ${output} = distance(result, expected) <= tolerance ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
+  % endif
+</%def>
+
+<%def name="make_vertex_data(glsl_version)" filter='trim'>
+  % if glsl_version >= 140:
+    [vertex data]
+    vertex/float/2
+    -1.0 -1.0 
+     1.0 -1.0
+     1.0  1.0
+    -1.0  1.0 
+  % endif
+</%def>
diff --git a/generated_tests/templates/gen_builtin_uniform_tests/vs.shader_test.mako b/generated_tests/templates/gen_builtin_uniform_tests/vs.shader_test.mako
new file mode 100644
index 0000000..c03cd06
--- /dev/null
+++ b/generated_tests/templates/gen_builtin_uniform_tests/vs.shader_test.mako
@@ -0,0 +1,52 @@
+## Copyright (C) 2014 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 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.
+##
+## Create a vertex shader test.
+##
+<%namespace name="utils" file="utils.mako"/>
+
+[require]
+GLSL >= ${'{:1.2f}'.format(float(glsl_version) / 100)}
+
+[vertex shader]
+% if signature.extension:
+#extension GL_${signature.extension} : require
+% endif
+% if glsl_version >= 140:
+  in vec4 vertex;
+  out vec4 color;
+  ${utils.make_shader(signature, comparator, 'color', prefix=['gl_Position = vertex;'], extension=False)}
+% else:
+  varying vec4 color;
+  ${utils.make_shader(signature, comparator, 'color', prefix=['gl_Position = gl_Vertex;'], extension=False)}
+% endif
+
+[fragment shader]
+varying vec4 color;
+
+void main()
+{
+  gl_FragColor = color;
+}
+
+${utils.make_vertex_data(glsl_version)}
+
+[test]
+${utils.make_test(vectors, signature, draw, comparator)}
-- 
2.2.0



More information about the Piglit mailing list