framework/replay: re-try more aggressively, even over the 50x HTTP errors
[piglit.git] / generated_tests / gen_constant_array_size_tests.py
blobfd3db8ffacfe83a5d5e3495feaf376c9da726533
1 # coding=utf-8
3 # Copyright © 2011 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.
24 # Generate a pair of glsl parser tests for every overloaded version of
25 # every built-in function, which test that the built-in functions are
26 # handled properly when applied to constant arguments inside an array
27 # size declaration.
29 # In each pair of generated tests, one test exercises the built-in
30 # function in vertex shaders, and the other exercises it in fragment
31 # shaders.
33 # This program outputs, to stdout, the name of each file it generates.
34 # With the optional argument --names-only, it only outputs the names
35 # of the files; it doesn't generate them.
37 from builtin_function import *
38 import abc
39 import optparse
40 import os
41 import os.path
43 from modules import utils
45 class ParserTest(object):
46 """Class used to build a test of a single built-in. This is an
47 abstract base class--derived types should override test_suffix(),
48 output_var(), and other functions if necessary.
49 """
51 def __init__(self, signature, test_vectors):
52 """Prepare to build a test for a single built-in. signature
53 is the signature of the built-in (a key from the
54 builtin_function.test_suite dict), and test_vectors is the
55 list of test vectors for testing the given builtin (the
56 corresponding value from the builtin_function.test_suite
57 dict).
58 """
59 self.__signature = signature
60 self.__test_vectors = test_vectors
62 def glsl_version(self):
63 if self.__signature.version_introduced < 120:
64 # Before version 1.20, built-in function invocations
65 # weren't allowed in constant expressions. So even if
66 # this built-in was introduced prior to 1.20, test it in
67 # version 1.20.
68 return 120
69 else:
70 return self.__signature.version_introduced
72 def version_directive(self):
73 return '#version {0}\n'.format(self.glsl_version())
75 def additional_declarations(self):
76 """Return a string containing any additional declarations that
77 should be placed after the version directive. Returns the
78 empty string by default.
79 """
80 return ''
82 def additional_extensions(self):
83 """Return a list (or other iterable) containing any additional
84 extension requirements that the test has. Returns the empty
85 list by default.
86 """
87 ret = []
88 if self.__signature.extension:
89 ret.append(self.__signature.extension)
91 return ret
93 @abc.abstractmethod
94 def test_suffix(self):
95 """Return the suffix that should be used in the test file name
96 to identify the type of shader, e.g. "vert" for a vertex
97 shader test.
98 """
100 def make_condition(self, test_vector):
101 """Generate a GLSL constant expression that should evaluate to
102 true if the GLSL compiler's constant evaluation produces the
103 correct result for the given test vector, and false if not.
105 invocation = self.__signature.template.format(
106 *[glsl_constant(x) for x in test_vector.arguments])
107 if self.__signature.rettype.base_type == glsl_float:
108 # Test floating-point values within tolerance
109 if self.__signature.name == 'distance':
110 # Don't use the distance() function to test itself.
111 return '{0} <= {1} && {1} <= {2}'.format(
112 test_vector.result - test_vector.tolerance,
113 invocation,
114 test_vector.result + test_vector.tolerance)
115 elif self.__signature.rettype.is_matrix:
116 # We can't apply distance() to matrices. So apply it
117 # to each column and root-sum-square the results. It
118 # is safe to use pow() here because its behavior is
119 # verified in the pow() tests.
120 terms = []
121 for col in range(self.__signature.rettype.num_cols):
122 terms.append('pow(distance({0}[{1}], {2}), 2)'.format(
123 invocation, col,
124 glsl_constant(test_vector.result[:, col])))
125 rss_distance = ' + '.join(terms)
126 sq_tolerance = test_vector.tolerance * test_vector.tolerance
127 return '{0} <= {1}'.format(
128 rss_distance, glsl_constant(sq_tolerance))
129 else:
130 return 'distance({0}, {1}) <= {2}'.format(
131 invocation, glsl_constant(test_vector.result),
132 glsl_constant(test_vector.tolerance))
133 else:
134 # Test non-floating point values exactly
135 assert not self.__signature.rettype.is_matrix
136 if self.__signature.name == 'equal':
137 # Don't use the equal() function to test itself.
138 assert self.__signature.rettype.is_vector
139 terms = []
140 for row in range(self.__signature.rettype.num_rows):
141 terms.append('{0}[{1}] == {2}'.format(
142 invocation, row,
143 glsl_constant(test_vector.result[row])))
144 return ' && '.join(terms)
145 elif self.__signature.rettype.is_vector:
146 return 'all(equal({0}, {1}))'.format(
147 invocation, glsl_constant(test_vector.result))
148 else:
149 return '{0} == {1}'.format(
150 invocation, glsl_constant(test_vector.result))
152 def make_shader(self):
153 """Generate the shader code necessary to test the built-in."""
154 shader = self.version_directive()
155 if self.__signature.extension:
156 shader += '#extension GL_{0} : require\n'.format(self.__signature.extension)
157 shader += self.additional_declarations()
158 shader += '\n'
159 shader += 'void main()\n'
160 shader += '{\n'
161 lengths = []
162 for i, test_vector in enumerate(self.__test_vectors):
163 shader += ' float[{0} ? 1 : -1] array{1};\n'.format(
164 self.make_condition(test_vector), i)
165 lengths.append('array{0}.length()'.format(i))
166 shader += ' {0} = vec4({1});\n'.format(
167 self.output_var(), ' + '.join(lengths))
168 shader += '}\n'
169 return shader
171 def filename(self):
172 argtype_names = '-'.join(
173 str(argtype) for argtype in self.__signature.argtypes)
174 if self.__signature.extension:
175 subdir = self.__signature.extension.lower()
176 else:
177 subdir = 'glsl-{0:1.2f}'.format(float(self.glsl_version()) / 100)
178 return os.path.join(
179 'spec', subdir, 'compiler', 'built-in-functions',
180 '{0}-{1}.{2}'.format(
181 self.__signature.name, argtype_names, self.test_suffix()))
183 def generate_parser_test(self):
184 """Generate the test and write it to the output file."""
185 parser_test = '/* [config]\n'
186 parser_test += ' * expect_result: pass\n'
187 parser_test += ' * glsl_version: {0:1.2f}\n'.format(
188 float(self.glsl_version()) / 100)
189 req_extensions = list(self.additional_extensions())
190 if req_extensions:
191 parser_test += ' * require_extensions: {}\n'.format(
192 ' '.join('GL_{}'.format(r) for r in req_extensions))
193 parser_test += ' * [end config]\n'
194 parser_test += ' *\n'
195 parser_test += ' * Check that the following test vectors are constant'\
196 ' folded correctly:\n'
197 for test_vector in self.__test_vectors:
198 parser_test += ' * {0} => {1}\n'.format(
199 self.__signature.template.format(
200 *[glsl_constant(arg) for arg in test_vector.arguments]),
201 glsl_constant(test_vector.result))
202 parser_test += ' */\n'
203 parser_test += self.make_shader()
204 filename = self.filename()
205 dirname = os.path.dirname(filename)
206 utils.safe_makedirs(dirname)
207 with open(filename, 'w') as f:
208 f.write(parser_test)
211 class VertexParserTest(ParserTest):
212 """Derived class for tests that exercise the built-in in a vertex
213 shader.
215 def test_suffix(self):
216 return 'vert'
218 def output_var(self):
219 return 'gl_Position'
222 class GeometryParserTest(ParserTest):
223 """Derived class for tests that exercise the built-in in a geometry
224 shader.
226 def glsl_version(self):
227 return max(150, ParserTest.glsl_version(self))
229 def test_suffix(self):
230 return 'geom'
232 def output_var(self):
233 return 'gl_Position'
236 class FragmentParserTest(ParserTest):
237 """Derived class for tests that exercise the built-in in a fagment
238 shader.
240 def test_suffix(self):
241 return 'frag'
243 def output_var(self):
244 return 'gl_FragColor'
247 def all_tests():
248 for signature, test_vectors in sorted(test_suite.items()):
249 # Assignment operators other than = cannot be used in the constant
250 # array size tests
251 if not signature.name.startswith('op-assign'):
252 yield VertexParserTest(signature, test_vectors)
253 yield GeometryParserTest(signature, test_vectors)
254 yield FragmentParserTest(signature, test_vectors)
257 def main():
258 desc = 'Generate shader tests that test built-in functions using constant'\
259 'array sizes'
260 usage = 'usage: %prog [-h] [--names-only]'
261 parser = optparse.OptionParser(description=desc, usage=usage)
262 parser.add_option('--names-only',
263 dest='names_only',
264 action='store_true',
265 help="Don't output files, just generate a list of"
266 "filenames to stdout")
267 options, args = parser.parse_args()
269 for test in all_tests():
270 if not options.names_only:
271 test.generate_parser_test()
272 print(test.filename())
275 if __name__ == '__main__':
276 main()