]> git.cworth.org Git - apitrace-tests/blobdiff - app_driver.py
Only invoke pkg_check_modules when PKG_CONFIG_FOUND is true.
[apitrace-tests] / app_driver.py
index a44badea1566d4248e80ed28374359dd22710fe7..3589fd009f8548d1b2b0698396dee038b7840bc8 100755 (executable)
@@ -42,102 +42,25 @@ except ImportError:
     from StringIO import StringIO
 
 
+import tracematch
 from base_driver import *
 
 
-class TraceChecker:
+class SrcTraceParser(tracematch.SrcTraceParser):
 
-    def __init__(self, srcStream, refFileName, verbose=False):
-        self.srcStream = srcStream
-        self.refFileName = refFileName
-        if refFileName:
-            self.refStream = open(refFileName, 'rt')
-        else:
-            self.refStream = None
-        self.verbose = verbose
-        self.doubleBuffer = False
-        self.callNo = 0
-        self.refLine = ''
-        self.images = []
-        self.states = []
-
-    call_re = re.compile(r'^([0-9]+) (\w+)\(')
-
-    def check(self):
-
-        swapbuffers = 0
-        flushes = 0
-
-        srcLines = []
-        self.consumeRefLine()
-        for line in self.srcStream:
-            line = line.rstrip()
-            if self.verbose:
-                sys.stdout.write(line + '\n')
-            mo = self.call_re.match(line)
-            if mo:
-                self.callNo = int(mo.group(1))
-                function_name = mo.group(2)
-                if function_name.find('SwapBuffers') != -1 or \
-                   line.find('kCGLPFADoubleBuffer') != -1:
-                    swapbuffers += 1
-                if function_name in ('glFlush', 'glFinish'):
-                    flushes += 1
-                srcLine = line[mo.start(2):]
-            else:
-                srcLine = line
-            if self.refLine:
-                if srcLine == self.refLine:
-                    self.consumeRefLine()
-                    srcLines = []
-                else:
-                    srcLines.append(srcLine)
-
-        if self.refLine:
-            if srcLines:
-                fail('missing call `%s` (found `%s`)' % (self.refLine, srcLines[0]))
-            else:
-                fail('missing call %s' % self.refLine)
+    def __init__(self, stream):
+        tracematch.SrcTraceParser.__init__(self, stream)
+        self.swapbuffers = 0
 
-        if swapbuffers:
-            self.doubleBuffer = True
-        else:
-            self.doubleBuffer = False
+    def handleCall(self, callNo, functionName, args, ret):
+        tracematch.SrcTraceParser.handleCall(self, callNo, functionName, args, ret)
 
-    def consumeRefLine(self):
-        if not self.refStream:
-            self.refLine = ''
-            return
+        if functionName.find('SwapBuffers') != -1 or \
+           repr(args).find('kCGLPFADoubleBuffer') != -1:
+            self.swapbuffers += 1
 
-        while True:
-            line = self.refStream.readline()
-            if not line:
-                break
-            line = line.rstrip()
-            if line.startswith('#'):
-                self.handlePragma(line)
-            else:
-                break
-        self.refLine = line
-
-    def handlePragma(self, line):
-        pragma, rest = line.split(None, 1)
-        if pragma == '#image':
-            imageFileName = self.getAbsPath(rest)
-            self.images.append((self.callNo, imageFileName))
-        elif pragma == '#state':
-            stateFileName = self.getAbsPath(rest)
-            self.states.append((self.callNo, stateFileName))
-        else:
-            assert False
 
-    def getAbsPath(self, path):
-        '''Get the absolute from a path relative to the reference filename'''
-        return os.path.abspath(os.path.join(os.path.dirname(self.refFileName), path))
-
-
-
-class TestCase:
+class AppDriver(Driver):
 
     cmd = None
     cwd = None
@@ -155,6 +78,7 @@ class TestCase:
     threshold_precision = 12.0
 
     def __init__(self):
+        Driver.__init__(self)
         self.stateCache = {}
     
     def runApp(self):
@@ -164,22 +88,49 @@ class TestCase:
         if not self.cmd:
             return
 
+        sys.stderr.write('Run application...\n')
+
         p = popen(self.cmd, cwd=self.cwd)
         p.wait()
-        if p.returncode:
+        if p.returncode != 0:
             skip('application returned code %i' % p.returncode)
 
