]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
Recognize glFrameTerminatorGREMEDY as swapbuffer frame marker.
[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         frame->setParentTrace(this);
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();
179             currentFrame->setParentTrace(this);
180             currentFrame->number = m_frames.count();
181         }
182         apiCall->setParentFrame(currentFrame);
183         currentFrame->addCall(apiCall);
184         if (ApiTrace::isCallAFrameMarker(apiCall,
185                                          m_frameMarker)) {
186             m_frames.append(currentFrame);
187             currentFrame = 0;
188         }
189     }
190     //last frames won't have markers
191     //  it's just a bunch of Delete calls for every object
192     //  after the last SwapBuffers
193     if (currentFrame) {
194         m_frames.append(currentFrame);
195         currentFrame = 0;
196     }
197     emit endAddingFrames();
198 }
199
200 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
201 {
202     for (int i = 0; i < m_calls.count(); ++i) {
203         ApiTraceCall *call = m_calls[i];
204         if (call->index() == idx)
205             return call;
206     }
207     return NULL;
208 }
209
210 ApiTraceState ApiTrace::defaultState() const
211 {
212     ApiTraceFrame *frame = frameAt(0);
213     if (!frame)
214         return ApiTraceState();
215
216     return frame->state();
217 }
218
219 void ApiTrace::callEdited(ApiTraceCall *call)
220 {
221     if (!m_editedCalls.contains(call)) {
222         //lets generate a temp filename
223         QString tempPath = QDir::tempPath();
224         m_tempFileName = QString::fromLatin1("%1/%2.edited")
225                          .arg(tempPath)
226                          .arg(m_fileName);
227     }
228     m_editedCalls.insert(call);
229     m_needsSaving = true;
230
231     emit changed(call);
232 }
233
234 void ApiTrace::callReverted(ApiTraceCall *call)
235 {
236     m_editedCalls.remove(call);
237
238     if (m_editedCalls.isEmpty()) {
239         m_needsSaving = false;
240     }
241     emit changed(call);
242 }
243
244 bool ApiTrace::edited() const
245 {
246     return !m_editedCalls.isEmpty();
247 }
248
249 bool ApiTrace::needsSaving() const
250 {
251     return m_needsSaving;
252 }
253
254 void ApiTrace::save()
255 {
256     QFileInfo fi(m_tempFileName);
257     QDir dir;
258     emit startedSaving();
259     dir.mkpath(fi.absolutePath());
260     m_saver->saveFile(m_tempFileName, m_calls);
261 }
262
263 void ApiTrace::slotSaved()
264 {
265     m_needsSaving = false;
266 }
267
268 bool ApiTrace::isSaving() const
269 {
270     return m_saver->isRunning();
271 }
272
273 void ApiTrace::callError(ApiTraceCall *call)
274 {
275     Q_ASSERT(call);
276
277     if (call->hasError())
278         m_errors.insert(call);
279     else
280         m_errors.remove(call);
281
282     emit changed(call);
283 }
284
285 bool ApiTrace::hasErrors() const
286 {
287     return !m_errors.isEmpty();
288 }
289
290 #include "apitrace.moc"