]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
9c99cfabf624b0adcbacb72a8ace9327f9567781
[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 QList<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     int currentFrames = m_frames.count();
150     int numNewFrames = frames.count();
151
152     emit beginAddingFrames(currentFrames, numNewFrames);
153
154     m_frames += frames;
155
156     int currentCalls = m_calls.count();
157     int numNewCalls = 0;
158     foreach(ApiTraceFrame *frame, frames) {
159         Q_ASSERT(this == frame->parentTrace());
160         numNewCalls += frame->numChildren();
161         m_calls += frame->calls();
162     }
163
164     emit endAddingFrames();
165     emit callsAdded(currentCalls, numNewCalls);
166 }
167
168 void ApiTrace::detectFrames()
169 {
170     if (m_calls.isEmpty())
171         return;
172
173     emit beginAddingFrames(0, m_frames.count());
174
175     ApiTraceFrame *currentFrame = 0;
176     foreach(ApiTraceCall *apiCall, m_calls) {
177         if (!currentFrame) {
178             currentFrame = new ApiTraceFrame(this);
179             currentFrame->number = m_frames.count();
180         }
181         apiCall->setParentFrame(currentFrame);
182         currentFrame->addCall(apiCall);
183         if (ApiTrace::isCallAFrameMarker(apiCall,
184                                          m_frameMarker)) {
185             m_frames.append(currentFrame);
186             currentFrame = 0;
187         }
188     }
189     //last frames won't have markers
190     //  it's just a bunch of Delete calls for every object
191     //  after the last SwapBuffers
192     if (currentFrame) {
193         m_frames.append(currentFrame);
194         currentFrame = 0;
195     }
196     emit endAddingFrames();
197 }
198
199 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
200 {
201     for (int i = 0; i < m_calls.count(); ++i) {
202         ApiTraceCall *call = m_calls[i];
203         if (call->index() == idx)
204             return call;
205     }
206     return NULL;
207 }
208
209 ApiTraceState ApiTrace::defaultState() const
210 {
211     ApiTraceFrame *frame = frameAt(0);
212     if (!frame)
213         return ApiTraceState();
214
215     return frame->state();
216 }
217
218 void ApiTrace::callEdited(ApiTraceCall *call)
219 {
220     if (!m_editedCalls.contains(call)) {
221         //lets generate a temp filename
222         QString tempPath = QDir::tempPath();
223         m_tempFileName = QString::fromLatin1("%1/%2.edited")
224                          .arg(tempPath)
225                          .arg(m_fileName);
226     }
227     m_editedCalls.insert(call);
228     m_needsSaving = true;
229
230     emit changed(call);
231 }
232
233 void ApiTrace::callReverted(ApiTraceCall *call)
234 {
235     m_editedCalls.remove(call);
236
237     if (m_editedCalls.isEmpty()) {
238         m_needsSaving = false;
239     }
240     emit changed(call);
241 }
242
243 bool ApiTrace::edited() const
244 {
245     return !m_editedCalls.isEmpty();
246 }
247
248 bool ApiTrace::needsSaving() const
249 {
250     return m_needsSaving;
251 }
252
253 void ApiTrace::save()
254 {
255     QFileInfo fi(m_tempFileName);
256     QDir dir;
257     emit startedSaving();
258     dir.mkpath(fi.absolutePath());
259     m_saver->saveFile(m_tempFileName, m_calls);
260 }
261
262 void ApiTrace::slotSaved()
263 {
264     m_needsSaving = false;
265 }
266
267 bool ApiTrace::isSaving() const
268 {
269     return m_saver->isRunning();
270 }
271
272 void ApiTrace::callError(ApiTraceCall *call)
273 {
274     Q_ASSERT(call);
275
276     if (call->hasError())
277         m_errors.insert(call);
278     else
279         m_errors.remove(call);
280
281     emit changed(call);
282 }
283
284 bool ApiTrace::hasErrors() const
285 {
286     return !m_errors.isEmpty();
287 }
288
289 ApiTraceCallSignature * ApiTrace::signature(const QString &callName)
290 {
291     return m_signatures[callName];
292 }
293
294 void ApiTrace::addSignature(ApiTraceCallSignature *signature)
295 {
296     m_signatures.insert(signature->name(), signature);
297 }
298
299 #include "apitrace.moc"