]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
376b73fe3cce24e85af08613e0759aaa6059600c
[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     case FrameMarker_Flush:
45         return call->name() == QLatin1String("glFlush");
46     case FrameMarker_Finish:
47         return call->name() == QLatin1String("glFinish");
48     case FrameMarker_Clear:
49         return call->name() == QLatin1String("glClear");
50     }
51
52     Q_ASSERT(!"unknown frame marker");
53
54     return false;
55 }
56
57 bool ApiTrace::isEmpty() const
58 {
59     return m_calls.isEmpty();
60 }
61
62 QString ApiTrace::fileName() const
63 {
64     if (edited())
65         return m_tempFileName;
66
67     return m_fileName;
68 }
69
70 ApiTrace::FrameMarker ApiTrace::frameMarker() const
71 {
72     return m_frameMarker;
73 }
74
75 QList<ApiTraceCall*> ApiTrace::calls() const
76 {
77     return m_calls;
78 }
79
80 ApiTraceCall * ApiTrace::callAt(int idx) const
81 {
82     return m_calls.value(idx);
83 }
84
85 int ApiTrace::numCalls() const
86 {
87     return m_calls.count();
88 }
89
90 QList<ApiTraceFrame*> ApiTrace::frames() const
91 {
92     return m_frames;
93 }
94
95 ApiTraceFrame * ApiTrace::frameAt(int idx) const
96 {
97     return m_frames.value(idx);
98 }
99
100 int ApiTrace::numFrames() const
101 {
102     return m_frames.count();
103 }
104
105 int ApiTrace::numCallsInFrame(int idx) const
106 {
107     const ApiTraceFrame *frame = frameAt(idx);
108     if (frame)
109         return frame->numChildren();
110     else
111         return 0;
112 }
113
114 void ApiTrace::setFileName(const QString &name)
115 {
116     if (m_fileName != name) {
117         m_fileName = name;
118
119         if (m_loader->isRunning()) {
120             m_loader->terminate();
121             m_loader->wait();
122         }
123         m_frames.clear();
124         m_calls.clear();
125         m_errors.clear();
126         m_editedCalls.clear();
127         m_needsSaving = false;
128         emit invalidated();
129
130         m_loader->loadFile(m_fileName);
131     }
132 }
133
134 void ApiTrace::setFrameMarker(FrameMarker marker)
135 {
136     if (m_frameMarker != marker) {
137         emit framesInvalidated();
138
139         qDeleteAll(m_frames);
140         m_frames.clear();
141         detectFrames();
142     }
143 }
144
145 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
146 {
147     int currentFrames = m_frames.count();
148     int numNewFrames = frames.count();
149
150     emit beginAddingFrames(currentFrames, numNewFrames);
151
152     m_frames += frames;
153
154     int currentCalls = m_calls.count();
155     int numNewCalls = 0;
156     foreach(ApiTraceFrame *frame, frames) {
157         frame->setParentTrace(this);
158         numNewCalls += frame->numChildren();
159         m_calls += frame->calls();
160     }
161
162     emit endAddingFrames();
163     emit callsAdded(currentCalls, numNewCalls);
164 }
165
166 void ApiTrace::detectFrames()
167 {
168     if (m_calls.isEmpty())
169         return;
170
171     emit beginAddingFrames(0, m_frames.count());
172
173     ApiTraceFrame *currentFrame = 0;
174     foreach(ApiTraceCall *apiCall, m_calls) {
175         if (!currentFrame) {
176             currentFrame = new ApiTraceFrame();
177             currentFrame->setParentTrace(this);
178             currentFrame->number = m_frames.count();
179         }
180         apiCall->setParentFrame(currentFrame);
181         currentFrame->addCall(apiCall);
182         if (ApiTrace::isCallAFrameMarker(apiCall,
183                                          m_frameMarker)) {
184             m_frames.append(currentFrame);
185             currentFrame = 0;
186         }
187     }
188     //last frames won't have markers
189     //  it's just a bunch of Delete calls for every object
190     //  after the last SwapBuffers
191     if (currentFrame) {
192         m_frames.append(currentFrame);
193         currentFrame = 0;
194     }
195     emit endAddingFrames();
196 }
197
198 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
199 {
200     for (int i = 0; i < m_calls.count(); ++i) {
201         ApiTraceCall *call = m_calls[i];
202         if (call->index() == idx)
203             return call;
204     }
205     return NULL;
206 }
207
208 ApiTraceState ApiTrace::defaultState() const
209 {
210     ApiTraceFrame *frame = frameAt(0);
211     if (!frame)
212         return ApiTraceState();
213
214     return frame->state();
215 }
216
217 void ApiTrace::callEdited(ApiTraceCall *call)
218 {
219     if (!m_editedCalls.contains(call)) {
220         //lets generate a temp filename
221         QString tempPath = QDir::tempPath();
222         m_tempFileName = QString::fromLatin1("%1/%2.edited")
223                          .arg(tempPath)
224                          .arg(m_fileName);
225     }
226     m_editedCalls.insert(call);
227     m_needsSaving = true;
228
229     emit changed(call);
230 }
231
232 void ApiTrace::callReverted(ApiTraceCall *call)
233 {
234     m_editedCalls.remove(call);
235
236     if (m_editedCalls.isEmpty()) {
237         m_needsSaving = false;
238     }
239     emit changed(call);
240 }
241
242 bool ApiTrace::edited() const
243 {
244     return !m_editedCalls.isEmpty();
245 }
246
247 bool ApiTrace::needsSaving() const
248 {
249     return m_needsSaving;
250 }
251
252 void ApiTrace::save()
253 {
254     QFileInfo fi(m_tempFileName);
255     QDir dir;
256     emit startedSaving();
257     dir.mkpath(fi.absolutePath());
258     m_saver->saveFile(m_tempFileName, m_calls);
259 }
260
261 void ApiTrace::slotSaved()
262 {
263     m_needsSaving = false;
264 }
265
266 bool ApiTrace::isSaving() const
267 {
268     return m_saver->isRunning();
269 }
270
271 void ApiTrace::callError(ApiTraceCall *call)
272 {
273     Q_ASSERT(call);
274
275     if (call->hasError())
276         m_errors.insert(call);
277     else
278         m_errors.remove(call);
279
280     emit changed(call);
281 }
282
283 bool ApiTrace::hasErrors() const
284 {
285     return !m_errors.isEmpty();
286 }
287
288 #include "apitrace.moc"