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