]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
a7333aa9e6b799786ec3ba8b7d47d5f3b3cb562f
[apitrace] / gui / apitrace.cpp
1 #include "apitrace.h"
2
3 #include "traceloader.h"
4 #include "saverthread.h"
5
6 #include <QDebug>
7 #include <QDir>
8 #include <QThread>
9
10 ApiTrace::ApiTrace()
11     : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
12       m_needsSaving(false)
13 {
14     m_loader = new TraceLoader();
15
16     connect(this, SIGNAL(loadTrace(QString)),
17             m_loader, SLOT(loadTrace(QString)));
18     connect(this, SIGNAL(requestFrame(ApiTraceFrame*)),
19             m_loader, SLOT(loadFrame(ApiTraceFrame*)));
20     connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
21             this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
22     connect(m_loader,
23             SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)),
24             this,
25             SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)));
26     connect(m_loader, SIGNAL(finishedParsing()),
27             this, SLOT(finishedParsing()));
28     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     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*)));
44     connect(this, SIGNAL(loaderFindCallIndex(int)),
45             m_loader, SLOT(findCallIndex(int)));
46     connect(m_loader, SIGNAL(foundCallIndex(ApiTraceCall*)),
47             this, SIGNAL(foundCallIndex(ApiTraceCall*)));
48
49
50     connect(m_loader, SIGNAL(startedParsing()),
51             this, SIGNAL(startedLoadingTrace()));
52     connect(m_loader, SIGNAL(parsed(int)),
53             this, SIGNAL(loaded(int)));
54     connect(m_loader, SIGNAL(finishedParsing()),
55             this, SIGNAL(finishedLoadingTrace()));
56
57
58     m_saver = new SaverThread(this);
59     connect(m_saver, SIGNAL(traceSaved()),
60             this, SLOT(slotSaved()));
61     connect(m_saver, SIGNAL(traceSaved()),
62             this, SIGNAL(saved()));
63
64     m_loaderThread = new QThread();
65     m_loader->moveToThread(m_loaderThread);
66     m_loaderThread->start();
67 }
68
69 ApiTrace::~ApiTrace()
70 {
71     m_loaderThread->quit();
72     m_loaderThread->deleteLater();
73     qDeleteAll(m_calls);
74     qDeleteAll(m_frames);
75     delete m_loader;
76     delete m_saver;
77 }
78
79 bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
80                                   ApiTrace::FrameMarker marker)
81 {
82     if (!call)
83         return false;
84
85     switch (marker) {
86     case FrameMarker_SwapBuffers:
87         return call->name().contains(QLatin1String("SwapBuffers")) ||
88                call->name() == QLatin1String("CGLFlushDrawable") ||
89                call->name() == QLatin1String("glFrameTerminatorGREMEDY");
90     case FrameMarker_Flush:
91         return call->name() == QLatin1String("glFlush");
92     case FrameMarker_Finish:
93         return call->name() == QLatin1String("glFinish");
94     case FrameMarker_Clear:
95         return call->name() == QLatin1String("glClear");
96     }
97
98     Q_ASSERT(!"unknown frame marker");
99
100     return false;
101 }
102
103 bool ApiTrace::isEmpty() const
104 {
105     return m_calls.isEmpty();
106 }
107
108 QString ApiTrace::fileName() const
109 {
110     if (edited())
111         return m_tempFileName;
112
113     return m_fileName;
114 }
115
116 ApiTrace::FrameMarker ApiTrace::frameMarker() const
117 {
118     return m_frameMarker;
119 }
120
121 QList<ApiTraceFrame*> ApiTrace::frames() const
122 {
123     return m_frames;
124 }
125
126 ApiTraceFrame * ApiTrace::frameAt(int idx) const
127 {
128     return m_frames.value(idx);
129 }
130
131 int ApiTrace::numFrames() const
132 {
133     return m_frames.count();
134 }
135
136 int ApiTrace::numCallsInFrame(int idx) const
137 {
138     const ApiTraceFrame *frame = frameAt(idx);
139     if (frame)
140         return frame->numChildren();
141     else
142         return 0;
143 }
144
145 void ApiTrace::setFileName(const QString &name)
146 {
147     if (m_fileName != name) {
148         m_fileName = name;
149
150         m_frames.clear();
151         m_calls.clear();
152         m_errors.clear();
153         m_editedCalls.clear();
154         m_needsSaving = false;
155         emit invalidated();
156
157 //        m_loader->loadTrace(m_fileName);
158         emit loadTrace(m_fileName);
159     }
160 }
161
162 void ApiTrace::setFrameMarker(FrameMarker marker)
163 {
164     if (m_frameMarker != marker) {
165         emit framesInvalidated();
166
167         qDeleteAll(m_frames);
168         m_frames.clear();
169         detectFrames();
170     }
171 }
172
173 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
174 {
175     QVector<ApiTraceCall*> calls;
176     int currentFrames = m_frames.count();
177     int numNewFrames = frames.count();
178
179     emit beginAddingFrames(currentFrames, numNewFrames);
180
181     m_frames += frames;
182
183     int currentCalls = m_calls.count();
184     int numNewCalls = 0;
185     foreach(ApiTraceFrame *frame, frames) {
186         frame->setParentTrace(this);
187         numNewCalls += frame->numChildren();
188         calls += frame->calls();
189     }
190     m_calls.reserve(m_calls.count() + calls.count() + 1);
191     m_calls += calls;
192
193     emit endAddingFrames();
194     emit callsAdded(currentCalls, numNewCalls);
195 }
196
197 void ApiTrace::detectFrames()
198 {
199     if (m_calls.isEmpty())
200         return;
201
202     emit beginAddingFrames(0, m_frames.count());
203
204     ApiTraceFrame *currentFrame = 0;
205     foreach(ApiTraceCall *apiCall, m_calls) {
206         if (!currentFrame) {
207             currentFrame = new ApiTraceFrame(this);
208             currentFrame->number = m_frames.count();
209             currentFrame->setLoaded(true);
210         }
211         apiCall->setParentFrame(currentFrame);
212         currentFrame->addCall(apiCall);
213         if (ApiTrace::isCallAFrameMarker(apiCall,
214                                          m_frameMarker)) {
215             m_frames.append(currentFrame);
216             currentFrame = 0;
217         }
218     }
219     //last frames won't have markers
220     //  it's just a bunch of Delete calls for every object
221     //  after the last SwapBuffers
222     if (currentFrame) {
223         m_frames.append(currentFrame);
224         currentFrame = 0;
225     }
226     emit endAddingFrames();
227 }
228
229 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
230 {
231     for (int i = 0; i < m_calls.count(); ++i) {
232         ApiTraceCall *call = m_calls[i];
233         if (call->index() == idx)
234             return call;
235     }
236     return NULL;
237 }
238
239 ApiTraceState ApiTrace::defaultState() const
240 {
241     ApiTraceFrame *frame = frameAt(0);
242     if (!frame || !frame->hasState())
243         return ApiTraceState();
244
245     return *frame->state();
246 }
247
248 void ApiTrace::callEdited(ApiTraceCall *call)
249 {
250     if (!m_editedCalls.contains(call)) {
251         //lets generate a temp filename
252         QString tempPath = QDir::tempPath();
253         m_tempFileName = QString::fromLatin1("%1/%2.edited")
254                          .arg(tempPath)
255                          .arg(m_fileName);
256     }
257     m_editedCalls.insert(call);
258     m_needsSaving = true;
259
260     emit changed(call);
261 }
262
263 void ApiTrace::callReverted(ApiTraceCall *call)
264 {
265     m_editedCalls.remove(call);
266
267     if (m_editedCalls.isEmpty()) {
268         m_needsSaving = false;
269     }
270     emit changed(call);
271 }
272
273 bool ApiTrace::edited() const
274 {
275     return !m_editedCalls.isEmpty();
276 }
277
278 bool ApiTrace::needsSaving() const
279 {
280     return m_needsSaving;
281 }
282
283 void ApiTrace::save()
284 {
285     QFileInfo fi(m_tempFileName);
286     QDir dir;
287     emit startedSaving();
288     dir.mkpath(fi.absolutePath());
289     m_saver->saveFile(m_tempFileName, m_calls);
290 }
291
292 void ApiTrace::slotSaved()
293 {
294     m_needsSaving = false;
295 }
296
297 bool ApiTrace::isSaving() const
298 {
299     return m_saver->isRunning();
300 }
301
302 void ApiTrace::callError(ApiTraceCall *call)
303 {
304     Q_ASSERT(call);
305
306     if (call->hasError())
307         m_errors.insert(call);
308     else
309         m_errors.remove(call);
310
311     emit changed(call);
312 }
313
314 bool ApiTrace::hasErrors() const
315 {
316     return !m_errors.isEmpty();
317 }
318
319 void ApiTrace::loadFrame(ApiTraceFrame *frame)
320 {
321     Q_ASSERT(!frame->loaded());
322     emit requestFrame(frame);
323 }
324
325 void ApiTrace::finishedParsing()
326 {
327     ApiTraceFrame *firstFrame = m_frames[0];
328     if (firstFrame && !firstFrame->loaded()) {
329         loadFrame(firstFrame);
330     }
331 }
332
333 void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
334                                  const QVector<ApiTraceCall*> &calls,
335                                  quint64 binaryDataSize)
336 {
337     Q_ASSERT(frame->numChildrenToLoad() == calls.size());
338     emit beginLoadingFrame(frame, calls.size());
339     frame->setCalls(calls, binaryDataSize);
340     emit endLoadingFrame(frame);
341 }
342
343 void ApiTrace::findNext(ApiTraceFrame *frame,
344                         ApiTraceCall *from,
345                         const QString &str,
346                         Qt::CaseSensitivity sensitivity)
347 {
348     ApiTraceCall *foundCall = 0;
349     int frameIdx = m_frames.indexOf(frame);
350
351     if (frame->loaded()) {
352         foundCall = frame->findNextCall(from, str, sensitivity);
353         if (foundCall) {
354             emit findResult(SearchFound, foundCall);
355             return;
356         }
357
358         //if the frame is loaded we already searched it above
359         // so skip it
360         frameIdx += 1;
361     }
362
363     for (int i = frameIdx; i < m_frames.count(); ++i) {
364         ApiTraceFrame *frame = m_frames[i];
365         if (!frame->loaded()) {
366             emit loaderSearchNext(i, str, sensitivity);
367             return;
368         } else {
369             ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
370             if (call) {
371                 emit findResult(SearchFound, call);
372                 return;
373             }
374         }
375     }
376     emit findResult(SearchWrapped, 0);
377 }
378
379 void ApiTrace::findPrev(ApiTraceFrame *frame,
380                         ApiTraceCall *from,
381                         const QString &str,
382                         Qt::CaseSensitivity sensitivity)
383 {
384     ApiTraceCall *foundCall = 0;
385     int frameIdx = m_frames.indexOf(frame);
386
387     if (frame->loaded()) {
388         foundCall = frame->findPrevCall(from, str, sensitivity);
389         if (foundCall) {
390             emit findResult(SearchFound, foundCall);
391             return;
392         }
393
394         //if the frame is loaded we already searched it above
395         // so skip it
396         frameIdx -= 1;
397     }
398
399     for (int i = frameIdx; i >= 0; --i) {
400         ApiTraceFrame *frame = m_frames[i];
401         if (!frame->loaded()) {
402             emit loaderSearchPrev(i, str, sensitivity);
403             return;
404         } else {
405             ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
406             if (call) {
407                 emit findResult(SearchFound, call);
408                 return;
409             }
410         }
411     }
412     emit findResult(SearchWrapped, 0);
413 }
414
415 void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
416                                   ApiTraceCall *call)
417 {
418     //qDebug()<<"Search result = "<<result
419     //       <<", call is = "<<call;
420     emit findResult(result, call);
421 }
422
423 void ApiTrace::findFrameStart(ApiTraceFrame *frame)
424 {
425     if (frame->loaded()) {
426         emit foundFrameStart(frame);
427     } else {
428         emit loaderFindFrameStart(frame);
429     }
430 }
431
432 void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
433 {
434     if (frame->loaded()) {
435         emit foundFrameEnd(frame);
436     } else {
437         emit loaderFindFrameEnd(frame);
438     }
439 }
440
441 void ApiTrace::findCallIndex(int index)
442 {
443     int frameIdx = callInFrame(index);
444     ApiTraceFrame *frame = 0;
445
446     if (frameIdx < 0) {
447         emit foundCallIndex(0);
448         return;
449     }
450
451     frame = m_frames[frameIdx];
452
453     if (frame) {
454         if (frame->loaded()) {
455             ApiTraceCall *call = frame->callWithIndex(index);
456             emit foundCallIndex(call);
457         } else {
458             emit loaderFindCallIndex(index);
459         }
460     }
461 }
462
463 int ApiTrace::callInFrame(int callIdx) const
464 {
465     unsigned numCalls = 0;
466
467     for (int frameIdx = 0; frameIdx <= m_frames.size(); ++frameIdx) {
468         const ApiTraceFrame *frame = m_frames[frameIdx];
469         unsigned numCallsInFrame =  frame->loaded()
470                 ? frame->numChildren()
471                 : frame->numChildrenToLoad();
472         unsigned firstCall = numCalls;
473         unsigned endCall = numCalls + numCallsInFrame;
474         if (firstCall <= callIdx && endCall > callIdx) {
475             return frameIdx;
476         }
477         numCalls = endCall;
478     }
479
480     return -1;
481 }
482
483 #include "apitrace.moc"