framework/replay: re-try more aggressively, even over the 50x HTTP errors
[piglit.git] / generated_tests / gen_shader_precision_tests.py
blob6bf09671d40466adaa0f2ebe7c4d50abc9df77c3
1 # coding=utf-8
3 # Copyright © 2014 Intel Corporation
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 # and/or sell copies of the Software, and to permit persons to whom the
10 # Software is furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
14 # Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 # DEALINGS IN THE SOFTWARE.
25 """Generate a set of shader_runner tests for overloaded versions of every
26 built-in function specified in arb_shader_precision, based on the test
27 vectors computed by builtin_function.py, and structured according to the mako
28 templates in templates/gen_shader_precision_tests.
30 The vertex, geometry, and fragment shader types are exercised by each test.
31 In all cases, the inputs to the built-in functions come from uniforms, so
32 that the effectiveness of the test won't be circumvented by constant folding
33 in the GLSL compiler.
35 The tests operate by invoking the built-in function in the appropriate
36 shader, calculating any deviance from the expected value (in ulps), comparing
37 the deviance to a supplied tolerance (according to those specified in
38 arb_shader_precision), and then outputting the pass/fail result as a solid
39 rgba color which is then checked using shader_runner's "probe rgba" command.
41 For built-in functions whose result type is multi-valued (vec or mat), the
42 tests calculate the error in ulps for each element separately, but compare
43 only the largest error value to the tolerance. This accounts for cases where
44 error varies among the elements of a vec or mat result.
46 This program updates the tolerance values in the test vectors with tolerances
47 sourced from the GLSL spec (v4.5) and adds a few new tests as well.
49 This program outputs, to stdout, the name of each file it generates.
50 """
52 from builtin_function import *
53 import os
54 import numpy
55 import struct
57 from templates import template_file
61 tolerances = {'pow': 16.0,
62 'exp': 3.0,
63 'exp2': 3.0,
64 'log': 3.0,
65 'log2': 3.0,
66 'sqrt': 3.0,
67 'inversesqrt': 2.0,
68 'op-div': 2.5,
69 'op-assign-div': 2.5,
72 shader_precision_spec_fns = ('op-add', 'op-assign-add',
73 'op-sub', 'op-assign-sub',
74 'op-mult', 'op-assign-mult',
75 'op-div', 'op-assign-div',
76 'degrees', 'radians',
77 'pow',
78 'exp',
79 'exp2',
80 'log', 'log2',
81 'sqrt', 'inversesqrt')
83 def _is_sequence(arg):
84 Sequence = collections.abc.Sequence
85 return isinstance(arg, (Sequence, numpy.ndarray))
87 def _floatToBits(f):
88 s = struct.pack('>f', f)
89 return struct.unpack('>L', s)[0]
91 # The precision for log and log2 from the GLSL spec:
92 # 3 ULP outside the range [0.5, 2.0].
93 # Absolute error < 2^-21 inside the range [0.5, 2.0].
94 def _log_tol(compcnt, args, i, j):
95 arg = args[j][i] if compcnt > 1 else args[0]
96 if arg < 0.5 or arg > 2.0:
97 return 3.0
98 elif arg >= 0.5 and arg < 1.0:
99 # in the range [0.5, 1.0), one ulp is 5.960464478e-08,
100 # so 2^-21 is 8 ulps
101 return 8.0
102 else:
103 # in the range [1.0, 2.0), one ulp is 1.192092896e-07,
104 # so 2^-21 is 4 ulps
105 return 4.0
107 # The precision for exp and exp2 from the GLSL spec:
108 # (3 + 2 * |x|) ULP.
109 def _exp_tol(compcnt, args, i, j):
110 arg = args[j][i] if compcnt > 1 else args[0]
111 return 3.0 + 2.0 * abs(arg)
113 # The precision for division from the GLSL spec:
114 # 2.5 ULP for b in the range [2^-126, 2^126].
115 def _div_tol(compcnt, args, i, j):
116 divisor = args[1][i] if _is_sequence(args[1]) else args[1]
117 assert (divisor >= pow(2,-126) and divisor <= pow(2,126)) or \
118 (divisor <= -pow(2,-126) and divisor >= -pow(2,126))
119 return 2.5
121 # The precision for pow from the GLSL spec:
122 # Inherited from exp2 (x * log2 (y)).
123 def _pow_tol(compcnt, args, i, j):
124 x = args[0][i] if _is_sequence(args[0]) else args[0]
125 y = args[1][i] if _is_sequence(args[1]) else args[1]
126 return(_exp_tol(0, [x * _log_tol(0, [y], 0, 0)], 0, 0))
129 _tol_fns = { 'op-add': (lambda *args: 0.0),
130 'op-assign-add': (lambda *args: 0.0),
131 'op-sub': (lambda *args: 0.0),
132 'op-assign-sub': (lambda *args: 0.0),
133 'op-mult': (lambda *args: 0.0),
134 'op-assign-mult': (lambda *args: 0.0),
135 'op-div': (lambda compcnt, args, i, j: _div_tol(compcnt, args, i, j)),
136 'op-assign-div': (lambda compcnt, args, i, j: _div_tol(compcnt, args, i, j)),
137 'degrees': (lambda *args: 2.5),
138 'radians': (lambda *args: 2.5),
139 'pow': (lambda compcnt, args, i, j: _pow_tol(compcnt, args, i, j)),
140 'exp': _exp_tol,
141 'exp2': _exp_tol,
142 'log': _log_tol,
143 'log2': _log_tol,
144 'sqrt': (lambda *args: 2.5),
145 'inversesqrt': (lambda *args: 2.0) }
148 def _gen_tolerance(name, rettype, args):
149 ret = []
150 compcnt = rettype.num_cols * rettype.num_rows
152 for j in range(rettype.num_cols):
153 for i in range(rettype.num_rows):
154 assert _tol_fns[name]
155 ret.append(_tol_fns[name](compcnt, args, i, j))
156 return ret
158 def make_indexers(signature):
159 """Build a list of strings which index into every possible
160 value of the result. For example, if the result is a vec2,
161 then build the indexers ['[0]', '[1]'].
163 if signature.rettype.num_cols == 1:
164 col_indexers = ['']
165 else:
166 col_indexers = ['[{0}]'.format(i) for i in range(signature.rettype.num_cols)]
167 if signature.rettype.num_rows == 1:
168 row_indexers = ['']
169 else:
170 row_indexers = ['[{0}]'.format(i) for i in range(signature.rettype.num_rows)]
171 return [col_indexer + row_indexer
172 for col_indexer in col_indexers for row_indexer in row_indexers]
174 def shader_runner_type(glsl_type):
175 """Return the appropriate type name necessary for binding a
176 uniform of the given type using shader_runner's "uniform" command.
177 Boolean values and vectors are converted to ints, and square
178 matrices are written in "matNxN" form.
180 if glsl_type.base_type == glsl_bool:
181 if glsl_type.is_scalar:
182 return 'int'
183 else:
184 return 'ivec{0}'.format(glsl_type.num_rows)
185 elif glsl_type.is_matrix:
186 return 'mat{0}x{1}'.format(glsl_type.num_cols, glsl_type.num_rows)
187 else:
188 return str(glsl_type)
190 def shader_runner_format(values):
191 """Format the given values for use in a shader_runner "uniform" or
192 "probe rgba" command. Sequences of values are separated by spaces.
195 if _is_sequence(values):
196 retval = ''
197 for x in values:
198 assert isinstance(x, (float, np.float32))
199 retval += ' {0:#08x}'.format(_floatToBits(x))
200 else:
201 assert isinstance(values, (float, np.float32))
202 retval = '{0:#08x}'.format(_floatToBits(values))
204 return retval
206 def drop_signbit(xs):
207 if (np.isscalar(xs)):
208 return xs.dtype.type(0.0) if xs == 0.0 else xs
209 return np.array([xs.dtype.type(0.0) if x == 0.0 else x for x in xs],
210 xs.dtype)
212 def main():
213 """ Main function """
215 for signature, test_vectors in test_suite.items():
216 arg_float_check = all(arg.base_type == glsl_float for arg in signature.argtypes)
217 arg_mat_check = any(arg.is_matrix for arg in signature.argtypes)
218 # Filter the test vectors down to only those which deal exclusively in
219 # non-matrix float types and are specified in the spec
220 if (signature.rettype.base_type == glsl_float and
221 arg_float_check and
222 signature.name in shader_precision_spec_fns and
223 not arg_mat_check):
224 # replace the tolerances in each test_vector with
225 # our own tolerances specified in ulps
226 refined_test_vectors = []
227 complex_tol_type = signature.rettype
228 for test_vector in test_vectors:
229 tolerance = _gen_tolerance(signature.name, signature.rettype, test_vector.arguments)
230 result = drop_signbit(test_vector.result)
231 refined_test_vectors.append(TestVector(test_vector.arguments, result, tolerance))
232 # Then generate the shader_test scripts
233 for shader_stage in ('vs', 'fs', 'gs'):
234 template = template_file('gen_shader_precision_tests', '{0}.mako'.format(shader_stage))
235 output_filename = os.path.join( 'spec', 'arb_shader_precision',
236 '{0}-{1}-{2}.shader_test'.format(
237 shader_stage, signature.name,
238 '-'.join(str(argtype)
239 for argtype in signature.argtypes)))
240 print(output_filename)
241 dirname = os.path.dirname(output_filename)
242 if not os.path.exists(dirname):
243 os.makedirs(dirname)
244 indexers = make_indexers(signature)
245 num_elements = signature.rettype.num_cols * signature.rettype.num_rows
246 invocation = signature.template.format( *['arg{0}'.format(i)
247 for i in range(len(signature.argtypes))])
248 with open(output_filename, 'w') as f:
249 f.write(template.render_unicode( signature=signature,
250 is_complex_tolerance=_is_sequence(tolerance),
251 complex_tol_type=signature.rettype,
252 test_vectors=refined_test_vectors,
253 invocation=invocation,
254 num_elements=num_elements,
255 indexers=indexers,
256 shader_runner_type=shader_runner_type,
257 shader_runner_format=shader_runner_format,
258 column_major_values=column_major_values ))
260 if __name__ == "__main__":
261 main()