blob: f3b95dc13c58e979e05b59da1998318da0dec5f9 [file] [log] [blame]
Zack Rusinf6667d12011-03-30 11:03:37 -04001#include "apitrace.h"
2
3#include "loaderthread.h"
Zack Rusind809a062011-04-17 23:30:58 -04004#include "saverthread.h"
Zack Rusinf6667d12011-03-30 11:03:37 -04005
Zack Rusin63efea82011-04-17 17:10:45 -04006#include <QDir>
7
Zack Rusinf6667d12011-03-30 11:03:37 -04008ApiTrace::ApiTrace()
Zack Rusin63efea82011-04-17 17:10:45 -04009 : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
10 m_needsSaving(false)
Zack Rusinf6667d12011-03-30 11:03:37 -040011{
12 m_loader = new LoaderThread(this);
13 connect(m_loader, SIGNAL(parsedFrames(const QList<ApiTraceFrame*>)),
14 this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
Zack Rusinde4ea412011-03-30 11:30:08 -040015 connect(m_loader, SIGNAL(started()),
16 this, SIGNAL(startedLoadingTrace()));
17 connect(m_loader, SIGNAL(finished()),
18 this, SIGNAL(finishedLoadingTrace()));
Zack Rusind809a062011-04-17 23:30:58 -040019
20 m_saver = new SaverThread(this);
Zack Rusin9af5bff2011-04-18 01:05:50 -040021 connect(m_saver, SIGNAL(traceSaved()),
22 this, SLOT(slotSaved()));
23 connect(m_saver, SIGNAL(traceSaved()),
24 this, SIGNAL(saved()));
Zack Rusinf6667d12011-03-30 11:03:37 -040025}
26
27ApiTrace::~ApiTrace()
28{
29 qDeleteAll(m_calls);
30 qDeleteAll(m_frames);
31 delete m_loader;
Zack Rusind809a062011-04-17 23:30:58 -040032 delete m_saver;
Zack Rusinf6667d12011-03-30 11:03:37 -040033}
34
35bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
36 ApiTrace::FrameMarker marker)
37{
38 if (!call)
39 return false;
40
41 switch (marker) {
42 case FrameMarker_SwapBuffers:
José Fonseca3e9ff852011-06-06 19:37:09 +010043 return call->name().contains(QLatin1String("SwapBuffers")) ||
José Fonsecadb678122011-07-29 17:20:05 +010044 call->name() == QLatin1String("CGLFlushDrawable") ||
45 call->name() == QLatin1String("glFrameTerminatorGREMEDY");
Zack Rusinf6667d12011-03-30 11:03:37 -040046 case FrameMarker_Flush:
Zack Rusinead6aad2011-04-15 22:16:18 -040047 return call->name() == QLatin1String("glFlush");
Zack Rusinf6667d12011-03-30 11:03:37 -040048 case FrameMarker_Finish:
Zack Rusinead6aad2011-04-15 22:16:18 -040049 return call->name() == QLatin1String("glFinish");
Zack Rusinf6667d12011-03-30 11:03:37 -040050 case FrameMarker_Clear:
Zack Rusinead6aad2011-04-15 22:16:18 -040051 return call->name() == QLatin1String("glClear");
Zack Rusinf6667d12011-03-30 11:03:37 -040052 }
53
54 Q_ASSERT(!"unknown frame marker");
55
56 return false;
57}
58
59bool ApiTrace::isEmpty() const
60{
61 return m_calls.isEmpty();
62}
63
64QString ApiTrace::fileName() const
65{
Zack Rusin63efea82011-04-17 17:10:45 -040066 if (edited())
67 return m_tempFileName;
68
Zack Rusinf6667d12011-03-30 11:03:37 -040069 return m_fileName;
70}
71
72ApiTrace::FrameMarker ApiTrace::frameMarker() const
73{
74 return m_frameMarker;
75}
76
77QList<ApiTraceCall*> ApiTrace::calls() const
78{
79 return m_calls;
80}
81
82ApiTraceCall * ApiTrace::callAt(int idx) const
83{
84 return m_calls.value(idx);
85}
86
87int ApiTrace::numCalls() const
88{
89 return m_calls.count();
90}
91
92QList<ApiTraceFrame*> ApiTrace::frames() const
93{
94 return m_frames;
95}
96
97ApiTraceFrame * ApiTrace::frameAt(int idx) const
98{
99 return m_frames.value(idx);
100}
101
102int ApiTrace::numFrames() const
103{
104 return m_frames.count();
105}
106
107int ApiTrace::numCallsInFrame(int idx) const
108{
109 const ApiTraceFrame *frame = frameAt(idx);
110 if (frame)
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400111 return frame->numChildren();
Zack Rusinf6667d12011-03-30 11:03:37 -0400112 else
113 return 0;
114}
115
116void 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 }
Zack Rusinca164112011-04-11 02:23:09 -0400125 m_frames.clear();
126 m_calls.clear();
Zack Rusin30069572011-04-20 18:21:11 -0400127 m_errors.clear();
128 m_editedCalls.clear();
129 m_needsSaving = false;
Zack Rusinf6667d12011-03-30 11:03:37 -0400130 emit invalidated();
131
132 m_loader->loadFile(m_fileName);
133 }
134}
135
136void 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
147void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
148{
Zack Rusin410a8f32011-08-28 02:38:34 -0400149 QList<ApiTraceCall*> calls;
Zack Rusinf6667d12011-03-30 11:03:37 -0400150 int currentFrames = m_frames.count();
151 int numNewFrames = frames.count();
Zack Rusinb56e03d2011-04-20 23:58:52 -0400152
153 emit beginAddingFrames(currentFrames, numNewFrames);
154
Zack Rusinf6667d12011-03-30 11:03:37 -0400155 m_frames += frames;
156
157 int currentCalls = m_calls.count();
158 int numNewCalls = 0;
159 foreach(ApiTraceFrame *frame, frames) {
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400160 Q_ASSERT(this == frame->parentTrace());
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400161 numNewCalls += frame->numChildren();
Zack Rusin410a8f32011-08-28 02:38:34 -0400162 calls += frame->calls();
Zack Rusinf6667d12011-03-30 11:03:37 -0400163 }
Zack Rusin410a8f32011-08-28 02:38:34 -0400164 m_calls.reserve(m_calls.count() + calls.count());
165 m_calls += calls;
Zack Rusinf6667d12011-03-30 11:03:37 -0400166
Zack Rusinb56e03d2011-04-20 23:58:52 -0400167 emit endAddingFrames();
Zack Rusinf6667d12011-03-30 11:03:37 -0400168 emit callsAdded(currentCalls, numNewCalls);
169}
170
171void ApiTrace::detectFrames()
172{
173 if (m_calls.isEmpty())
174 return;
175
Zack Rusinb56e03d2011-04-20 23:58:52 -0400176 emit beginAddingFrames(0, m_frames.count());
177
Zack Rusinf6667d12011-03-30 11:03:37 -0400178 ApiTraceFrame *currentFrame = 0;
179 foreach(ApiTraceCall *apiCall, m_calls) {
180 if (!currentFrame) {
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400181 currentFrame = new ApiTraceFrame(this);
Zack Rusinf6667d12011-03-30 11:03:37 -0400182 currentFrame->number = m_frames.count();
183 }
Zack Rusinead6aad2011-04-15 22:16:18 -0400184 apiCall->setParentFrame(currentFrame);
Zack Rusin1d31b6c2011-04-26 22:30:25 -0400185 currentFrame->addCall(apiCall);
Zack Rusinf6667d12011-03-30 11:03:37 -0400186 if (ApiTrace::isCallAFrameMarker(apiCall,
187 m_frameMarker)) {
188 m_frames.append(currentFrame);
189 currentFrame = 0;
190 }
191 }
192 //last frames won't have markers
193 // it's just a bunch of Delete calls for every object
194 // after the last SwapBuffers
195 if (currentFrame) {
196 m_frames.append(currentFrame);
197 currentFrame = 0;
198 }
Zack Rusinb56e03d2011-04-20 23:58:52 -0400199 emit endAddingFrames();
Zack Rusinf6667d12011-03-30 11:03:37 -0400200}
201
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400202ApiTraceCall * ApiTrace::callWithIndex(int idx) const
203{
204 for (int i = 0; i < m_calls.count(); ++i) {
205 ApiTraceCall *call = m_calls[i];
Zack Rusinead6aad2011-04-15 22:16:18 -0400206 if (call->index() == idx)
Zack Rusinf04cf8a2011-04-12 23:21:52 -0400207 return call;
208 }
209 return NULL;
210}
211
Zack Rusine2dfa2e2011-04-13 01:35:03 -0400212ApiTraceState ApiTrace::defaultState() const
213{
214 ApiTraceFrame *frame = frameAt(0);
215 if (!frame)
216 return ApiTraceState();
217
218 return frame->state();
219}
220
Zack Rusin661842d2011-04-17 01:59:16 -0400221void ApiTrace::callEdited(ApiTraceCall *call)
222{
Zack Rusin63efea82011-04-17 17:10:45 -0400223 if (!m_editedCalls.contains(call)) {
224 //lets generate a temp filename
225 QString tempPath = QDir::tempPath();
Zack Rusin63efea82011-04-17 17:10:45 -0400226 m_tempFileName = QString::fromLatin1("%1/%2.edited")
227 .arg(tempPath)
228 .arg(m_fileName);
Zack Rusin63efea82011-04-17 17:10:45 -0400229 }
Zack Rusin661842d2011-04-17 01:59:16 -0400230 m_editedCalls.insert(call);
Zack Rusin9af5bff2011-04-18 01:05:50 -0400231 m_needsSaving = true;
Zack Rusin63efea82011-04-17 17:10:45 -0400232
Zack Rusin661842d2011-04-17 01:59:16 -0400233 emit changed(call);
234}
235
236void ApiTrace::callReverted(ApiTraceCall *call)
237{
238 m_editedCalls.remove(call);
Zack Rusin63efea82011-04-17 17:10:45 -0400239
240 if (m_editedCalls.isEmpty()) {
241 m_needsSaving = false;
242 }
Zack Rusin661842d2011-04-17 01:59:16 -0400243 emit changed(call);
244}
245
Zack Rusin0ddd2502011-04-17 02:34:45 -0400246bool ApiTrace::edited() const
Zack Rusin661842d2011-04-17 01:59:16 -0400247{
248 return !m_editedCalls.isEmpty();
249}
250
Zack Rusin63efea82011-04-17 17:10:45 -0400251bool ApiTrace::needsSaving() const
252{
253 return m_needsSaving;
254}
255
256void ApiTrace::save()
257{
258 QFileInfo fi(m_tempFileName);
259 QDir dir;
Zack Rusin9af5bff2011-04-18 01:05:50 -0400260 emit startedSaving();
Zack Rusin63efea82011-04-17 17:10:45 -0400261 dir.mkpath(fi.absolutePath());
Zack Rusind809a062011-04-17 23:30:58 -0400262 m_saver->saveFile(m_tempFileName, m_calls);
Zack Rusin63efea82011-04-17 17:10:45 -0400263}
264
Zack Rusin9af5bff2011-04-18 01:05:50 -0400265void ApiTrace::slotSaved()
266{
267 m_needsSaving = false;
268}
269
270bool ApiTrace::isSaving() const
271{
272 return m_saver->isRunning();
273}
274
Zack Rusinb53b1612011-04-19 01:33:58 -0400275void ApiTrace::callError(ApiTraceCall *call)
276{
Zack Rusincc0b4912011-04-19 01:59:20 -0400277 Q_ASSERT(call);
278
279 if (call->hasError())
280 m_errors.insert(call);
281 else
282 m_errors.remove(call);
283
Zack Rusinb53b1612011-04-19 01:33:58 -0400284 emit changed(call);
285}
286
Zack Rusincc0b4912011-04-19 01:59:20 -0400287bool ApiTrace::hasErrors() const
288{
289 return !m_errors.isEmpty();
290}
291
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400292ApiTraceCallSignature * ApiTrace::signature(const QString &callName)
293{
294 return m_signatures[callName];
295}
296
297void ApiTrace::addSignature(ApiTraceCallSignature *signature)
298{
299 m_signatures.insert(signature->name(), signature);
300}
301
Zack Rusinf6667d12011-03-30 11:03:37 -0400302#include "apitrace.moc"