blob: c8cb0860bc87ce710da0be504cae706b9ae7538b [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 Rusin8f98c3a2011-09-11 18:21:29 -040044
Zack Rusinebf971e2011-09-06 17:44:43 -040045
46 connect(m_loader, SIGNAL(startedParsing()),
Zack Rusinde4ea412011-03-30 11:30:08 -040047 this, SIGNAL(startedLoadingTrace()));
Zack Rusinebf971e2011-09-06 17:44:43 -040048 connect(m_loader, SIGNAL(parsed(int)),
49 this, SIGNAL(loaded(int)));
50 connect(m_loader, SIGNAL(finishedParsing()),
Zack Rusinde4ea412011-03-30 11:30:08 -040051 this, SIGNAL(finishedLoadingTrace()));
Zack Rusind809a062011-04-17 23:30:58 -040052
Zack Rusinebf971e2011-09-06 17:44:43 -040053
Zack Rusind809a062011-04-17 23:30:58 -040054 m_saver = new SaverThread(this);
Zack Rusin9af5bff2011-04-18 01:05:50 -040055 connect(m_saver, SIGNAL(traceSaved()),
56 this, SLOT(slotSaved()));
57 connect(m_saver, SIGNAL(traceSaved()),
58 this, SIGNAL(saved()));
Zack Rusinebf971e2011-09-06 17:44:43 -040059
60 m_loaderThread = new QThread();
61 m_loader->moveToThread(m_loaderThread);
62 m_loaderThread->start();
Zack Rusinf6667d12011-03-30 11:03:37 -040063}
64
65ApiTrace::~ApiTrace()
66{
Zack Rusinebf971e2011-09-06 17:44:43 -040067 m_loaderThread->quit();
68 m_loaderThread->deleteLater();
Zack Rusinf6667d12011-03-30 11:03:37 -040069 qDeleteAll(m_calls);
70 qDeleteAll(m_frames);
71 delete m_loader;
Zack Rusind809a062011-04-17 23:30:58 -040072 delete m_saver;
Zack Rusinf6667d12011-03-30 11:03:37 -040073}
74
75bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
76 ApiTrace::FrameMarker marker)
77{
78 if (!call)
79 return false;
80
81 switch (marker) {
82 case FrameMarker_SwapBuffers:
José Fonseca3e9ff852011-06-06 19:37:09 +010083 return call->name().contains(QLatin1String("SwapBuffers")) ||
José Fonsecadb678122011-07-29 17:20:05 +010084 call->name() == QLatin1String("CGLFlushDrawable") ||
85 call->name() == QLatin1String("glFrameTerminatorGREMEDY");
Zack Rusinf6667d12011-03-30 11:03:37 -040086 case FrameMarker_Flush:
Zack Rusinead6aad2011-04-15 22:16:18 -040087 return call->name() == QLatin1String("glFlush");
Zack Rusinf6667d12011-03-30 11:03:37 -040088 case FrameMarker_Finish:
Zack Rusinead6aad2011-04-15 22:16:18 -040089 return call->name() == QLatin1String("glFinish");
Zack Rusinf6667d12011-03-30 11:03:37 -040090 case FrameMarker_Clear:
Zack Rusinead6aad2011-04-15 22:16:18 -040091 return call->name() == QLatin1String("glClear");
Zack Rusinf6667d12011-03-30 11:03:37 -040092 }
93
94 Q_ASSERT(!"unknown frame marker");
95
96 return false;
97}
98
99bool ApiTrace::isEmpty() const
100{
101 return m_calls.isEmpty();
102}
103
104QString ApiTrace::fileName() const
105{
Zack Rusin63efea82011-04-17 17:10:45 -0400106 if (edited())
107 return m_tempFileName;
108
Zack Rusinf6667d12011-03-30 11:03:37 -0400109 return m_fileName;
110}
111
112ApiTrace::FrameMarker ApiTrace::frameMarker() const
113{
114 return m_frameMarker;
115}
116
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400117QVector<ApiTraceCall*> ApiTrace::calls() const
Zack Rusinf6667d12011-03-30 11:03:37 -0400118{
119 return m_calls;
120}
121
Zack Rusinf6667d12011-03-30 11:03:37 -0400122int ApiTrace::numCalls() const
123{
124 return m_calls.count();
125}
126
127QList<ApiTraceFrame*> ApiTrace::frames() const
128{
129 return m_frames;
130}
131
132ApiTraceFrame * ApiTrace::frameAt(int idx) const
133{
134 return m_frames.value(idx);
135}
136
137int ApiTrace::numFrames() const
138{
139 return m_frames.count();
140}
141
142int ApiTrace::numCallsInFrame(int idx) const
143{
144 const ApiTraceFrame *frame = frameAt(idx);
145 if (frame)
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400146 return frame->numChildren();
Zack Rusinf6667d12011-03-30 11:03:37 -0400147 else
148 return 0;
149}
150
151void ApiTrace::setFileName(const QString &name)
152{
153 if (m_fileName != name) {
154 m_fileName = name;
155
Zack Rusinca164112011-04-11 02:23:09 -0400156 m_frames.clear();
157 m_calls.clear();
Zack Rusin30069572011-04-20 18:21:11 -0400158 m_errors.clear();
159 m_editedCalls.clear();
160 m_needsSaving = false;
Zack Rusinf6667d12011-03-30 11:03:37 -0400161 emit invalidated();
162
Zack Rusinebf971e2011-09-06 17:44:43 -0400163// m_loader->loadTrace(m_fileName);
164 emit loadTrace(m_fileName);
Zack Rusinf6667d12011-03-30 11:03:37 -0400165 }
166}
167
168void ApiTrace::setFrameMarker(FrameMarker marker)
169{
170 if (m_frameMarker != marker) {
171 emit framesInvalidated();
172
173 qDeleteAll(m_frames);
174 m_frames.clear();
175 detectFrames();
176 }
177}
178
179void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
180{
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400181 QVector<ApiTraceCall*> calls;
Zack Rusinf6667d12011-03-30 11:03:37 -0400182 int currentFrames = m_frames.count();
183 int numNewFrames = frames.count();
Zack Rusinb56e03d2011-04-20 23:58:52 -0400184
185 emit beginAddingFrames(currentFrames, numNewFrames);
186
Zack Rusinf6667d12011-03-30 11:03:37 -0400187 m_frames += frames;
188
189 int currentCalls = m_calls.count();
190 int numNewCalls = 0;
191 foreach(ApiTraceFrame *frame, frames) {
Zack Rusinebf971e2011-09-06 17:44:43 -0400192 frame->setParentTrace(this);
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400193 numNewCalls += frame->numChildren();
Zack Rusin410a8f32011-08-28 02:38:34 -0400194 calls += frame->calls();
Zack Rusinf6667d12011-03-30 11:03:37 -0400195 }
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400196 m_calls.reserve(m_calls.count() + calls.count() + 1);
Zack Rusin410a8f32011-08-28 02:38:34 -0400197 m_calls += calls;
Zack Rusinf6667d12011-03-30 11:03:37 -0400198
Zack Rusinb56e03d2011-04-20 23:58:52 -0400199 emit endAddingFrames();
Zack Rusinf6667d12011-03-30 11:03:37 -0400200 emit callsAdded(currentCalls, numNewCalls);
201}
202
203void ApiTrace::detectFrames()
204{
205 if (m_calls.isEmpty())
206 return;
207
Zack Rusinb56e03d2011-04-20 23:58:52 -0400208 emit beginAddingFrames(0, m_frames.count());
209
Zack Rusinf6667d12011-03-30 11:03:37 -0400210 ApiTraceFrame *currentFrame = 0;
211 foreach(ApiTraceCall *apiCall, m_calls) {
212 if (!currentFrame) {
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400213 currentFrame = new ApiTraceFrame(this);
Zack Rusinf6667d12011-03-30 11:03:37 -0400214 currentFrame->number = m_frames.count();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400215 currentFrame->setLoaded(true);
Zack Rusinf6667d12011-03-30 11:03:37 -0400216 }
Zack Rusinead6aad2011-04-15 22:16:18 -0400217 apiCall->setParentFrame(currentFrame);
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400218 currentFrame->addCall(apiCall);
Zack Rusinf6667d12011-03-30 11:03:37 -0400219 if (ApiTrace::isCallAFrameMarker(apiCall,
220 m_frameMarker)) {
221 m_frames.append(currentFrame);
222 currentFrame = 0;
223 }
224 }
225 //last frames won't have markers
226 // it's just a bunch of Delete calls for every object
227 // after the last SwapBuffers
228 if (currentFrame) {
229 m_frames.append(currentFrame);
230 currentFrame = 0;
231 }
Zack Rusinb56e03d2011-04-20 23:58:52 -0400232 emit endAddingFrames();
Zack Rusinf6667d12011-03-30 11:03:37 -0400233}
234
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400235ApiTraceCall * ApiTrace::callWithIndex(int idx) const
236{
237 for (int i = 0; i < m_calls.count(); ++i) {
238 ApiTraceCall *call = m_calls[i];
Zack Rusinead6aad2011-04-15 22:16:18 -0400239 if (call->index() == idx)
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400240 return call;
241 }
242 return NULL;
243}
244
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400245ApiTraceState ApiTrace::defaultState() const
246{
247 ApiTraceFrame *frame = frameAt(0);
Zack Rusined40bc62011-08-28 17:11:02 -0400248 if (!frame || !frame->hasState())
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400249 return ApiTraceState();
250
Zack Rusined40bc62011-08-28 17:11:02 -0400251 return *frame->state();
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400252}
253
Zack Rusin661842d2011-04-17 01:59:16 -0400254void ApiTrace::callEdited(ApiTraceCall *call)
255{
Zack Rusin63efea82011-04-17 17:10:45 -0400256 if (!m_editedCalls.contains(call)) {
257 //lets generate a temp filename
258 QString tempPath = QDir::tempPath();
Zack Rusin63efea82011-04-17 17:10:45 -0400259 m_tempFileName = QString::fromLatin1("%1/%2.edited")
260 .arg(tempPath)
261 .arg(m_fileName);
Zack Rusin63efea82011-04-17 17:10:45 -0400262 }
Zack Rusin661842d2011-04-17 01:59:16 -0400263 m_editedCalls.insert(call);
Zack Rusin9af5bff2011-04-18 01:05:50 -0400264 m_needsSaving = true;
Zack Rusin63efea82011-04-17 17:10:45 -0400265
Zack Rusin661842d2011-04-17 01:59:16 -0400266 emit changed(call);
267}
268
269void ApiTrace::callReverted(ApiTraceCall *call)
270{
271 m_editedCalls.remove(call);
Zack Rusin63efea82011-04-17 17:10:45 -0400272
273 if (m_editedCalls.isEmpty()) {
274 m_needsSaving = false;
275 }
Zack Rusin661842d2011-04-17 01:59:16 -0400276 emit changed(call);
277}
278
Zack Rusin0ddd2502011-04-17 02:34:45 -0400279bool ApiTrace::edited() const
Zack Rusin661842d2011-04-17 01:59:16 -0400280{
281 return !m_editedCalls.isEmpty();
282}
283
Zack Rusin63efea82011-04-17 17:10:45 -0400284bool ApiTrace::needsSaving() const
285{
286 return m_needsSaving;
287}
288
289void ApiTrace::save()
290{
291 QFileInfo fi(m_tempFileName);
292 QDir dir;
Zack Rusin9af5bff2011-04-18 01:05:50 -0400293 emit startedSaving();
Zack Rusin63efea82011-04-17 17:10:45 -0400294 dir.mkpath(fi.absolutePath());
Zack Rusind809a062011-04-17 23:30:58 -0400295 m_saver->saveFile(m_tempFileName, m_calls);
Zack Rusin63efea82011-04-17 17:10:45 -0400296}
297
Zack Rusin9af5bff2011-04-18 01:05:50 -0400298void ApiTrace::slotSaved()
299{
300 m_needsSaving = false;
301}
302
303bool ApiTrace::isSaving() const
304{
305 return m_saver->isRunning();
306}
307
Zack Rusinb53b1612011-04-19 01:33:58 -0400308void ApiTrace::callError(ApiTraceCall *call)
309{
Zack Rusincc0b4912011-04-19 01:59:20 -0400310 Q_ASSERT(call);
311
312 if (call->hasError())
313 m_errors.insert(call);
314 else
315 m_errors.remove(call);
316
Zack Rusinb53b1612011-04-19 01:33:58 -0400317 emit changed(call);
318}
319
Zack Rusincc0b4912011-04-19 01:59:20 -0400320bool ApiTrace::hasErrors() const
321{
322 return !m_errors.isEmpty();
323}
324
Zack Rusin3176ebe2011-09-06 21:11:36 -0400325void ApiTrace::loadFrame(ApiTraceFrame *frame)
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400326{
Zack Rusin3176ebe2011-09-06 21:11:36 -0400327 Q_ASSERT(!frame->loaded());
328 emit requestFrame(frame);
Zack Rusin35c27932011-08-28 21:16:22 -0400329}
330
Zack Rusinf682e192011-09-07 01:36:41 -0400331void ApiTrace::finishedParsing()
332{
333 ApiTraceFrame *firstFrame = m_frames[0];
334 if (firstFrame && !firstFrame->loaded()) {
335 loadFrame(firstFrame);
336 }
337}
338
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400339void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
340 const QVector<ApiTraceCall*> &calls,
341 quint64 binaryDataSize)
Zack Rusinf682e192011-09-07 01:36:41 -0400342{
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400343 Q_ASSERT(frame->numChildrenToLoad() == calls.size());
344 emit beginLoadingFrame(frame, calls.size());
345 frame->setCalls(calls, binaryDataSize);
Zack Rusinf682e192011-09-07 01:36:41 -0400346 emit endLoadingFrame(frame);
347}
348
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400349void ApiTrace::findNext(ApiTraceFrame *frame,
350 ApiTraceCall *from,
351 const QString &str,
352 Qt::CaseSensitivity sensitivity)
353{
354 ApiTraceCall *foundCall = 0;
355 int frameIdx = m_frames.indexOf(frame);
356
357 if (frame->loaded()) {
358 foundCall = frame->findNextCall(from, str, sensitivity);
359 if (foundCall) {
360 emit findResult(SearchFound, foundCall);
361 return;
362 }
363
364 //if the frame is loaded we already searched it above
365 // so skip it
366 frameIdx += 1;
367 }
368
369 for (int i = frameIdx; i < m_frames.count(); ++i) {
370 ApiTraceFrame *frame = m_frames[i];
371 if (!frame->loaded()) {
372 emit loaderSearchNext(i, str, sensitivity);
373 return;
374 } else {
375 ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
376 if (call) {
377 emit findResult(SearchFound, call);
Zack Rusin121e3162011-09-13 01:35:12 -0400378 return;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400379 }
380 }
381 }
382 emit findResult(SearchWrapped, 0);
383}
384
385void ApiTrace::findPrev(ApiTraceFrame *frame,
386 ApiTraceCall *from,
387 const QString &str,
388 Qt::CaseSensitivity sensitivity)
389{
390 ApiTraceCall *foundCall = 0;
391 int frameIdx = m_frames.indexOf(frame);
392
393 if (frame->loaded()) {
394 foundCall = frame->findPrevCall(from, str, sensitivity);
395 if (foundCall) {
396 emit findResult(SearchFound, foundCall);
397 return;
398 }
399
400 //if the frame is loaded we already searched it above
401 // so skip it
402 frameIdx -= 1;
403 }
404
Zack Rusin121e3162011-09-13 01:35:12 -0400405 for (int i = frameIdx; i >= 0; --i) {
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400406 ApiTraceFrame *frame = m_frames[i];
407 if (!frame->loaded()) {
408 emit loaderSearchPrev(i, str, sensitivity);
409 return;
410 } else {
411 ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
412 if (call) {
413 emit findResult(SearchFound, call);
Zack Rusin121e3162011-09-13 01:35:12 -0400414 return;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400415 }
416 }
417 }
418 emit findResult(SearchWrapped, 0);
419}
420
421void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
422 ApiTraceCall *call)
423{
424 //qDebug()<<"Search result = "<<result
425 // <<", call is = "<<call;
426 emit findResult(result, call);
427}
428
Zack Rusin93e4d152011-09-13 02:23:39 -0400429void ApiTrace::findFrameStart(ApiTraceFrame *frame)
430{
431 if (frame->loaded()) {
432 emit foundFrameStart(frame);
433 } else {
434 emit loaderFindFrameStart(frame);
435 }
436}
437
438void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
439{
440 if (frame->loaded()) {
441 emit foundFrameEnd(frame);
442 } else {
443 emit loaderFindFrameEnd(frame);
444 }
445}
446
Zack Rusinf6667d12011-03-30 11:03:37 -0400447#include "apitrace.moc"