X-Git-Url: https://git.cworth.org/git?p=apitrace-tests;a=blobdiff_plain;f=app_driver.py;h=0e6cc37c65c5f68ab82b82b4e16cc70f358ebe6e;hp=8dd7b5e782dbff73b96d163ecb9ba44789799f47;hb=8351c1e187d8f65477db05a07bacd5d184c2b950;hpb=31b8ad2c38b6697088ab30422bb32d703947c43a diff --git a/app_driver.py b/app_driver.py index 8dd7b5e..0e6cc37 100755 --- a/app_driver.py +++ b/app_driver.py @@ -42,99 +42,22 @@ 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) - - if swapbuffers: - self.doubleBuffer = True - else: - self.doubleBuffer = False - - def consumeRefLine(self): - if not self.refStream: - self.refLine = '' - return + def __init__(self, stream): + tracematch.SrcTraceParser.__init__(self, stream) + self.swapbuffers = 0 - 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)) + def handleCall(self, callNo, functionName, args, ret): + tracematch.SrcTraceParser.handleCall(self, callNo, functionName, args, ret) + if functionName.find('SwapBuffers') != -1 or \ + repr(args).find('kCGLPFADoubleBuffer') != -1: + self.swapbuffers += 1 class AppDriver(Driver): @@ -165,11 +88,16 @@ class AppDriver(Driver): 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) + sys.stdout.flush() + sys.stderr.write('\n') + api_trace_map = { 'gl': 'gl', 'egl_gl': 'egl', @@ -179,6 +107,9 @@ class AppDriver(Driver): 'd3d8': 'd3d8', 'd3d9': 'd3d9', 'd3d10': 'd3d10', + 'd3d10_1': 'd3d10_1', + 'd3d11': 'd3d11', + 'd3d11_1': 'd3d11', } api_retrace_map = { @@ -186,13 +117,20 @@ class AppDriver(Driver): '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 @@ -214,8 +152,9 @@ class AppDriver(Driver): cmd = [ options.apitrace, 'trace', - '--api', self.api_trace_map[self.api], - '--output', self.trace_file, + '-v', + '-a', self.api_trace_map[self.api], + '-o', self.trace_file, '--' ] + cmd if self.max_frames is not None: @@ -223,34 +162,79 @@ class AppDriver(Driver): 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): - cmd = [options.apitrace, 'dump', '--color=never', self.trace_file] - p = popen(cmd, stdout=subprocess.PIPE) + sys.stderr.write('Comparing trace %s against %s...\n' % (self.trace_file, self.ref_dump)) + + cmd = [options.apitrace, 'dump', '--verbose', '--color=never', self.trace_file] + p = popen(cmd, stdout=subprocess.PIPE, universal_newlines=True) + + srcParser = SrcTraceParser(p.stdout) + srcTrace = srcParser.parse() + self.doubleBuffer = srcParser.swapbuffers > 0 - checker = TraceChecker(p.stdout, self.ref_dump, self.verbose) - checker.check() + 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) @@ -268,7 +252,12 @@ class AppDriver(Driver): 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) @@ -286,6 +275,9 @@ class AppDriver(Driver): 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 @@ -311,23 +303,27 @@ class AppDriver(Driver): 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) if self.doubleBuffer: - attachments = ['GL_BACK', 'GL_BACK_LEFT', 'GL_BACK_RIGHT', 'GL_COLOR_ATTACHMENT0'] + attachments = ['GL_BACK', 'GL_BACK_LEFT', 'GL_BACK_RIGHT', 'GL_COLOR_ATTACHMENT0', 'RENDER_TARGET_0'] else: - attachments = ['GL_FRONT', 'GL_FRONT_LEFT', 'GL_FRONT_RIGHT', 'GL_COLOR_ATTACHMENT0'] + attachments = ['GL_FRONT', 'GL_FRONT_LEFT', 'GL_FRONT_RIGHT', 'GL_COLOR_ATTACHMENT0', 'RENDER_TARGET_0'] imageObj = self.getFramebufferAttachment(state, attachments) data = imageObj['__data__'] stream = StringIO(base64.b64decode(data)) im = Image.open(stream) - im.save('test.png') return im def getFramebufferAttachment(self, state, attachments): @@ -370,19 +366,9 @@ class AppDriver(Driver): 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 @@ -414,7 +400,8 @@ class AppDriver(Driver): def _retrace(self, args = None, stdout=subprocess.PIPE): retrace = self.api_retrace_map[self.api] - cmd = [get_build_program(retrace)] + #cmd = [get_build_program(retrace)] + cmd = [options.apitrace, 'retrace'] if self.doubleBuffer: cmd += ['-db'] else: