| #!/usr/bin/env python3 |
| ########################################################################## |
| # |
| # Copyright 2012 VMware Inc. |
| # All Rights Reserved. |
| # |
| # Permission is hereby granted, free of charge, to any person obtaining a copy |
| # of this software and associated documentation files (the 'Software'), to deal |
| # in the Software without restriction, including without limitation the rights |
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| # copies of the Software, and to permit persons to whom the Software is |
| # furnished to do so, subject to the following conditions: |
| # |
| # The above copyright notice and this permission notice shall be included in |
| # all copies or substantial portions of the Software. |
| # |
| # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| # THE SOFTWARE. |
| # |
| ##########################################################################/ |
| |
| '''Convert traces to/from PIX. |
| ''' |
| |
| |
| import optparse |
| import os.path |
| import subprocess |
| import platform |
| import sys |
| |
| |
| def callProcess(cmd): |
| if options.verbose: |
| sys.stderr.write(' '.join(cmd) + '\n') |
| ret = subprocess.call(cmd) |
| if ret: |
| exeName = os.path.basename(cmd[0]) |
| sys.stderr.write('error: %s failed with exit code %u\n' % (exeName, ret)) |
| sys.exit(ret) |
| return ret |
| |
| |
| def verifyTrace(outTrace): |
| if os.path.exists(outTrace): |
| sys.stderr.write('info: %s written\n' % outTrace) |
| if options.verify: |
| callProcess([options.retrace, os.path.abspath(outTrace)]) |
| else: |
| sys.stderr.write('error: %s not written\n' % outTrace) |
| sys.exit(1) |
| |
| |
| def getPixExe(): |
| try: |
| programFiles = os.environ['ProgramFiles(x86)'] |
| except KeyError: |
| programFiles = os.environ['ProgramFiles'] |
| try: |
| dxsdkDir = os.environ['DXSDK_DIR'] |
| except KeyError: |
| dxsdkDir = os.path.join(programFiles, "Microsoft DirectX SDL (June 2010)") |
| pixExe = os.path.join(dxsdkDir, "Utilities", "bin", 'x86', 'PIXwin.exe') |
| return pixExe |
| |
| |
| def convertToPix(inTrace, outPixrun): |
| pixExe = getPixExe() |
| |
| pixExp = os.path.join(os.path.dirname(__file__), 'apitrace.PIXExp') |
| |
| # http://social.msdn.microsoft.com/Forums/sv/devdocs/thread/15addc0c-036d-413a-854a-35637ccbb834 |
| # http://src.chromium.org/svn/trunk/o3d/tests/test_driver.py |
| cmd = [ |
| getPixExe(), |
| pixExp, |
| '-start', |
| '-runfile', os.path.abspath(outPixrun), |
| '-targetpath', os.path.abspath(options.retrace), |
| #'-targetstartfolder', ..., |
| '-targetargs', os.path.abspath(inTrace), |
| ] |
| |
| callProcess(cmd) |
| if os.path.exists(outPixrun): |
| sys.stderr.write('info: %s written\n' % outPixrun) |
| if options.verify: |
| subprocess.call([pixExe, os.path.abspath(outPixrun)]) |
| else: |
| sys.stderr.write('error: %s not written\n' % outPixrun) |
| sys.exit(1) |
| |
| |
| def detectApiFromCsv(inCsv): |
| import csv |
| csvReader = csv.reader(open(inCsv, 'rt'), ) |
| for row in csvReader: |
| print(row) |
| event = row[2] |
| print(event) |
| if event.startswith("Direct3DCreate9"): |
| return "d3d9" |
| if event.startswith("CreateDXGIFactory"): |
| return "dxgi" |
| if event.startswith("D3D10CreateDevice"): |
| return "d3d10" |
| if event.startswith("D3D11CreateDevice"): |
| return "d3d11" |
| assert False |
| |
| |
| def convertFromPix(inPix, outTrace): |
| pixExe = getPixExe() |
| |
| api = options.api |
| |
| if True: |
| # Use -exporttocsv option to detect which API to use |
| cmd = [ |
| pixExe, |
| inPix, |
| '-exporttocsv', |
| ] |
| |
| # XXX: output filename is ignored |
| inPixDir, inPixFileName = os.path.split(inPix) |
| inPixName, inPixExt = os.path.splitext(inPixFileName) |
| outCsv = os.path.join(inPixDir, inPixName + '.csv') |
| |
| if os.path.exists(outCsv): |
| os.remove(outCsv) |
| |
| callProcess(cmd) |
| |
| if os.path.isfile(outCsv): |
| api = detectApiFromCsv(outCsv) |
| |
| cmd = [ |
| options.apitrace, |
| 'trace', |
| '-a', api, |
| '-o', outTrace, |
| pixExe, |
| inPix, |
| ] |
| |
| # XXX: Autodetect somehow |
| if not options.single_frame: |
| # Full capture |
| cmd += ['-playstandalone'] |
| else: |
| # Single-frame capture |
| cmd += ['-autorenderto', 'nul:'] |
| |
| callProcess(cmd) |
| verifyTrace(outTrace) |
| |
| |
| def getDxcapExe(): |
| winDir = os.environ['windir'] |
| if 'ProgramFiles(x86)' in os.environ: |
| sysSubDir = 'SysWOW64' |
| else: |
| sysSubDir = 'System32' |
| dxcapExe = os.path.join(winDir, sysSubDir, 'dxcap.exe') |
| return dxcapExe |
| |
| |
| def convertToDxcap(inTrace, outDxcaprun): |
| # https://msdn.microsoft.com/en-us/library/vstudio/dn774939.aspx |
| |
| dxcapExe = getDxcapExe() |
| |
| cmd = [ |
| getDxcapExe(), |
| '-rawmode', |
| '-file', os.path.abspath(outDxcaprun), |
| '-c', |
| options.retrace, |
| '-b', |
| os.path.abspath(inTrace), |
| ] |
| |
| callProcess(cmd) |
| if os.path.exists(outDxcaprun): |
| sys.stderr.write('info: %s written\n' % outDxcaprun) |
| if options.verify: |
| callProcess([dxcapExe, '-p', os.path.abspath(outDxcaprun)]) |
| else: |
| sys.stderr.write('error: %s not written\n' % outDxcaprun) |
| sys.exit(1) |
| |
| |
| def convertFromDxcap(inDxcap, outTrace): |
| dxcapExe = getDxcapExe() |
| |
| cmd = [ |
| options.apitrace, |
| 'trace', |
| '-a', options.api, |
| '-o', outTrace, |
| '--', |
| dxcapExe, |
| '-rawmode', |
| '-p', inDxcap, |
| ] |
| |
| callProcess(cmd) |
| verifyTrace(outTrace) |
| |
| |
| def main(): |
| global options |
| |
| # Parse command line options |
| optparser = optparse.OptionParser( |
| usage='\n\t%prog [options] <trace> ...', |
| version='%%prog') |
| optparser.add_option( |
| '--apitrace', metavar='PROGRAM', |
| type='string', dest='apitrace', default='apitrace.exe', |
| help='path to apitrace command [default: %default]') |
| optparser.add_option( |
| '-a', '--api', metavar='API', |
| type='string', dest='api', default='dxgi', |
| help='api [default: %default]') |
| optparser.add_option( |
| '-r', '--retrace', metavar='PROGRAM', |
| type='string', dest='retrace', default='d3dretrace.exe', |
| help='path to retrace command [default: %default]') |
| optparser.add_option( |
| '-v', '--verbose', |
| action='store_true', dest='verbose', default=False, |
| help='verbose output') |
| optparser.add_option( |
| '-o', '--output', metavar='FILE', |
| type="string", dest="output", |
| help="output file [default: stdout]") |
| optparser.add_option( |
| '--single-frame', |
| action='store_true', dest='single_frame', default=False, |
| help='single-frame PIXRun capture') |
| optparser.add_option( |
| '--verify', |
| action='store_true', dest='verify', default=False, |
| help='verify output by replaying it') |
| |
| (options, args) = optparser.parse_args(sys.argv[1:]) |
| if not args: |
| optparser.error("incorrect number of arguments") |
| |
| for inFile in args: |
| name, inExt = os.path.splitext(os.path.basename(inFile)) |
| if inExt.lower() == '.trace': |
| convert = convertToDxcap |
| outExt = '.vsglog' |
| if options.output: |
| _, outExt = os.path.splitext(options.output) |
| if outExt.lower() == '.pixrun': |
| convert = convertToPix |
| elif inExt.lower() == '.vsglog': |
| convert = convertFromDxcap |
| outExt = '.trace' |
| elif inExt.lower() == '.pixrun': |
| convert = convertFromPix |
| outExt = '.trace' |
| else: |
| optparser.error("unexpected file extensions `%s`" % inExt) |
| if options.output: |
| outFile = options.output |
| else: |
| outFile = name + outExt |
| |
| if os.path.exists(outFile): |
| os.remove(outFile) |
| convert(inFile, outFile) |
| |
| |
| if __name__ == '__main__': |
| main() |