]> git.cworth.org Git - apitrace-tests/blob - mesademos.py
Generate a HTML report.
[apitrace-tests] / mesademos.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
28 '''Apitrace test suite based on Mesa demos.'''
29
30
31
32 import os.path
33 import optparse
34 import sys
35 import subprocess
36 import time
37 import re
38 import signal
39
40
41 ansi_re = re.compile('\x1b\[[0-9]{1,2}(;[0-9]{1,2}){0,2}m')
42
43
44 def ansi_strip(s):
45     # http://www.theeggeadventure.com/wikimedia/index.php/Linux_Tips#Use_sed_to_remove_ANSI_colors
46     return ansi_re.sub('', s)
47
48
49 def popen(command, *args, **kwargs):
50     if 'cwd' in kwargs:
51         sys.stdout.write('cd %s && ' % kwargs['cwd'])
52     if 'env' in kwargs:
53         for name, value in kwargs['env'].iteritems():
54             if value != os.environ.get(name, None):
55                 sys.stdout.write('%s=%s ' % (name, value))
56     sys.stdout.write(' '.join(command) + '\n')
57     sys.stdout.flush()
58     return subprocess.Popen(command, *args, **kwargs)
59
60
61 ignored_function_names = set([
62     'glGetString',
63     'glXGetCurrentDisplay',
64     'glXGetClientString',
65     'glXGetProcAddress',
66     'glXGetProcAddressARB',
67     'glXQueryVersion',
68     'glXGetVisualFromFBConfig',
69     'glXChooseFBConfig',
70     'glXCreateNewContext',
71     'glXMakeContextCurrent',
72     'glXQueryExtension',
73     'glXIsDirect',
74 ])
75
76
77 def image_tag(html, image):
78     url = os.path.relpath(image, options.results)
79     html.write('        <td><a href="%s"><img src="%s"/></a></td>\n' % (url, url))
80
81
82 def runtest(html, demo):
83     html.write('      <tr>\n')
84
85     app = os.path.join(options.mesa_demos, 'src', demo)
86
87     dirname, basename = os.path.split(app)
88     
89     trace = os.path.abspath(os.path.join(options.results, demo.replace('/', '-') + '.trace'))
90
91     env = os.environ.copy()
92     env['LD_PRELOAD'] = os.path.abspath(os.path.join(options.build, 'glxtrace.so'))
93     env['TRACE_FILE'] = trace
94     
95     args = [os.path.join('.', basename)]
96     p = popen(args, env=env, cwd=dirname)
97     try:
98         time.sleep(1)
99
100         # http://stackoverflow.com/questions/151407/how-to-get-an-x11-window-from-a-process-id
101         ref_image = os.path.join(options.results, demo.replace('/', '-') + '.ref.png')
102         #subprocess.call(['xwininfo', '-root', '-tree'])
103         subprocess.call("xwd -name '%s' | xwdtopnm | pnmtopng > '%s'" % (args[0], ref_image), shell=True)
104
105     finally:
106         os.kill(p.pid, signal.SIGTERM)
107
108     p = popen([os.path.join(options.build, 'tracedump'), trace], stdout=subprocess.PIPE)
109     stdout, _ = p.communicate()
110
111     call_re = re.compile('^([0-9]+) (\w+)\(')
112     double_buffer = False
113     for orig_line in stdout.split('\n'):
114         line = ansi_strip(orig_line)
115         mo = call_re.match(line)
116         if mo:
117             call_no = int(mo.group(1))
118             function_name = mo.group(2)
119             if function_name in ignored_function_names:
120                 continue
121             if function_name == 'glXSwapBuffers':
122                 double_buffer = True
123         #print orig_line
124
125     args = [os.path.join(options.build, 'glretrace')]
126     if double_buffer:
127         args += ['-db']
128     else:
129         args += ['-sb']
130     snapshot_prefix = os.path.join(options.results, demo.replace('/', '-') + '.')
131     args += ['-s', snapshot_prefix]
132     args += [trace]
133     p = popen(args, stdout=subprocess.PIPE)
134     stdout, _ = p.communicate()
135     image_re = re.compile('^Wrote (.*\.png)$')
136     image = None
137     for line in stdout.split('\n'):
138         mo = image_re.match(line)
139         if mo:
140             image = mo.group(1)
141     
142     image_tag(html, ref_image)
143     if image:
144         delta_image = os.path.join(options.results, demo.replace('/', '-') + '.diff.png')
145         p = popen(["compare", '-alpha', 'opaque', '-metric', 'AE', '-fuzz', '5%', ref_image, image, delta_image])
146         _, stderr = p.communicate()
147         image_tag(html, image)
148         image_tag(html, delta_image)
149
150     html.write('      </tr>\n')
151     html.flush()
152
153
154 tests = [
155     'trivial/clear-color',
156     'trivial/clear-fbo',
157     'trivial/clear-fbo-scissor',
158     'trivial/clear-fbo-tex',
159     'trivial/clear-random',
160     #'trivial/clear-repeat',
161     'trivial/clear-scissor',
162     'trivial/clear-undefined',
163     'trivial/createwin',
164     'trivial/dlist-begin-call-end',
165     'trivial/dlist-dangling',
166     'trivial/dlist-degenerate',
167     'trivial/dlist-edgeflag',
168     'trivial/dlist-edgeflag-dangling',
169     'trivial/dlist-flat-tri',
170     'trivial/dlist-mat-tri',
171     'trivial/dlist-recursive-call',
172     'trivial/dlist-tri-flat-tri',
173     'trivial/dlist-tri-mat-tri',
174     'trivial/draw2arrays',
175     'trivial/drawarrays',
176     'trivial/drawelements',
177     'trivial/drawelements-large',
178     'trivial/drawrange',
179     'trivial/flat-clip',
180     'trivial/fs-tri',
181     'trivial/line',
182     'trivial/line-clip',
183     'trivial/line-cull',
184     'trivial/line-flat',
185     'trivial/line-smooth',
186     'trivial/line-stipple-wide',
187     'trivial/line-userclip',
188     'trivial/line-userclip-clip',
189     'trivial/line-userclip-nop',
190     'trivial/line-userclip-nop-clip',
191     'trivial/line-wide',
192     'trivial/line-xor',
193     'trivial/lineloop',
194     'trivial/lineloop-clip',
195     'trivial/lineloop-elts',
196     'trivial/linestrip',
197     'trivial/linestrip-clip',
198     'trivial/linestrip-flat-stipple',
199     'trivial/linestrip-stipple',
200     'trivial/linestrip-stipple-wide',
201     'trivial/long-fixed-func',
202     'trivial/pgon-mode',
203     'trivial/point',
204     'trivial/point-clip',
205     'trivial/point-param',
206     'trivial/point-sprite',
207     'trivial/point-wide',
208     'trivial/point-wide-smooth',
209     'trivial/poly',
210     'trivial/poly-flat',
211     'trivial/poly-flat-clip',
212     'trivial/poly-flat-unfilled-clip',
213     'trivial/poly-unfilled',
214     'trivial/quad',
215     'trivial/quad-clip',
216     'trivial/quad-clip-all-vertices',
217     'trivial/quad-clip-nearplane',
218     'trivial/quad-degenerate',
219     'trivial/quad-flat',
220     'trivial/quad-offset-factor',
221     'trivial/quad-offset-unfilled',
222     'trivial/quad-offset-units',
223     'trivial/quad-tex-2d',
224     'trivial/quad-tex-3d',
225     'trivial/quad-tex-alpha',
226     'trivial/quad-tex-pbo',
227     'trivial/quad-tex-sub',
228     'trivial/quad-unfilled',
229     'trivial/quad-unfilled-clip',
230     'trivial/quad-unfilled-stipple',
231     'trivial/quads',
232     'trivial/quadstrip',
233     'trivial/quadstrip-clip',
234     'trivial/quadstrip-cont',
235     'trivial/quadstrip-flat',
236     'trivial/readpixels',
237     'trivial/sub-tex',
238     'trivial/tex-quads',
239     'trivial/tri',
240     'trivial/tri-alpha',
241     'trivial/tri-alpha-tex',
242     'trivial/tri-array-interleaved',
243     'trivial/tri-blend',
244     'trivial/tri-blend-color',
245     'trivial/tri-blend-max',
246     'trivial/tri-blend-min',
247     'trivial/tri-blend-revsub',
248     'trivial/tri-blend-sub',
249     'trivial/tri-clear',
250     'trivial/tri-clip',
251     'trivial/tri-cull',
252     'trivial/tri-cull-both',
253     'trivial/tri-dlist',
254     'trivial/tri-edgeflag',
255     'trivial/tri-edgeflag-array',
256     'trivial/tri-fbo',
257     'trivial/tri-fbo-tex',
258     'trivial/tri-fbo-tex-mip',
259     'trivial/tri-flat',
260     'trivial/tri-flat-clip',
261     'trivial/tri-fog',
262     'trivial/tri-fp',
263     'trivial/tri-fp-const-imm',
264     'trivial/tri-lit',
265     'trivial/tri-lit-material',
266     'trivial/tri-logicop-none',
267     'trivial/tri-logicop-xor',
268     'trivial/tri-mask-tri',
269     'trivial/tri-multitex-vbo',
270     'trivial/tri-orig',
271     'trivial/tri-point-line-clipped',
272     'trivial/tri-query',
273     'trivial/tri-repeat',
274     'trivial/tri-scissor-tri',
275     'trivial/tri-square',
276     'trivial/tri-stencil',
277     'trivial/tri-stipple',
278     'trivial/tri-tex',
279     'trivial/tri-tex-1d',
280     'trivial/tri-tex-3d',
281     'trivial/tri-tri',
282     'trivial/tri-unfilled',
283     'trivial/tri-unfilled-clip',
284     'trivial/tri-unfilled-edgeflag',
285     'trivial/tri-unfilled-fog',
286     'trivial/tri-unfilled-point',
287     'trivial/tri-unfilled-smooth',
288     'trivial/tri-unfilled-tri',
289     'trivial/tri-unfilled-tri-lit',
290     'trivial/tri-unfilled-userclip',
291     'trivial/tri-unfilled-userclip-stip',
292     'trivial/tri-userclip',
293     'trivial/tri-viewport',
294     'trivial/tri-z',
295     'trivial/tri-z-9',
296     'trivial/tri-z-eq',
297     'trivial/trifan',
298     'trivial/trifan-flat',
299     'trivial/trifan-flat-clip',
300     'trivial/trifan-flat-unfilled-clip',
301     'trivial/trifan-unfilled',
302     'trivial/tristrip',
303     'trivial/tristrip-clip',
304     'trivial/tristrip-flat',
305     'trivial/vbo-drawarrays',
306     'trivial/vbo-drawelements',
307     'trivial/vbo-drawrange',
308     'trivial/vbo-noninterleaved',
309     'trivial/vbo-tri',
310     'trivial/vp-array',
311     'trivial/vp-array-hf',
312     'trivial/vp-array-int',
313     'trivial/vp-clip',
314     'trivial/vp-line-clip',
315     'trivial/vp-tri',
316     'trivial/vp-tri-cb',
317     'trivial/vp-tri-cb-pos',
318     'trivial/vp-tri-cb-tex',
319     'trivial/vp-tri-imm',
320     'trivial/vp-tri-invariant',
321     'trivial/vp-tri-swap',
322     'trivial/vp-tri-tex',
323     'trivial/vp-unfilled',
324
325     #'demos/arbfplight',
326     #'demos/arbfslight',
327     #'demos/arbocclude',
328     #'demos/arbocclude2',
329     #'demos/bounce',
330     #'demos/clearspd',
331     #'demos/copypix',
332     #'demos/cubemap',
333     #'demos/dinoshade',
334     #'demos/dissolve',
335     #'demos/drawpix',
336     #'demos/engine',
337     #'demos/fbo_firecube',
338     #'demos/fbotexture',
339     #'demos/fire',
340     #'demos/fogcoord',
341     #'demos/fplight',
342     #'demos/fslight',
343     #'demos/gamma',
344     #'demos/gearbox',
345     #'demos/gears',
346     #'demos/geartrain',
347     #'demos/glinfo',
348     #'demos/gloss',
349     #'demos/gltestperf',
350     #'demos/ipers',
351     #'demos/isosurf',
352     #'demos/lodbias',
353     #'demos/morph3d',
354     #'demos/multiarb',
355     #'demos/paltex',
356     #'demos/pointblast',
357     #'demos/projtex',
358     #'demos/rain',
359     #'demos/ray',
360     #'demos/readpix',
361     #'demos/reflect',
362     #'demos/renormal',
363     #'demos/shadowtex',
364     #'demos/singlebuffer',
365     #'demos/spectex',
366     #'demos/spriteblast',
367     #'demos/stex3d',
368     #'demos/teapot',
369     #'demos/terrain',
370     #'demos/tessdemo',
371     #'demos/texcyl',
372     #'demos/texenv',
373     #'demos/textures',
374     #'demos/trispd',
375     #'demos/tunnel',
376     #'demos/tunnel2',
377     #'demos/vao_demo',
378     #'demos/winpos',
379     #'fp/fp-tri',
380     #'fp/point-position',
381     #'fp/tri-depth',
382     #'fp/tri-depth2',
383     #'fp/tri-depthwrite',
384     #'fp/tri-depthwrite2',
385     #'fp/tri-param',
386     #'fp/tri-tex',
387     #'fpglsl/fp-tri',
388     #'glsl/array',
389     #'glsl/bezier',
390     #'glsl/bitmap',
391     #'glsl/brick',
392     #'glsl/bump',
393     #'glsl/convolutions',
394     #'glsl/deriv',
395     #'glsl/fragcoord',
396     #'glsl/fsraytrace',
397     #'glsl/geom-sprites',
398     #'glsl/geom-stipple-lines',
399     #'glsl/geom-wide-lines',
400     #'glsl/identity',
401     #'glsl/linktest',
402     #'glsl/mandelbrot',
403     #'glsl/multinoise',
404     #'glsl/multitex',
405     #'glsl/noise',
406     #'glsl/noise2',
407     #'glsl/pointcoord',
408     #'glsl/points',
409     #'glsl/samplers',
410     #'glsl/shadow_sampler',
411     #'glsl/shtest',
412     #'glsl/skinning',
413     #'glsl/texaaline',
414     #'glsl/texdemo1',
415     #'glsl/toyball',
416     #'glsl/trirast',
417     #'glsl/twoside',
418     #'glsl/vert-or-frag-only',
419     #'glsl/vert-tex',
420     #'glsl/vsraytrace',
421     #'gs/gs-tri',
422     #'perf/copytex',
423     #'perf/drawoverhead',
424     #'perf/fbobind',
425     #'perf/fill',
426     #'perf/genmipmap',
427     #'perf/readpixels',
428     #'perf/swapbuffers',
429     #'perf/teximage',
430     #'perf/vbo',
431     #'perf/vertexrate',
432     #'redbook/aaindex',
433     #'redbook/aapoly',
434     #'redbook/aargb',
435     #'redbook/accanti',
436     #'redbook/accpersp',
437     #'redbook/alpha',
438     #'redbook/alpha3D',
439     #'redbook/anti',
440     #'redbook/bezcurve',
441     #'redbook/bezmesh',
442     #'redbook/checker',
443     #'redbook/clip',
444     #'redbook/colormat',
445     #'redbook/combiner',
446     #'redbook/convolution',
447     #'redbook/cube',
448     #'redbook/cubemap',
449     #'redbook/depthcue',
450     #'redbook/dof',
451     #'redbook/double',
452     #'redbook/drawf',
453     #'redbook/feedback',
454     #'redbook/fog',
455     #'redbook/fogcoord',
456     #'redbook/fogindex',
457     #'redbook/font',
458     #'redbook/hello',
459     #'redbook/histogram',
460     #'redbook/image',
461     #'redbook/light',
462     #'redbook/lines',
463     #'redbook/list',
464     #'redbook/material',
465     #'redbook/minmax',
466     #'redbook/mipmap',
467     #'redbook/model',
468     #'redbook/movelight',
469     #'redbook/multisamp',
470     #'redbook/multitex',
471     #'redbook/mvarray',
472     #'redbook/nurbs',
473     #'redbook/pickdepth',
474     #'redbook/picksquare',
475     #'redbook/plane',
476     #'redbook/planet',
477     #'redbook/pointp',
478     #'redbook/polyoff',
479     #'redbook/polys',
480     #'redbook/quadric',
481     #'redbook/robot',
482     #'redbook/sccolorlight',
483     #'redbook/scene',
484     #'redbook/scenebamb',
485     #'redbook/sceneflat',
486     #'redbook/select',
487     #'redbook/shadowmap',
488     #'redbook/smooth',
489     #'redbook/stencil',
490     #'redbook/stroke',
491     #'redbook/surface',
492     #'redbook/surfpoints',
493     #'redbook/teaambient',
494     #'redbook/teapots',
495     #'redbook/tess',
496     #'redbook/tesswind',
497     #'redbook/texbind',
498     #'redbook/texgen',
499     #'redbook/texprox',
500     #'redbook/texsub',
501     #'redbook/texture3d',
502     #'redbook/texturesurf',
503     #'redbook/torus',
504     #'redbook/trim',
505     #'redbook/unproject',
506     #'redbook/varray',
507     #'redbook/wrap',
508     #'samples/accum',
509     #'samples/bitmap1',
510     #'samples/bitmap2',
511     #'samples/blendeq',
512     #'samples/blendxor',
513     #'samples/copy',
514     #'samples/cursor',
515     #'samples/depth',
516     #'samples/eval',
517     #'samples/fog',
518     #'samples/font',
519     #'samples/line',
520     #'samples/logo',
521     #'samples/nurb',
522     #'samples/oglinfo',
523     #'samples/olympic',
524     #'samples/overlay',
525     #'samples/point',
526     #'samples/prim',
527     #'samples/quad',
528     #'samples/rgbtoppm',
529     #'samples/select',
530     #'samples/shape',
531     #'samples/sphere',
532     #'samples/star',
533     #'samples/stencil',
534     #'samples/stretch',
535     #'samples/texture',
536     #'samples/tri',
537     #'samples/wave',
538     #'slang/cltest',
539     #'slang/sotest',
540     #'slang/vstest',
541     'tests/afsmultiarb',
542     'tests/antialias',
543     'tests/arbfpspec',
544     'tests/arbfptest1',
545     'tests/arbfptexture',
546     'tests/arbfptrig',
547     'tests/arbgpuprog',
548     'tests/arbnpot',
549     'tests/arbnpot-mipmap',
550     'tests/arbvptest1',
551     'tests/arbvptest3',
552     'tests/arbvptorus',
553     'tests/arbvpwarpmesh',
554     'tests/arraytexture',
555     'tests/auxbuffer',
556     'tests/blendxor',
557     'tests/blitfb',
558     'tests/bufferobj',
559     'tests/bug_3050',
560     'tests/bug_3101',
561     'tests/bug_3195',
562     'tests/bug_texstore_i8',
563     'tests/bumpmap',
564     'tests/calibrate_rast',
565     'tests/condrender',
566     'tests/copypixrate',
567     'tests/cva',
568     'tests/cva_huge',
569     'tests/cylwrap',
570     'tests/drawbuffers',
571     'tests/drawbuffers2',
572     'tests/drawstencil',
573     'tests/exactrast',
574     'tests/ext422square',
575     'tests/fbotest1',
576     'tests/fbotest2',
577     'tests/fbotest3',
578     'tests/fillrate',
579     'tests/floattex',
580     'tests/fogcoord',
581     'tests/fptest1',
582     'tests/fptexture',
583     'tests/getteximage',
584     'tests/glutfx',
585     'tests/interleave',
586     'tests/invert',
587     'tests/jkrahntest',
588     'tests/lineclip',
589     'tests/manytex',
590     'tests/mapbufrange',
591     'tests/minmag',
592     'tests/mipgen',
593     'tests/mipmap_comp',
594     'tests/mipmap_comp_tests',
595     'tests/mipmap_limits',
596     'tests/mipmap_tunnel',
597     'tests/mipmap_view',
598     'tests/multipal',
599     'tests/multitexarray',
600     'tests/multiwindow',
601     'tests/no_s3tc',
602     'tests/occlude',
603     'tests/packedpixels',
604     'tests/pbo',
605     'tests/persp_hint',
606     'tests/prim',
607     'tests/prog_parameter',
608     'tests/quads',
609     'tests/random',
610     'tests/readrate',
611     'tests/rubberband',
612     'tests/scissor',
613     'tests/scissor-viewport',
614     'tests/seccolor',
615     'tests/shader-interp',
616     'tests/shader_api',
617     'tests/shadow-sample',
618     'tests/sharedtex',
619     'tests/stencilreaddraw',
620     'tests/stencilwrap',
621     'tests/step',
622     'tests/streaming_rect',
623     'tests/subtex',
624     'tests/subtexrate',
625     'tests/tex1d',
626     'tests/texcmp',
627     'tests/texcompress2',
628     'tests/texcompsub',
629     'tests/texdown',
630     'tests/texfilt',
631     'tests/texgenmix',
632     'tests/texleak',
633     'tests/texline',
634     'tests/texobj',
635     'tests/texobjshare',
636     'tests/texrect',
637     'tests/unfilledclip',
638     'tests/vparray',
639     'tests/vpeval',
640     'tests/vptest1',
641     'tests/vptest2',
642     'tests/vptest3',
643     'tests/vptorus',
644     'tests/vpwarpmesh',
645     'tests/yuvrect',
646     'tests/yuvsquare',
647     'tests/zbitmap',
648     'tests/zcomp',
649     'tests/zdrawpix',
650     'tests/zreaddraw',
651     #'vp/vp-tris',
652     #'vpglsl/vp-tris',
653     #'xdemos/corender',
654     #'xdemos/glsync',
655     #'xdemos/glthreads',
656     #'xdemos/glxcontexts',
657     #'xdemos/glxdemo',
658     #'xdemos/glxgears',
659     #'xdemos/glxgears_fbconfig',
660     #'xdemos/glxgears_pixmap',
661     #'xdemos/glxheads',
662     #'xdemos/glxinfo',
663     #'xdemos/glxpbdemo',
664     #'xdemos/glxpixmap',
665     #'xdemos/glxsnoop',
666     #'xdemos/glxswapcontrol',
667     #'xdemos/manywin',
668     #'xdemos/msctest',
669     #'xdemos/multictx',
670     #'xdemos/offset',
671     #'xdemos/omlsync',
672     #'xdemos/opencloseopen',
673     #'xdemos/overlay',
674     #'xdemos/pbdemo',
675     #'xdemos/pbinfo',
676     #'xdemos/shape',
677     #'xdemos/sharedtex',
678     #'xdemos/sharedtex_mt',
679     #'xdemos/texture_from_pixmap',
680     #'xdemos/wincopy',
681     #'xdemos/xfont',
682     #'xdemos/xrotfontdemo',
683     #'xdemos/yuvrect_client',
684 ]
685
686
687 _tests = [
688     'trivial/tri',
689     'trivial/tri-tex',
690 ]
691
692
693 def main():
694     global options
695
696     # Parse command line options
697     optparser = optparse.OptionParser(
698         usage='\n\t%prog [options] [demo] ...',
699         version='%%prog')
700     optparser.add_option(
701         '--build', metavar='PATH',
702         type='string', dest='build', default='.',
703         help='path to apitrace build [default=%default]')
704     optparser.add_option(
705         '--results', metavar='PATH',
706         type='string', dest='results', default='.',
707         help='results directory [default=%default]')
708     optparser.add_option(
709         '--mesa-demos', metavar='PATH',
710         type='string', dest='mesa_demos', default=os.environ.get('MESA_DEMOS'),
711         help='path to Mesa demos [default=%default]')
712
713     (options, args) = optparser.parse_args(sys.argv[1:])
714
715     if not options.mesa_demos:
716         optparser.error('path to Mesa demos not specified')
717     if not os.path.exists(options.results):
718         os.makedirs(options.results)
719
720     html = open(os.path.join(options.results, 'index.html'), 'wt')
721     html.write('<html>\n')
722     html.write('  <body>\n')
723     html.write('    <table border="1">\n')
724     html.write('      <tr><th>Ref</th><th>Src</th><th>&Delta;</th></tr>\n')
725     if not args:
726         args = tests
727     for test in args:
728        runtest(html, test)
729     html.write('    </table>\n')
730     html.write('  </body>\n')
731     html.write('</html>\n')
732
733
734 if __name__ == '__main__':
735     main()