]> git.cworth.org Git - apitrace-tests/blob - driver.py
Distinguish better egl tests from others.
[apitrace-tests] / driver.py
1 #!/usr/bin/env python
2 ##########################################################################
3 #
4 # Copyright 2011 Jose Fonseca
5 # All Rights Reserved.
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 # THE SOFTWARE.
24 #
25 ##########################################################################/
26
27 '''Main test driver.'''
28
29
30 import optparse
31 import os.path
32 import platform
33 import re
34 import shutil
35 import subprocess
36 import sys
37 import time
38
39
40 def popen(command, *args, **kwargs):
41     if kwargs.get('cwd', None) is not None:
42         sys.stdout.write('cd %s && ' % kwargs['cwd'])
43     if 'env' in kwargs:
44         for name, value in kwargs['env'].iteritems():
45             if value != os.environ.get(name, None):
46                 sys.stdout.write('%s=%s ' % (name, value))
47     sys.stdout.write(' '.join(command) + '\n')
48     sys.stdout.flush()
49     return subprocess.Popen(command, *args, **kwargs)
50
51
52 def _get_build_path(path):
53     if options.build is not None:
54         path = os.path.abspath(os.path.join(options.build, path))
55     if not os.path.exists(path):
56         sys.stderr.write('error: %s does not exist\n' % path)
57         sys.exit(1)
58     return path
59
60 def _get_build_program(program):
61     if platform.system() == 'Windows':
62         program += '.exe'
63     return _get_build_path(program)
64
65
66 class TestCase:
67
68     api = 'gl'
69     max_frames = None
70     trace_file = None
71
72     def __init__(self, name, args, cwd=None, build=None, results = '.'):
73         self.name = name
74         self.args = args
75         self.cwd = cwd
76         self.build = build
77         self.results = results
78
79         if not os.path.exists(results):
80             os.makedirs(results)
81
82     expected_dump = None
83
84     def standalone(self):
85         p = popen(self.args, cwd=self.cwd)
86         p.wait()
87         if p.returncode:
88             self.skip('application returned code %i' % p.returncode)
89
90     api_map = {
91         'gl': 'gl',
92         'egl_gl': 'egl',
93         'egl_gles1': 'egl',
94         'egl_gles2': 'egl',
95     }
96
97     def trace(self):
98         if self.trace_file is None:
99             self.trace_file = os.path.abspath(os.path.join(self.results, self.name + '.trace'))
100         if os.path.exists(self.trace_file):
101             os.remove(self.trace_file)
102         else:
103             trace_dir = os.path.dirname(self.trace_file)
104             if not os.path.exists(trace_dir):
105                 os.makedirs(trace_dir)
106
107         cmd = self.args
108         env = os.environ.copy()
109         
110         system = platform.system()
111         local_wrapper = None
112         if system == 'Windows':
113             wrapper = _get_build_path('wrappers/opengl32.dll')
114             local_wrapper = os.path.join(os.path.dirname(self.args[0]), os.path.basename(wrapper))
115             shutil.copy(wrapper, local_wrapper)
116             env['TRACE_FILE'] = self.trace_file
117         else:
118             apitrace = _get_build_program('apitrace')
119             cmd = [
120                 apitrace, 'trace', 
121                 '--api', self.api_map[self.api],
122                 '--output', self.trace_file,
123                 '--'
124             ] + cmd
125         if self.max_frames is not None:
126             env['TRACE_FRAMES'] = str(self.max_frames)
127
128         try:
129             p = popen(cmd, env=env, cwd=self.cwd)
130             p.wait()
131         finally:
132             if local_wrapper is not None:
133                 os.remove(local_wrapper)
134
135         if not os.path.exists(self.trace_file):
136             self.fail('no trace file generated\n')
137     
138     call_re = re.compile(r'^([0-9]+) (\w+)\(')
139
140     def dump(self):
141
142         cmd = [_get_build_program('apitrace'), 'dump', '--color=never', self.trace_file]
143         p = popen(cmd, stdout=subprocess.PIPE)
144
145         swapbuffers = 0
146         flushes = 0
147
148         ref_line = ''
149         src_lines = []
150         if self.ref_dump is not None:
151             ref = open(self.ref_dump, 'rt')
152             ref_line = ref.readline().rstrip()
153         for line in p.stdout:
154             line = line.rstrip()
155             print line
156             mo = self.call_re.match(line)
157             if mo:
158                 call_no = int(mo.group(1))
159                 function_name = mo.group(2)
160                 if function_name == 'glXSwapBuffers':
161                     swapbuffers += 1
162                 if function_name in ('glFlush', 'glFinish'):
163                     flushes += 1
164                 src_line = line[mo.start(2):]
165             else:
166                 src_line = line
167             if ref_line:
168                 if src_line == ref_line:
169                     sys.stdout.write(src_line + '\n')
170                     ref_line = ref.readline().rstrip()
171                     src_lines = []
172                 else:
173                     src_lines.append(src_line)
174
175         p.wait()
176         if p.returncode != 0:
177             self.fail('`apitrace dump` returned code %i' % p.returncode)
178         if ref_line:
179             if src_lines:
180                 self.fail('missing call `%s` (found `%s`)' % (ref_line, src_lines[0]))
181             else:
182                 self.fail('missing call %s' % ref_line)
183
184     def run(self):
185         self.standalone()
186         self.trace()
187         self.dump()
188
189         self.pass_()
190         return
191
192         ref_prefix = os.path.abspath(os.path.join(self.results, self.name + '.ref.'))
193         src_prefix = os.path.join(self.results, self.name + '.src.')
194         diff_prefix = os.path.join(self.results, self.name + '.diff.')
195
196
197         if not os.path.isfile(trace):
198             sys.stdout.write('SKIP (no trace)\n')
199             return
200         args = [_get_build_path('glretrace')]
201         if swapbuffers:
202             args += ['-db']
203             frames = swapbuffers
204         else:
205             args += ['-sb']
206             frames = flushes
207         args += ['-s', src_prefix]
208         args += [trace]
209         p = popen(args, stdout=subprocess.PIPE)
210         image_re = re.compile(r'^Wrote (.*\.png)$')
211         images = []
212         for line in p.stdout:
213             line = line.rstrip()
214             mo = image_re.match(line)
215             if mo:
216                 image = mo.group(1)
217                 if image.startswith(src_prefix):
218                     image = image[len(src_prefix):]
219                     images.append(image)
220         p.wait()
221         if p.returncode != 0:
222             sys.stdout.write('FAIL (glretrace)\n')
223             return
224
225         for image in images:
226             ref_image = ref_prefix + image
227             src_image = src_prefix + image
228             diff_image = diff_prefix + image
229             
230             if not os.path.isfile(ref_image):
231                 continue
232             assert os.path.isfile(src_image)
233
234             comparer = Comparer(ref_image, src_image)
235             match = comparer.ae()
236             sys.stdout.write('%s: %s bits\n' % (image, comparer.precision()))
237             if not match:
238                 comparer.write_diff(diff_image)
239                 #report.add_snapshot(ref_image, src_image, diff_image)
240                 sys.stdout.write('FAIL (snapshot)\n')
241                 return
242
243     def fail(self, reason=None):
244         self._exit('FAIL', 1, reason)
245
246     def skip(self, reason=None):
247         self._exit('SKIP', 0, reason)
248
249     def pass_(self, reason=None):
250         self._exit('PASS', 0, reason)
251
252     def _exit(self, status, code, reason=None):
253         if reason is None:
254             reason = ''
255         else:
256             reason = ' (%s)' % reason
257         sys.stdout.write('%s%s\n' % (status, reason))
258         sys.exit(code)
259
260
261
262 def main():
263     global options
264
265     # Parse command line options
266     optparser = optparse.OptionParser(
267         usage='\n\t%prog [options] -- program [args] ...',
268         version='%%prog')
269     optparser.add_option(
270         '-a', '--api', metavar='API',
271         type='string', dest='api', default='gl',
272         help='api to trace')
273     optparser.add_option(
274         '-B', '--build', metavar='PATH',
275         type='string', dest='build', default='..',
276         help='path to apitrace build')
277     optparser.add_option(
278         '-C', '--directory', metavar='PATH',
279         type='string', dest='cwd', default=None,
280         help='change to directory')
281     optparser.add_option(
282         '-R', '--results', metavar='PATH',
283         type='string', dest='results', default='.',
284         help='results directory [default=%default]')
285     optparser.add_option(
286         '--ref-dump', metavar='PATH',
287         type='string', dest='ref_dump', default=None,
288         help='reference dump')
289
290     (options, args) = optparser.parse_args(sys.argv[1:])
291     if not args:
292         optparser.error('program must be specified')
293
294     test = TestCase(
295         name = os.path.basename(args[0]), 
296         args = args,
297         cwd = options.cwd,
298         build = options.build,
299         results = options.results,
300     )
301     test.api = options.api
302     test.ref_dump = options.ref_dump
303
304     test.run()
305
306
307 if __name__ == '__main__':
308     main()