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