]> git.notmuchmail.org Git - apitrace/blob - gui/apitrace.cpp
Recognize CGLFlushDrawable as a swapbuffer.
[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     case FrameMarker_Flush:
46         return call->name() == QLatin1String("glFlush");
47     case FrameMarker_Finish:
48         return call->name() == QLatin1String("glFinish");
49     case FrameMarker_Clear:
50         return call->name() == QLatin1String("glClear");
51     }
52
53     Q_ASSERT(!"unknown frame marker");
54
55     return false;
56 }
57
58 bool ApiTrace::isEmpty() const
59 {
60     return m_calls.isEmpty();
61 }
62
63 QString ApiTrace::fileName() const
64 {
65     if (edited())
66         return m_tempFileName;
67
68     return m_fileName;
69 }
70
71 ApiTrace::FrameMarker ApiTrace::frameMarker() const
72 {
73     return m_frameMarker;
74 }
75
76 QList<ApiTraceCall*> ApiTrace::calls() const
77 {
78     return m_calls;
79 }
80
81 ApiTraceCall * ApiTrace::callAt(int idx) const
82 {
83     return m_calls.value(idx);
84 }
85
86 int ApiTrace::numCalls() const
87 {
88     return m_calls.count();
89 }
90
91 QList<ApiTraceFrame*> ApiTrace::frames() const
92 {
93     return m_frames;
94 }
95
96 ApiTraceFrame * ApiTrace::frameAt(int idx) const
97 {
98     return m_frames.value(idx);
99 }
100
101 int ApiTrace::numFrames() const
102 {
103     return m_frames.count();
104 }
105
106 int ApiTrace::numCallsInFrame(int idx) const
107 {
108     const ApiTraceFrame *frame = frameAt(idx);
109     if (frame)
110         return frame->numChildren();
111     else
112         return 0;
113 }
114
115 void ApiTrace::setFileName(const QString &name)
116 {
117     if (m_fileName != name) {
118         m_fileName = name;
119
120         if (m_loader->isRunning()) {
121             m_loader->terminate();
122             m_loader->wait();
123         }
124         m_frames.clear();
125         m_calls.clear();
126         m_errors.clear();
127         m_editedCalls.clear();
128         m_needsSaving = false;
129         emit invalidated();
130
131         m_loader->loadFile(m_fileName);
132     }
133 }
134
135 void ApiTrace::setFrameMarker(FrameMarker marker)
136 {
137     if (m_frameMarker != marker) {
138         emit framesInvalidated();
139
140         qDeleteAll(m_frames);
141         m_frames.clear();
142         detectFrames();
143     }
144 }
145
146 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
147 {
148     int currentFrames = m_frames.count();
149     int numNewFrames = frames.count();
150
151     emit beginAddingFrames(currentFrames, numNewFrames);
152
153     m_frames += frames;
154
155     int currentCalls = m_calls.count();
156     int numNewCalls = 0;
157     foreach(ApiTraceFrame *frame, frames) {
158         frame->setParentTrace(this);
159         numNewCalls += frame->numChildren();
160         m_calls += frame->calls();
161     }
162
163     emit endAddingFrames();
164     emit callsAdded(currentCalls, numNewCalls);
165 }
166
167 void ApiTrace::detectFrames()
168 {
169     if (m_calls.isEmpty())
170         return;
171
172     emit beginAddingFrames(0, m_frames.count());
173
174     ApiTraceFrame *currentFrame = 0;
175     foreach(ApiTraceCall *apiCall, m_calls) {
176         if (!currentFrame) {
177             currentFrame = new ApiTraceFrame();
178             currentFrame->setParentTrace(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 #include "apitrace.moc"