]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
Delete loadertest and cleanup some of the new api.
[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_frames);
74     delete m_loader;
75     delete m_saver;
76 }
77
78 bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
79                                   ApiTrace::FrameMarker marker)
80 {
81     if (!call)
82         return false;
83
84     switch (marker) {
85     case FrameMarker_SwapBuffers:
86         return call->name().contains(QLatin1String("SwapBuffers")) ||
87                call->name() == QLatin1String("CGLFlushDrawable") ||
88                call->name() == QLatin1String("glFrameTerminatorGREMEDY");
89     case FrameMarker_Flush:
90         return call->name() == QLatin1String("glFlush");
91     case FrameMarker_Finish:
92         return call->name() == QLatin1String("glFinish");
93     case FrameMarker_Clear:
94         return call->name() == QLatin1String("glClear");
95     }
96
97     Q_ASSERT(!"unknown frame marker");
98
99     return false;
100 }
101
102 bool ApiTrace::isEmpty() const
103 {
104     return m_frames.isEmpty();
105 }
106
107 QString ApiTrace::fileName() const
108 {
109     if (edited())
110         return m_tempFileName;
111
112     return m_fileName;
113 }
114
115 ApiTrace::FrameMarker ApiTrace::frameMarker() const
116 {
117     return m_frameMarker;
118 }
119
120 QList<ApiTraceFrame*> ApiTrace::frames() const
121 {
122     return m_frames;
123 }
124
125 ApiTraceFrame * ApiTrace::frameAt(int idx) const
126 {
127     return m_frames.value(idx);
128 }
129
130 int ApiTrace::numFrames() const
131 {
132     return m_frames.count();
133 }
134
135 int ApiTrace::numCallsInFrame(int idx) const
136 {
137     const ApiTraceFrame *frame = frameAt(idx);
138     if (frame)
139         return frame->numChildren();
140     else
141         return 0;
142 }
143
144 void ApiTrace::setFileName(const QString &name)
145 {
146     if (m_fileName != name) {
147         m_fileName = name;
148
149         m_frames.clear();
150         m_errors.clear();
151         m_editedCalls.clear();
152         m_needsSaving = false;
153         emit invalidated();
154
155         emit loadTrace(m_fileName);
156     }
157 }
158
159 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
160 {
161     QVector<ApiTraceCall*> calls;
162     int currentFrames = m_frames.count();
163     int numNewFrames = frames.count();
164
165     emit beginAddingFrames(currentFrames, numNewFrames);
166
167     m_frames += frames;
168
169     int numNewCalls = 0;
170     foreach(ApiTraceFrame *frame, frames) {
171         frame->setParentTrace(this);
172         numNewCalls += frame->numChildren();
173         calls += frame->calls();
174     }
175
176     emit endAddingFrames();
177 }
178
179 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
180 {
181     for (int i = 0; i < m_frames.count(); ++i) {
182         ApiTraceCall *call = m_frames[i]->callWithIndex(idx);
183         if (call)
184             return call;
185     }
186     return NULL;
187 }
188
189 ApiTraceState ApiTrace::defaultState() const
190 {
191     ApiTraceFrame *frame = frameAt(0);
192     if (!frame || !frame->isLoaded() || frame->isEmpty())
193         return ApiTraceState();
194
195     ApiTraceCall *firstCall = frame->calls().first();
196     if (!firstCall->hasState()) {
197         return ApiTraceState();
198     }
199
200     return *firstCall->state();
201 }
202
203 void ApiTrace::callEdited(ApiTraceCall *call)
204 {
205     if (!m_editedCalls.contains(call)) {
206         //lets generate a temp filename
207         QString tempPath = QDir::tempPath();
208         m_tempFileName = QString::fromLatin1("%1/%2.edited")
209                          .arg(tempPath)
210                          .arg(m_fileName);
211     }
212     m_editedCalls.insert(call);
213     m_needsSaving = true;
214
215     emit changed(call);
216 }
217
218 void ApiTrace::callReverted(ApiTraceCall *call)
219 {
220     m_editedCalls.remove(call);
221
222     if (m_editedCalls.isEmpty()) {
223         m_needsSaving = false;
224     }
225     emit changed(call);
226 }
227
228 bool ApiTrace::edited() const
229 {
230     return !m_editedCalls.isEmpty();
231 }
232
233 bool ApiTrace::needsSaving() const
234 {
235     return m_needsSaving;
236 }
237
238 void ApiTrace::save()
239 {
240     QFileInfo fi(m_tempFileName);
241     QDir dir;
242     emit startedSaving();
243     dir.mkpath(fi.absolutePath());
244     m_saver->saveFile(m_tempFileName,
245                       m_fileName,
246                       m_editedCalls);
247 }
248
249 void ApiTrace::slotSaved()
250 {
251     m_needsSaving = false;
252 }
253
254 bool ApiTrace::isSaving() const
255 {
256     return m_saver->isRunning();
257 }
258
259 bool ApiTrace::hasErrors() const
260 {
261     return !m_errors.isEmpty();
262 }
263
264 void ApiTrace::loadFrame(ApiTraceFrame *frame)
265 {
266     Q_ASSERT(!frame->isLoaded());
267     emit requestFrame(frame);
268 }
269
270 void ApiTrace::finishedParsing()
271 {
272     ApiTraceFrame *firstFrame = m_frames[0];
273     if (firstFrame && !firstFrame->isLoaded()) {
274         loadFrame(firstFrame);
275     }
276 }
277
278 void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
279                                  const QVector<ApiTraceCall*> &calls,
280                                  quint64 binaryDataSize)
281 {
282     Q_ASSERT(frame->numChildrenToLoad() == calls.size());
283     emit beginLoadingFrame(frame, calls.size());
284     frame->setCalls(calls, binaryDataSize);
285     emit endLoadingFrame(frame);
286
287     if (!m_queuedErrors.isEmpty()) {
288         QList< QPair<ApiTraceFrame*, ApiTraceError> >::iterator itr;
289         for (itr = m_queuedErrors.begin(); itr != m_queuedErrors.end();
290              ++itr) {
291             const ApiTraceError &error = (*itr).second;
292             if ((*itr).first == frame) {
293                 ApiTraceCall *call = frame->callWithIndex(error.callIndex);
294
295                 if (!call) {
296                     continue;
297                 }
298
299                 call->setError(error.message);
300                 m_queuedErrors.erase(itr);
301
302                 if (call->hasError()) {
303                     m_errors.insert(call);
304                 } else {
305                     m_errors.remove(call);
306                 }
307                 emit changed(call);
308             }
309         }
310     }
311 }
312
313 void ApiTrace::findNext(ApiTraceFrame *frame,
314                         ApiTraceCall *from,
315                         const QString &str,
316                         Qt::CaseSensitivity sensitivity)
317 {
318     ApiTraceCall *foundCall = 0;
319     int frameIdx = m_frames.indexOf(frame);
320
321     if (frame->isLoaded()) {
322         foundCall = frame->findNextCall(from, str, sensitivity);
323         if (foundCall) {
324             emit findResult(SearchResult_Found, foundCall);
325             return;
326         }
327
328         //if the frame is loaded we already searched it above
329         // so skip it
330         frameIdx += 1;
331     }
332
333     for (int i = frameIdx; i < m_frames.count(); ++i) {
334         ApiTraceFrame *frame = m_frames[i];
335         if (!frame->isLoaded()) {
336             emit loaderSearchNext(i, str, sensitivity);
337             return;
338         } else {
339             ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
340             if (call) {
341                 emit findResult(SearchResult_Found, call);
342                 return;
343             }
344         }
345     }
346     emit findResult(SearchResult_Wrapped, 0);
347 }
348
349 void ApiTrace::findPrev(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->isLoaded()) {
358         foundCall = frame->findPrevCall(from, str, sensitivity);
359         if (foundCall) {
360             emit findResult(SearchResult_Found, 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 >= 0; --i) {
370         ApiTraceFrame *frame = m_frames[i];
371         if (!frame->isLoaded()) {
372             emit loaderSearchPrev(i, str, sensitivity);
373             return;
374         } else {
375             ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
376             if (call) {
377                 emit findResult(SearchResult_Found, call);
378                 return;
379             }
380         }
381     }
382     emit findResult(SearchResult_Wrapped, 0);
383 }
384
385 void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
386                                   ApiTraceCall *call)
387 {
388     //qDebug()<<"Search result = "<<result
389     //       <<", call is = "<<call;
390     emit findResult(result, call);
391 }
392
393 void ApiTrace::findFrameStart(ApiTraceFrame *frame)
394 {
395     if (frame->isLoaded()) {
396         emit foundFrameStart(frame);
397     } else {
398         emit loaderFindFrameStart(frame);
399     }
400 }
401
402 void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
403 {
404     if (frame->isLoaded()) {
405         emit foundFrameEnd(frame);
406     } else {
407         emit loaderFindFrameEnd(frame);
408     }
409 }
410
411 void ApiTrace::findCallIndex(int index)
412 {
413     int frameIdx = callInFrame(index);
414     ApiTraceFrame *frame = 0;
415
416     if (frameIdx < 0) {
417         emit foundCallIndex(0);
418         return;
419     }
420
421     frame = m_frames[frameIdx];
422
423     if (frame) {
424         if (frame->isLoaded()) {
425             ApiTraceCall *call = frame->callWithIndex(index);
426             emit foundCallIndex(call);
427         } else {
428             emit loaderFindCallIndex(index);
429         }
430     }
431 }
432
433 int ApiTrace::callInFrame(int callIdx) const
434 {
435     unsigned numCalls = 0;
436
437     for (int frameIdx = 0; frameIdx <= m_frames.size(); ++frameIdx) {
438         const ApiTraceFrame *frame = m_frames[frameIdx];
439         unsigned numCallsInFrame =  frame->isLoaded()
440                 ? frame->numChildren()
441                 : frame->numChildrenToLoad();
442         unsigned firstCall = numCalls;
443         unsigned endCall = numCalls + numCallsInFrame;
444         if (firstCall <= callIdx && endCall > callIdx) {
445             return frameIdx;
446         }
447         numCalls = endCall;
448     }
449
450     return -1;
451 }
452
453 void ApiTrace::setCallError(const ApiTraceError &error)
454 {
455     int frameIdx = callInFrame(error.callIndex);
456     ApiTraceFrame *frame = 0;
457
458     if (frameIdx < 0) {
459         return;
460     }
461     frame = m_frames[frameIdx];
462
463     if (frame->isLoaded()) {
464         ApiTraceCall *call = frame->callWithIndex(error.callIndex);
465         call->setError(error.message);
466         if (call->hasError()) {
467             m_errors.insert(call);
468         } else {
469             m_errors.remove(call);
470         }
471         emit changed(call);
472     } else {
473         emit requestFrame(frame);
474         m_queuedErrors.append(qMakePair(frame, error));
475     }
476 }
477
478 #include "apitrace.moc"