[Piglit] [PATCH RFC v2] arb_shader_precision: add tests for floating point precision

Micah Fedke micah.fedke at collabora.co.uk
Fri Nov 7 15:01:41 PST 2014


This generated_tests script creates a suite of tests that measure the
floating point precision of most GLSL built-ins, according to
ARB_shader_precision.  Test vectors come from builtin_function.py, but
are filtered down to avoid non-float types.

These tests are reporting precision errors in ceil, cross, mod,
op-assign-div, op-assign-mult, div, mult, reflect and refract on
Ivybridge.
---

Updates since the first RFC:
Moved tests from tests/spec/ to generated_tests/ for much less NIH.  The
generator script creates fs, vs, gs and cs tests for all vectors that deal in
floats (eg. op-add-float-float but not op-add-ivec3-int).  Trig functions and
determinant() are excluded, as these do not have a required precision per
ARB_shader_precision.

I am concerned that the test vectors provided by builtin_function.py don't
probe the limits of the floating point format sufficiently, as floating point
error varies across the range of available floats, but this should be enough
for a first swing.

Note: I am new to the project and don't have commit access.

 generated_tests/CMakeLists.txt                |   5 +
 generated_tests/gen_shader_precision_tests.py | 610 ++++++++++++++++++++++++++
 tests/all.py                                  |  19 +
 3 files changed, 634 insertions(+)
 create mode 100644 generated_tests/gen_shader_precision_tests.py

diff --git a/generated_tests/CMakeLists.txt b/generated_tests/CMakeLists.txt
index 6d27b3e..ee381ac 100644
--- a/generated_tests/CMakeLists.txt
+++ b/generated_tests/CMakeLists.txt
@@ -31,6 +31,10 @@ piglit_make_generated_tests(
 	gen_constant_array_size_tests.py
 	builtin_function.py)
 piglit_make_generated_tests(
+	shader_precision_tests.list
+	gen_shader_precision_tests.py
+	builtin_function.py)
+piglit_make_generated_tests(
 	const_builtin_equal_tests.list
 	gen_const_builtin_equal_tests.py)
 piglit_make_generated_tests(
@@ -100,6 +104,7 @@ add_custom_target(gen-tests ALL
 		outerproduct_invalid_params.list
 		builtin_uniform_tests.list
 		constant_array_size_tests.list
+		shader_precision_tests.list
 		const_builtin_equal_tests.list
 		builtin_cl_int_tests.list
 		builtin_cl_math_tests.list
diff --git a/generated_tests/gen_shader_precision_tests.py b/generated_tests/gen_shader_precision_tests.py
new file mode 100644
index 0000000..3f091a8
--- /dev/null
+++ b/generated_tests/gen_shader_precision_tests.py
@@ -0,0 +1,610 @@
+# coding=utf-8
+#
+# 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.
+
+# Generate a set of shader_runner tests for every overloaded version
+# of every built-in function, based on the test vectors computed by
+# builtin_function.py.
+#
+# In each set of generated tests, one test exercises the built-in
+# function in each type of shader (vertex, geometry, and fragment).
+# In all cases, the inputs to the built-in function come from
+# uniforms, so that the effectiveness of the test won't be
+# circumvented by constant folding in the GLSL compiler.
+#
+# The tests operate by invoking the built-in function in the
+# appropriate shader, applying a scale and offset so that the expected
+# values are in the range [0.25, 0.75], and then outputting the result
+# as a solid rgba color, which is then checked using shader_runner's
+# "probe rgba" command.
+#
+# For built-in functions whose result type is a matrix, the test
+# checks one column at a time.
+#
+# This program outputs, to stdout, the name of each file it generates.
+# With the optional argument --names-only, it only outputs the names
+# of the files; it doesn't generate them.
+
+from builtin_function import *
+import abc
+import numpy
+import optparse
+import os
+import os.path
+import sys
+
+
+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_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 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)
+        # need special handling when testing distance or when the rettype
+        # is a matrix or vector
+        if self.__signature.name == 'distance' or \
+                self.__signature.rettype.is_matrix or self.__signature.rettype.is_vector:
+            statements += '  int resultbits[{0}] = int[{0}]({1});\n'.format(
+                self.__signature.rettype.num_cols*self.__signature.rettype.num_rows, ', '.join(
+                    'floatBitsToInt(result{0})'.format(indexer) for indexer in self.make_indexers()))
+            statements += '  int expectedbits[{0}] = int[{0}]({1});\n'.format(
+                self.__signature.rettype.num_cols*self.__signature.rettype.num_rows, ', '.join(
+                    'floatBitsToInt(expected{0})'.format(indexer) for indexer in self.make_indexers()))
+            statements += '  bool signerr = {0};\n'.format(
+                    ' || '.join(('(resultbits[{0}]>>31 != expectedbits[{0}]>>31)'.format(index) 
+                        for index in range(0, self.__signature.rettype.num_cols*self.__signature.rettype.num_rows))))
+            # use the equivalent length(p0-p1) when testing distance()
+            if self.__signature.name == 'distance':
+                statements += '  {0} ulps = {0}({1});\n'.format(
+                        self.__signature.rettype, ', '.join(
+                        'length(resultbits[{0}] - expectedbits[{0}])'.format(index) 
+                        for index in range(0, self.__signature.rettype.num_cols*self.__signature.rettype.num_rows)))
+            else:
+                statements += '  {0} ulps = {0}({1});\n'.format(
+                        self.__signature.rettype, ', '.join(
+                        'distance(resultbits[{0}],expectedbits[{0}])'.format(index) 
+                        for index in range(0, self.__signature.rettype.num_cols*self.__signature.rettype.num_rows)))
+            indexers = self.make_indexers()
+            statements += '  float max_error = {0}{1}{2}{3};\n'.format(
+                   'max( ' if self.__signature.rettype.num_cols*self.__signature.rettype.num_rows > 2 else '',
+                   'max('.join(
+                       'ulps{0}, '.format(indexer)
+                       for indexer in indexers[:len(indexers)-2]), 
+                   'max(ulps{0}, ulps{1})'.format(indexers[len(indexers)-2], indexers[len(indexers)-1]),
+                   ''.join(')'.format(index) for index in range(0, self.__signature.rettype.num_cols*self.__signature.rettype.num_rows-2)))
+            condition = '!signerr && max_error <= tolerance'
+        else:
+            statements += '  int resultbits = floatBitsToInt(result);\n'
+            statements += '  int expectedbits = floatBitsToInt(expected);\n'
+            statements += '  bool signerr = resultbits>>31 != expectedbits>>31;\n'
+            statements += '  float ulps = distance(resultbits, expectedbits);\n'
+            condition = '!signerr && ulps <= 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(column_major_values(test_vector.result)))
+        override_tolerances = {'pow': 16.0, 
+                               'exp': 3.0,
+                               'exp2': 3.0,
+                               'log': 3.0,
+                               'log2': 3.0,
+                               'sqrt': 3.0,
+                               'inversesqrt': 2.0}
+        if self.__signature.name in override_tolerances:
+           override_tolerance = override_tolerances[self.__signature.name]
+        else:
+           override_tolerance = 0.0
+        test += 'uniform float tolerance {0}\n'.format(
+            override_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):
+        """Prepare to build a test for a single built-in.  signature
+        is the signature of the built-in (a key from the
+        builtin_function.test_suite dict), and test_vectors is the
+        list of test vectors for testing the given builtin (the
+        corresponding value from the builtin_function.test_suite
+        dict).
+        """
+        self._signature = signature
+        self._test_vectors = test_vectors
+        if signature.rettype.base_type == glsl_float or signature.rettype.base_type == glsl_bool:
+            self._comparator = FloatComparator(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(
+                        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 += 'piglit_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, 'precision', 'built-in-functions',
+            '{0}-{1}-{2}{3}.shader_test'.format(
+                self.test_prefix(), self._signature.name, argtype_names,
+                self._comparator.testname_suffix()))
+
+    def generate_shader_test(self):
+        """Generate the test and write it to the output file."""
+        shader_test = '[require]\n'
+        # ARB_shader_precision was introduced in GL 4.1 / GLSL 4.10
+        shader_test += 'GLSL >= 4.10\n'
+        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)
+
+
+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 piglit_vertex;\n' +
+                'out vec4 color;\n',
+                '  gl_Position = piglit_vertex;\n',
+                'color', '')
+        else:
+            return self.make_test_shader(
+                'attribute vec4 piglit_vertex;\n' +
+                'varying vec4 color;\n',
+                '  gl_Position = piglit_vertex;\n',
+                'color', '')
+
+    def make_fragment_shader(self):
+        shader = '''varying vec4 color;
+
+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 piglit_vertex;\n"
+        shader += "varying vec4 vertex_to_gs;\n"
+
+        shader += "void main()\n"
+        shader += "{\n"
+        shader += "     vertex_to_gs = piglit_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 = ""
+        shader += "attribute vec4 piglit_vertex;\n"
+        shader += "void main()\n"
+        shader += "{\n"
+        shader += "        gl_Position = piglit_vertex;\n"
+        shader += "}\n"
+
+        return shader
+
+    def make_fragment_shader(self):
+        return self.make_test_shader('', '', 'gl_FragColor', '')
+
+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 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')
+
+    def make_test_init(self):
+        return '''uniform int tex 0
+texture rgbw 0 (16, 16)
+image texture 0
+fb tex 2d 0
+'''
+
+
+    def draw_command(self):
+        return 'compute 1 1 1\n'
+
+
+def all_tests():
+    trig_names = ('sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh')
+    for signature, test_vectors in sorted(test_suite.items()):
+        # Create a bool list of all the arguments for this vector telling whether 
+        # each is a float type (float, vec2, mat2, etc.) or not
+        arg_float_check = tuple(
+                        arg.base_type == glsl_float for arg in signature.argtypes)
+        # Filter the test vectors down to only those which deal exclusively in float types
+        #and are not trig functions or determinant()
+        if signature.rettype.base_type == glsl_float and \
+           arg_float_check and \
+           all(arg_float_check) and \
+           signature.name not in trig_names and \
+           signature.name != 'determinant':
+            yield VertexShaderTest(signature, test_vectors)
+            yield GeometryShaderTest(signature, test_vectors)
+            yield FragmentShaderTest(signature, test_vectors)
+            yield ComputeShaderTest(signature, test_vectors)
+
+
+def main():
+    numpy.set_printoptions(precision=11)
+    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()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/all.py b/tests/all.py
index 3a2f4e2..d56582e 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -1061,6 +1061,9 @@ spec['glsl-1.10']['built-in constants'] = PiglitGLTest('built-in-constants ' + o
 
 spec['glsl-1.10']['api'] = {}
 add_concurrent_test(spec['glsl-1.10']['api'], 'getactiveattrib 110');
+spec['glsl-1.10']['precision'] = {}
+add_shader_test_dir(spec['glsl-1.10']['precision'], os.path.join(generatedTestDir, 'spec', 'glsl-1.10', 'precision'),
+                    recursive=True)
 
 # Group spec/glsl-1.20
 spec['glsl-1.20'] = {}
@@ -1135,6 +1138,10 @@ add_concurrent_test(spec['glsl-1.20']['execution'], 'tex-miplevel-selection GL2:
 add_concurrent_test(spec['glsl-1.20']['execution'], 'tex-miplevel-selection GL2:textureProj(bias) 1DShadow')
 add_concurrent_test(spec['glsl-1.20']['execution'], 'tex-miplevel-selection GL2:textureProj(bias) 2DShadow')
 
+spec['glsl-1.20']['precision'] = {}
+add_shader_test_dir(spec['glsl-1.20']['precision'], os.path.join(generatedTestDir, 'spec', 'glsl-1.20', 'precision'),
+                    recursive=True)
+
 
 # Group spec/glsl-1.30
 spec['glsl-1.30'] = {}
@@ -1386,6 +1393,10 @@ add_concurrent_test(spec['glsl-1.30']['execution'], 'tex-miplevel-selection text
 add_concurrent_test(spec['glsl-1.30']['execution'], 'tex-miplevel-selection textureProjGradOffset 1DShadow')
 add_concurrent_test(spec['glsl-1.30']['execution'], 'tex-miplevel-selection textureProjGradOffset 2DShadow')
 
+spec['glsl-1.30']['precision'] = {}
+add_shader_test_dir(spec['glsl-1.30']['precision'], os.path.join(generatedTestDir, 'spec', 'glsl-1.30', 'precision'),
+                    recursive=True)
+
 # Group spec/glsl-1.40
 spec['glsl-1.40'] = {}
 import_glsl_parser_tests(spec['glsl-1.40'],
@@ -1420,6 +1431,10 @@ for stage in ['vs', 'gs', 'fs']:
                 'texelFetch offset 140 {0} {1}'.format(stage, sampler),
                 run_concurrent=True)
 
+spec['glsl-1.40']['precision'] = {}
+add_shader_test_dir(spec['glsl-1.40']['precision'], os.path.join(generatedTestDir, 'spec', 'glsl-1.40', 'precision'),
+                    recursive=True)
+
 spec['glsl-1.50'] = {}
 import_glsl_parser_tests(spec['glsl-1.50'],
                          os.path.join(testsDir, 'spec', 'glsl-1.50'),
@@ -1498,6 +1513,10 @@ for output_layout in ['points', 'lines', 'lines_adjacency', 'triangles',
                         'glsl-1.50-gs-output-layout-qualifiers {0}'.format(
                             output_layout))
 
+spec['glsl-1.50']['precision'] = {}
+add_shader_test_dir(spec['glsl-1.50']['precision'], os.path.join(generatedTestDir, 'spec', 'glsl-1.50', 'precision'),
+                    recursive=True)
+
 spec['glsl-3.30'] = {}
 spec['glsl-3.30']['built-in constants'] = PiglitGLTest('built-in-constants ' + os.path.join(testsDir, 'spec/glsl-3.30/minimum-maximums.txt'), run_concurrent=True)
 
-- 
2.1.2


More information about the Piglit mailing list