-    api_map = {
+        sys.stdout.flush()
+        sys.stderr.write('\n')
+
+    api_trace_map = {
         'gl': 'gl',
         'egl_gl': 'egl',
         'egl_gles1': 'egl',
         'egl_gles2': 'egl',
+        'd3d7': 'd3d7',
+        'd3d8': 'd3d8',
+        'd3d9': 'd3d9',
+        'd3d10': 'd3d10',
+        'd3d10_1': 'd3d10_1',
+        'd3d11': 'd3d11',
+        'd3d11_1': 'd3d11',
+    }
+
+    api_retrace_map = {
+        'gl': 'glretrace',
+        'egl_gl': 'eglretrace',
+        'egl_gles1': 'eglretrace',
+        'egl_gles2': 'eglretrace',
+        #'d3d8': 'd3dretrace',
+        'd3d9': 'd3dretrace',
+        'd3d10': 'd3dretrace',
+        'd3d10_1': 'd3dretrace',
+        'd3d11': 'd3dretrace',
+        'd3d11_1': 'd3dretrace',
     }
 
     def traceApp(self):
         if not self.cmd:
             return
 
+        sys.stderr.write('Capturing trace...\n')
+
         if self.trace_file is None:
             if self.ref_dump is not None:
                 name = self.ref_dump
@@ -201,7 +152,7 @@ class TestCase:
         
         cmd = [
             options.apitrace, 'trace', 
-            '--api', self.api_map[self.api],
+            '--api', self.api_trace_map[self.api],
             '--output', self.trace_file,
             '--'
         ] + cmd
@@ -210,31 +161,79 @@ class TestCase:
 
         p = popen(cmd, env=env, cwd=self.cwd)
         p.wait()
+        if p.returncode != 0:
+            fail('`apitrace trace` returned code %i' % p.returncode)
 
         if not os.path.exists(self.trace_file):
             fail('no trace file generated\n')
+
+        sys.stdout.flush()
+        sys.stderr.write('\n')
     
     def checkTrace(self):
+        sys.stderr.write('Comparing trace %s against %s...\n' % (self.trace_file, self.ref_dump))
+
         cmd = [options.apitrace, 'dump', '--color=never', self.trace_file]
         p = popen(cmd, stdout=subprocess.PIPE)
 
-        checker = TraceChecker(p.stdout, self.ref_dump, self.verbose)
-        checker.check()
+        srcParser = SrcTraceParser(p.stdout)
+        srcTrace = srcParser.parse()
+        self.doubleBuffer = srcParser.swapbuffers > 0
+
+        images = []
+        states = []
+
+        if self.ref_dump:
+            refParser = tracematch.RefTraceParser(self.ref_dump)
+            refTrace = refParser.parse()
+
+            try:
+                mo = refTrace.match(srcTrace)
+            except tracematch.TraceMismatch, ex:
+                fail(str(ex))
+
+            dirName, baseName = os.path.split(os.path.abspath(self.ref_dump))
+            prefix, _ = os.path.splitext(baseName)
+            prefix += '.'
+            fileNames = os.listdir(dirName)
+            for fileName in fileNames:
+                if fileName.startswith(prefix) and fileName != self.ref_dump:
+                    rest = fileName[len(prefix):]
+                    paramName, ext = os.path.splitext(rest)
+                    if ext in ('.json', '.png'):
+                        if paramName.isdigit():
+                            callNo = int(paramName)
+                        else:
+                            try:
+                                callNo = mo.params[paramName]
+                            except KeyError:
+                                fail('could not find parameter %s for %s' % (paramName, fileName))
+                        filePath = os.path.join(dirName, fileName)
+                        if ext == '.png':
+                            images.append((callNo, filePath))
+                        if ext == '.json':
+                            states.append((callNo, filePath))
         p.wait()
         if p.returncode != 0:
             fail('`apitrace dump` returned code %i' % p.returncode)
 
-        self.doubleBuffer = checker.doubleBuffer
+        sys.stdout.flush()
+        sys.stderr.write('\n')
+
+        if self.api not in self.api_retrace_map:
+            return
 
-        for callNo, refImageFileName in checker.images:
+        for callNo, refImageFileName in images:
             self.checkImage(callNo, refImageFileName)
-        for callNo, refStateFileName in checker.states:
+        for callNo, refStateFileName in states:
             self.checkState(callNo, refStateFileName)
 
     def checkImage(self, callNo, refImageFileName):
+        sys.stderr.write('Comparing snapshot from call %u against %s...\n' % (callNo, refImageFileName))
         try:
             from PIL import Image
         except ImportError:
+            sys.stderr.write('warning: PIL not found, skipping image comparison\n');
             return
 
         srcImage = self.getImage(callNo)
@@ -252,7 +251,12 @@ class TestCase:
             comparer.write_diff(diffImageFileName)
             fail('snapshot from call %u does not match %s' % (callNo, refImageFileName))
 
+        sys.stdout.flush()
+        sys.stderr.write('\n')
+
     def checkState(self, callNo, refStateFileName):
+        sys.stderr.write('Comparing state dump from call %u against %s...\n' % (callNo, refStateFileName))
+
         srcState = self.getState(callNo)
         refState = self.getRefState(refStateFileName)
 
@@ -270,6 +274,9 @@ class TestCase:
             differ.visit(refState, srcState)
             fail('state from call %u does not match %s' % (callNo, refStateFileName))
 
+        sys.stdout.flush()
+        sys.stderr.write('\n')
+
     def getRefState(self, refStateFileName):
         stream = open(refStateFileName, 'rt')
         from jsondiff import load
@@ -292,11 +299,19 @@ class TestCase:
         open(filename, 'wt').write(s)
 
     def retrace(self):
+        if self.api not in self.api_retrace_map:
+            return
+
+        sys.stderr.write('Retracing %s...\n' % (self.trace_file,))
+
         p = self._retrace()
         p.wait()
         if p.returncode != 0:
             fail('retrace failed with code %i' % (p.returncode))
 
+        sys.stdout.flush()
+        sys.stderr.write('\n')
+
     def getImage(self, callNo):
         from PIL import Image
         state = self.getState(callNo)
@@ -351,19 +366,9 @@ class TestCase:
         except KeyError:
             return
 
-        # On NVIDIA drivers glGetIntegerv(GL_INDEX_WRITEMASK) returns -1
+        # On NVIDIA drivers glGetIntegerv(GL_INDEX_WRITEMASK) returns 255
         self.replaceState(parameters, 'GL_INDEX_WRITEMASK', 255, -1)
 
-        # On Gallium 
-        if 'Gallium' in parameters['GL_RENDERER'].split():
-            # Gallium drivers have wrong defaults for draw/read buffer state
-            self.replaceState(parameters, 'GL_DRAW_BUFFER', 'GL_BACK_LEFT', 'GL_BACK')
-            self.replaceState(parameters, 'GL_DRAW_BUFFER0', 'GL_BACK_LEFT', 'GL_BACK')
-            self.replaceState(parameters, 'GL_READ_BUFFER', 'GL_BACK_LEFT', 'GL_BACK')
-            self.replaceState(parameters, 'GL_DRAW_BUFFER', 'GL_FRONT_LEFT', 'GL_FRONT')
-            self.replaceState(parameters, 'GL_DRAW_BUFFER0', 'GL_FRONT_LEFT', 'GL_FRONT')
-            self.replaceState(parameters, 'GL_READ_BUFFER', 'GL_FRONT_LEFT', 'GL_FRONT')
-
     def adjustRefState(self, state):
         # Do some adjustments on reference state to eliminate failures from
         # bugs/issues outside of apitrace
@@ -394,8 +399,9 @@ class TestCase:
             pass
 
     def _retrace(self, args = None, stdout=subprocess.PIPE):
-        retrace = self.api_map[self.api] + 'retrace'
-        cmd = [get_build_program(retrace)]
+        retrace = self.api_retrace_map[self.api]
+        #cmd = [get_build_program(retrace)]
+        cmd = [options.apitrace, 'retrace']
         if self.doubleBuffer:
             cmd += ['-db']
         else:
@@ -405,19 +411,8 @@ class TestCase:
         cmd += [self.trace_file]
         return popen(cmd, stdout=stdout)
 
-    def run(self):
-        self.runApp()
-        self.traceApp()
-        self.checkTrace()
-        self.retrace()
-
-        pass_()
-
-
-class AppMain(Main):
-
     def createOptParser(self):
-        optparser = Main.createOptParser(self)
+        optparser = Driver.createOptParser(self)
 
         optparser.add_option(
             '-a', '--api', metavar='API',
@@ -434,7 +429,7 @@ class AppMain(Main):
 
         return optparser
 
-    def main(self):
+    def run(self):
         global options
 
         (options, args) = self.parseOptions()
@@ -442,17 +437,20 @@ class AppMain(Main):
         if not os.path.exists(options.results):
             os.makedirs(options.results)
 
-        test = TestCase()
-        test.verbose = options.verbose
+        self.verbose = options.verbose
 
-        test.cmd = args
-        test.cwd = options.cwd
-        test.api = options.api
-        test.ref_dump = options.ref_dump
-        test.results = options.results
+        self.cmd = args
+        self.cwd = options.cwd
+        self.api = options.api
+        self.ref_dump = options.ref_dump
+        self.results = options.results
 
-        test.run()
+        self.runApp()
+        self.traceApp()
+        self.checkTrace()
+        self.retrace()
 
+        pass_()
 
 if __name__ == '__main__':
-    AppMain().main()
+    AppDriver().run()