blob: 7a04756bc26fab1f8160a2c4d4cb625f165fd508 [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_calls);
74 qDeleteAll(m_frames);
75 delete m_loader;
Zack Rusind809a062011-04-17 23:30:58 -040076 delete m_saver;
Zack Rusinf6667d12011-03-30 11:03:37 -040077}
78
79bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
80 ApiTrace::FrameMarker marker)
81{
82 if (!call)
83 return false;
84
85 switch (marker) {
86 case FrameMarker_SwapBuffers:
José Fonseca3e9ff852011-06-06 19:37:09 +010087 return call->name().contains(QLatin1String("SwapBuffers")) ||
José Fonsecadb678122011-07-29 17:20:05 +010088 call->name() == QLatin1String("CGLFlushDrawable") ||
89 call->name() == QLatin1String("glFrameTerminatorGREMEDY");
Zack Rusinf6667d12011-03-30 11:03:37 -040090 case FrameMarker_Flush:
Zack Rusinead6aad2011-04-15 22:16:18 -040091 return call->name() == QLatin1String("glFlush");
Zack Rusinf6667d12011-03-30 11:03:37 -040092 case FrameMarker_Finish:
Zack Rusinead6aad2011-04-15 22:16:18 -040093 return call->name() == QLatin1String("glFinish");
Zack Rusinf6667d12011-03-30 11:03:37 -040094 case FrameMarker_Clear:
Zack Rusinead6aad2011-04-15 22:16:18 -040095 return call->name() == QLatin1String("glClear");
Zack Rusinf6667d12011-03-30 11:03:37 -040096 }
97
98 Q_ASSERT(!"unknown frame marker");
99
100 return false;
101}
102
103bool ApiTrace::isEmpty() const
104{
105 return m_calls.isEmpty();
106}
107
108QString ApiTrace::fileName() const
109{
Zack Rusin63efea82011-04-17 17:10:45 -0400110 if (edited())
111 return m_tempFileName;
112
Zack Rusinf6667d12011-03-30 11:03:37 -0400113 return m_fileName;
114}
115
116ApiTrace::FrameMarker ApiTrace::frameMarker() const
117{
118 return m_frameMarker;
119}
120
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400121QVector<ApiTraceCall*> ApiTrace::calls() const
Zack Rusinf6667d12011-03-30 11:03:37 -0400122{
123 return m_calls;
124}
125
Zack Rusinf6667d12011-03-30 11:03:37 -0400126int ApiTrace::numCalls() const
127{
128 return m_calls.count();
129}
130
131QList<ApiTraceFrame*> ApiTrace::frames() const
132{
133 return m_frames;
134}
135
136ApiTraceFrame * ApiTrace::frameAt(int idx) const
137{
138 return m_frames.value(idx);
139}
140
141int ApiTrace::numFrames() const
142{
143 return m_frames.count();
144}
145
146int ApiTrace::numCallsInFrame(int idx) const
147{
148 const ApiTraceFrame *frame = frameAt(idx);
149 if (frame)
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400150 return frame->numChildren();
Zack Rusinf6667d12011-03-30 11:03:37 -0400151 else
152 return 0;
153}
154
155void ApiTrace::setFileName(const QString &name)
156{
157 if (m_fileName != name) {
158 m_fileName = name;
159
Zack Rusinca164112011-04-11 02:23:09 -0400160 m_frames.clear();
161 m_calls.clear();
Zack Rusin30069572011-04-20 18:21:11 -0400162 m_errors.clear();
163 m_editedCalls.clear();
164 m_needsSaving = false;
Zack Rusinf6667d12011-03-30 11:03:37 -0400165 emit invalidated();
166
Zack Rusinebf971e2011-09-06 17:44:43 -0400167// m_loader->loadTrace(m_fileName);
168 emit loadTrace(m_fileName);
Zack Rusinf6667d12011-03-30 11:03:37 -0400169 }
170}
171
172void ApiTrace::setFrameMarker(FrameMarker marker)
173{
174 if (m_frameMarker != marker) {
175 emit framesInvalidated();
176
177 qDeleteAll(m_frames);
178 m_frames.clear();
179 detectFrames();
180 }
181}
182
183void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
184{
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400185 QVector<ApiTraceCall*> calls;
Zack Rusinf6667d12011-03-30 11:03:37 -0400186 int currentFrames = m_frames.count();
187 int numNewFrames = frames.count();
Zack Rusinb56e03d2011-04-20 23:58:52 -0400188
189 emit beginAddingFrames(currentFrames, numNewFrames);
190
Zack Rusinf6667d12011-03-30 11:03:37 -0400191 m_frames += frames;
192
193 int currentCalls = m_calls.count();
194 int numNewCalls = 0;
195 foreach(ApiTraceFrame *frame, frames) {
Zack Rusinebf971e2011-09-06 17:44:43 -0400196 frame->setParentTrace(this);
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400197 numNewCalls += frame->numChildren();
Zack Rusin410a8f32011-08-28 02:38:34 -0400198 calls += frame->calls();
Zack Rusinf6667d12011-03-30 11:03:37 -0400199 }
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400200 m_calls.reserve(m_calls.count() + calls.count() + 1);
Zack Rusin410a8f32011-08-28 02:38:34 -0400201 m_calls += calls;
Zack Rusinf6667d12011-03-30 11:03:37 -0400202
Zack Rusinb56e03d2011-04-20 23:58:52 -0400203 emit endAddingFrames();
Zack Rusinf6667d12011-03-30 11:03:37 -0400204 emit callsAdded(currentCalls, numNewCalls);
205}
206
207void ApiTrace::detectFrames()
208{
209 if (m_calls.isEmpty())
210 return;
211
Zack Rusinb56e03d2011-04-20 23:58:52 -0400212 emit beginAddingFrames(0, m_frames.count());
213
Zack Rusinf6667d12011-03-30 11:03:37 -0400214 ApiTraceFrame *currentFrame = 0;
215 foreach(ApiTraceCall *apiCall, m_calls) {
216 if (!currentFrame) {
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400217 currentFrame = new ApiTraceFrame(this);
Zack Rusinf6667d12011-03-30 11:03:37 -0400218 currentFrame->number = m_frames.count();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400219 currentFrame->setLoaded(true);
Zack Rusinf6667d12011-03-30 11:03:37 -0400220 }
Zack Rusinead6aad2011-04-15 22:16:18 -0400221 apiCall->setParentFrame(currentFrame);
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400222 currentFrame->addCall(apiCall);
Zack Rusinf6667d12011-03-30 11:03:37 -0400223 if (ApiTrace::isCallAFrameMarker(apiCall,
224 m_frameMarker)) {
225 m_frames.append(currentFrame);
226 currentFrame = 0;
227 }
228 }
229 //last frames won't have markers
230 // it's just a bunch of Delete calls for every object
231 // after the last SwapBuffers
232 if (currentFrame) {
233 m_frames.append(currentFrame);
234 currentFrame = 0;
235 }
Zack Rusinb56e03d2011-04-20 23:58:52 -0400236 emit endAddingFrames();
Zack Rusinf6667d12011-03-30 11:03:37 -0400237}
238
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400239ApiTraceCall * ApiTrace::callWithIndex(int idx) const
240{
241 for (int i = 0; i < m_calls.count(); ++i) {
242 ApiTraceCall *call = m_calls[i];
Zack Rusinead6aad2011-04-15 22:16:18 -0400243 if (call->index() == idx)
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400244 return call;
245 }
246 return NULL;
247}
248
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400249ApiTraceState ApiTrace::defaultState() const
250{
251 ApiTraceFrame *frame = frameAt(0);
Zack Rusined40bc62011-08-28 17:11:02 -0400252 if (!frame || !frame->hasState())
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400253 return ApiTraceState();
254
Zack Rusined40bc62011-08-28 17:11:02 -0400255 return *frame->state();
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400256}
257
Zack Rusin661842d2011-04-17 01:59:16 -0400258void ApiTrace::callEdited(ApiTraceCall *call)
259{
Zack Rusin63efea82011-04-17 17:10:45 -0400260 if (!m_editedCalls.contains(call)) {
261 //lets generate a temp filename
262 QString tempPath = QDir::tempPath();
Zack Rusin63efea82011-04-17 17:10:45 -0400263 m_tempFileName = QString::fromLatin1("%1/%2.edited")
264 .arg(tempPath)
265 .arg(m_fileName);
Zack Rusin63efea82011-04-17 17:10:45 -0400266 }
Zack Rusin661842d2011-04-17 01:59:16 -0400267 m_editedCalls.insert(call);
Zack Rusin9af5bff2011-04-18 01:05:50 -0400268 m_needsSaving = true;
Zack Rusin63efea82011-04-17 17:10:45 -0400269
Zack Rusin661842d2011-04-17 01:59:16 -0400270 emit changed(call);
271}
272
273void ApiTrace::callReverted(ApiTraceCall *call)
274{
275 m_editedCalls.remove(call);
Zack Rusin63efea82011-04-17 17:10:45 -0400276
277 if (m_editedCalls.isEmpty()) {
278 m_needsSaving = false;
279 }
Zack Rusin661842d2011-04-17 01:59:16 -0400280 emit changed(call);
281}
282
Zack Rusin0ddd2502011-04-17 02:34:45 -0400283bool ApiTrace::edited() const
Zack Rusin661842d2011-04-17 01:59:16 -0400284{
285 return !m_editedCalls.isEmpty();
286}
287
Zack Rusin63efea82011-04-17 17:10:45 -0400288bool ApiTrace::needsSaving() const
289{
290 return m_needsSaving;
291}
292
293void ApiTrace::save()
294{
295 QFileInfo fi(m_tempFileName);
296 QDir dir;
Zack Rusin9af5bff2011-04-18 01:05:50 -0400297 emit startedSaving();
Zack Rusin63efea82011-04-17 17:10:45 -0400298 dir.mkpath(fi.absolutePath());
Zack Rusind809a062011-04-17 23:30:58 -0400299 m_saver->saveFile(m_tempFileName, m_calls);
Zack Rusin63efea82011-04-17 17:10:45 -0400300}
301
Zack Rusin9af5bff2011-04-18 01:05:50 -0400302void ApiTrace::slotSaved()
303{
304 m_needsSaving = false;
305}
306
307bool ApiTrace::isSaving() const
308{
309 return m_saver->isRunning();
310}
311
Zack Rusinb53b1612011-04-19 01:33:58 -0400312void ApiTrace::callError(ApiTraceCall *call)
313{
Zack Rusincc0b4912011-04-19 01:59:20 -0400314 Q_ASSERT(call);
315
316 if (call->hasError())
317 m_errors.insert(call);
318 else
319 m_errors.remove(call);
320
Zack Rusinb53b1612011-04-19 01:33:58 -0400321 emit changed(call);
322}
323
Zack Rusincc0b4912011-04-19 01:59:20 -0400324bool ApiTrace::hasErrors() const
325{
326 return !m_errors.isEmpty();
327}
328
Zack Rusin3176ebe2011-09-06 21:11:36 -0400329void ApiTrace::loadFrame(ApiTraceFrame *frame)
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400330{
Zack Rusin3176ebe2011-09-06 21:11:36 -0400331 Q_ASSERT(!frame->loaded());
332 emit requestFrame(frame);
Zack Rusin35c27932011-08-28 21:16:22 -0400333}
334
Zack Rusinf682e192011-09-07 01:36:41 -0400335void ApiTrace::finishedParsing()
336{
337 ApiTraceFrame *firstFrame = m_frames[0];
338 if (firstFrame && !firstFrame->loaded()) {
339 loadFrame(firstFrame);
340 }
341}
342
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400343void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
344 const QVector<ApiTraceCall*> &calls,
345 quint64 binaryDataSize)
Zack Rusinf682e192011-09-07 01:36:41 -0400346{
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400347 Q_ASSERT(frame->numChildrenToLoad() == calls.size());
348 emit beginLoadingFrame(frame, calls.size());
349 frame->setCalls(calls, binaryDataSize);
Zack Rusinf682e192011-09-07 01:36:41 -0400350 emit endLoadingFrame(frame);
351}
352
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400353void ApiTrace::findNext(ApiTraceFrame *frame,
354 ApiTraceCall *from,
355 const QString &str,
356 Qt::CaseSensitivity sensitivity)
357{
358 ApiTraceCall *foundCall = 0;
359 int frameIdx = m_frames.indexOf(frame);
360
361 if (frame->loaded()) {
362 foundCall = frame->findNextCall(from, str, sensitivity);
363 if (foundCall) {
364 emit findResult(SearchFound, foundCall);
365 return;
366 }
367
368 //if the frame is loaded we already searched it above
369 // so skip it
370 frameIdx += 1;
371 }
372
373 for (int i = frameIdx; i < m_frames.count(); ++i) {
374 ApiTraceFrame *frame = m_frames[i];
375 if (!frame->loaded()) {
376 emit loaderSearchNext(i, str, sensitivity);
377 return;
378 } else {
379 ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
380 if (call) {
381 emit findResult(SearchFound, call);
Zack Rusin121e3162011-09-13 01:35:12 -0400382 return;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400383 }
384 }
385 }
386 emit findResult(SearchWrapped, 0);
387}
388
389void ApiTrace::findPrev(ApiTraceFrame *frame,
390 ApiTraceCall *from,
391 const QString &str,
392 Qt::CaseSensitivity sensitivity)
393{
394 ApiTraceCall *foundCall = 0;
395 int frameIdx = m_frames.indexOf(frame);
396
397 if (frame->loaded()) {
398 foundCall = frame->findPrevCall(from, str, sensitivity);
399 if (foundCall) {
400 emit findResult(SearchFound, foundCall);
401 return;
402 }
403
404 //if the frame is loaded we already searched it above
405 // so skip it
406 frameIdx -= 1;
407 }
408
Zack Rusin121e3162011-09-13 01:35:12 -0400409 for (int i = frameIdx; i >= 0; --i) {
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400410 ApiTraceFrame *frame = m_frames[i];
411 if (!frame->loaded()) {
412 emit loaderSearchPrev(i, str, sensitivity);
413 return;
414 } else {
415 ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
416 if (call) {
417 emit findResult(SearchFound, call);
Zack Rusin121e3162011-09-13 01:35:12 -0400418 return;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400419 }
420 }
421 }
422 emit findResult(SearchWrapped, 0);
423}
424
425void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
426 ApiTraceCall *call)
427{
428 //qDebug()<<"Search result = "<<result
429 // <<", call is = "<<call;
430 emit findResult(result, call);
431}
432
Zack Rusin93e4d152011-09-13 02:23:39 -0400433void ApiTrace::findFrameStart(ApiTraceFrame *frame)
434{
435 if (frame->loaded()) {
436 emit foundFrameStart(frame);
437 } else {
438 emit loaderFindFrameStart(frame);
439 }
440}
441
442void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
443{
444 if (frame->loaded()) {
445 emit foundFrameEnd(frame);
446 } else {
447 emit loaderFindFrameEnd(frame);
448 }
449}
450
Zack Rusinda7579b2011-09-13 17:33:05 -0400451void ApiTrace::findCallIndex(int index)
452{
453 int frameIdx = callInFrame(index);
454 ApiTraceFrame *frame = 0;
455
456 if (frameIdx < 0) {
457 emit foundCallIndex(0);
458 return;
459 }
460
461 frame = m_frames[frameIdx];
462
463 if (frame) {
464 if (frame->loaded()) {
465 ApiTraceCall *call = frame->callWithIndex(index);
466 emit foundCallIndex(call);
467 } else {
468 emit loaderFindCallIndex(index);
469 }
470 }
471}
472
473int ApiTrace::callInFrame(int callIdx) const
474{
475 unsigned numCalls = 0;
476
477 for (int frameIdx = 0; frameIdx <= m_frames.size(); ++frameIdx) {
478 const ApiTraceFrame *frame = m_frames[frameIdx];
479 unsigned numCallsInFrame = frame->loaded()
480 ? frame->numChildren()
481 : frame->numChildrenToLoad();
482 unsigned firstCall = numCalls;
483 unsigned endCall = numCalls + numCallsInFrame;
484 if (firstCall <= callIdx && endCall > callIdx) {
485 return frameIdx;
486 }
487 numCalls = endCall;
488 }
489
490 return -1;
491}
492
Zack Rusinf6667d12011-03-30 11:03:37 -0400493#include "apitrace.moc"