]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
Merge branch 'glproc-cleanup'
[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(loaderSearch(ApiTrace::SearchRequest)),
29             m_loader, SLOT(search(ApiTrace::SearchRequest)));
30     connect(m_loader,
31             SIGNAL(searchResult(ApiTrace::SearchRequest,ApiTrace::SearchResult,ApiTraceCall*)),
32             this,
33             SLOT(loaderSearchResult(ApiTrace::SearchRequest,ApiTrace::SearchResult,ApiTraceCall*)));
34     connect(this, SIGNAL(loaderFindFrameStart(ApiTraceFrame*)),
35             m_loader, SLOT(findFrameStart(ApiTraceFrame*)));
36     connect(this, SIGNAL(loaderFindFrameEnd(ApiTraceFrame*)),
37             m_loader, SLOT(findFrameEnd(ApiTraceFrame*)));
38     connect(m_loader, SIGNAL(foundFrameStart(ApiTraceFrame*)),
39             this, SIGNAL(foundFrameStart(ApiTraceFrame*)));
40     connect(m_loader, SIGNAL(foundFrameEnd(ApiTraceFrame*)),
41             this, SIGNAL(foundFrameEnd(ApiTraceFrame*)));
42     connect(this, SIGNAL(loaderFindCallIndex(int)),
43             m_loader, SLOT(findCallIndex(int)));
44     connect(m_loader, SIGNAL(foundCallIndex(ApiTraceCall*)),
45             this, SIGNAL(foundCallIndex(ApiTraceCall*)));
46
47
48     connect(m_loader, SIGNAL(startedParsing()),
49             this, SIGNAL(startedLoadingTrace()));
50     connect(m_loader, SIGNAL(parsed(int)),
51             this, SIGNAL(loaded(int)));
52     connect(m_loader, SIGNAL(finishedParsing()),
53             this, SIGNAL(finishedLoadingTrace()));
54
55
56     m_saver = new SaverThread(this);
57     connect(m_saver, SIGNAL(traceSaved()),
58             this, SLOT(slotSaved()));
59     connect(m_saver, SIGNAL(traceSaved()),
60             this, SIGNAL(saved()));
61
62     m_loaderThread = new QThread();
63     m_loader->moveToThread(m_loaderThread);
64     m_loaderThread->start();
65 }
66
67 ApiTrace::~ApiTrace()
68 {
69     m_loaderThread->quit();
70     m_loaderThread->deleteLater();
71     qDeleteAll(m_frames);
72     delete m_loader;
73     delete m_saver;
74 }
75
76 bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
77                                   ApiTrace::FrameMarker marker)
78 {
79     if (!call) {
80         return false;
81     }
82
83     switch (marker) {
84     case FrameMarker_SwapBuffers:
85         return call->flags() & trace::CALL_FLAG_END_FRAME;
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_frames.isEmpty();
102 }
103
104 QString ApiTrace::fileName() const
105 {
106     if (edited()) {
107         return m_tempFileName;
108     }
109
110     return m_fileName;
111 }
112
113 ApiTrace::FrameMarker ApiTrace::frameMarker() const
114 {
115     return m_frameMarker;
116 }
117
118 QList<ApiTraceFrame*> ApiTrace::frames() const
119 {
120     return m_frames;
121 }
122
123 ApiTraceFrame * ApiTrace::frameAt(int idx) const
124 {
125     return m_frames.value(idx);
126 }
127
128 int ApiTrace::numFrames() const
129 {
130     return m_frames.count();
131 }
132
133 int ApiTrace::numCallsInFrame(int idx) const
134 {
135     const ApiTraceFrame *frame = frameAt(idx);
136     if (frame) {
137         return frame->numChildren();
138     } else {
139         return 0;
140     }
141 }
142
143 void ApiTrace::setFileName(const QString &name)
144 {
145     if (m_fileName != name) {
146         m_fileName = name;
147         m_tempFileName = QString();
148
149         m_frames.clear();
150         m_errors.clear();
151         m_editedCalls.clear();
152         m_queuedErrors.clear();
153         m_needsSaving = false;
154         emit invalidated();
155
156         emit loadTrace(m_fileName);
157     }
158 }
159
160 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
161 {
162     int currentFrames = m_frames.count();
163     int numNewFrames = frames.count();
164
165     emit beginAddingFrames(currentFrames, numNewFrames);
166
167     m_frames += frames;
168
169     foreach(ApiTraceFrame *frame, frames) {
170         frame->setParentTrace(this);
171     }
172
173     emit endAddingFrames();
174 }
175
176 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
177 {
178     for (int i = 0; i < m_frames.count(); ++i) {
179         ApiTraceCall *call = m_frames[i]->callWithIndex(idx);
180         if (call) {
181             return call;
182         }
183     }
184     return NULL;
185 }
186
187 ApiTraceState ApiTrace::defaultState() const
188 {
189     ApiTraceFrame *frame = frameAt(0);
190     if (!frame || !frame->isLoaded() || frame->isEmpty()) {
191         return ApiTraceState();
192     }
193
194     ApiTraceCall *firstCall = frame->calls().first();
195     if (!firstCall->hasState()) {
196         return ApiTraceState();
197     }
198
199     return *firstCall->state();
200 }
201
202 void ApiTrace::callEdited(ApiTraceCall *call)
203 {
204     if (!m_editedCalls.contains(call)) {
205         //lets generate a temp filename
206         QString tempPath = QDir::tempPath();
207         m_tempFileName = QString::fromLatin1("%1/%2.edited")
208                          .arg(tempPath)
209                          .arg(m_fileName);
210     }
211     m_editedCalls.insert(call);
212     m_needsSaving = true;
213
214     emit changed(call);
215 }
216
217 void ApiTrace::callReverted(ApiTraceCall *call)
218 {
219     m_editedCalls.remove(call);
220
221     if (m_editedCalls.isEmpty()) {
222         m_needsSaving = false;
223     }
224     emit changed(call);
225 }
226
227 bool ApiTrace::edited() const
228 {
229     return !m_editedCalls.isEmpty();
230 }
231
232 bool ApiTrace::needsSaving() const
233 {
234     return m_needsSaving;
235 }
236
237 void ApiTrace::save()
238 {
239     QFileInfo fi(m_tempFileName);
240     QDir dir;
241     emit startedSaving();
242     dir.mkpath(fi.absolutePath());
243     m_saver->saveFile(m_tempFileName,
244                       m_fileName,
245                       m_editedCalls);
246 }
247
248 void ApiTrace::slotSaved()
249 {
250     m_needsSaving = false;
251 }
252
253 bool ApiTrace::isSaving() const
254 {
255     return m_saver->isRunning();
256 }
257
258 bool ApiTrace::hasErrors() const
259 {
260     return !m_errors.isEmpty();
261 }
262
263 void ApiTrace::loadFrame(ApiTraceFrame *frame)
264 {
265     if (!isFrameLoading(frame)) {
266         Q_ASSERT(!frame->isLoaded());
267         m_loadingFrames.insert(frame);
268         emit requestFrame(frame);
269     }
270 }
271
272 void ApiTrace::finishedParsing()
273 {
274     ApiTraceFrame *firstFrame = m_frames[0];
275     if (firstFrame && !firstFrame->isLoaded()) {
276         loadFrame(firstFrame);
277     }
278 }
279
280 void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
281                                  const QVector<ApiTraceCall*> &calls,
282                                  quint64 binaryDataSize)
283 {
284     Q_ASSERT(frame->numChildrenToLoad() == calls.size());
285
286     if (!frame->isLoaded()) {
287         emit beginLoadingFrame(frame, calls.size());
288         frame->setCalls(calls, binaryDataSize);
289         emit endLoadingFrame(frame);
290         m_loadingFrames.remove(frame);
291     }
292
293     if (!m_queuedErrors.isEmpty()) {
294         QList< QPair<ApiTraceFrame*, ApiTraceError> >::iterator itr;
295         for (itr = m_queuedErrors.begin(); itr != m_queuedErrors.end();
296              ++itr) {
297             const ApiTraceError &error = (*itr).second;
298             if ((*itr).first == frame) {
299                 ApiTraceCall *call = frame->callWithIndex(error.callIndex);
300
301                 if (!call) {
302                     continue;
303                 }
304
305                 call->setError(error.message);
306                 m_queuedErrors.erase(itr);
307
308                 if (call->hasError()) {
309                     m_errors.insert(call);
310                 } else {
311                     m_errors.remove(call);
312                 }
313                 emit changed(call);
314             }
315         }
316     }
317 }
318
319 void ApiTrace::findNext(ApiTraceFrame *frame,
320                         ApiTraceCall *from,
321                         const QString &str,
322                         Qt::CaseSensitivity sensitivity)
323 {
324     ApiTraceCall *foundCall = 0;
325     int frameIdx = m_frames.indexOf(frame);
326     SearchRequest request(SearchRequest::Next,
327                           frame, from, str, sensitivity);
328
329     if (frame->isLoaded()) {
330         foundCall = frame->findNextCall(from, str, sensitivity);
331         if (foundCall) {
332             emit findResult(request, SearchResult_Found, foundCall);
333             return;
334         }
335
336         //if the frame is loaded we already searched it above
337         // so skip it
338         frameIdx += 1;
339     }
340
341     //for the rest of the frames we search from beginning
342     request.from = 0;
343     for (int i = frameIdx; i < m_frames.count(); ++i) {
344         ApiTraceFrame *frame = m_frames[i];
345         request.frame = frame;
346         if (!frame->isLoaded()) {
347             emit loaderSearch(request);
348             return;
349         } else {
350             ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
351             if (call) {
352                 emit findResult(request, SearchResult_Found, call);
353                 return;
354             }
355         }
356     }
357     emit findResult(request, SearchResult_Wrapped, 0);
358 }
359
360 void ApiTrace::findPrev(ApiTraceFrame *frame,
361                         ApiTraceCall *from,
362                         const QString &str,
363                         Qt::CaseSensitivity sensitivity)
364 {
365     ApiTraceCall *foundCall = 0;
366     int frameIdx = m_frames.indexOf(frame);
367     SearchRequest request(SearchRequest::Prev,
368                           frame, from, str, sensitivity);
369
370     if (frame->isLoaded()) {
371         foundCall = frame->findPrevCall(from, str, sensitivity);
372         if (foundCall) {
373             emit findResult(request, SearchResult_Found, foundCall);
374             return;
375         }
376
377         //if the frame is loaded we already searched it above
378         // so skip it
379         frameIdx -= 1;
380     }
381
382     request.from = 0;
383     for (int i = frameIdx; i >= 0; --i) {
384         ApiTraceFrame *frame = m_frames[i];
385         request.frame = frame;
386         if (!frame->isLoaded()) {
387             emit loaderSearch(request);
388             return;
389         } else {
390             ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
391             if (call) {
392                 emit findResult(request, SearchResult_Found, call);
393                 return;
394             }
395         }
396     }
397     emit findResult(request, SearchResult_Wrapped, 0);
398 }
399
400 void ApiTrace::loaderSearchResult(const ApiTrace::SearchRequest &request,
401                                   ApiTrace::SearchResult result,
402                                   ApiTraceCall *call)
403 {
404     //qDebug()<<"Search result = "<<result
405     //       <<", call is = "<<call;
406     emit findResult(request, result, call);
407 }
408
409 void ApiTrace::findFrameStart(ApiTraceFrame *frame)
410 {
411     if (frame->isLoaded()) {
412         emit foundFrameStart(frame);
413     } else {
414         emit loaderFindFrameStart(frame);
415     }
416 }
417
418 void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
419 {
420     if (frame->isLoaded()) {
421         emit foundFrameEnd(frame);
422     } else {
423         emit loaderFindFrameEnd(frame);
424     }
425 }
426
427 void ApiTrace::findCallIndex(int index)
428 {
429     int frameIdx = callInFrame(index);
430     ApiTraceFrame *frame = 0;
431
432     if (frameIdx < 0) {
433         emit foundCallIndex(0);
434         return;
435     }
436
437     frame = m_frames[frameIdx];
438
439     if (frame) {
440         if (frame->isLoaded()) {
441             ApiTraceCall *call = frame->callWithIndex(index);
442             emit foundCallIndex(call);
443         } else {
444             emit loaderFindCallIndex(index);
445         }
446     }
447 }
448
449 int ApiTrace::callInFrame(int callIdx) const
450 {
451     unsigned numCalls = 0;
452
453     for (int frameIdx = 0; frameIdx <= m_frames.size(); ++frameIdx) {
454         const ApiTraceFrame *frame = m_frames[frameIdx];
455         unsigned numCallsInFrame =  frame->isLoaded()
456                 ? frame->numChildren()
457                 : frame->numChildrenToLoad();
458         unsigned firstCall = numCalls;
459         unsigned endCall = numCalls + numCallsInFrame;
460         if (firstCall <= callIdx && endCall > callIdx) {
461             return frameIdx;
462         }
463         numCalls = endCall;
464     }
465
466     return -1;
467 }
468
469 void ApiTrace::setCallError(const ApiTraceError &error)
470 {
471     int frameIdx = callInFrame(error.callIndex);
472     ApiTraceFrame *frame = 0;
473
474     if (frameIdx < 0) {
475         return;
476     }
477     frame = m_frames[frameIdx];
478
479     if (frame->isLoaded()) {
480         ApiTraceCall *call = frame->callWithIndex(error.callIndex);
481         call->setError(error.message);
482         if (call->hasError()) {
483             m_errors.insert(call);
484         } else {
485             m_errors.remove(call);
486         }
487         emit changed(call);
488     } else {
489         loadFrame(frame);
490         m_queuedErrors.append(qMakePair(frame, error));
491     }
492 }
493
494 bool ApiTrace::isFrameLoading(ApiTraceFrame *frame) const
495 {
496     return m_loadingFrames.contains(frame);
497 }
498
499 #include "apitrace.moc"