blob: 1f285a8cf1c666d0de41be5fc196ecb981a4ed00 [file] [log] [blame]
Jose Fonseca247e1fa2019-04-28 14:14:44 +01001#!/usr/bin/env python3
José Fonseca2cce1922012-12-11 19:51:26 +00002##########################################################################
3#
4# Copyright 2012 VMware Inc.
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'''Convert traces to/from PIX.
28'''
29
30
31import optparse
32import os.path
33import subprocess
34import platform
35import sys
36
37
José Fonsecaf3cb6202015-02-08 00:05:35 +000038def callProcess(cmd):
39 if options.verbose:
40 sys.stderr.write(' '.join(cmd) + '\n')
41 ret = subprocess.call(cmd)
42 if ret:
43 exeName = os.path.basename(cmd[0])
44 sys.stderr.write('error: %s failed with exit code %u\n' % (exeName, ret))
45 sys.exit(ret)
46 return ret
47
48
49def verifyTrace(outTrace):
50 if os.path.exists(outTrace):
51 sys.stderr.write('info: %s written\n' % outTrace)
52 if options.verify:
53 callProcess([options.retrace, os.path.abspath(outTrace)])
54 else:
55 sys.stderr.write('error: %s not written\n' % outTrace)
56 sys.exit(1)
57
58
José Fonseca8b9f78b2013-04-25 15:22:53 +010059def getPixExe():
José Fonseca2cce1922012-12-11 19:51:26 +000060 try:
José Fonseca87f97d22012-12-11 20:37:39 +000061 programFiles = os.environ['ProgramFiles(x86)']
62 except KeyError:
63 programFiles = os.environ['ProgramFiles']
64 try:
José Fonseca2cce1922012-12-11 19:51:26 +000065 dxsdkDir = os.environ['DXSDK_DIR']
66 except KeyError:
67 dxsdkDir = os.path.join(programFiles, "Microsoft DirectX SDL (June 2010)")
José Fonseca8b9f78b2013-04-25 15:22:53 +010068 pixExe = os.path.join(dxsdkDir, "Utilities", "bin", 'x86', 'PIXwin.exe')
69 return pixExe
70
71
José Fonseca8b9f78b2013-04-25 15:22:53 +010072def convertToPix(inTrace, outPixrun):
José Fonsecaf3cb6202015-02-08 00:05:35 +000073 pixExe = getPixExe()
José Fonseca2cce1922012-12-11 19:51:26 +000074
75 pixExp = os.path.join(os.path.dirname(__file__), 'apitrace.PIXExp')
76
77 # http://social.msdn.microsoft.com/Forums/sv/devdocs/thread/15addc0c-036d-413a-854a-35637ccbb834
78 # http://src.chromium.org/svn/trunk/o3d/tests/test_driver.py
79 cmd = [
José Fonseca8b9f78b2013-04-25 15:22:53 +010080 getPixExe(),
José Fonseca2cce1922012-12-11 19:51:26 +000081 pixExp,
82 '-start',
83 '-runfile', os.path.abspath(outPixrun),
84 '-targetpath', os.path.abspath(options.retrace),
85 #'-targetstartfolder', ...,
86 '-targetargs', os.path.abspath(inTrace),
87 ]
88
José Fonseca8b9f78b2013-04-25 15:22:53 +010089 callProcess(cmd)
José Fonseca2cce1922012-12-11 19:51:26 +000090 if os.path.exists(outPixrun):
91 sys.stderr.write('info: %s written\n' % outPixrun)
José Fonseca8b9f78b2013-04-25 15:22:53 +010092 if options.verify:
José Fonsecaf3cb6202015-02-08 00:05:35 +000093 subprocess.call([pixExe, os.path.abspath(outPixrun)])
José Fonseca2cce1922012-12-11 19:51:26 +000094 else:
95 sys.stderr.write('error: %s not written\n' % outPixrun)
96 sys.exit(1)
97
98
José Fonseca7b5e68d2015-03-26 15:21:46 +000099def detectApiFromCsv(inCsv):
100 import csv
101 csvReader = csv.reader(open(inCsv, 'rt'), )
102 for row in csvReader:
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100103 print(row)
José Fonseca7b5e68d2015-03-26 15:21:46 +0000104 event = row[2]
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100105 print(event)
José Fonseca7b5e68d2015-03-26 15:21:46 +0000106 if event.startswith("Direct3DCreate9"):
107 return "d3d9"
108 if event.startswith("CreateDXGIFactory"):
109 return "dxgi"
110 if event.startswith("D3D10CreateDevice"):
111 return "d3d10"
112 if event.startswith("D3D11CreateDevice"):
113 return "d3d11"
114 assert False
115
116
José Fonseca8b9f78b2013-04-25 15:22:53 +0100117def convertFromPix(inPix, outTrace):
118 pixExe = getPixExe()
119
José Fonseca7b5e68d2015-03-26 15:21:46 +0000120 api = options.api
121
122 if True:
123 # Use -exporttocsv option to detect which API to use
José Fonseca8b9f78b2013-04-25 15:22:53 +0100124 cmd = [
125 pixExe,
126 inPix,
José Fonseca7b5e68d2015-03-26 15:21:46 +0000127 '-exporttocsv',
José Fonseca8b9f78b2013-04-25 15:22:53 +0100128 ]
José Fonseca7b5e68d2015-03-26 15:21:46 +0000129
130 # XXX: output filename is ignored
131 inPixDir, inPixFileName = os.path.split(inPix)
132 inPixName, inPixExt = os.path.splitext(inPixFileName)
133 outCsv = os.path.join(inPixDir, inPixName + '.csv')
134
135 if os.path.exists(outCsv):
136 os.remove(outCsv)
137
José Fonseca8b9f78b2013-04-25 15:22:53 +0100138 callProcess(cmd)
139
José Fonseca7b5e68d2015-03-26 15:21:46 +0000140 if os.path.isfile(outCsv):
141 api = detectApiFromCsv(outCsv)
142
José Fonseca8b9f78b2013-04-25 15:22:53 +0100143 cmd = [
144 options.apitrace,
145 'trace',
José Fonseca7b5e68d2015-03-26 15:21:46 +0000146 '-a', api,
José Fonseca8b9f78b2013-04-25 15:22:53 +0100147 '-o', outTrace,
148 pixExe,
149 inPix,
José Fonseca8b9f78b2013-04-25 15:22:53 +0100150 ]
José Fonseca56e6eca2015-03-26 15:22:17 +0000151
152 # XXX: Autodetect somehow
153 if not options.single_frame:
154 # Full capture
155 cmd += ['-playstandalone']
156 else:
157 # Single-frame capture
158 cmd += ['-autorenderto', 'nul:']
José Fonseca8b9f78b2013-04-25 15:22:53 +0100159
160 callProcess(cmd)
José Fonsecaf3cb6202015-02-08 00:05:35 +0000161 verifyTrace(outTrace)
162
163
164def getDxcapExe():
165 winDir = os.environ['windir']
166 if 'ProgramFiles(x86)' in os.environ:
167 sysSubDir = 'SysWOW64'
José Fonseca8b9f78b2013-04-25 15:22:53 +0100168 else:
José Fonsecaf3cb6202015-02-08 00:05:35 +0000169 sysSubDir = 'System32'
170 dxcapExe = os.path.join(winDir, sysSubDir, 'dxcap.exe')
171 return dxcapExe
172
173
174def convertToDxcap(inTrace, outDxcaprun):
175 # https://msdn.microsoft.com/en-us/library/vstudio/dn774939.aspx
176
177 dxcapExe = getDxcapExe()
178
179 cmd = [
180 getDxcapExe(),
181 '-rawmode',
182 '-file', os.path.abspath(outDxcaprun),
183 '-c',
184 options.retrace,
185 '-b',
186 os.path.abspath(inTrace),
187 ]
188
189 callProcess(cmd)
190 if os.path.exists(outDxcaprun):
191 sys.stderr.write('info: %s written\n' % outDxcaprun)
192 if options.verify:
193 callProcess([dxcapExe, '-p', os.path.abspath(outDxcaprun)])
194 else:
195 sys.stderr.write('error: %s not written\n' % outDxcaprun)
José Fonseca8b9f78b2013-04-25 15:22:53 +0100196 sys.exit(1)
197
198
José Fonsecaf3cb6202015-02-08 00:05:35 +0000199def convertFromDxcap(inDxcap, outTrace):
200 dxcapExe = getDxcapExe()
201
202 cmd = [
203 options.apitrace,
204 'trace',
205 '-a', options.api,
206 '-o', outTrace,
207 '--',
208 dxcapExe,
209 '-rawmode',
210 '-p', inDxcap,
211 ]
212
213 callProcess(cmd)
214 verifyTrace(outTrace)
215
216
José Fonseca2cce1922012-12-11 19:51:26 +0000217def main():
218 global options
219
220 # Parse command line options
221 optparser = optparse.OptionParser(
222 usage='\n\t%prog [options] <trace> ...',
223 version='%%prog')
224 optparser.add_option(
José Fonseca8b9f78b2013-04-25 15:22:53 +0100225 '--apitrace', metavar='PROGRAM',
226 type='string', dest='apitrace', default='apitrace.exe',
José Fonsecacd442802013-06-08 14:05:19 +0100227 help='path to apitrace command [default: %default]')
José Fonseca8b9f78b2013-04-25 15:22:53 +0100228 optparser.add_option(
229 '-a', '--api', metavar='API',
José Fonsecaf3cb6202015-02-08 00:05:35 +0000230 type='string', dest='api', default='dxgi',
José Fonseca8b9f78b2013-04-25 15:22:53 +0100231 help='api [default: %default]')
232 optparser.add_option(
José Fonseca2cce1922012-12-11 19:51:26 +0000233 '-r', '--retrace', metavar='PROGRAM',
José Fonseca8b9f78b2013-04-25 15:22:53 +0100234 type='string', dest='retrace', default='d3dretrace.exe',
José Fonsecacd442802013-06-08 14:05:19 +0100235 help='path to retrace command [default: %default]')
José Fonseca2cce1922012-12-11 19:51:26 +0000236 optparser.add_option(
237 '-v', '--verbose',
238 action='store_true', dest='verbose', default=False,
239 help='verbose output')
240 optparser.add_option(
241 '-o', '--output', metavar='FILE',
242 type="string", dest="output",
243 help="output file [default: stdout]")
José Fonseca8b9f78b2013-04-25 15:22:53 +0100244 optparser.add_option(
José Fonseca56e6eca2015-03-26 15:22:17 +0000245 '--single-frame',
246 action='store_true', dest='single_frame', default=False,
247 help='single-frame PIXRun capture')
248 optparser.add_option(
José Fonseca8b9f78b2013-04-25 15:22:53 +0100249 '--verify',
250 action='store_true', dest='verify', default=False,
251 help='verify output by replaying it')
José Fonseca2cce1922012-12-11 19:51:26 +0000252
253 (options, args) = optparser.parse_args(sys.argv[1:])
254 if not args:
255 optparser.error("incorrect number of arguments")
256
José Fonseca8b9f78b2013-04-25 15:22:53 +0100257 for inFile in args:
258 name, inExt = os.path.splitext(os.path.basename(inFile))
José Fonseca8b9f78b2013-04-25 15:22:53 +0100259 if inExt.lower() == '.trace':
José Fonsecaf3cb6202015-02-08 00:05:35 +0000260 convert = convertToDxcap
261 outExt = '.vsglog'
262 if options.output:
263 _, outExt = os.path.splitext(options.output)
264 if outExt.lower() == '.pixrun':
265 convert = convertToPix
266 elif inExt.lower() == '.vsglog':
267 convert = convertFromDxcap
268 outExt = '.trace'
José Fonseca8b9f78b2013-04-25 15:22:53 +0100269 elif inExt.lower() == '.pixrun':
270 convert = convertFromPix
271 outExt = '.trace'
José Fonseca2cce1922012-12-11 19:51:26 +0000272 else:
José Fonseca8b9f78b2013-04-25 15:22:53 +0100273 optparser.error("unexpected file extensions `%s`" % inExt)
274 if options.output:
275 outFile = options.output
276 else:
277 outFile = name + outExt
José Fonseca56e6eca2015-03-26 15:22:17 +0000278
279 if os.path.exists(outFile):
280 os.remove(outFile)
José Fonseca8b9f78b2013-04-25 15:22:53 +0100281 convert(inFile, outFile)
José Fonseca2cce1922012-12-11 19:51:26 +0000282
283
284if __name__ == '__main__':
285 main()