]> git.cworth.org Git - apitrace/blob - gui/retracer.cpp
Attempt to allow to control image dynamic range.
[apitrace] / gui / retracer.cpp
1 #include "retracer.h"
2
3 #include "apitracecall.h"
4
5 #include <QDebug>
6 #include <QVariant>
7
8 #include <qjson/parser.h>
9
10 Retracer::Retracer(QObject *parent)
11     : QThread(parent),
12       m_benchmarking(false),
13       m_doubleBuffered(true),
14       m_captureState(false),
15       m_captureCall(0)
16 {
17 #ifdef Q_OS_WIN
18     QString format = QLatin1String("%1;");
19 #else
20     QString format = QLatin1String("%1:");
21 #endif
22     QString buildPath = format.arg(APITRACE_BINARY_DIR);
23     m_processEnvironment = QProcessEnvironment::systemEnvironment();
24     m_processEnvironment.insert("PATH", buildPath +
25                                 m_processEnvironment.value("PATH"));
26
27     qputenv("PATH",
28             m_processEnvironment.value("PATH").toLatin1());
29 }
30
31 QString Retracer::fileName() const
32 {
33     return m_fileName;
34 }
35
36 void Retracer::setFileName(const QString &name)
37 {
38     m_fileName = name;
39 }
40
41 void Retracer::setAPI(trace::API api)
42 {
43     m_api = api;
44 }
45
46 bool Retracer::isBenchmarking() const
47 {
48     return m_benchmarking;
49 }
50
51 void Retracer::setBenchmarking(bool bench)
52 {
53     m_benchmarking = bench;
54 }
55
56 bool Retracer::isDoubleBuffered() const
57 {
58     return m_doubleBuffered;
59 }
60
61 void Retracer::setDoubleBuffered(bool db)
62 {
63     m_doubleBuffered = db;
64 }
65
66 void Retracer::setCaptureAtCallNumber(qlonglong num)
67 {
68     m_captureCall = num;
69 }
70
71 qlonglong Retracer::captureAtCallNumber() const
72 {
73     return m_captureCall;
74 }
75
76 bool Retracer::captureState() const
77 {
78     return m_captureState;
79 }
80
81 void Retracer::setCaptureState(bool enable)
82 {
83     m_captureState = enable;
84 }
85
86
87 void Retracer::run()
88 {
89     RetraceProcess *retrace = new RetraceProcess();
90     retrace->process()->setProcessEnvironment(m_processEnvironment);
91
92     retrace->setFileName(m_fileName);
93     retrace->setAPI(m_api);
94     retrace->setBenchmarking(m_benchmarking);
95     retrace->setDoubleBuffered(m_doubleBuffered);
96     retrace->setCaptureState(m_captureState);
97     retrace->setCaptureAtCallNumber(m_captureCall);
98
99     connect(retrace, SIGNAL(finished(const QString&)),
100             this, SLOT(cleanup()));
101     connect(retrace, SIGNAL(error(const QString&)),
102             this, SLOT(cleanup()));
103     connect(retrace, SIGNAL(finished(const QString&)),
104             this, SIGNAL(finished(const QString&)));
105     connect(retrace, SIGNAL(error(const QString&)),
106             this, SIGNAL(error(const QString&)));
107     connect(retrace, SIGNAL(foundState(ApiTraceState*)),
108             this, SIGNAL(foundState(ApiTraceState*)));
109     connect(retrace, SIGNAL(retraceErrors(const QList<ApiTraceError>&)),
110             this, SIGNAL(retraceErrors(const QList<ApiTraceError>&)));
111
112     retrace->start();
113
114     exec();
115
116     /* means we need to kill the process */
117     if (retrace->process()->state() != QProcess::NotRunning) {
118         retrace->terminate();
119     }
120
121     delete retrace;
122 }
123
124
125 void RetraceProcess::start()
126 {
127     QString prog;
128     QStringList arguments;
129
130     if (m_api == trace::API_GL) {
131         prog = QLatin1String("glretrace");
132     } else if (m_api == trace::API_EGL) {
133         prog = QLatin1String("eglretrace");
134     } else {
135         assert(0);
136         return;
137     }
138
139     if (m_doubleBuffered) {
140         arguments << QLatin1String("-db");
141     } else {
142         arguments << QLatin1String("-sb");
143     }
144
145     if (m_captureState) {
146         arguments << QLatin1String("-D");
147         arguments << QString::number(m_captureCall);
148     } else {
149         if (m_benchmarking) {
150             arguments << QLatin1String("-b");
151         }
152     }
153
154     arguments << m_fileName;
155
156     m_process->start(prog, arguments);
157 }
158
159
160 void RetraceProcess::replayFinished(int exitCode, QProcess::ExitStatus exitStatus)
161 {
162     QByteArray output = m_process->readAllStandardOutput();
163     QString msg;
164     QString errStr = m_process->readAllStandardError();
165
166 #if 0
167     qDebug()<<"Process finished = ";
168     qDebug()<<"\terr = "<<errStr;
169     qDebug()<<"\tout = "<<output;
170 #endif
171
172     if (exitStatus != QProcess::NormalExit) {
173         msg = QLatin1String("Process crashed");
174     } else if (exitCode != 0) {
175         msg = QLatin1String("Process exited with non zero exit code");
176     } else {
177         if (m_captureState) {
178             bool ok = false;
179             QVariantMap parsedJson = m_jsonParser->parse(output, &ok).toMap();
180             ApiTraceState *state = new ApiTraceState(parsedJson);
181             emit foundState(state);
182             msg = tr("State fetched.");
183         } else {
184             msg = QString::fromUtf8(output);
185         }
186     }
187
188     QStringList errorLines = errStr.split('\n');
189     QList<ApiTraceError> errors;
190     QRegExp regexp("(^\\d+): +(\\b\\w+\\b): (.+$)");
191     foreach(QString line, errorLines) {
192         if (regexp.indexIn(line) != -1) {
193             ApiTraceError error;
194             error.callIndex = regexp.cap(1).toInt();
195             error.type = regexp.cap(2);
196             error.message = regexp.cap(3);
197             errors.append(error);
198         }
199     }
200     if (!errors.isEmpty()) {
201         emit retraceErrors(errors);
202     }
203     emit finished(msg);
204 }
205
206 void RetraceProcess::replayError(QProcess::ProcessError err)
207 {
208     /*
209      * XXX: this function is likely unnecessary and should be eliminated given
210      * that replayFinished is always called, even on errors.
211      */
212
213 #if 0
214     qDebug()<<"Process error = "<<err;
215     qDebug()<<"\terr = "<<m_process->readAllStandardError();
216     qDebug()<<"\tout = "<<m_process->readAllStandardOutput();
217 #endif
218
219     emit error(
220         tr("Couldn't execute the replay file '%1'").arg(m_fileName));
221 }
222
223 Q_DECLARE_METATYPE(QList<ApiTraceError>);
224 RetraceProcess::RetraceProcess(QObject *parent)
225     : QObject(parent)
226 {
227     m_process = new QProcess(this);
228     m_jsonParser = new QJson::Parser();
229
230     qRegisterMetaType<QList<ApiTraceError> >();
231
232     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
233             this, SLOT(replayFinished(int, QProcess::ExitStatus)));
234     connect(m_process, SIGNAL(error(QProcess::ProcessError)),
235             this, SLOT(replayError(QProcess::ProcessError)));
236 }
237
238 QProcess * RetraceProcess::process() const
239 {
240     return m_process;
241 }
242
243 QString RetraceProcess::fileName() const
244 {
245     return m_fileName;
246 }
247
248 void RetraceProcess::setFileName(const QString &name)
249 {
250     m_fileName = name;
251 }
252
253 void RetraceProcess::setAPI(trace::API api)
254 {
255     m_api = api;
256 }
257
258 bool RetraceProcess::isBenchmarking() const
259 {
260     return m_benchmarking;
261 }
262
263 void RetraceProcess::setBenchmarking(bool bench)
264 {
265     m_benchmarking = bench;
266 }
267
268 bool RetraceProcess::isDoubleBuffered() const
269 {
270     return m_doubleBuffered;
271 }
272
273 void RetraceProcess::setDoubleBuffered(bool db)
274 {
275     m_doubleBuffered = db;
276 }
277
278 void RetraceProcess::setCaptureAtCallNumber(qlonglong num)
279 {
280     m_captureCall = num;
281 }
282
283 qlonglong RetraceProcess::captureAtCallNumber() const
284 {
285     return m_captureCall;
286 }
287
288 bool RetraceProcess::captureState() const
289 {
290     return m_captureState;
291 }
292
293 void RetraceProcess::setCaptureState(bool enable)
294 {
295     m_captureState = enable;
296 }
297
298 void RetraceProcess::terminate()
299 {
300     if (m_process) {
301         m_process->terminate();
302         emit finished(tr("Process terminated."));
303     }
304 }
305
306 void Retracer::cleanup()
307 {
308     quit();
309 }
310
311 RetraceProcess::~RetraceProcess()
312 {
313     delete m_jsonParser;
314 }
315
316 #include "retracer.moc"