]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
c8cb0860bc87ce710da0be504cae706b9ae7538b
[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
45
46     connect(m_loader, SIGNAL(startedParsing()),
47             this, SIGNAL(startedLoadingTrace()));
48     connect(m_loader, SIGNAL(parsed(int)),
49             this, SIGNAL(loaded(int)));
50     connect(m_loader, SIGNAL(finishedParsing()),
51             this, SIGNAL(finishedLoadingTrace()));
52
53
54     m_saver = new SaverThread(this);
55     connect(m_saver, SIGNAL(traceSaved()),
56             this, SLOT(slotSaved()));
57     connect(m_saver, SIGNAL(traceSaved()),
58             this, SIGNAL(saved()));
59
60     m_loaderThread = new QThread();
61     m_loader->moveToThread(m_loaderThread);
62     m_loaderThread->start();
63 }
64
65 ApiTrace::~ApiTrace()
66 {
67     m_loaderThread->quit();
68     m_loaderThread->deleteLater();
69     qDeleteAll(m_calls);
70     qDeleteAll(m_frames);
71     delete m_loader;
72     delete m_saver;
73 }
74
75 bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
76                                   ApiTrace::FrameMarker marker)
77 {
78     if (!call)
79         return false;
80
81     switch (marker) {
82     case FrameMarker_SwapBuffers:
83         return call->name().contains(QLatin1String("SwapBuffers")) ||
84                call->name() == QLatin1String("CGLFlushDrawable") ||
85                call->name() == QLatin1String("glFrameTerminatorGREMEDY");
86     case FrameMarker_Flush:
87         return call->name() == QLatin1String("glFlush");
88     case FrameMarker_Finish:
89         return call->name() == QLatin1String("glFinish");
90     case FrameMarker_Clear:
91         return call->name() == QLatin1String("glClear");
92     }
93
94     Q_ASSERT(!"unknown frame marker");
95
96     return false;
97 }
98
99 bool ApiTrace::isEmpty() const
100 {
101     return m_calls.isEmpty();
102 }
103
104 QString ApiTrace::fileName() const
105 {
106     if (edited())
107         return m_tempFileName;
108
109     return m_fileName;
110 }
111
112 ApiTrace::FrameMarker ApiTrace::frameMarker() const
113 {
114     return m_frameMarker;
115 }
116
117 QVector<ApiTraceCall*> ApiTrace::calls() const
118 {
119     return m_calls;
120 }
121
122 int ApiTrace::numCalls() const
123 {
124     return m_calls.count();
125 }
126
127 QList<ApiTraceFrame*> ApiTrace::frames() const
128 {
129     return m_frames;
130 }
131
132 ApiTraceFrame * ApiTrace::frameAt(int idx) const
133 {
134     return m_frames.value(idx);
135 }
136
137 int ApiTrace::numFrames() const
138 {
139     return m_frames.count();
140 }
141
142 int ApiTrace::numCallsInFrame(int idx) const
143 {
144     const ApiTraceFrame *frame = frameAt(idx);
145     if (frame)
146         return frame->numChildren();
147     else
148         return 0;
149 }
150
151 void ApiTrace::setFileName(const QString &name)
152 {
153     if (m_fileName != name) {
154         m_fileName = name;
155
156         m_frames.clear();
157         m_calls.clear();
158         m_errors.clear();
159         m_editedCalls.clear();
160         m_needsSaving = false;
161         emit invalidated();
162
163 //        m_loader->loadTrace(m_fileName);
164         emit loadTrace(m_fileName);
165     }
166 }
167
168 void 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
179 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
180 {
181     QVector<ApiTraceCall*> calls;
182     int currentFrames = m_frames.count();
183     int numNewFrames = frames.count();
184
185     emit beginAddingFrames(currentFrames, numNewFrames);
186
187     m_frames += frames;
188
189     int currentCalls = m_calls.count();
190     int numNewCalls = 0;
191     foreach(ApiTraceFrame *frame, frames) {
192         frame->setParentTrace(this);
193         numNewCalls += frame->numChildren();
194         calls += frame->calls();
195     }
196     m_calls.reserve(m_calls.count() + calls.count() + 1);
197     m_calls += calls;
198
199     emit endAddingFrames();
200     emit callsAdded(currentCalls, numNewCalls);
201 }
202
203 void ApiTrace::detectFrames()
204 {
205     if (m_calls.isEmpty())
206         return;
207
208     emit beginAddingFrames(0, m_frames.count());
209
210     ApiTraceFrame *currentFrame = 0;
211     foreach(ApiTraceCall *apiCall, m_calls) {
212         if (!currentFrame) {
213             currentFrame = new ApiTraceFrame(this);
214             currentFrame->number = m_frames.count();
215             currentFrame->setLoaded(true);
216         }
217         apiCall->setParentFrame(currentFrame);
218         currentFrame->addCall(apiCall);
219         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     }
232     emit endAddingFrames();
233 }
234
235 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
236 {
237     for (int i = 0; i < m_calls.count(); ++i) {
238         ApiTraceCall *call = m_calls[i];
239         if (call->index() == idx)
240             return call;
241     }
242     return NULL;
243 }
244
245 ApiTraceState ApiTrace::defaultState() const
246 {
247     ApiTraceFrame *frame = frameAt(0);
248     if (!frame || !frame->hasState())
249         return ApiTraceState();
250
251     return *frame->state();
252 }
253
254 void ApiTrace::callEdited(ApiTraceCall *call)
255 {
256     if (!m_editedCalls.contains(call)) {
257         //lets generate a temp filename
258         QString tempPath = QDir::tempPath();
259         m_tempFileName = QString::fromLatin1("%1/%2.edited")
260                          .arg(tempPath)
261                          .arg(m_fileName);
262     }
263     m_editedCalls.insert(call);
264     m_needsSaving = true;
265
266     emit changed(call);
267 }
268
269 void ApiTrace::callReverted(ApiTraceCall *call)
270 {
271     m_editedCalls.remove(call);
272
273     if (m_editedCalls.isEmpty()) {
274         m_needsSaving = false;
275     }
276     emit changed(call);
277 }
278
279 bool ApiTrace::edited() const
280 {
281     return !m_editedCalls.isEmpty();
282 }
283
284 bool ApiTrace::needsSaving() const
285 {
286     return m_needsSaving;
287 }
288
289 void ApiTrace::save()
290 {
291     QFileInfo fi(m_tempFileName);
292     QDir dir;
293     emit startedSaving();
294     dir.mkpath(fi.absolutePath());
295     m_saver->saveFile(m_tempFileName, m_calls);
296 }
297
298 void ApiTrace::slotSaved()
299 {
300     m_needsSaving = false;
301 }
302
303 bool ApiTrace::isSaving() const
304 {
305     return m_saver->isRunning();
306 }
307
308 void ApiTrace::callError(ApiTraceCall *call)
309 {
310     Q_ASSERT(call);
311
312     if (call->hasError())
313         m_errors.insert(call);
314     else
315         m_errors.remove(call);
316
317     emit changed(call);
318 }
319
320 bool ApiTrace::hasErrors() const
321 {
322     return !m_errors.isEmpty();
323 }
324
325 void ApiTrace::loadFrame(ApiTraceFrame *frame)
326 {
327     Q_ASSERT(!frame->loaded());
328     emit requestFrame(frame);
329 }
330
331 void ApiTrace::finishedParsing()
332 {
333     ApiTraceFrame *firstFrame = m_frames[0];
334     if (firstFrame && !firstFrame->loaded()) {
335         loadFrame(firstFrame);
336     }
337 }
338
339 void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
340                                  const QVector<ApiTraceCall*> &calls,
341                                  quint64 binaryDataSize)
342 {
343     Q_ASSERT(frame->numChildrenToLoad() == calls.size());
344     emit beginLoadingFrame(frame, calls.size());
345     frame->setCalls(calls, binaryDataSize);
346     emit endLoadingFrame(frame);
347 }
348
349 void 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);
378                 return;
379             }
380         }
381     }
382     emit findResult(SearchWrapped, 0);
383 }
384
385 void 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
405     for (int i = frameIdx; i >= 0; --i) {
406         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);
414                 return;
415             }
416         }
417     }
418     emit findResult(SearchWrapped, 0);
419 }
420
421 void 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
429 void ApiTrace::findFrameStart(ApiTraceFrame *frame)
430 {
431     if (frame->loaded()) {
432         emit foundFrameStart(frame);
433     } else {
434         emit loaderFindFrameStart(frame);
435     }
436 }
437
438 void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
439 {
440     if (frame->loaded()) {
441         emit foundFrameEnd(frame);
442     } else {
443         emit loaderFindFrameEnd(frame);
444     }
445 }
446
447 #include "apitrace.moc"