]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
Implement an incremental on demand loader for the gui.
[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             currentFrame->setLoaded(true);
184         }
185         apiCall->setParentFrame(currentFrame);
186         currentFrame->addCall(apiCall);
187         if (ApiTrace::isCallAFrameMarker(apiCall,
188                                          m_frameMarker)) {
189             m_frames.append(currentFrame);
190             currentFrame = 0;
191         }
192     }
193     //last frames won't have markers
194     //  it's just a bunch of Delete calls for every object
195     //  after the last SwapBuffers
196     if (currentFrame) {
197         m_frames.append(currentFrame);
198         currentFrame = 0;
199     }
200     emit endAddingFrames();
201 }
202
203 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
204 {
205     for (int i = 0; i < m_calls.count(); ++i) {
206         ApiTraceCall *call = m_calls[i];
207         if (call->index() == idx)
208             return call;
209     }
210     return NULL;
211 }
212
213 ApiTraceState ApiTrace::defaultState() const
214 {
215     ApiTraceFrame *frame = frameAt(0);
216     if (!frame || !frame->hasState())
217         return ApiTraceState();
218
219     return *frame->state();
220 }
221
222 void ApiTrace::callEdited(ApiTraceCall *call)
223 {
224     if (!m_editedCalls.contains(call)) {
225         //lets generate a temp filename
226         QString tempPath = QDir::tempPath();
227         m_tempFileName = QString::fromLatin1("%1/%2.edited")
228                          .arg(tempPath)
229                          .arg(m_fileName);
230     }
231     m_editedCalls.insert(call);
232     m_needsSaving = true;
233
234     emit changed(call);
235 }
236
237 void ApiTrace::callReverted(ApiTraceCall *call)
238 {
239     m_editedCalls.remove(call);
240
241     if (m_editedCalls.isEmpty()) {
242         m_needsSaving = false;
243     }
244     emit changed(call);
245 }
246
247 bool ApiTrace::edited() const
248 {
249     return !m_editedCalls.isEmpty();
250 }
251
252 bool ApiTrace::needsSaving() const
253 {
254     return m_needsSaving;
255 }
256
257 void ApiTrace::save()
258 {
259     QFileInfo fi(m_tempFileName);
260     QDir dir;
261     emit startedSaving();
262     dir.mkpath(fi.absolutePath());
263     m_saver->saveFile(m_tempFileName, m_calls);
264 }
265
266 void ApiTrace::slotSaved()
267 {
268     m_needsSaving = false;
269 }
270
271 bool ApiTrace::isSaving() const
272 {
273     return m_saver->isRunning();
274 }
275
276 void ApiTrace::callError(ApiTraceCall *call)
277 {
278     Q_ASSERT(call);
279
280     if (call->hasError())
281         m_errors.insert(call);
282     else
283         m_errors.remove(call);
284
285     emit changed(call);
286 }
287
288 bool ApiTrace::hasErrors() const
289 {
290     return !m_errors.isEmpty();
291 }
292
293 ApiTraceCallSignature * ApiTrace::signature(unsigned id)
294 {
295     if (id >= m_signatures.count()) {
296         m_signatures.resize(id + 1);
297         return NULL;
298     } else {
299         return m_signatures[id];
300     }
301 }
302
303 void ApiTrace::addSignature(unsigned id, ApiTraceCallSignature *signature)
304 {
305     m_signatures[id] = signature;
306 }
307
308 ApiTraceEnumSignature * ApiTrace::enumSignature(unsigned id)
309 {
310     if (id >= m_enumSignatures.count()) {
311         m_enumSignatures.resize(id + 1);
312         return NULL;
313     } else {
314         return m_enumSignatures[id];
315     }
316 }
317
318 void ApiTrace::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
319 {
320     m_enumSignatures[id] = signature;
321 }
322
323 #include "apitrace.moc"