blob: bff1686a9a3076add8058fcad199a483b9b5e873 [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*)));
36
Zack Rusinebf971e2011-09-06 17:44:43 -040037
38 connect(m_loader, SIGNAL(startedParsing()),
Zack Rusinde4ea412011-03-30 11:30:08 -040039 this, SIGNAL(startedLoadingTrace()));
Zack Rusinebf971e2011-09-06 17:44:43 -040040 connect(m_loader, SIGNAL(parsed(int)),
41 this, SIGNAL(loaded(int)));
42 connect(m_loader, SIGNAL(finishedParsing()),
Zack Rusinde4ea412011-03-30 11:30:08 -040043 this, SIGNAL(finishedLoadingTrace()));
Zack Rusind809a062011-04-17 23:30:58 -040044
Zack Rusinebf971e2011-09-06 17:44:43 -040045
Zack Rusind809a062011-04-17 23:30:58 -040046 m_saver = new SaverThread(this);
Zack Rusin9af5bff2011-04-18 01:05:50 -040047 connect(m_saver, SIGNAL(traceSaved()),
48 this, SLOT(slotSaved()));
49 connect(m_saver, SIGNAL(traceSaved()),
50 this, SIGNAL(saved()));
Zack Rusinebf971e2011-09-06 17:44:43 -040051
52 m_loaderThread = new QThread();
53 m_loader->moveToThread(m_loaderThread);
54 m_loaderThread->start();
Zack Rusinf6667d12011-03-30 11:03:37 -040055}
56
57ApiTrace::~ApiTrace()
58{
Zack Rusinebf971e2011-09-06 17:44:43 -040059 m_loaderThread->quit();
60 m_loaderThread->deleteLater();
Zack Rusinf6667d12011-03-30 11:03:37 -040061 qDeleteAll(m_calls);
62 qDeleteAll(m_frames);
63 delete m_loader;
Zack Rusind809a062011-04-17 23:30:58 -040064 delete m_saver;
Zack Rusinf6667d12011-03-30 11:03:37 -040065}
66
67bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
68 ApiTrace::FrameMarker marker)
69{
70 if (!call)
71 return false;
72
73 switch (marker) {
74 case FrameMarker_SwapBuffers:
José Fonseca3e9ff852011-06-06 19:37:09 +010075 return call->name().contains(QLatin1String("SwapBuffers")) ||
José Fonsecadb678122011-07-29 17:20:05 +010076 call->name() == QLatin1String("CGLFlushDrawable") ||
77 call->name() == QLatin1String("glFrameTerminatorGREMEDY");
Zack Rusinf6667d12011-03-30 11:03:37 -040078 case FrameMarker_Flush:
Zack Rusinead6aad2011-04-15 22:16:18 -040079 return call->name() == QLatin1String("glFlush");
Zack Rusinf6667d12011-03-30 11:03:37 -040080 case FrameMarker_Finish:
Zack Rusinead6aad2011-04-15 22:16:18 -040081 return call->name() == QLatin1String("glFinish");
Zack Rusinf6667d12011-03-30 11:03:37 -040082 case FrameMarker_Clear:
Zack Rusinead6aad2011-04-15 22:16:18 -040083 return call->name() == QLatin1String("glClear");
Zack Rusinf6667d12011-03-30 11:03:37 -040084 }
85
86 Q_ASSERT(!"unknown frame marker");
87
88 return false;
89}
90
91bool ApiTrace::isEmpty() const
92{
93 return m_calls.isEmpty();
94}
95
96QString ApiTrace::fileName() const
97{
Zack Rusin63efea82011-04-17 17:10:45 -040098 if (edited())
99 return m_tempFileName;
100
Zack Rusinf6667d12011-03-30 11:03:37 -0400101 return m_fileName;
102}
103
104ApiTrace::FrameMarker ApiTrace::frameMarker() const
105{
106 return m_frameMarker;
107}
108
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400109QVector<ApiTraceCall*> ApiTrace::calls() const
Zack Rusinf6667d12011-03-30 11:03:37 -0400110{
111 return m_calls;
112}
113
Zack Rusinf6667d12011-03-30 11:03:37 -0400114int ApiTrace::numCalls() const
115{
116 return m_calls.count();
117}
118
119QList<ApiTraceFrame*> ApiTrace::frames() const
120{
121 return m_frames;
122}
123
124ApiTraceFrame * ApiTrace::frameAt(int idx) const
125{
126 return m_frames.value(idx);
127}
128
129int ApiTrace::numFrames() const
130{
131 return m_frames.count();
132}
133
134int ApiTrace::numCallsInFrame(int idx) const
135{
136 const ApiTraceFrame *frame = frameAt(idx);
137 if (frame)
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400138 return frame->numChildren();
Zack Rusinf6667d12011-03-30 11:03:37 -0400139 else
140 return 0;
141}
142
143void ApiTrace::setFileName(const QString &name)
144{
145 if (m_fileName != name) {
146 m_fileName = name;
147
Zack Rusinca164112011-04-11 02:23:09 -0400148 m_frames.clear();
149 m_calls.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
160void ApiTrace::setFrameMarker(FrameMarker marker)
161{
162 if (m_frameMarker != marker) {
163 emit framesInvalidated();
164
165 qDeleteAll(m_frames);
166 m_frames.clear();
167 detectFrames();
168 }
169}
170
171void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
172{
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400173 QVector<ApiTraceCall*> calls;
Zack Rusinf6667d12011-03-30 11:03:37 -0400174 int currentFrames = m_frames.count();
175 int numNewFrames = frames.count();
Zack Rusinb56e03d2011-04-20 23:58:52 -0400176
177 emit beginAddingFrames(currentFrames, numNewFrames);
178
Zack Rusinf6667d12011-03-30 11:03:37 -0400179 m_frames += frames;
180
181 int currentCalls = m_calls.count();
182 int numNewCalls = 0;
183 foreach(ApiTraceFrame *frame, frames) {
Zack Rusinebf971e2011-09-06 17:44:43 -0400184 frame->setParentTrace(this);
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400185 numNewCalls += frame->numChildren();
Zack Rusin410a8f32011-08-28 02:38:34 -0400186 calls += frame->calls();
Zack Rusinf6667d12011-03-30 11:03:37 -0400187 }
Zack Rusin4d0ef5d2011-08-28 22:05:31 -0400188 m_calls.reserve(m_calls.count() + calls.count() + 1);
Zack Rusin410a8f32011-08-28 02:38:34 -0400189 m_calls += calls;
Zack Rusinf6667d12011-03-30 11:03:37 -0400190
Zack Rusinb56e03d2011-04-20 23:58:52 -0400191 emit endAddingFrames();
Zack Rusinf6667d12011-03-30 11:03:37 -0400192 emit callsAdded(currentCalls, numNewCalls);
193}
194
195void ApiTrace::detectFrames()
196{
197 if (m_calls.isEmpty())
198 return;
199
Zack Rusinb56e03d2011-04-20 23:58:52 -0400200 emit beginAddingFrames(0, m_frames.count());
201
Zack Rusinf6667d12011-03-30 11:03:37 -0400202 ApiTraceFrame *currentFrame = 0;
203 foreach(ApiTraceCall *apiCall, m_calls) {
204 if (!currentFrame) {
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400205 currentFrame = new ApiTraceFrame(this);
Zack Rusinf6667d12011-03-30 11:03:37 -0400206 currentFrame->number = m_frames.count();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400207 currentFrame->setLoaded(true);
Zack Rusinf6667d12011-03-30 11:03:37 -0400208 }
Zack Rusinead6aad2011-04-15 22:16:18 -0400209 apiCall->setParentFrame(currentFrame);
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400210 currentFrame->addCall(apiCall);
Zack Rusinf6667d12011-03-30 11:03:37 -0400211 if (ApiTrace::isCallAFrameMarker(apiCall,
212 m_frameMarker)) {
213 m_frames.append(currentFrame);
214 currentFrame = 0;
215 }
216 }
217 //last frames won't have markers
218 // it's just a bunch of Delete calls for every object
219 // after the last SwapBuffers
220 if (currentFrame) {
221 m_frames.append(currentFrame);
222 currentFrame = 0;
223 }
Zack Rusinb56e03d2011-04-20 23:58:52 -0400224 emit endAddingFrames();
Zack Rusinf6667d12011-03-30 11:03:37 -0400225}
226
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400227ApiTraceCall * ApiTrace::callWithIndex(int idx) const
228{
229 for (int i = 0; i < m_calls.count(); ++i) {
230 ApiTraceCall *call = m_calls[i];
Zack Rusinead6aad2011-04-15 22:16:18 -0400231 if (call->index() == idx)
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400232 return call;
233 }
234 return NULL;
235}
236
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400237ApiTraceState ApiTrace::defaultState() const
238{
239 ApiTraceFrame *frame = frameAt(0);
Zack Rusined40bc62011-08-28 17:11:02 -0400240 if (!frame || !frame->hasState())
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400241 return ApiTraceState();
242
Zack Rusined40bc62011-08-28 17:11:02 -0400243 return *frame->state();
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400244}
245
Zack Rusin661842d2011-04-17 01:59:16 -0400246void ApiTrace::callEdited(ApiTraceCall *call)
247{
Zack Rusin63efea82011-04-17 17:10:45 -0400248 if (!m_editedCalls.contains(call)) {
249 //lets generate a temp filename
250 QString tempPath = QDir::tempPath();
Zack Rusin63efea82011-04-17 17:10:45 -0400251 m_tempFileName = QString::fromLatin1("%1/%2.edited")
252 .arg(tempPath)
253 .arg(m_fileName);
Zack Rusin63efea82011-04-17 17:10:45 -0400254 }
Zack Rusin661842d2011-04-17 01:59:16 -0400255 m_editedCalls.insert(call);
Zack Rusin9af5bff2011-04-18 01:05:50 -0400256 m_needsSaving = true;
Zack Rusin63efea82011-04-17 17:10:45 -0400257
Zack Rusin661842d2011-04-17 01:59:16 -0400258 emit changed(call);
259}
260
261void ApiTrace::callReverted(ApiTraceCall *call)
262{
263 m_editedCalls.remove(call);
Zack Rusin63efea82011-04-17 17:10:45 -0400264
265 if (m_editedCalls.isEmpty()) {
266 m_needsSaving = false;
267 }
Zack Rusin661842d2011-04-17 01:59:16 -0400268 emit changed(call);
269}
270
Zack Rusin0ddd2502011-04-17 02:34:45 -0400271bool ApiTrace::edited() const
Zack Rusin661842d2011-04-17 01:59:16 -0400272{
273 return !m_editedCalls.isEmpty();
274}
275
Zack Rusin63efea82011-04-17 17:10:45 -0400276bool ApiTrace::needsSaving() const
277{
278 return m_needsSaving;
279}
280
281void ApiTrace::save()
282{
283 QFileInfo fi(m_tempFileName);
284 QDir dir;
Zack Rusin9af5bff2011-04-18 01:05:50 -0400285 emit startedSaving();
Zack Rusin63efea82011-04-17 17:10:45 -0400286 dir.mkpath(fi.absolutePath());
Zack Rusind809a062011-04-17 23:30:58 -0400287 m_saver->saveFile(m_tempFileName, m_calls);
Zack Rusin63efea82011-04-17 17:10:45 -0400288}
289
Zack Rusin9af5bff2011-04-18 01:05:50 -0400290void ApiTrace::slotSaved()
291{
292 m_needsSaving = false;
293}
294
295bool ApiTrace::isSaving() const
296{
297 return m_saver->isRunning();
298}
299
Zack Rusinb53b1612011-04-19 01:33:58 -0400300void ApiTrace::callError(ApiTraceCall *call)
301{
Zack Rusincc0b4912011-04-19 01:59:20 -0400302 Q_ASSERT(call);
303
304 if (call->hasError())
305 m_errors.insert(call);
306 else
307 m_errors.remove(call);
308
Zack Rusinb53b1612011-04-19 01:33:58 -0400309 emit changed(call);
310}
311
Zack Rusincc0b4912011-04-19 01:59:20 -0400312bool ApiTrace::hasErrors() const
313{
314 return !m_errors.isEmpty();
315}
316
Zack Rusin3176ebe2011-09-06 21:11:36 -0400317void ApiTrace::loadFrame(ApiTraceFrame *frame)
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400318{
Zack Rusin3176ebe2011-09-06 21:11:36 -0400319 Q_ASSERT(!frame->loaded());
320 emit requestFrame(frame);
Zack Rusin35c27932011-08-28 21:16:22 -0400321}
322
Zack Rusinf682e192011-09-07 01:36:41 -0400323void ApiTrace::finishedParsing()
324{
325 ApiTraceFrame *firstFrame = m_frames[0];
326 if (firstFrame && !firstFrame->loaded()) {
327 loadFrame(firstFrame);
328 }
329}
330
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400331void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
332 const QVector<ApiTraceCall*> &calls,
333 quint64 binaryDataSize)
Zack Rusinf682e192011-09-07 01:36:41 -0400334{
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400335 Q_ASSERT(frame->numChildrenToLoad() == calls.size());
336 emit beginLoadingFrame(frame, calls.size());
337 frame->setCalls(calls, binaryDataSize);
Zack Rusinf682e192011-09-07 01:36:41 -0400338 emit endLoadingFrame(frame);
339}
340
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400341void ApiTrace::findNext(ApiTraceFrame *frame,
342 ApiTraceCall *from,
343 const QString &str,
344 Qt::CaseSensitivity sensitivity)
345{
346 ApiTraceCall *foundCall = 0;
347 int frameIdx = m_frames.indexOf(frame);
348
349 if (frame->loaded()) {
350 foundCall = frame->findNextCall(from, str, sensitivity);
351 if (foundCall) {
352 emit findResult(SearchFound, foundCall);
353 return;
354 }
355
356 //if the frame is loaded we already searched it above
357 // so skip it
358 frameIdx += 1;
359 }
360
361 for (int i = frameIdx; i < m_frames.count(); ++i) {
362 ApiTraceFrame *frame = m_frames[i];
363 if (!frame->loaded()) {
364 emit loaderSearchNext(i, str, sensitivity);
365 return;
366 } else {
367 ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
368 if (call) {
369 emit findResult(SearchFound, call);
370 }
371 }
372 }
373 emit findResult(SearchWrapped, 0);
374}
375
376void ApiTrace::findPrev(ApiTraceFrame *frame,
377 ApiTraceCall *from,
378 const QString &str,
379 Qt::CaseSensitivity sensitivity)
380{
381 ApiTraceCall *foundCall = 0;
382 int frameIdx = m_frames.indexOf(frame);
383
384 if (frame->loaded()) {
385 foundCall = frame->findPrevCall(from, str, sensitivity);
386 if (foundCall) {
387 emit findResult(SearchFound, foundCall);
388 return;
389 }
390
391 //if the frame is loaded we already searched it above
392 // so skip it
393 frameIdx -= 1;
394 }
395
396 for (int i = frameIdx; i <= 0; --i) {
397 ApiTraceFrame *frame = m_frames[i];
398 if (!frame->loaded()) {
399 emit loaderSearchPrev(i, str, sensitivity);
400 return;
401 } else {
402 ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
403 if (call) {
404 emit findResult(SearchFound, call);
405 }
406 }
407 }
408 emit findResult(SearchWrapped, 0);
409}
410
411void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
412 ApiTraceCall *call)
413{
414 //qDebug()<<"Search result = "<<result
415 // <<", call is = "<<call;
416 emit findResult(result, call);
417}
418
Zack Rusinf6667d12011-03-30 11:03:37 -0400419#include "apitrace.moc"