blob: 77e8750e2a5cfd5eb61462aef782eaca502b284e [file] [log] [blame]
Zack Rusin20b1f6d2011-09-06 11:50:07 -04001#include "traceloader.h"
2
Zack Rusin3176ebe2011-09-06 21:11:36 -04003#include "apitrace.h"
Zack Rusin20b1f6d2011-09-06 11:50:07 -04004#include <QDebug>
5#include <QFile>
6
7#define FRAMES_TO_CACHE 100
8
9static ApiTraceCall *
10apiCallFromTraceCall(const Trace::Call *call,
11 const QHash<QString, QUrl> &helpHash,
Zack Rusinebf971e2011-09-06 17:44:43 -040012 ApiTraceFrame *frame,
13 TraceLoader *loader)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040014{
Zack Rusinebf971e2011-09-06 17:44:43 -040015 ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040016
17 apiCall->setHelpUrl(helpHash.value(apiCall->name()));
18
19 return apiCall;
20}
21
Zack Rusinebf971e2011-09-06 17:44:43 -040022TraceLoader::TraceLoader(QObject *parent)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040023 : QObject(parent),
Zack Rusin20b1f6d2011-09-06 11:50:07 -040024 m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
25{
26}
27
28TraceLoader::~TraceLoader()
29{
30 m_parser.close();
31}
32
33void TraceLoader::loadTrace(const QString &filename)
34{
35 if (m_helpHash.isEmpty()) {
36 loadHelpFile();
37 }
38
39 if (!m_parser.open(filename.toLatin1())) {
40 qDebug() << "error: failed to open " << filename;
41 return;
42 }
Zack Rusinebf971e2011-09-06 17:44:43 -040043 qDebug()<<"load trace with "<<filename;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040044 emit startedParsing();
45
Zack Rusinebf971e2011-09-06 17:44:43 -040046 qDebug() <<"\t support offsets = "<<m_parser.supportsOffsets();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040047 if (m_parser.supportsOffsets()) {
Zack Rusinac92a212011-09-06 18:25:34 -040048 scanTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040049 } else {
Zack Rusinac92a212011-09-06 18:25:34 -040050 //Load the entire file into memory
51 parseTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040052 }
53
54 emit finishedParsing();
55}
56
Zack Rusin3176ebe2011-09-06 21:11:36 -040057void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040058{
59 if (m_parser.supportsOffsets()) {
Zack Rusin3176ebe2011-09-06 21:11:36 -040060 unsigned frameIdx = currentFrame->number;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040061 int numOfCalls = numberOfCallsInFrame(frameIdx);
Zack Rusin3176ebe2011-09-06 21:11:36 -040062
Zack Rusin20b1f6d2011-09-06 11:50:07 -040063 if (numOfCalls) {
Zack Rusin3176ebe2011-09-06 21:11:36 -040064 quint64 binaryDataSize = 0;
65 QVector<ApiTraceCall*> calls(numOfCalls);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040066 const FrameOffset &frameOffset = m_frameOffsets[frameIdx];
Zack Rusin3176ebe2011-09-06 21:11:36 -040067
Zack Rusin20b1f6d2011-09-06 11:50:07 -040068 m_parser.setCurrentOffset(frameOffset.start);
69 m_parser.setCurrentCallNumber(frameOffset.callNumber);
70
71 Trace::Call *call;
72 int parsedCalls = 0;
73 while ((call = m_parser.parse_call())) {
Zack Rusin3176ebe2011-09-06 21:11:36 -040074 ApiTraceCall *apiCall =
75 apiCallFromTraceCall(call, m_helpHash,
76 currentFrame, this);
77 calls[parsedCalls] = apiCall;
78 Q_ASSERT(calls[parsedCalls]);
79 if (apiCall->hasBinaryData()) {
80 QByteArray data =
81 apiCall->arguments()[
82 apiCall->binaryDataIndex()].toByteArray();
83 binaryDataSize += data.size();
84 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -040085
Zack Rusin20b1f6d2011-09-06 11:50:07 -040086 ++parsedCalls;
87
Zack Rusin3176ebe2011-09-06 21:11:36 -040088 delete call;
89
90 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
Zack Rusin20b1f6d2011-09-06 11:50:07 -040091 break;
92 }
93
94 }
95 assert(parsedCalls == numOfCalls);
Zack Rusin3176ebe2011-09-06 21:11:36 -040096 Q_ASSERT(parsedCalls == calls.size());
97 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
98 calls.squeeze();
99 currentFrame->setCalls(calls, binaryDataSize);
100 emit frameLoaded(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400101 }
102 }
103}
104
105void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
106{
107 m_frameMarker = marker;
108}
109
110bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
111{
112 std::string name = call->name();
113
114 switch (m_frameMarker) {
115 case ApiTrace::FrameMarker_SwapBuffers:
Zack Rusinac92a212011-09-06 18:25:34 -0400116 return name.find("SwapBuffers") != std::string::npos ||
117 name == "CGLFlushDrawable" ||
118 name == "glFrameTerminatorGREMEDY";
119 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400120 case ApiTrace::FrameMarker_Flush:
Zack Rusinac92a212011-09-06 18:25:34 -0400121 return name == "glFlush";
122 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400123 case ApiTrace::FrameMarker_Finish:
Zack Rusinac92a212011-09-06 18:25:34 -0400124 return name == "glFinish";
125 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400126 case ApiTrace::FrameMarker_Clear:
Zack Rusinac92a212011-09-06 18:25:34 -0400127 return name == "glClear";
128 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400129 }
130 return false;
131}
132
133int TraceLoader::numberOfFrames() const
134{
135 return m_frameOffsets.size();
136}
137
138int TraceLoader::numberOfCallsInFrame(int frameIdx) const
139{
140 if (frameIdx > m_frameOffsets.size()) {
141 return 0;
142 }
143 FrameOffsets::const_iterator itr =
Zack Rusinac92a212011-09-06 18:25:34 -0400144 m_frameOffsets.find(frameIdx);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400145 return itr->numberOfCalls;
146}
147
148void TraceLoader::loadHelpFile()
149{
Zack Rusinac92a212011-09-06 18:25:34 -0400150 QFile file(":/resources/glreference.tsv");
151 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
152 QString line;
153 while (!file.atEnd()) {
154 line = file.readLine();
155 QString function = line.section('\t', 0, 0).trimmed();
156 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
157 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
158 m_helpHash.insert(function, url);
159 }
160 } else {
161 qWarning() << "Couldn't open reference file "
162 << file.fileName();
163 }
164 file.close();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400165}
166
167void TraceLoader::scanTrace()
168{
Zack Rusinac92a212011-09-06 18:25:34 -0400169 QList<ApiTraceFrame*> frames;
170 ApiTraceFrame *currentFrame = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400171
Zack Rusinac92a212011-09-06 18:25:34 -0400172 Trace::Call *call;
173 Trace::File::Offset startOffset;
174 int numOfFrames = 0;
175 int numOfCalls = 0;
176 unsigned callNum = 0;
177 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400178
Zack Rusinac92a212011-09-06 18:25:34 -0400179 startOffset = m_parser.currentOffset();
180 callNum = m_parser.currentCallNumber();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400181
Zack Rusinac92a212011-09-06 18:25:34 -0400182 while ((call = m_parser.scan_call())) {
183 ++numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400184
Zack Rusinac92a212011-09-06 18:25:34 -0400185 if (isCallAFrameMarker(call)) {
186 Trace::File::Offset endOffset = m_parser.currentOffset();
187 FrameOffset frameOffset(startOffset);
188 frameOffset.numberOfCalls = numOfCalls;
189 frameOffset.callNumber = callNum;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400190
Zack Rusinac92a212011-09-06 18:25:34 -0400191 currentFrame = new ApiTraceFrame();
192 currentFrame->number = numOfFrames;
193 currentFrame->setNumChildren(numOfCalls);
194 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400195
Zack Rusinac92a212011-09-06 18:25:34 -0400196 m_frameOffsets[numOfFrames] = frameOffset;
197 ++numOfFrames;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400198
Zack Rusinac92a212011-09-06 18:25:34 -0400199 if (m_parser.percentRead() - lastPercentReport >= 5) {
200 emit parsed(m_parser.percentRead());
201 lastPercentReport = m_parser.percentRead();
202 }
203 startOffset = endOffset;
204 callNum = m_parser.currentCallNumber();
205 numOfCalls = 0;
206 }
Zack Rusinac92a212011-09-06 18:25:34 -0400207 delete call;
208 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400209
Zack Rusinac92a212011-09-06 18:25:34 -0400210 if (numOfCalls) {
Zack Rusin3176ebe2011-09-06 21:11:36 -0400211 //Trace::File::Offset endOffset = m_parser.currentOffset();
Zack Rusinac92a212011-09-06 18:25:34 -0400212 FrameOffset frameOffset(startOffset);
213 frameOffset.numberOfCalls = numOfCalls;
214 frameOffset.callNumber = callNum;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400215
Zack Rusinac92a212011-09-06 18:25:34 -0400216 currentFrame = new ApiTraceFrame();
217 currentFrame->number = numOfFrames;
218 currentFrame->setNumChildren(numOfCalls);
219 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400220
Zack Rusinac92a212011-09-06 18:25:34 -0400221 m_frameOffsets[numOfFrames] = frameOffset;
222 ++numOfFrames;
223 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400224
Zack Rusinac92a212011-09-06 18:25:34 -0400225 emit parsed(100);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400226
Zack Rusinac92a212011-09-06 18:25:34 -0400227 emit framesLoaded(frames);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400228}
229
230void TraceLoader::parseTrace()
231{
Zack Rusinac92a212011-09-06 18:25:34 -0400232 QList<ApiTraceFrame*> frames;
233 ApiTraceFrame *currentFrame = 0;
234 int frameCount = 0;
235 QVector<ApiTraceCall*> calls;
236 quint64 binaryDataSize = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400237
Zack Rusinac92a212011-09-06 18:25:34 -0400238 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400239
Zack Rusinac92a212011-09-06 18:25:34 -0400240 Trace::Call *call = m_parser.parse_call();
241 while (call) {
242 //std::cout << *call;
243 if (!currentFrame) {
244 currentFrame = new ApiTraceFrame();
245 currentFrame->number = frameCount;
246 ++frameCount;
247 }
248 ApiTraceCall *apiCall =
249 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
250 calls.append(apiCall);
251 if (apiCall->hasBinaryData()) {
252 QByteArray data =
253 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
254 binaryDataSize += data.size();
255 }
256 if (ApiTrace::isCallAFrameMarker(apiCall,
257 m_frameMarker)) {
258 calls.squeeze();
259 currentFrame->setCalls(calls, binaryDataSize);
260 calls.clear();
261 frames.append(currentFrame);
262 currentFrame = 0;
263 binaryDataSize = 0;
264 if (frames.count() >= FRAMES_TO_CACHE) {
265 emit framesLoaded(frames);
266 frames.clear();
267 }
268 if (m_parser.percentRead() - lastPercentReport >= 5) {
269 emit parsed(m_parser.percentRead());
270 lastPercentReport = m_parser.percentRead();
271 }
272 }
273 delete call;
274 call = m_parser.parse_call();
275 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400276
Zack Rusinac92a212011-09-06 18:25:34 -0400277 //last frames won't have markers
278 // it's just a bunch of Delete calls for every object
279 // after the last SwapBuffers
280 if (currentFrame) {
281 calls.squeeze();
282 currentFrame->setCalls(calls, binaryDataSize);
283 frames.append(currentFrame);
284 currentFrame = 0;
285 }
286 if (frames.count()) {
287 emit framesLoaded(frames);
288 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400289}
290
291
Zack Rusinebf971e2011-09-06 17:44:43 -0400292ApiTraceCallSignature * TraceLoader::signature(unsigned id)
293{
294 if (id >= m_signatures.count()) {
295 m_signatures.resize(id + 1);
296 return NULL;
297 } else {
298 return m_signatures[id];
299 }
300}
301
302void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
303{
304 m_signatures[id] = signature;
305}
306
307ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
308{
309 if (id >= m_enumSignatures.count()) {
310 m_enumSignatures.resize(id + 1);
311 return NULL;
312 } else {
313 return m_enumSignatures[id];
314 }
315}
316
317void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
318{
319 m_enumSignatures[id] = signature;
320}
321
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400322#include "traceloader.moc"