def popen(command, *args, **kwargs):
if kwargs.get('cwd', None) is not None:
sys.stdout.write('cd %s && ' % kwargs['cwd'])
- if 'env' in kwargs:
- for name, value in kwargs['env'].iteritems():
+
+ try:
+ env = kwargs.pop('env')
+ except KeyError:
+ env = None
+ else:
+ names = env.keys()
+ names.sort()
+ for name in names:
+ value = env[name]
if value != os.environ.get(name, None):
sys.stdout.write('%s=%s ' % (name, value))
+ env[name] = str(value)
+
sys.stdout.write(' '.join(command) + '\n')
sys.stdout.flush()
- return subprocess.Popen(command, *args, **kwargs)
+
+ return subprocess.Popen(command, *args, env=env, **kwargs)
def _get_build_path(path):
sys.stdout.write(line + '\n')
mo = self.call_re.match(line)
if mo:
- self.call_no = int(mo.group(1))
+ self.callNo = int(mo.group(1))
function_name = mo.group(2)
if function_name.find('SwapBuffers') != -1 or \
line.find('kCGLPFADoubleBuffer') != -1:
verbose = False
+ threshold_precision = 12.0
+
def __init__(self):
self.stateCache = {}
return
if self.trace_file is None:
- name = os.path.basename(self.cmd[0])
+ if self.ref_dump is not None:
+ name = self.ref_dump
+ else:
+ name = self.cmd[0]
+ name, ext = os.path.splitext(os.path.basename(name))
+ while ext:
+ name, ext = os.path.splitext(os.path.basename(name))
self.trace_file = os.path.abspath(os.path.join(self.results, name + '.trace'))
if os.path.exists(self.trace_file):
os.remove(self.trace_file)
wrapper = _get_build_path('wrappers/opengl32.dll')
local_wrapper = os.path.join(os.path.dirname(self.cmd[0]), os.path.basename(wrapper))
shutil.copy(wrapper, local_wrapper)
- env['TRACE_FILE'] = self.trace_file
+ env['TRACE_FILE'] = str(self.trace_file)
else:
apitrace = _get_build_program('apitrace')
cmd = [
from snapdiff import Comparer
comparer = Comparer(refImage, srcImage)
- match = comparer.ae()
- if not match:
+ precision = comparer.precision(filter=True)
+ sys.stdout.write('precision of %f bits against %s\n' % (precision, refImageFileName))
+ if precision < self.threshold_precision:
prefix = '%s.%u' % (self.getNamePrefix(), callNo)
srcImageFileName = prefix + '.src.png'
+ srcImage.save(srcImageFileName)
diffImageFileName = prefix + '.diff.png'
comparer.write_diff(diffImageFileName)
fail('snapshot from call %u does not match %s' % (callNo, refImageFileName))
def checkState(self, callNo, refStateFileName):
srcState = self.getState(callNo)
- refState = json.load(open(refStateFileName, 'rt'), strict=False)
+ refState = self.getRefState(refStateFileName)
from jsondiff import Comparer, Differ
comparer = Comparer(ignore_added = True)
differ.visit(refState, srcState)
fail('state from call %u does not match %s' % (callNo, refStateFileName))
+ def getRefState(self, refStateFileName):
+ stream = open(refStateFileName, 'rt')
+ from jsondiff import load
+ state = load(stream)
+ self.adjustRefState(state)
+ return state
+
def getNamePrefix(self):
name = os.path.basename(self.ref_dump)
try:
def getImage(self, callNo):
state = self.getState(callNo)
- framebuffer = state['framebuffer']
if self.doubleBuffer:
- imageObj = framebuffer['GL_BACK']
+ attachments = ['GL_BACK', 'GL_BACK_LEFT', 'GL_BACK_RIGHT', 'GL_COLOR_ATTACHMENT0']
else:
- imageObj = framebuffer['GL_FRONT']
+ attachments = ['GL_FRONT', 'GL_FRONT_LEFT', 'GL_FRONT_RIGHT', 'GL_COLOR_ATTACHMENT0']
+ 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):
+ framebufferObj = state['framebuffer']
+ for attachment in attachments:
+ try:
+ attachmentObj = framebufferObj[attachment]
+ except KeyError:
+ pass
+ else:
+ return attachmentObj
+ raise Exception("no attachment found")
+
def getState(self, callNo):
try:
state = self.stateCache[callNo]
if p.returncode != 0:
fail('retrace returned code %i' % (p.returncode))
+ self.adjustSrcState(state)
+
self.stateCache[callNo] = state
return state
+ def adjustSrcState(self, state):
+ # Do some adjustments on the obtained state to eliminate failures from
+ # bugs/issues outside of apitrace
+
+ try:
+ parameters = state['parameters']
+ except KeyError:
+ return
+
+ # On NVIDIA drivers glGetIntegerv(GL_INDEX_WRITEMASK) returns -1
+ 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
+
+ try:
+ parameters = state['parameters']
+ except KeyError:
+ return
+
+ if platform.system() == 'Darwin':
+ # Mac OS X drivers fail on GL_COLOR_SUM
+ # XXX: investigate this
+ self.removeState(parameters, 'GL_COLOR_SUM')
+
+ def replaceState(self, obj, key, srcValue, dstValue):
+ try:
+ value = obj[key]
+ except KeyError:
+ pass
+ else:
+ if value == srcValue:
+ obj[key] = dstValue
+
+ def removeState(self, obj, key):
+ try:
+ del obj[key]
+ except KeyError:
+ pass
+
def _retrace(self, args = None, stdout=subprocess.PIPE):
retrace = self.api_map[self.api] + 'retrace'
- cmd = [_get_build_path(retrace)]
+ cmd = [_get_build_program(retrace)]
if self.doubleBuffer:
cmd += ['-db']
else: