diff options
author | Paul Berry <stereotype441@gmail.com> | 2011-08-10 16:03:43 -0700 |
---|---|---|
committer | Paul Berry <stereotype441@gmail.com> | 2011-08-15 11:18:46 -0700 |
commit | 62f30256a3970b847ef228dabc4a4c07f0b19b84 (patch) | |
tree | a895a562ea5f760126b16c53f834d377d924e64c | |
parent | 70bff3c40bba136c29e04fddfbc42f81a9a500cd (diff) |
Add operator tests to auto-generated built-in function tests.
This patch adds tests for the following built-in GLSL operators:
- op-add, op-sub, op-mult, op-div: binary arithemetic operators on
floats, vecs, mats, ints, and ivecs.
- op-uplus, op-neg: unary arithmetic operators on floats, vecs, mats,
ints, and ivecs.
- op-gt, op-lt, op-ge, op-le: comparison operators on ints and floats.
- op-eq, op-ne: equality and inequality comparison on any GLSL 1.20 type.
- op-and, op-or, op-xor: logical operations on bools.
- op-not: unary logical not on bools.
- op-selection: trinary selection operator (x?y:z), where the first
argument is a bool and the second and third arguments are any GLSL
1.20 type.
Note that implicit type conversions are not tested. So, for instance,
int * ivec is tested, but float * ivec is not. This was in an effort
to avoid generating an outrageous number of tests.
Note also that the "shortcut" behavior of logical and/or and trinary
selection is not tested.
These tests leverage the same test generation framework used to test
built-in functions, so the tests exercise vertex shaders, fragment
shaders, and constant folding.
All in all 1332 tests are added, in the subtrees
spec/glsl-1.{10,20}/{compiler,execution}/built-in-functions.
Reviewed-by: Eric Anholt <eric@anholt.net>
-rw-r--r-- | generated_tests/builtin_function.py | 273 | ||||
-rw-r--r-- | generated_tests/gen_builtin_uniform_tests.py | 39 | ||||
-rw-r--r-- | generated_tests/gen_constant_array_size_tests.py | 23 |
3 files changed, 266 insertions, 69 deletions
diff --git a/generated_tests/builtin_function.py b/generated_tests/builtin_function.py index 7a4244157..efc4afaad 100644 --- a/generated_tests/builtin_function.py +++ b/generated_tests/builtin_function.py @@ -22,17 +22,25 @@ # DEALINGS IN THE SOFTWARE. # This source file defines a set of test vectors that can be used to -# test GLSL's built-in functions. It is intended to be used by -# Python code that generates Piglit tests. +# test GLSL's built-in functions and operators. It is intended to be +# used by Python code that generates Piglit tests. # # The key export is the dictionary test_suite. It contains an entry -# for each possible overload of every pure built-in function. By -# iterating through this dictionary you can find a set of test vectors -# for testing nearly every built-in GLSL function. Notable exceptions -# include the fragment shader functions dFdx(), dFdy(), and fwidth(), -# the texture lookup functions, and the ftransform() function, since -# they are not pure, so they can't be tested using simple test -# vectors. +# for each possible overload of every pure built-in function and +# operator. By iterating through this dictionary you can find a set +# of test vectors for testing nearly every built-in GLSL function. +# +# The following functions are not included, since they are not pure, +# so they can't be tested using simple vectors: +# - dFdx() +# - dFdy() +# - fwidth() +# - ftransform() +# - Increment and decrement operators +# +# Also not tested are array subscripting, field/method selection, +# swizzling, the function call operator, assignment, and the sequence +# operator. import collections import itertools @@ -140,13 +148,18 @@ glsl_mat4x4 = glsl_mat4 # Named tuple representing the signature of a single overload of a -# built-in GLSL function: -# - name is the function name. +# built-in GLSL function or operator: +# - name is a name suitable for use in test filenames. For functions, +# this is the name of the function. For operators, it is a short +# description of the operator, beginning with "op", e.g. "op-plus". +# - template is a Python format string that can be used to construct +# GLSL code that invokes the function or operator. # - version_introduced earliest version of GLSL the test applies to # (as a string, e.g. '1.10'). -# - rettype is the return type of the function (as a GlslBuiltinType). -# - argtypes is a tuple containing the types of each function -# parameter (as GlslBuiltinTypes). +# - rettype is the return type of the function or operator (as a +# GlslBuiltinType). +# - argtypes is a tuple containing the types of each parameter (as +# GlslBuiltinTypes). # # For example, the function # @@ -154,10 +167,12 @@ glsl_mat4x4 = glsl_mat4 # # has a signature of # -# Signature(name='step', version_introduced='1.10', rettype='vec3', +# Signature(name='step', template='step({0}, {1})', +# version_introduced='1.10', rettype='vec3', # argtypes=('float', 'vec3')) Signature = collections.namedtuple( - 'Signature', ('name', 'version_introduced', 'rettype', 'argtypes')) + 'Signature', + ('name', 'template', 'version_introduced', 'rettype', 'argtypes')) @@ -292,6 +307,41 @@ test_suite = {} # in cases where there is a behavioral difference). These functions # return None if the behavior of the GLSL built-in is undefined for # the given set of inputs. +def _multiply(x, y): + x_type = glsl_type_of(x) + y_type = glsl_type_of(y) + + if x_type.is_vector and y_type.is_vector: + # vector * vector is done componentwise. + return x * y + else: + # All other cases are standard linear algebraic + # multiplication, which numpy calls "dot". + return np.dot(x, y) + +def _divide(x, y): + if any(y_element == 0 for y_element in column_major_values(y)): + # Division by zero is undefined. + return None + if glsl_type_of(x).base_type == glsl_int: + # The GLSL spec does not make it clear what the rounding rules + # are when performing integer division. C99 requires + # round-toward-zero, so in the absence of any other + # information, assume that's the correct behavior for GLSL. + # + # Python and numpy's rounding rules are inconsistent, so to + # make sure we get round-toward-zero behavior, divide the + # absolute values of x and y, and then fix the sign. + return (np.abs(x) // np.abs(y)) * (np.sign(x) * np.sign(y)) + else: + return x / y + +def _equal(x, y): + return all(column_major_values(x == y)) + +def _not_equal(x, y): + return not _equal(x, y) + def _arctan2(y, x): if x == y == 0.0: return None @@ -521,7 +571,8 @@ def _vectorize_test_vectors(test_vectors, scalar_arg_indices, vector_length): -def _store_test_vector(test_suite_dict, name, glsl_version, test_vector): +def _store_test_vector(test_suite_dict, name, glsl_version, test_vector, + template = None): """Store a test vector in the appropriate place in test_suite_dict. The dictionary key (which is a Signature tuple) is generated by consulting the argument and return types of the @@ -529,25 +580,38 @@ def _store_test_vector(test_suite_dict, name, glsl_version, test_vector): glsl_version is adjusted if necessary to reflect when the argument and return types were introduced into GLSL. + + If template is supplied, it is used insted as the template for the + Signature objects generated. """ + if template is None: + arg_indices = xrange(len(test_vector.arguments)) + template = '{0}({1})'.format( + name, ', '.join('{{{0}}}'.format(i) for i in arg_indices)) rettype = glsl_type_of(test_vector.result) argtypes = tuple(glsl_type_of(arg) for arg in test_vector.arguments) adjusted_glsl_version = max( glsl_version, rettype.version_introduced, *[t.version_introduced for t in argtypes]) - signature = Signature(name, adjusted_glsl_version, rettype, argtypes) + signature = Signature( + name, template, adjusted_glsl_version, rettype, argtypes) if signature not in test_suite_dict: test_suite_dict[signature] = [] test_suite_dict[signature].append(test_vector) -def _store_test_vectors(test_suite_dict, name, glsl_version, test_vectors): +def _store_test_vectors(test_suite_dict, name, glsl_version, test_vectors, + template = None): """Store multiple test vectors in the appropriate places in test_suite_dict. + + If template is supplied, it is used insted as the template for the + Signature objects generated. """ for test_vector in test_vectors: - _store_test_vector(test_suite_dict, name, glsl_version, test_vector) + _store_test_vector(test_suite_dict, name, glsl_version, test_vector, + template = template) @@ -707,9 +771,81 @@ def _make_vector_or_matrix_test_vectors(test_suite_dict): that operate on vectors/matrices as a whole. Examples include length(), dot(), cross(), normalize(), and refract(). """ - _std_vectors = [ - -1.33, - 0.85, + def match_args(*indices): + """Return a function that determines whether the type of the + arguments at the given indices match. + + For example: + + match(1, 3) + + is equivalent to: + + lambda a, b, c, d: glsl_type_of(b) == glsl_type_of(d) + """ + return lambda *args: _argument_types_match(args, indices) + def match_simple_binop(x, y): + """Detemine whether the type of the arguments is compatible + for a simple binary operator (such as '+'). + + Arguments are compatible if one is a scalar and the other is a + vector/matrix with the same base type, or if they are the same + type. + """ + x_type = glsl_type_of(x) + y_type = glsl_type_of(y) + if x_type.base_type != y_type.base_type: + return False + if x_type.is_scalar or y_type.is_scalar: + return True + return x_type == y_type + def match_multiply(x, y): + """Determine whether the type of the arguments is compatible + for multiply. + + Arguments are compatible if they are scalars, vectors, or + matrices with the same base type, and the vector/matrix sizes + are properly matched. + """ + x_type = glsl_type_of(x) + y_type = glsl_type_of(y) + if x_type.base_type != y_type.base_type: + return False + if x_type.is_scalar or y_type.is_scalar: + return True + if x_type.is_vector and y_type.is_matrix: + # When multiplying vector * matrix, the vector is + # transposed to a row vector. So its row count must match + # the row count of the matrix. + return x_type.num_rows == y_type.num_rows + elif x_type.is_vector: + assert y_type.is_vector + # When multiplying vector * vector, the multiplication is + # done componentwise, so the types must match exactly. + return x_type == y_type + else: + assert x_type.is_matrix + # When multiplying matrix * matrix or matrix * vector, a + # standard linear algebraic multiply is used, so x's + # column count must match y's row count. + return x_type.num_cols == y_type.num_rows + + bools = [False, True] + bvecs = [np.array(bs) for bs in itertools.product(bools, bools)] + \ + [np.array(bs) for bs in itertools.product(bools, bools, bools)] + \ + [np.array(bs) for bs in itertools.product(bools, bools, bools, bools)] + ints = [12, -6, 74, -32, 0] + ivecs = [ + np.array([38, 35]), + np.array([64, -9]), + np.array([-36, 32, -88]), + np.array([59, 77, 68]), + np.array([-66, 72, 87, -75]), + np.array([-24, 40, -23, 74]) + ] + nz_floats = [-1.33, 0.85] + floats = [0.0] + nz_floats + vecs = [ np.array([-0.10, -1.20]), np.array([-0.42, 0.48]), np.array([-0.03, -0.85, -0.94]), @@ -717,13 +853,13 @@ def _make_vector_or_matrix_test_vectors(test_suite_dict): np.array([-1.65, 1.33, 1.93, 0.76]), np.array([0.80, -0.15, -0.51, 0.0]) ] - _std_vectors3 = [ + nz_floats_vecs = nz_floats + vecs + vec3s = [ np.array([-0.03, -0.85, -0.94]), np.array([1.67, 0.66, 1.87]), ] - _normalized_vectors = [_normalize(x) for x in _std_vectors] - _nontrivial_vectors = [x for x in _std_vectors if not isinstance(x, FLOATING_TYPES)] - _std_matrices = [ + norm_floats_vecs = [_normalize(x) for x in nz_floats_vecs] + mats = [ np.array([[ 1.60, 0.76], [ 1.53, -1.00]]), # mat2 np.array([[-0.13, -0.87], @@ -779,13 +915,9 @@ def _make_vector_or_matrix_test_vectors(test_suite_dict): [ 0.14, 0.18, -0.56], [ 0.40, -0.77, 1.76]]), # mat3x4 ] - _ft = [False, True] - _bvecs = [np.array(bs) for bs in itertools.product(_ft, _ft)] + \ - [np.array(bs) for bs in itertools.product(_ft, _ft, _ft)] + \ - [np.array(bs) for bs in itertools.product(_ft, _ft, _ft, _ft)] def f(name, arity, glsl_version, python_equivalent, - argument_indices_to_match, test_inputs, - tolerance_function = _strict_tolerance): + filter, test_inputs, tolerance_function = _strict_tolerance, + template = None): """Make test vectors for the function with the given name and arity, which was introduced in the given glsl_version. @@ -794,9 +926,9 @@ def _make_vector_or_matrix_test_vectors(test_suite_dict): output of the GLSL function is undefined. However, it need not check that the lengths of the input vectors are all the same. - If argument_indices_to_match is not None, it is a sequence of - argument indices indicating which arguments of the function - need to have matching types. + If filter is not None, it will be called with each set of + arguments, and test cases will only be generated if the filter + returns True. test_inputs is a list, the ith element of which is a list of vectors and/or scalars that are suitable for use as the ith @@ -805,34 +937,71 @@ def _make_vector_or_matrix_test_vectors(test_suite_dict): If tolerance_function is supplied, it is a function which should be used to compute the tolerance for the test vectors. Otherwise, _strict_tolerance is used. + + If template is supplied, it is used insted as the template for + the Signature objects generated. """ test_inputs = make_arguments(test_inputs) - if argument_indices_to_match is not None: + if filter is not None: test_inputs = [ arguments for arguments in test_inputs - if _argument_types_match(arguments, argument_indices_to_match)] + if filter(*arguments)] _store_test_vectors( test_suite_dict, name, glsl_version, _simulate_function( - test_inputs, python_equivalent, tolerance_function)) - f('length', 1, '1.10', np.linalg.norm, None, [_std_vectors]) - f('distance', 2, '1.10', lambda x, y: np.linalg.norm(x-y), [0, 1], [_std_vectors, _std_vectors]) - f('dot', 2, '1.10', np.dot, [0, 1], [_std_vectors, _std_vectors]) - f('cross', 2, '1.10', np.cross, [0, 1], [_std_vectors3, _std_vectors3], _cross_product_tolerance) - f('normalize', 1, '1.10', _normalize, None, [_std_vectors]) - f('faceforward', 3, '1.10', _faceforward, [0, 1, 2], [_std_vectors, _std_vectors, _std_vectors]) - f('reflect', 2, '1.10', _reflect, [0, 1], [_std_vectors, _normalized_vectors]) - f('refract', 3, '1.10', _refract, [0, 1], [_normalized_vectors, _normalized_vectors, [0.5, 2.0]]) + test_inputs, python_equivalent, tolerance_function), + template = template) + f('op-add', 2, '1.10', lambda x, y: x + y, match_simple_binop, [floats+vecs+mats+ints+ivecs, floats+vecs+mats+ints+ivecs], template = '({0} + {1})') + f('op-sub', 2, '1.10', lambda x, y: x - y, match_simple_binop, [floats+vecs+mats+ints+ivecs, floats+vecs+mats+ints+ivecs], template = '({0} - {1})') + f('op-mult', 2, '1.10', _multiply, match_multiply, [floats+vecs+mats+ints+ivecs, floats+vecs+mats+ints+ivecs], template = '({0} * {1})') + f('op-div', 2, '1.10', _divide, match_simple_binop, [floats+vecs+mats+ints+ivecs, floats+vecs+mats+ints+ivecs], template = '({0} / {1})') + f('op-uplus', 1, '1.10', lambda x: +x, None, [floats+vecs+mats+ints+ivecs], template = '(+ {0})') + f('op-neg', 1, '1.10', lambda x: -x, None, [floats+vecs+mats+ints+ivecs], template = '(- {0})') + f('op-gt', 2, '1.10', lambda x, y: x > y, match_args(0, 1), [ints+floats, ints+floats], template = '({0} > {1})') + f('op-lt', 2, '1.10', lambda x, y: x < y, match_args(0, 1), [ints+floats, ints+floats], template = '({0} < {1})') + f('op-ge', 2, '1.10', lambda x, y: x >= y, match_args(0, 1), [ints+floats, ints+floats], template = '({0} >= {1})') + f('op-le', 2, '1.10', lambda x, y: x <= y, match_args(0, 1), [ints+floats, ints+floats], template = '({0} <= {1})') + f('op-eq', 2, '1.10', _equal, match_args(0, 1), [floats+vecs+mats+ints+ivecs+bools+bvecs, floats+vecs+mats+ints+ivecs+bools+bvecs], template = '({0} == {1})') + f('op-ne', 2, '1.10', _not_equal, match_args(0, 1), [floats+vecs+mats+ints+ivecs+bools+bvecs, floats+vecs+mats+ints+ivecs+bools+bvecs], template = '({0} != {1})') + f('op-and', 2, '1.10', lambda x, y: x and y, None, [bools, bools], template = '({0} && {1})') + f('op-or', 2, '1.10', lambda x, y: x or y, None, [bools, bools], template = '({0} || {1})') + f('op-xor', 2, '1.10', lambda x, y: x != y, None, [bools, bools], template = '({0} ^^ {1})') + f('op-not', 1, '1.10', lambda x: not x, None, [bools], template = '(! {0})') + f('op-selection', 3, '1.10', lambda x, y, z: y if x else z, match_args(1, 2), [bools, floats+vecs+mats+ints+ivecs+bools+bvecs, floats+vecs+mats+ints+ivecs+bools+bvecs], template = '({0} ? {1} : {2})') + f('length', 1, '1.10', np.linalg.norm, None, [floats+vecs]) + f('distance', 2, '1.10', lambda x, y: np.linalg.norm(x-y), match_args(0, 1), [floats+vecs, floats+vecs]) + f('dot', 2, '1.10', np.dot, match_args(0, 1), [floats+vecs, floats+vecs]) + f('cross', 2, '1.10', np.cross, match_args(0, 1), [vec3s, vec3s], _cross_product_tolerance) + f('normalize', 1, '1.10', _normalize, None, [nz_floats_vecs]) + f('faceforward', 3, '1.10', _faceforward, match_args(0, 1, 2), [floats+vecs, floats+vecs, floats+vecs]) + f('reflect', 2, '1.10', _reflect, match_args(0, 1), [floats+vecs, norm_floats_vecs]) + f('refract', 3, '1.10', _refract, match_args(0, 1), [norm_floats_vecs, norm_floats_vecs, [0.5, 2.0]]) # Note: technically matrixCompMult operates componentwise. # However, since it is the only componentwise function to operate # on matrices, it is easier to generate test cases for it here # than to add matrix support to _make_componentwise_test_vectors. - f('matrixCompMult', 2, '1.10', lambda x, y: x*y, [0, 1], [_std_matrices, _std_matrices]) + f('matrixCompMult', 2, '1.10', lambda x, y: x*y, match_args(0, 1), [mats, mats]) - f('outerProduct', 2, '1.20', np.outer, None, [_nontrivial_vectors, _nontrivial_vectors]) - f('transpose', 1, '1.20', np.transpose, None, [_std_matrices]) - f('any', 1, '1.10', any, None, [_bvecs]) - f('all', 1, '1.10', all, None, [_bvecs]) + f('outerProduct', 2, '1.20', np.outer, None, [vecs, vecs]) + f('transpose', 1, '1.20', np.transpose, None, [mats]) + f('any', 1, '1.10', any, None, [bvecs]) + f('all', 1, '1.10', all, None, [bvecs]) _make_vector_or_matrix_test_vectors(test_suite) + + + +def _check_signature_safety(test_suite_dict): + """As a final safety check, verify that for each possible + combination of name and argtypes, there is exactly one + signature. + """ + name_argtype_combos = set() + for signature in test_suite_dict: + name_argtype_combo = (signature.name, signature.argtypes) + if name_argtype_combo in name_argtype_combos: + raise Exception( + 'Duplicate signature found for {0}'.format(name_argtype_combo)) + name_argtype_combos.add(name_argtype_combo) +_check_signature_safety(test_suite) diff --git a/generated_tests/gen_builtin_uniform_tests.py b/generated_tests/gen_builtin_uniform_tests.py index 64cb9272d..752cfb72d 100644 --- a/generated_tests/gen_builtin_uniform_tests.py +++ b/generated_tests/gen_builtin_uniform_tests.py @@ -158,6 +158,29 @@ class BoolComparator(Comparator): +class IntComparator(Comparator): + 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, output_var): + return ' {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)') + + def make_result_test(self, test_num, test_vector): + test = 'uniform {0} expected {1}\n'.format( + shader_runner_type(self.__signature.rettype), + shader_runner_format(column_major_values(test_vector.result))) + test += 'draw rect -1 -1 2 2\n' + test += 'probe rgba {0} 0 0.0 1.0 0.0 1.0\n'.format(test_num) + return test + + + class FloatComparator(Comparator): def __init__(self, signature): self.__signature = signature @@ -239,6 +262,8 @@ class ShaderTest(object): self._comparator = BoolComparator(signature) elif signature.rettype.base_type == glsl_float: self._comparator = FloatComparator(signature) + elif signature.rettype.base_type == glsl_int: + self._comparator = IntComparator(signature) else: raise Exception('Unexpected rettype {0}'.format(signature.rettype)) @@ -288,10 +313,11 @@ class ShaderTest(object): shader += 'void main()\n' shader += '{\n' shader += additional_statements - args = ', '.join( - 'arg{0}'.format(i) for i in xrange(len(self._signature.argtypes))) - shader += ' {0} result = {1}({2});\n'.format( - self._signature.rettype, self._signature.name, args) + invocation = self._signature.template.format( + *['arg{0}'.format(i) + for i in xrange(len(self._signature.argtypes))]) + shader += ' {0} result = {1};\n'.format( + self._signature.rettype, invocation) shader += self._comparator.make_result_handler(output_var) shader += '}\n' return shader @@ -307,7 +333,10 @@ class ShaderTest(object): shader_runner_type(self._signature.argtypes[i]), i, shader_runner_format( column_major_values(test_vector.arguments[i]))) - test += self._comparator.make_result_test(test_num, test_vector) + # 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) return test def filename(self): diff --git a/generated_tests/gen_constant_array_size_tests.py b/generated_tests/gen_constant_array_size_tests.py index 8258866c0..5a54e0032 100644 --- a/generated_tests/gen_constant_array_size_tests.py +++ b/generated_tests/gen_constant_array_size_tests.py @@ -84,16 +84,15 @@ class ParserTest(object): true if the GLSL compiler's constant evaluation produces the correct result for the given test vector, and false if not. """ - funcall = '{0}({1})'.format( - self.__signature.name, ', '.join( - glsl_constant(x) for x in test_vector.arguments)) + invocation = self.__signature.template.format( + *[glsl_constant(x) for x in test_vector.arguments]) if self.__signature.rettype.base_type == glsl_float: # Test floating-point values within tolerance if self.__signature.name == 'distance': # Don't use the distance() function to test itself. return '{0} <= {1} && {1} <= {2}'.format( test_vector.result - test_vector.tolerance, - funcall, + invocation, test_vector.result + test_vector.tolerance) elif self.__signature.rettype.is_matrix: # We can't apply distance() to matrices. So apply it @@ -103,7 +102,7 @@ class ParserTest(object): terms = [] for col in xrange(self.__signature.rettype.num_cols): terms.append('pow(distance({0}[{1}], {2}), 2)'.format( - funcall, col, + invocation, col, glsl_constant(test_vector.result[:,col]))) rss_distance = ' + '.join(terms) sq_tolerance = test_vector.tolerance * test_vector.tolerance @@ -111,7 +110,7 @@ class ParserTest(object): rss_distance, glsl_constant(sq_tolerance)) else: return 'distance({0}, {1}) <= {2}'.format( - funcall, glsl_constant(test_vector.result), + invocation, glsl_constant(test_vector.result), glsl_constant(test_vector.tolerance)) else: # Test non-floating point values exactly @@ -122,15 +121,15 @@ class ParserTest(object): terms = [] for row in xrange(self.__signature.rettype.num_rows): terms.append('{0}[{1}] == {2}'.format( - funcall, row, + invocation, row, glsl_constant(test_vector.result[row]))) return ' && '.join(terms) elif self.__signature.rettype.is_vector: return 'all(equal({0}, {1}))'.format( - funcall, glsl_constant(test_vector.result)) + invocation, glsl_constant(test_vector.result)) else: return '{0} == {1}'.format( - funcall, glsl_constant(test_vector.result)) + invocation, glsl_constant(test_vector.result)) def make_shader(self): """Generate the shader code necessary to test the built-in.""" @@ -166,9 +165,9 @@ class ParserTest(object): parser_test += ' *\n' parser_test += ' * Check that the following test vectors are constant folded correctly:\n' for test_vector in self.__test_vectors: - parser_test += ' * {0}({1}) => {2}\n'.format( - self.__signature.name, - ', '.join(glsl_constant(arg) for arg in test_vector.arguments), + parser_test += ' * {0} => {1}\n'.format( + self.__signature.template.format( + *[glsl_constant(arg) for arg in test_vector.arguments]), glsl_constant(test_vector.result)) parser_test += ' */\n' parser_test += self.make_shader() |