blob: 1087ccab1e698d8207a372deff0ac6a8b5fbe74a [file] [log] [blame]
Zack Rusinf6667d12011-03-30 11:03:37 -04001#include "apitrace.h"
2
Zack Rusinebf971e2011-09-06 17:44:43 -04003#include "traceloader.h"
Zack Rusind809a062011-04-17 23:30:58 -04004#include "saverthread.h"
Zack Rusinf6667d12011-03-30 11:03:37 -04005
Zack Rusin3176ebe2011-09-06 21:11:36 -04006#include <QDebug>
Zack Rusin63efea82011-04-17 17:10:45 -04007#include <QDir>
Zack Rusinebf971e2011-09-06 17:44:43 -04008#include <QThread>
Zack Rusin63efea82011-04-17 17:10:45 -04009
Zack Rusinf6667d12011-03-30 11:03:37 -040010ApiTrace::ApiTrace()
Zack Rusin63efea82011-04-17 17:10:45 -040011 : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
12 m_needsSaving(false)
Zack Rusinf6667d12011-03-30 11:03:37 -040013{
Zack Rusinebf971e2011-09-06 17:44:43 -040014 m_loader = new TraceLoader();
Zack Rusinf682e192011-09-07 01:36:41 -040015
Zack Rusinebf971e2011-09-06 17:44:43 -040016 connect(this, SIGNAL(loadTrace(QString)),
17 m_loader, SLOT(loadTrace(QString)));
Zack Rusin3176ebe2011-09-06 21:11:36 -040018 connect(this, SIGNAL(requestFrame(ApiTraceFrame*)),
19 m_loader, SLOT(loadFrame(ApiTraceFrame*)));
Zack Rusinebf971e2011-09-06 17:44:43 -040020 connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
Zack Rusinf6667d12011-03-30 11:03:37 -040021 this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
Zack Rusin8f98c3a2011-09-11 18:21:29 -040022 connect(m_loader,
23 SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)),
24 this,
25 SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)));
Zack Rusinf682e192011-09-07 01:36:41 -040026 connect(m_loader, SIGNAL(finishedParsing()),
27 this, SLOT(finishedParsing()));
Zack Rusin8f98c3a2011-09-11 18:21:29 -040028 connect(this, SIGNAL(loaderSearchNext(int,QString,Qt::CaseSensitivity)),
29 m_loader, SLOT(searchNext(int,QString,Qt::CaseSensitivity)));
30 connect(this, SIGNAL(loaderSearchPrev(int,QString,Qt::CaseSensitivity)),
31 m_loader, SLOT(searchPrev(int,QString,Qt::CaseSensitivity)));
32 connect(m_loader,
33 SIGNAL(searchResult(ApiTrace::SearchResult,ApiTraceCall*)),
34 this,
35 SLOT(loaderSearchResult(ApiTrace::SearchResult,ApiTraceCall*)));
Zack Rusin93e4d152011-09-13 02:23:39 -040036 connect(this, SIGNAL(loaderFindFrameStart(ApiTraceFrame*)),
37 m_loader, SLOT(findFrameStart(ApiTraceFrame*)));
38 connect(this, SIGNAL(loaderFindFrameEnd(ApiTraceFrame*)),
39 m_loader, SLOT(findFrameEnd(ApiTraceFrame*)));
40 connect(m_loader, SIGNAL(foundFrameStart(ApiTraceFrame*)),
41 this, SIGNAL(foundFrameStart(ApiTraceFrame*)));
42 connect(m_loader, SIGNAL(foundFrameEnd(ApiTraceFrame*)),
43 this, SIGNAL(foundFrameEnd(ApiTraceFrame*)));
Zack Rusinda7579b2011-09-13 17:33:05 -040044 connect(this, SIGNAL(loaderFindCallIndex(int)),
45 m_loader, SLOT(findCallIndex(int)));
46 connect(m_loader, SIGNAL(foundCallIndex(ApiTraceCall*)),
47 this, SIGNAL(foundCallIndex(ApiTraceCall*)));
Zack Rusin8f98c3a2011-09-11 18:21:29 -040048
Zack Rusinebf971e2011-09-06 17:44:43 -040049
50 connect(m_loader, SIGNAL(startedParsing()),
Zack Rusinde4ea412011-03-30 11:30:08 -040051 this, SIGNAL(startedLoadingTrace()));
Zack Rusinebf971e2011-09-06 17:44:43 -040052 connect(m_loader, SIGNAL(parsed(int)),
53 this, SIGNAL(loaded(int)));
54 connect(m_loader, SIGNAL(finishedParsing()),
Zack Rusinde4ea412011-03-30 11:30:08 -040055 this, SIGNAL(finishedLoadingTrace()));
Zack Rusind809a062011-04-17 23:30:58 -040056
Zack Rusinebf971e2011-09-06 17:44:43 -040057
Zack Rusind809a062011-04-17 23:30:58 -040058 m_saver = new SaverThread(this);
Zack Rusin9af5bff2011-04-18 01:05:50 -040059 connect(m_saver, SIGNAL(traceSaved()),
60 this, SLOT(slotSaved()));
61 connect(m_saver, SIGNAL(traceSaved()),
62 this, SIGNAL(saved()));
Zack Rusinebf971e2011-09-06 17:44:43 -040063
64 m_loaderThread = new QThread();
65 m_loader->moveToThread(m_loaderThread);
66 m_loaderThread->start();
Zack Rusinf6667d12011-03-30 11:03:37 -040067}
68
69ApiTrace::~ApiTrace()
70{
Zack Rusinebf971e2011-09-06 17:44:43 -040071 m_loaderThread->quit();
72 m_loaderThread->deleteLater();
Zack Rusinf6667d12011-03-30 11:03:37 -040073 qDeleteAll(m_frames);
74 delete m_loader;
Zack Rusind809a062011-04-17 23:30:58 -040075 delete m_saver;
Zack Rusinf6667d12011-03-30 11:03:37 -040076}
77
78bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
79 ApiTrace::FrameMarker marker)
80{
81 if (!call)
82 return false;
83
84 switch (marker) {
85 case FrameMarker_SwapBuffers:
José Fonseca3e9ff852011-06-06 19:37:09 +010086 return call->name().contains(QLatin1String("SwapBuffers")) ||
José Fonsecadb678122011-07-29 17:20:05 +010087 call->name() == QLatin1String("CGLFlushDrawable") ||
88 call->name() == QLatin1String("glFrameTerminatorGREMEDY");
Zack Rusinf6667d12011-03-30 11:03:37 -040089 case FrameMarker_Flush:
Zack Rusinead6aad2011-04-15 22:16:18 -040090 return call->name() == QLatin1String("glFlush");
Zack Rusinf6667d12011-03-30 11:03:37 -040091 case FrameMarker_Finish:
Zack Rusinead6aad2011-04-15 22:16:18 -040092 return call->name() == QLatin1String("glFinish");
Zack Rusinf6667d12011-03-30 11:03:37 -040093 case FrameMarker_Clear:
Zack Rusinead6aad2011-04-15 22:16:18 -040094 return call->name() == QLatin1String("glClear");
Zack Rusinf6667d12011-03-30 11:03:37 -040095 }
96
97 Q_ASSERT(!"unknown frame marker");
98
99 return false;
100}
101
102bool ApiTrace::isEmpty() const
103{
Zack Rusinc1743432011-09-13 17:58:58 -0400104 return m_frames.isEmpty();
Zack Rusinf6667d12011-03-30 11:03:37 -0400105}
106
107QString ApiTrace::fileName() const
108{
Zack Rusin63efea82011-04-17 17:10:45 -0400109 if (edited())
110 return m_tempFileName;
111
Zack Rusinf6667d12011-03-30 11:03:37 -0400112 return m_fileName;
113}
114
115ApiTrace::FrameMarker ApiTrace::frameMarker() const
116{
117 return m_frameMarker;
118}
119
Zack Rusinf6667d12011-03-30 11:03:37 -0400120QList<ApiTraceFrame*> ApiTrace::frames() const
121{
122 return m_frames;
123}
124
125ApiTraceFrame * ApiTrace::frameAt(int idx) const
126{
127 return m_frames.value(idx);
128}
129
130int ApiTrace::numFrames() const
131{
132 return m_frames.count();
133}
134
135int ApiTrace::numCallsInFrame(int idx) const
136{
137 const ApiTraceFrame *frame = frameAt(idx);
138 if (frame)
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400139 return frame->numChildren();
Zack Rusinf6667d12011-03-30 11:03:37 -0400140 else
141 return 0;
142}
143
144void ApiTrace::setFileName(const QString &name)
145{
146 if (m_fileName != name) {
147 m_fileName = name;
148
Zack Rusinca164112011-04-11 02:23:09 -0400149 m_frames.clear();
Zack Rusin30069572011-04-20 18:21:11 -0400150 m_errors.clear();
151 m_editedCalls.clear();
152 m_needsSaving = false;
Zack Rusinf6667d12011-03-30 11:03:37 -0400153 emit invalidated();
154
Zack Rusinebf971e2011-09-06 17:44:43 -0400155// m_loader->loadTrace(m_fileName);
156 emit loadTrace(m_fileName);
Zack Rusinf6667d12011-03-30 11:03:37 -0400157 }
158}
159
Zack Rusinf6667d12011-03-30 11:03:37 -0400160void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
161{
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400162 QVector<ApiTraceCall*> calls;
Zack Rusinf6667d12011-03-30 11:03:37 -0400163 int currentFrames = m_frames.count();
164 int numNewFrames = frames.count();
Zack Rusinb56e03d2011-04-20 23:58:52 -0400165
166 emit beginAddingFrames(currentFrames, numNewFrames);
167
Zack Rusinf6667d12011-03-30 11:03:37 -0400168 m_frames += frames;
169
Zack Rusinf6667d12011-03-30 11:03:37 -0400170 int numNewCalls = 0;
171 foreach(ApiTraceFrame *frame, frames) {
Zack Rusinebf971e2011-09-06 17:44:43 -0400172 frame->setParentTrace(this);
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400173 numNewCalls += frame->numChildren();
Zack Rusin410a8f32011-08-28 02:38:34 -0400174 calls += frame->calls();
Zack Rusinf6667d12011-03-30 11:03:37 -0400175 }
176
Zack Rusinb56e03d2011-04-20 23:58:52 -0400177 emit endAddingFrames();
Zack Rusinf6667d12011-03-30 11:03:37 -0400178}
179
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400180ApiTraceCall * ApiTrace::callWithIndex(int idx) const
181{
Zack Rusinc1743432011-09-13 17:58:58 -0400182 for (int i = 0; i < m_frames.count(); ++i) {
183 ApiTraceCall *call = m_frames[i]->callWithIndex(idx);
184 if (call)
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400185 return call;
186 }
187 return NULL;
188}
189
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400190ApiTraceState ApiTrace::defaultState() const
191{
192 ApiTraceFrame *frame = frameAt(0);
Zack Rusined40bc62011-08-28 17:11:02 -0400193 if (!frame || !frame->hasState())
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400194 return ApiTraceState();
195
Zack Rusined40bc62011-08-28 17:11:02 -0400196 return *frame->state();
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400197}
198
Zack Rusin661842d2011-04-17 01:59:16 -0400199void ApiTrace::callEdited(ApiTraceCall *call)
200{
Zack Rusin63efea82011-04-17 17:10:45 -0400201 if (!m_editedCalls.contains(call)) {
202 //lets generate a temp filename
203 QString tempPath = QDir::tempPath();
Zack Rusin63efea82011-04-17 17:10:45 -0400204 m_tempFileName = QString::fromLatin1("%1/%2.edited")
205 .arg(tempPath)
206 .arg(m_fileName);
Zack Rusin63efea82011-04-17 17:10:45 -0400207 }
Zack Rusin661842d2011-04-17 01:59:16 -0400208 m_editedCalls.insert(call);
Zack Rusin9af5bff2011-04-18 01:05:50 -0400209 m_needsSaving = true;
Zack Rusin63efea82011-04-17 17:10:45 -0400210
Zack Rusin661842d2011-04-17 01:59:16 -0400211 emit changed(call);
212}
213
214void ApiTrace::callReverted(ApiTraceCall *call)
215{
216 m_editedCalls.remove(call);
Zack Rusin63efea82011-04-17 17:10:45 -0400217
218 if (m_editedCalls.isEmpty()) {
219 m_needsSaving = false;
220 }
Zack Rusin661842d2011-04-17 01:59:16 -0400221 emit changed(call);
222}
223
Zack Rusin0ddd2502011-04-17 02:34:45 -0400224bool ApiTrace::edited() const
Zack Rusin661842d2011-04-17 01:59:16 -0400225{
226 return !m_editedCalls.isEmpty();
227}
228
Zack Rusin63efea82011-04-17 17:10:45 -0400229bool ApiTrace::needsSaving() const
230{
231 return m_needsSaving;
232}
233
234void ApiTrace::save()
235{
236 QFileInfo fi(m_tempFileName);
237 QDir dir;
Zack Rusin9af5bff2011-04-18 01:05:50 -0400238 emit startedSaving();
Zack Rusin63efea82011-04-17 17:10:45 -0400239 dir.mkpath(fi.absolutePath());
Zack Rusin9b31ffc2011-09-13 23:58:45 -0400240 m_saver->saveFile(m_tempFileName,
241 m_fileName,
242 m_editedCalls);
Zack Rusin63efea82011-04-17 17:10:45 -0400243}
244
Zack Rusin9af5bff2011-04-18 01:05:50 -0400245void ApiTrace::slotSaved()
246{
247 m_needsSaving = false;
248}
249
250bool ApiTrace::isSaving() const
251{
252 return m_saver->isRunning();
253}
254
Zack Rusincc0b4912011-04-19 01:59:20 -0400255bool ApiTrace::hasErrors() const
256{
257 return !m_errors.isEmpty();
258}
259
Zack Rusin3176ebe2011-09-06 21:11:36 -0400260void ApiTrace::loadFrame(ApiTraceFrame *frame)
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400261{
Zack Rusin3176ebe2011-09-06 21:11:36 -0400262 Q_ASSERT(!frame->loaded());
263 emit requestFrame(frame);
Zack Rusin35c27932011-08-28 21:16:22 -0400264}
265
Zack Rusinf682e192011-09-07 01:36:41 -0400266void ApiTrace::finishedParsing()
267{
268 ApiTraceFrame *firstFrame = m_frames[0];
269 if (firstFrame && !firstFrame->loaded()) {
270 loadFrame(firstFrame);
271 }
272}
273
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400274void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
275 const QVector<ApiTraceCall*> &calls,
276 quint64 binaryDataSize)
Zack Rusinf682e192011-09-07 01:36:41 -0400277{
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400278 Q_ASSERT(frame->numChildrenToLoad() == calls.size());
279 emit beginLoadingFrame(frame, calls.size());
280 frame->setCalls(calls, binaryDataSize);
Zack Rusinf682e192011-09-07 01:36:41 -0400281 emit endLoadingFrame(frame);
Zack Rusin10fd4772011-09-14 01:45:12 -0400282
283 if (!m_queuedErrors.isEmpty()) {
284 QList< QPair<ApiTraceFrame*, ApiTraceError> >::iterator itr;
285 for (itr = m_queuedErrors.begin(); itr != m_queuedErrors.end();
286 ++itr) {
287 const ApiTraceError &error = (*itr).second;
288 if ((*itr).first == frame) {
289 ApiTraceCall *call = frame->callWithIndex(error.callIndex);
290
291 if (!call) {
292 continue;
293 }
294
295 call->setError(error.message);
296 m_queuedErrors.erase(itr);
297
298 if (call->hasError()) {
299 m_errors.insert(call);
300 } else {
301 m_errors.remove(call);
302 }
303 emit changed(call);
304 }
305 }
306 }
Zack Rusinf682e192011-09-07 01:36:41 -0400307}
308
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400309void ApiTrace::findNext(ApiTraceFrame *frame,
310 ApiTraceCall *from,
311 const QString &str,
312 Qt::CaseSensitivity sensitivity)
313{
314 ApiTraceCall *foundCall = 0;
315 int frameIdx = m_frames.indexOf(frame);
316
317 if (frame->loaded()) {
318 foundCall = frame->findNextCall(from, str, sensitivity);
319 if (foundCall) {
320 emit findResult(SearchFound, foundCall);
321 return;
322 }
323
324 //if the frame is loaded we already searched it above
325 // so skip it
326 frameIdx += 1;
327 }
328
329 for (int i = frameIdx; i < m_frames.count(); ++i) {
330 ApiTraceFrame *frame = m_frames[i];
331 if (!frame->loaded()) {
332 emit loaderSearchNext(i, str, sensitivity);
333 return;
334 } else {
335 ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
336 if (call) {
337 emit findResult(SearchFound, call);
Zack Rusin121e3162011-09-13 01:35:12 -0400338 return;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400339 }
340 }
341 }
342 emit findResult(SearchWrapped, 0);
343}
344
345void ApiTrace::findPrev(ApiTraceFrame *frame,
346 ApiTraceCall *from,
347 const QString &str,
348 Qt::CaseSensitivity sensitivity)
349{
350 ApiTraceCall *foundCall = 0;
351 int frameIdx = m_frames.indexOf(frame);
352
353 if (frame->loaded()) {
354 foundCall = frame->findPrevCall(from, str, sensitivity);
355 if (foundCall) {
356 emit findResult(SearchFound, foundCall);
357 return;
358 }
359
360 //if the frame is loaded we already searched it above
361 // so skip it
362 frameIdx -= 1;
363 }
364
Zack Rusin121e3162011-09-13 01:35:12 -0400365 for (int i = frameIdx; i >= 0; --i) {
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400366 ApiTraceFrame *frame = m_frames[i];
367 if (!frame->loaded()) {
368 emit loaderSearchPrev(i, str, sensitivity);
369 return;
370 } else {
371 ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
372 if (call) {
373 emit findResult(SearchFound, call);
Zack Rusin121e3162011-09-13 01:35:12 -0400374 return;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400375 }
376 }
377 }
378 emit findResult(SearchWrapped, 0);
379}
380
381void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
382 ApiTraceCall *call)
383{
384 //qDebug()<<"Search result = "<<result
385 // <<", call is = "<<call;
386 emit findResult(result, call);
387}
388
Zack Rusin93e4d152011-09-13 02:23:39 -0400389void ApiTrace::findFrameStart(ApiTraceFrame *frame)
390{
391 if (frame->loaded()) {
392 emit foundFrameStart(frame);
393 } else {
394 emit loaderFindFrameStart(frame);
395 }
396}
397
398void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
399{
400 if (frame->loaded()) {
401 emit foundFrameEnd(frame);
402 } else {
403 emit loaderFindFrameEnd(frame);
404 }
405}
406
Zack Rusinda7579b2011-09-13 17:33:05 -0400407void ApiTrace::findCallIndex(int index)
408{
409 int frameIdx = callInFrame(index);
410 ApiTraceFrame *frame = 0;
411
412 if (frameIdx < 0) {
413 emit foundCallIndex(0);
414 return;
415 }
416
417 frame = m_frames[frameIdx];
418
419 if (frame) {
420 if (frame->loaded()) {
421 ApiTraceCall *call = frame->callWithIndex(index);
422 emit foundCallIndex(call);
423 } else {
424 emit loaderFindCallIndex(index);
425 }
426 }
427}
428
429int ApiTrace::callInFrame(int callIdx) const
430{
431 unsigned numCalls = 0;
432
433 for (int frameIdx = 0; frameIdx <= m_frames.size(); ++frameIdx) {
434 const ApiTraceFrame *frame = m_frames[frameIdx];
435 unsigned numCallsInFrame = frame->loaded()
436 ? frame->numChildren()
437 : frame->numChildrenToLoad();
438 unsigned firstCall = numCalls;
439 unsigned endCall = numCalls + numCallsInFrame;
440 if (firstCall <= callIdx && endCall > callIdx) {
441 return frameIdx;
442 }
443 numCalls = endCall;
444 }
445
446 return -1;
447}
448
Zack Rusin10fd4772011-09-14 01:45:12 -0400449void ApiTrace::setCallError(const ApiTraceError &error)
450{
451 int frameIdx = callInFrame(error.callIndex);
452 ApiTraceFrame *frame = 0;
453
454 if (frameIdx < 0) {
455 return;
456 }
457 frame = m_frames[frameIdx];
458
459 if (frame->loaded()) {
460 ApiTraceCall *call = frame->callWithIndex(error.callIndex);
461 call->setError(error.message);
462 if (call->hasError()) {
463 m_errors.insert(call);
464 } else {
465 m_errors.remove(call);
466 }
467 emit changed(call);
468 } else {
469 emit requestFrame(frame);
470 m_queuedErrors.append(qMakePair(frame, error));
471 }
472}
473
Zack Rusinf6667d12011-03-30 11:03:37 -0400474#include "apitrace.moc"