]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
2eb6ab52a665075752011cb6678c8c0189304c4e
[apitrace] / gui / apitrace.cpp
1 #include "apitrace.h"
2
3 #include "traceloader.h"
4 #include "saverthread.h"
5
6 #include <QDebug>
7 #include <QDir>
8 #include <QThread>
9
10 ApiTrace::ApiTrace()
11     : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
12       m_needsSaving(false)
13 {
14     m_loader = new TraceLoader();
15     connect(this, SIGNAL(loadTrace(QString)),
16             m_loader, SLOT(loadTrace(QString)));
17     connect(this, SIGNAL(requestFrame(ApiTraceFrame*)),
18             m_loader, SLOT(loadFrame(ApiTraceFrame*)));
19     connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
20             this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
21     connect(m_loader, SIGNAL(frameLoaded(ApiTraceFrame*)),
22             this, SIGNAL(frameLoaded(ApiTraceFrame*)));
23
24     connect(m_loader, SIGNAL(startedParsing()),
25             this, SIGNAL(startedLoadingTrace()));
26     connect(m_loader, SIGNAL(parsed(int)),
27             this, SIGNAL(loaded(int)));
28     connect(m_loader, SIGNAL(finishedParsing()),
29             this, SIGNAL(finishedLoadingTrace()));
30
31
32     m_saver = new SaverThread(this);
33     connect(m_saver, SIGNAL(traceSaved()),
34             this, SLOT(slotSaved()));
35     connect(m_saver, SIGNAL(traceSaved()),
36             this, SIGNAL(saved()));
37
38     m_loaderThread = new QThread();
39     m_loader->moveToThread(m_loaderThread);
40     m_loaderThread->start();
41 }
42
43 ApiTrace::~ApiTrace()
44 {
45     m_loaderThread->quit();
46     m_loaderThread->deleteLater();
47     qDeleteAll(m_calls);
48     qDeleteAll(m_frames);
49     delete m_loader;
50     delete m_saver;
51 }
52
53 bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
54                                   ApiTrace::FrameMarker marker)
55 {
56     if (!call)
57         return false;
58
59     switch (marker) {
60     case FrameMarker_SwapBuffers:
61         return call->name().contains(QLatin1String("SwapBuffers")) ||
62                call->name() == QLatin1String("CGLFlushDrawable") ||
63                call->name() == QLatin1String("glFrameTerminatorGREMEDY");
64     case FrameMarker_Flush:
65         return call->name() == QLatin1String("glFlush");
66     case FrameMarker_Finish:
67         return call->name() == QLatin1String("glFinish");
68     case FrameMarker_Clear:
69         return call->name() == QLatin1String("glClear");
70     }
71
72     Q_ASSERT(!"unknown frame marker");
73
74     return false;
75 }
76
77 bool ApiTrace::isEmpty() const
78 {
79     return m_calls.isEmpty();
80 }
81
82 QString ApiTrace::fileName() const
83 {
84     if (edited())
85         return m_tempFileName;
86
87     return m_fileName;
88 }
89
90 ApiTrace::FrameMarker ApiTrace::frameMarker() const
91 {
92     return m_frameMarker;
93 }
94
95 QVector<ApiTraceCall*> ApiTrace::calls() const
96 {
97     return m_calls;
98 }
99
100 int ApiTrace::numCalls() const
101 {
102     return m_calls.count();
103 }
104
105 QList<ApiTraceFrame*> ApiTrace::frames() const
106 {
107     return m_frames;
108 }
109
110 ApiTraceFrame * ApiTrace::frameAt(int idx) const
111 {
112     return m_frames.value(idx);
113 }
114
115 int ApiTrace::numFrames() const
116 {
117     return m_frames.count();
118 }
119
120 int ApiTrace::numCallsInFrame(int idx) const
121 {
122     const ApiTraceFrame *frame = frameAt(idx);
123     if (frame)
124         return frame->numChildren();
125     else
126         return 0;
127 }
128
129 void ApiTrace::setFileName(const QString &name)
130 {
131     if (m_fileName != name) {
132         m_fileName = name;
133
134         m_frames.clear();
135         m_calls.clear();
136         m_errors.clear();
137         m_editedCalls.clear();
138         m_needsSaving = false;
139         emit invalidated();
140
141 //        m_loader->loadTrace(m_fileName);
142         emit loadTrace(m_fileName);
143     }
144 }
145
146 void ApiTrace::setFrameMarker(FrameMarker marker)
147 {
148     if (m_frameMarker != marker) {
149         emit framesInvalidated();
150
151         qDeleteAll(m_frames);
152         m_frames.clear();
153         detectFrames();
154     }
155 }
156
157 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
158 {
159     QVector<ApiTraceCall*> calls;
160     int currentFrames = m_frames.count();
161     int numNewFrames = frames.count();
162
163     emit beginAddingFrames(currentFrames, numNewFrames);
164
165     m_frames += frames;
166
167     int currentCalls = m_calls.count();
168     int numNewCalls = 0;
169     foreach(ApiTraceFrame *frame, frames) {
170         frame->setParentTrace(this);
171         numNewCalls += frame->numChildren();
172         calls += frame->calls();
173     }
174     m_calls.reserve(m_calls.count() + calls.count() + 1);
175     m_calls += calls;
176
177     emit endAddingFrames();
178     emit callsAdded(currentCalls, numNewCalls);
179 }
180
181 void ApiTrace::detectFrames()
182 {
183     if (m_calls.isEmpty())
184         return;
185
186     emit beginAddingFrames(0, m_frames.count());
187
188     ApiTraceFrame *currentFrame = 0;
189     foreach(ApiTraceCall *apiCall, m_calls) {
190         if (!currentFrame) {
191             currentFrame = new ApiTraceFrame(this);
192             currentFrame->number = m_frames.count();
193             currentFrame->setLoaded(true);
194         }
195         apiCall->setParentFrame(currentFrame);
196         currentFrame->addCall(apiCall);
197         if (ApiTrace::isCallAFrameMarker(apiCall,
198                                          m_frameMarker)) {
199             m_frames.append(currentFrame);
200             currentFrame = 0;
201         }
202     }
203     //last frames won't have markers
204     //  it's just a bunch of Delete calls for every object
205     //  after the last SwapBuffers
206     if (currentFrame) {
207         m_frames.append(currentFrame);
208         currentFrame = 0;
209     }
210     emit endAddingFrames();
211 }
212
213 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
214 {
215     for (int i = 0; i < m_calls.count(); ++i) {
216         ApiTraceCall *call = m_calls[i];
217         if (call->index() == idx)
218             return call;
219     }
220     return NULL;
221 }
222
223 ApiTraceState ApiTrace::defaultState() const
224 {
225     ApiTraceFrame *frame = frameAt(0);
226     if (!frame || !frame->hasState())
227         return ApiTraceState();
228
229     return *frame->state();
230 }
231
232 void ApiTrace::callEdited(ApiTraceCall *call)
233 {
234     if (!m_editedCalls.contains(call)) {
235         //lets generate a temp filename
236         QString tempPath = QDir::tempPath();
237         m_tempFileName = QString::fromLatin1("%1/%2.edited")
238                          .arg(tempPath)
239                          .arg(m_fileName);
240     }
241     m_editedCalls.insert(call);
242     m_needsSaving = true;
243
244     emit changed(call);
245 }
246
247 void ApiTrace::callReverted(ApiTraceCall *call)
248 {
249     m_editedCalls.remove(call);
250
251     if (m_editedCalls.isEmpty()) {
252         m_needsSaving = false;
253     }
254     emit changed(call);
255 }
256
257 bool ApiTrace::edited() const
258 {
259     return !m_editedCalls.isEmpty();
260 }
261
262 bool ApiTrace::needsSaving() const
263 {
264     return m_needsSaving;
265 }
266
267 void ApiTrace::save()
268 {
269     QFileInfo fi(m_tempFileName);
270     QDir dir;
271     emit startedSaving();
272     dir.mkpath(fi.absolutePath());
273     m_saver->saveFile(m_tempFileName, m_calls);
274 }
275
276 void ApiTrace::slotSaved()
277 {
278     m_needsSaving = false;
279 }
280
281 bool ApiTrace::isSaving() const
282 {
283     return m_saver->isRunning();
284 }
285
286 void ApiTrace::callError(ApiTraceCall *call)
287 {
288     Q_ASSERT(call);
289
290     if (call->hasError())
291         m_errors.insert(call);
292     else
293         m_errors.remove(call);
294
295     emit changed(call);
296 }
297
298 bool ApiTrace::hasErrors() const
299 {
300     return !m_errors.isEmpty();
301 }
302
303 void ApiTrace::loadFrame(ApiTraceFrame *frame)
304 {
305     Q_ASSERT(!frame->loaded());
306     emit requestFrame(frame);
307 }
308
309 #include "apitrace.moc"