]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
51520c5e85df38cb2305914b7e798e714355cadc
[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
37
38     connect(m_loader, SIGNAL(startedParsing()),
39             this, SIGNAL(startedLoadingTrace()));
40     connect(m_loader, SIGNAL(parsed(int)),
41             this, SIGNAL(loaded(int)));
42     connect(m_loader, SIGNAL(finishedParsing()),
43             this, SIGNAL(finishedLoadingTrace()));
44
45
46     m_saver = new SaverThread(this);
47     connect(m_saver, SIGNAL(traceSaved()),
48             this, SLOT(slotSaved()));
49     connect(m_saver, SIGNAL(traceSaved()),
50             this, SIGNAL(saved()));
51
52     m_loaderThread = new QThread();
53     m_loader->moveToThread(m_loaderThread);
54     m_loaderThread->start();
55 }
56
57 ApiTrace::~ApiTrace()
58 {
59     m_loaderThread->quit();
60     m_loaderThread->deleteLater();
61     qDeleteAll(m_calls);
62     qDeleteAll(m_frames);
63     delete m_loader;
64     delete m_saver;
65 }
66
67 bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
68                                   ApiTrace::FrameMarker marker)
69 {
70     if (!call)
71         return false;
72
73     switch (marker) {
74     case FrameMarker_SwapBuffers:
75         return call->name().contains(QLatin1String("SwapBuffers")) ||
76                call->name() == QLatin1String("CGLFlushDrawable") ||
77                call->name() == QLatin1String("glFrameTerminatorGREMEDY");
78     case FrameMarker_Flush:
79         return call->name() == QLatin1String("glFlush");
80     case FrameMarker_Finish:
81         return call->name() == QLatin1String("glFinish");
82     case FrameMarker_Clear:
83         return call->name() == QLatin1String("glClear");
84     }
85
86     Q_ASSERT(!"unknown frame marker");
87
88     return false;
89 }
90
91 bool ApiTrace::isEmpty() const
92 {
93     return m_calls.isEmpty();
94 }
95
96 QString ApiTrace::fileName() const
97 {
98     if (edited())
99         return m_tempFileName;
100
101     return m_fileName;
102 }
103
104 ApiTrace::FrameMarker ApiTrace::frameMarker() const
105 {
106     return m_frameMarker;
107 }
108
109 QVector<ApiTraceCall*> ApiTrace::calls() const
110 {
111     return m_calls;
112 }
113
114 int ApiTrace::numCalls() const
115 {
116     return m_calls.count();
117 }
118
119 QList<ApiTraceFrame*> ApiTrace::frames() const
120 {
121     return m_frames;
122 }
123
124 ApiTraceFrame * ApiTrace::frameAt(int idx) const
125 {
126     return m_frames.value(idx);
127 }
128
129 int ApiTrace::numFrames() const
130 {
131     return m_frames.count();
132 }
133
134 int ApiTrace::numCallsInFrame(int idx) const
135 {
136     const ApiTraceFrame *frame = frameAt(idx);
137     if (frame)
138         return frame->numChildren();
139     else
140         return 0;
141 }
142
143 void ApiTrace::setFileName(const QString &name)
144 {
145     if (m_fileName != name) {
146         m_fileName = name;
147
148         m_frames.clear();
149         m_calls.clear();
150         m_errors.clear();
151         m_editedCalls.clear();
152         m_needsSaving = false;
153         emit invalidated();
154
155 //        m_loader->loadTrace(m_fileName);
156         emit loadTrace(m_fileName);
157     }
158 }
159
160 void 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
171 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
172 {
173     QVector<ApiTraceCall*> calls;
174     int currentFrames = m_frames.count();
175     int numNewFrames = frames.count();
176
177     emit beginAddingFrames(currentFrames, numNewFrames);
178
179     m_frames += frames;
180
181     int currentCalls = m_calls.count();
182     int numNewCalls = 0;
183     foreach(ApiTraceFrame *frame, frames) {
184         frame->setParentTrace(this);
185         numNewCalls += frame->numChildren();
186         calls += frame->calls();
187     }
188     m_calls.reserve(m_calls.count() + calls.count() + 1);
189     m_calls += calls;
190
191     emit endAddingFrames();
192     emit callsAdded(currentCalls, numNewCalls);
193 }
194
195 void ApiTrace::detectFrames()
196 {
197     if (m_calls.isEmpty())
198         return;
199
200     emit beginAddingFrames(0, m_frames.count());
201
202     ApiTraceFrame *currentFrame = 0;
203     foreach(ApiTraceCall *apiCall, m_calls) {
204         if (!currentFrame) {
205             currentFrame = new ApiTraceFrame(this);
206             currentFrame->number = m_frames.count();
207             currentFrame->setLoaded(true);
208         }
209         apiCall->setParentFrame(currentFrame);
210         currentFrame->addCall(apiCall);
211         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     }
224     emit endAddingFrames();
225 }
226
227 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
228 {
229     for (int i = 0; i < m_calls.count(); ++i) {
230         ApiTraceCall *call = m_calls[i];
231         if (call->index() == idx)
232             return call;
233     }
234     return NULL;
235 }
236
237 ApiTraceState ApiTrace::defaultState() const
238 {
239     ApiTraceFrame *frame = frameAt(0);
240     if (!frame || !frame->hasState())
241         return ApiTraceState();
242
243     return *frame->state();
244 }
245
246 void ApiTrace::callEdited(ApiTraceCall *call)
247 {
248     if (!m_editedCalls.contains(call)) {
249         //lets generate a temp filename
250         QString tempPath = QDir::tempPath();
251         m_tempFileName = QString::fromLatin1("%1/%2.edited")
252                          .arg(tempPath)
253                          .arg(m_fileName);
254     }
255     m_editedCalls.insert(call);
256     m_needsSaving = true;
257
258     emit changed(call);
259 }
260
261 void ApiTrace::callReverted(ApiTraceCall *call)
262 {
263     m_editedCalls.remove(call);
264
265     if (m_editedCalls.isEmpty()) {
266         m_needsSaving = false;
267     }
268     emit changed(call);
269 }
270
271 bool ApiTrace::edited() const
272 {
273     return !m_editedCalls.isEmpty();
274 }
275
276 bool ApiTrace::needsSaving() const
277 {
278     return m_needsSaving;
279 }
280
281 void ApiTrace::save()
282 {
283     QFileInfo fi(m_tempFileName);
284     QDir dir;
285     emit startedSaving();
286     dir.mkpath(fi.absolutePath());
287     m_saver->saveFile(m_tempFileName, m_calls);
288 }
289
290 void ApiTrace::slotSaved()
291 {
292     m_needsSaving = false;
293 }
294
295 bool ApiTrace::isSaving() const
296 {
297     return m_saver->isRunning();
298 }
299
300 void ApiTrace::callError(ApiTraceCall *call)
301 {
302     Q_ASSERT(call);
303
304     if (call->hasError())
305         m_errors.insert(call);
306     else
307         m_errors.remove(call);
308
309     emit changed(call);
310 }
311
312 bool ApiTrace::hasErrors() const
313 {
314     return !m_errors.isEmpty();
315 }
316
317 void ApiTrace::loadFrame(ApiTraceFrame *frame)
318 {
319     Q_ASSERT(!frame->loaded());
320     emit requestFrame(frame);
321 }
322
323 void ApiTrace::finishedParsing()
324 {
325     ApiTraceFrame *firstFrame = m_frames[0];
326     if (firstFrame && !firstFrame->loaded()) {
327         loadFrame(firstFrame);
328     }
329 }
330
331 void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
332                                  const QVector<ApiTraceCall*> &calls,
333                                  quint64 binaryDataSize)
334 {
335     Q_ASSERT(frame->numChildrenToLoad() == calls.size());
336     emit beginLoadingFrame(frame, calls.size());
337     frame->setCalls(calls, binaryDataSize);
338     emit endLoadingFrame(frame);
339 }
340
341 void 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                 return;
371             }
372         }
373     }
374     emit findResult(SearchWrapped, 0);
375 }
376
377 void ApiTrace::findPrev(ApiTraceFrame *frame,
378                         ApiTraceCall *from,
379                         const QString &str,
380                         Qt::CaseSensitivity sensitivity)
381 {
382     ApiTraceCall *foundCall = 0;
383     int frameIdx = m_frames.indexOf(frame);
384
385     if (frame->loaded()) {
386         foundCall = frame->findPrevCall(from, str, sensitivity);
387         if (foundCall) {
388             emit findResult(SearchFound, foundCall);
389             return;
390         }
391
392         //if the frame is loaded we already searched it above
393         // so skip it
394         frameIdx -= 1;
395     }
396
397     for (int i = frameIdx; i >= 0; --i) {
398         ApiTraceFrame *frame = m_frames[i];
399         if (!frame->loaded()) {
400             emit loaderSearchPrev(i, str, sensitivity);
401             return;
402         } else {
403             ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
404             if (call) {
405                 emit findResult(SearchFound, call);
406                 return;
407             }
408         }
409     }
410     emit findResult(SearchWrapped, 0);
411 }
412
413 void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
414                                   ApiTraceCall *call)
415 {
416     //qDebug()<<"Search result = "<<result
417     //       <<", call is = "<<call;
418     emit findResult(result, call);
419 }
420
421 #include "apitrace.moc"