]> git.cworth.org Git - apitrace/blob - retrace/retrace_main.cpp
Merge remote-tracking branch 'github/master' into d2d
[apitrace] / retrace / retrace_main.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <string.h>
28 #include <iostream>
29
30 #include "os_binary.hpp"
31 #include "os_time.hpp"
32 #include "image.hpp"
33 #include "trace_callset.hpp"
34 #include "trace_dump.hpp"
35 #include "retrace.hpp"
36
37
38 static bool waitOnFinish = false;
39
40 static const char *comparePrefix = NULL;
41 static const char *snapshotPrefix = NULL;
42 static trace::CallSet snapshotFrequency;
43 static trace::CallSet compareFrequency;
44
45 static unsigned dumpStateCallNo = ~0;
46
47
48 namespace retrace {
49
50
51 trace::Parser parser;
52 trace::Profiler profiler;
53
54
55 int verbosity = 0;
56 bool debug = true;
57 bool dumpingState = false;
58
59 bool doubleBuffer = true;
60 bool coreProfile = false;
61
62 bool profiling = false;
63 bool profilingGpuTimes = false;
64 bool profilingCpuTimes = false;
65 bool profilingPixelsDrawn = false;
66
67 unsigned frameNo = 0;
68 unsigned callNo = 0;
69
70
71 void
72 frameComplete(trace::Call &call) {
73     ++frameNo;
74 }
75
76
77 static void
78 takeSnapshot(unsigned call_no) {
79     assert(snapshotPrefix || comparePrefix);
80
81     image::Image *ref = NULL;
82
83     if (comparePrefix) {
84         os::String filename = os::String::format("%s%010u.png", comparePrefix, call_no);
85         ref = image::readPNG(filename);
86         if (!ref) {
87             return;
88         }
89         if (retrace::verbosity >= 0) {
90             std::cout << "Read " << filename << "\n";
91         }
92     }
93
94     image::Image *src = getSnapshot();
95     if (!src) {
96         return;
97     }
98
99     if (snapshotPrefix) {
100         if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) {
101             char comment[21];
102             snprintf(comment, sizeof comment, "%u", call_no);
103             src->writePNM(std::cout, comment);
104         } else {
105             os::String filename = os::String::format("%s%010u.png", snapshotPrefix, call_no);
106             if (src->writePNG(filename) && retrace::verbosity >= 0) {
107                 std::cout << "Wrote " << filename << "\n";
108             }
109         }
110     }
111
112     if (ref) {
113         std::cout << "Snapshot " << call_no << " average precision of " << src->compare(*ref) << " bits\n";
114         delete ref;
115     }
116
117     delete src;
118
119     return;
120 }
121
122
123 static void
124 mainLoop() {
125     retrace::Retracer retracer;
126
127     addCallbacks(retracer);
128
129     long long startTime = 0; 
130     frameNo = 0;
131
132     startTime = os::getTime();
133     trace::Call *call;
134
135     while ((call = retrace::parser.parse_call())) {
136         bool swapRenderTarget = call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET;
137         bool doSnapshot =
138             snapshotFrequency.contains(*call) ||
139             compareFrequency.contains(*call)
140         ;
141
142         // For calls which cause rendertargets to be swaped, we take the
143         // snapshot _before_ swapping the rendertargets.
144         if (doSnapshot && swapRenderTarget) {
145             if (call->flags & trace::CALL_FLAG_END_FRAME) {
146                 // For swapbuffers/presents we still use this call number,
147                 // spite not have been executed yet.
148                 takeSnapshot(call->no);
149             } else {
150                 // Whereas for ordinate fbo/rendertarget changes we use the
151                 // previous call's number.
152                 takeSnapshot(call->no - 1);
153             }
154         }
155
156         callNo = call->no;
157         retracer.retrace(*call);
158
159         if (doSnapshot && !swapRenderTarget) {
160             takeSnapshot(call->no);
161         }
162
163         if (call->no >= dumpStateCallNo &&
164             dumpState(std::cout)) {
165             exit(0);
166         }
167
168         delete call;
169     }
170
171     // Reached the end of trace
172     flushRendering();
173
174     long long endTime = os::getTime();
175     float timeInterval = (endTime - startTime) * (1.0 / os::timeFrequency);
176
177     if ((retrace::verbosity >= -1) || (retrace::profiling)) {
178         std::cout << 
179             "Rendered " << frameNo << " frames"
180             " in " <<  timeInterval << " secs,"
181             " average of " << (frameNo/timeInterval) << " fps\n";
182     }
183
184     if (waitOnFinish) {
185         waitForInput();
186     } else {
187         return;
188     }
189 }
190
191
192 } /* namespace retrace */
193
194
195 static void
196 usage(const char *argv0) {
197     std::cout << 
198         "Usage: " << argv0 << " [OPTION] TRACE [...]\n"
199         "Replay TRACE.\n"
200         "\n"
201         "  -b           benchmark mode (no error checking or warning messages)\n"
202         "  -pcpu        cpu profiling (cpu times per call)\n"
203         "  -pgpu        gpu profiling (gpu times per draw call)\n"
204         "  -ppd         pixels drawn profiling (pixels drawn per draw call)\n"
205         "  -c PREFIX    compare against snapshots\n"
206         "  -C CALLSET   calls to compare (default is every frame)\n"
207         "  -core        use core profile\n"
208         "  -db          use a double buffer visual (default)\n"
209         "  -sb          use a single buffer visual\n"
210         "  -s PREFIX    take snapshots; `-` for PNM stdout output\n"
211         "  -S CALLSET   calls to snapshot (default is every frame)\n"
212         "  -v           increase output verbosity\n"
213         "  -D CALLNO    dump state at specific call no\n"
214         "  -w           waitOnFinish on final frame\n";
215 }
216
217
218 extern "C"
219 int main(int argc, char **argv)
220 {
221     using namespace retrace;
222
223     assert(compareFrequency.empty());
224     assert(snapshotFrequency.empty());
225
226     int i;
227     for (i = 1; i < argc; ++i) {
228         const char *arg = argv[i];
229
230         if (arg[0] != '-') {
231             break;
232         }
233
234         if (!strcmp(arg, "--")) {
235             break;
236         } else if (!strcmp(arg, "-b")) {
237             retrace::debug = false;
238             retrace::verbosity = -1;
239         } else if (!strcmp(arg, "-c")) {
240             comparePrefix = argv[++i];
241             if (compareFrequency.empty()) {
242                 compareFrequency = trace::CallSet(trace::FREQUENCY_FRAME);
243             }
244         } else if (!strcmp(arg, "-C")) {
245             compareFrequency = trace::CallSet(argv[++i]);
246             if (comparePrefix == NULL) {
247                 comparePrefix = "";
248             }
249         } else if (!strcmp(arg, "-D")) {
250             dumpStateCallNo = atoi(argv[++i]);
251             dumpingState = true;
252             retrace::verbosity = -2;
253         } else if (!strcmp(arg, "-core")) {
254             retrace::coreProfile = true;
255         } else if (!strcmp(arg, "-db")) {
256             retrace::doubleBuffer = true;
257         } else if (!strcmp(arg, "-sb")) {
258             retrace::doubleBuffer = false;
259         } else if (!strcmp(arg, "--help")) {
260             usage(argv[0]);
261             return 0;
262         } else if (!strcmp(arg, "-s")) {
263             snapshotPrefix = argv[++i];
264             if (snapshotFrequency.empty()) {
265                 snapshotFrequency = trace::CallSet(trace::FREQUENCY_FRAME);
266             }
267             if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) {
268                 os::setBinaryMode(stdout);
269                 retrace::verbosity = -2;
270             }
271         } else if (!strcmp(arg, "-S")) {
272             snapshotFrequency = trace::CallSet(argv[++i]);
273             if (snapshotPrefix == NULL) {
274                 snapshotPrefix = "";
275             }
276         } else if (!strcmp(arg, "-v")) {
277             ++retrace::verbosity;
278         } else if (!strcmp(arg, "-w")) {
279             waitOnFinish = true;
280         } else if (arg[1] == 'p') {
281             retrace::debug = false;
282             retrace::profiling = true;
283             retrace::verbosity = -1;
284
285             if (!strcmp(arg, "-pcpu")) {
286                 retrace::profilingCpuTimes = true;
287             } else if (!strcmp(arg, "-pgpu")) {
288                 retrace::profilingGpuTimes = true;
289             } else if (!strcmp(arg, "-ppd")) {
290                 retrace::profilingPixelsDrawn = true;
291             }
292         } else {
293             std::cerr << "error: unknown option " << arg << "\n";
294             usage(argv[0]);
295             return 1;
296         }
297     }
298
299     retrace::setUp();
300     if (retrace::profiling) {
301         retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn);
302     }
303
304     for ( ; i < argc; ++i) {
305         if (!retrace::parser.open(argv[i])) {
306             std::cerr << "error: failed to open " << argv[i] << "\n";
307             return 1;
308         }
309
310         retrace::mainLoop();
311
312         retrace::parser.close();
313     }
314
315     // XXX: X often hangs on XCloseDisplay
316     //retrace::cleanUp();
317
318     return 0;
319 }
320