]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
Merge remote-tracking branch 'origin/master' into on-demand-loading
[apitrace] / gui / apitrace.cpp
1 #include "apitrace.h"
2
3 #include "loaderthread.h"
4 #include "saverthread.h"
5
6 #include <QDir>
7
8 ApiTrace::ApiTrace()
9     : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
10       m_needsSaving(false)
11 {
12     m_loader = new LoaderThread(this);
13     connect(m_loader, SIGNAL(parsedFrames(const QList<ApiTraceFrame*>)),
14             this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
15     connect(m_loader, SIGNAL(started()),
16             this, SIGNAL(startedLoadingTrace()));
17     connect(m_loader, SIGNAL(finished()),
18             this, SIGNAL(finishedLoadingTrace()));
19
20     m_saver = new SaverThread(this);
21     connect(m_saver, SIGNAL(traceSaved()),
22             this, SLOT(slotSaved()));
23     connect(m_saver, SIGNAL(traceSaved()),
24             this, SIGNAL(saved()));
25 }
26
27 ApiTrace::~ApiTrace()
28 {
29     qDeleteAll(m_calls);
30     qDeleteAll(m_frames);
31     delete m_loader;
32     delete m_saver;
33 }
34
35 bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
36                                   ApiTrace::FrameMarker marker)
37 {
38     if (!call)
39         return false;
40
41     switch (marker) {
42     case FrameMarker_SwapBuffers:
43         return call->name().contains(QLatin1String("SwapBuffers")) ||
44                call->name() == QLatin1String("CGLFlushDrawable") ||
45                call->name() == QLatin1String("glFrameTerminatorGREMEDY");
46     case FrameMarker_Flush:
47         return call->name() == QLatin1String("glFlush");
48     case FrameMarker_Finish:
49         return call->name() == QLatin1String("glFinish");
50     case FrameMarker_Clear:
51         return call->name() == QLatin1String("glClear");
52     }
53
54     Q_ASSERT(!"unknown frame marker");
55
56     return false;
57 }
58
59 bool ApiTrace::isEmpty() const
60 {
61     return m_calls.isEmpty();
62 }
63
64 QString ApiTrace::fileName() const
65 {
66     if (edited())
67         return m_tempFileName;
68
69     return m_fileName;
70 }
71
72 ApiTrace::FrameMarker ApiTrace::frameMarker() const
73 {
74     return m_frameMarker;
75 }
76
77 QVector<ApiTraceCall*> ApiTrace::calls() const
78 {
79     return m_calls;
80 }
81
82 ApiTraceCall * ApiTrace::callAt(int idx) const
83 {
84     return m_calls.value(idx);
85 }
86
87 int ApiTrace::numCalls() const
88 {
89     return m_calls.count();
90 }
91
92 QList<ApiTraceFrame*> ApiTrace::frames() const
93 {
94     return m_frames;
95 }
96
97 ApiTraceFrame * ApiTrace::frameAt(int idx) const
98 {
99     return m_frames.value(idx);
100 }
101
102 int ApiTrace::numFrames() const
103 {
104     return m_frames.count();
105 }
106
107 int ApiTrace::numCallsInFrame(int idx) const
108 {
109     const ApiTraceFrame *frame = frameAt(idx);
110     if (frame)
111         return frame->numChildren();
112     else
113         return 0;
114 }
115
116 void ApiTrace::setFileName(const QString &name)
117 {
118     if (m_fileName != name) {
119         m_fileName = name;
120
121         if (m_loader->isRunning()) {
122             m_loader->terminate();
123             m_loader->wait();
124         }
125         m_frames.clear();
126         m_calls.clear();
127         m_errors.clear();
128         m_editedCalls.clear();
129         m_needsSaving = false;
130         emit invalidated();
131
132         m_loader->loadFile(m_fileName);
133     }
134 }
135
136 void ApiTrace::setFrameMarker(FrameMarker marker)
137 {
138     if (m_frameMarker != marker) {
139         emit framesInvalidated();
140
141         qDeleteAll(m_frames);
142         m_frames.clear();
143         detectFrames();
144     }
145 }
146
147 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
148 {
149     QVector<ApiTraceCall*> calls;
150     int currentFrames = m_frames.count();
151     int numNewFrames = frames.count();
152
153     emit beginAddingFrames(currentFrames, numNewFrames);
154
155     m_frames += frames;
156
157     int currentCalls = m_calls.count();
158     int numNewCalls = 0;
159     foreach(ApiTraceFrame *frame, frames) {
160         Q_ASSERT(this == frame->parentTrace());
161         numNewCalls += frame->numChildren();
162         calls += frame->calls();
163     }
164     m_calls.reserve(m_calls.count() + calls.count() + 1);
165     m_calls += calls;
166
167     emit endAddingFrames();
168     emit callsAdded(currentCalls, numNewCalls);
169 }
170
171 void ApiTrace::detectFrames()
172 {
173     if (m_calls.isEmpty())
174         return;
175
176     emit beginAddingFrames(0, m_frames.count());
177
178     ApiTraceFrame *currentFrame = 0;
179     foreach(ApiTraceCall *apiCall, m_calls) {
180         if (!currentFrame) {
181             currentFrame = new ApiTraceFrame(this);
182             currentFrame->number = m_frames.count();
183         }
184         apiCall->setParentFrame(currentFrame);
185         currentFrame->addCall(apiCall);
186         if (ApiTrace::isCallAFrameMarker(apiCall,
187                                          m_frameMarker)) {
188             m_frames.append(currentFrame);
189             currentFrame = 0;
190         }
191     }
192     //last frames won't have markers
193     //  it's just a bunch of Delete calls for every object
194     //  after the last SwapBuffers
195     if (currentFrame) {
196         m_frames.append(currentFrame);
197         currentFrame = 0;
198     }
199     emit endAddingFrames();
200 }
201
202 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
203 {
204     for (int i = 0; i < m_calls.count(); ++i) {
205         ApiTraceCall *call = m_calls[i];
206         if (call->index() == idx)
207             return call;
208     }
209     return NULL;
210 }
211
212 ApiTraceState ApiTrace::defaultState() const
213 {
214     ApiTraceFrame *frame = frameAt(0);
215     if (!frame || !frame->hasState())
216         return ApiTraceState();
217
218     return *frame->state();
219 }
220
221 void ApiTrace::callEdited(ApiTraceCall *call)
222 {
223     if (!m_editedCalls.contains(call)) {
224         //lets generate a temp filename
225         QString tempPath = QDir::tempPath();
226         m_tempFileName = QString::fromLatin1("%1/%2.edited")
227                          .arg(tempPath)
228                          .arg(m_fileName);
229     }
230     m_editedCalls.insert(call);
231     m_needsSaving = true;
232
233     emit changed(call);
234 }
235
236 void ApiTrace::callReverted(ApiTraceCall *call)
237 {
238     m_editedCalls.remove(call);
239
240     if (m_editedCalls.isEmpty()) {
241         m_needsSaving = false;
242     }
243     emit changed(call);
244 }
245
246 bool ApiTrace::edited() const
247 {
248     return !m_editedCalls.isEmpty();
249 }
250
251 bool ApiTrace::needsSaving() const
252 {
253     return m_needsSaving;
254 }
255
256 void ApiTrace::save()
257 {
258     QFileInfo fi(m_tempFileName);
259     QDir dir;
260     emit startedSaving();
261     dir.mkpath(fi.absolutePath());
262     m_saver->saveFile(m_tempFileName, m_calls);
263 }
264
265 void ApiTrace::slotSaved()
266 {
267     m_needsSaving = false;
268 }
269
270 bool ApiTrace::isSaving() const
271 {
272     return m_saver->isRunning();
273 }
274
275 void ApiTrace::callError(ApiTraceCall *call)
276 {
277     Q_ASSERT(call);
278
279     if (call->hasError())
280         m_errors.insert(call);
281     else
282         m_errors.remove(call);
283
284     emit changed(call);
285 }
286
287 bool ApiTrace::hasErrors() const
288 {
289     return !m_errors.isEmpty();
290 }
291
292 ApiTraceCallSignature * ApiTrace::signature(unsigned id)
293 {
294     if (id >= m_signatures.count()) {
295         m_signatures.resize(id + 1);
296         return NULL;
297     } else {
298         return m_signatures[id];
299     }
300 }
301
302 void ApiTrace::addSignature(unsigned id, ApiTraceCallSignature *signature)
303 {
304     m_signatures[id] = signature;
305 }
306
307 ApiTraceEnumSignature * ApiTrace::enumSignature(unsigned id)
308 {
309     if (id >= m_enumSignatures.count()) {
310         m_enumSignatures.resize(id + 1);
311         return NULL;
312     } else {
313         return m_enumSignatures[id];
314     }
315 }
316
317 void ApiTrace::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
318 {
319     m_enumSignatures[id] = signature;
320 }
321
322 #include "apitrace.moc"