blob: a6ffd2978709a11d61c0323b9e687e34421c1520 [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);
José Fonseca61e61f72011-09-11 16:53:34 +010066 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
Zack Rusin3176ebe2011-09-06 21:11:36 -040067
José Fonseca61e61f72011-09-11 16:53:34 +010068 m_parser.setBookmark(frameBookmark.start);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040069
70 Trace::Call *call;
71 int parsedCalls = 0;
72 while ((call = m_parser.parse_call())) {
Zack Rusin3176ebe2011-09-06 21:11:36 -040073 ApiTraceCall *apiCall =
74 apiCallFromTraceCall(call, m_helpHash,
75 currentFrame, this);
76 calls[parsedCalls] = apiCall;
77 Q_ASSERT(calls[parsedCalls]);
78 if (apiCall->hasBinaryData()) {
79 QByteArray data =
80 apiCall->arguments()[
81 apiCall->binaryDataIndex()].toByteArray();
82 binaryDataSize += data.size();
83 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -040084
Zack Rusin20b1f6d2011-09-06 11:50:07 -040085 ++parsedCalls;
86
Zack Rusin3176ebe2011-09-06 21:11:36 -040087 delete call;
88
89 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
Zack Rusin20b1f6d2011-09-06 11:50:07 -040090 break;
91 }
92
93 }
94 assert(parsedCalls == numOfCalls);
Zack Rusin3176ebe2011-09-06 21:11:36 -040095 Q_ASSERT(parsedCalls == calls.size());
96 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
97 calls.squeeze();
98 currentFrame->setCalls(calls, binaryDataSize);
99 emit frameLoaded(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400100 }
101 }
102}
103
104void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
105{
106 m_frameMarker = marker;
107}
108
109bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
110{
111 std::string name = call->name();
112
113 switch (m_frameMarker) {
114 case ApiTrace::FrameMarker_SwapBuffers:
Zack Rusinac92a212011-09-06 18:25:34 -0400115 return name.find("SwapBuffers") != std::string::npos ||
116 name == "CGLFlushDrawable" ||
117 name == "glFrameTerminatorGREMEDY";
118 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400119 case ApiTrace::FrameMarker_Flush:
Zack Rusinac92a212011-09-06 18:25:34 -0400120 return name == "glFlush";
121 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400122 case ApiTrace::FrameMarker_Finish:
Zack Rusinac92a212011-09-06 18:25:34 -0400123 return name == "glFinish";
124 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400125 case ApiTrace::FrameMarker_Clear:
Zack Rusinac92a212011-09-06 18:25:34 -0400126 return name == "glClear";
127 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400128 }
129 return false;
130}
131
132int TraceLoader::numberOfFrames() const
133{
José Fonseca61e61f72011-09-11 16:53:34 +0100134 return m_frameBookmarks.size();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400135}
136
137int TraceLoader::numberOfCallsInFrame(int frameIdx) const
138{
José Fonseca61e61f72011-09-11 16:53:34 +0100139 if (frameIdx > m_frameBookmarks.size()) {
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400140 return 0;
141 }
José Fonseca61e61f72011-09-11 16:53:34 +0100142 FrameBookmarks::const_iterator itr =
143 m_frameBookmarks.find(frameIdx);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400144 return itr->numberOfCalls;
145}
146
147void TraceLoader::loadHelpFile()
148{
Zack Rusinac92a212011-09-06 18:25:34 -0400149 QFile file(":/resources/glreference.tsv");
150 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
151 QString line;
152 while (!file.atEnd()) {
153 line = file.readLine();
154 QString function = line.section('\t', 0, 0).trimmed();
155 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
156 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
157 m_helpHash.insert(function, url);
158 }
159 } else {
160 qWarning() << "Couldn't open reference file "
161 << file.fileName();
162 }
163 file.close();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400164}
165
166void TraceLoader::scanTrace()
167{
Zack Rusinac92a212011-09-06 18:25:34 -0400168 QList<ApiTraceFrame*> frames;
169 ApiTraceFrame *currentFrame = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400170
Zack Rusinac92a212011-09-06 18:25:34 -0400171 Trace::Call *call;
José Fonseca61e61f72011-09-11 16:53:34 +0100172 Trace::ParseBookmark startBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400173 int numOfFrames = 0;
174 int numOfCalls = 0;
Zack Rusinac92a212011-09-06 18:25:34 -0400175 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400176
José Fonseca61e61f72011-09-11 16:53:34 +0100177 m_parser.getBookmark(startBookmark);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400178
Zack Rusinac92a212011-09-06 18:25:34 -0400179 while ((call = m_parser.scan_call())) {
180 ++numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400181
Zack Rusinac92a212011-09-06 18:25:34 -0400182 if (isCallAFrameMarker(call)) {
José Fonseca61e61f72011-09-11 16:53:34 +0100183 FrameBookmark frameBookmark(startBookmark);
184 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400185
Zack Rusinac92a212011-09-06 18:25:34 -0400186 currentFrame = new ApiTraceFrame();
187 currentFrame->number = numOfFrames;
188 currentFrame->setNumChildren(numOfCalls);
189 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400190
José Fonseca61e61f72011-09-11 16:53:34 +0100191 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400192 ++numOfFrames;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400193
Zack Rusinac92a212011-09-06 18:25:34 -0400194 if (m_parser.percentRead() - lastPercentReport >= 5) {
195 emit parsed(m_parser.percentRead());
196 lastPercentReport = m_parser.percentRead();
197 }
José Fonseca61e61f72011-09-11 16:53:34 +0100198 m_parser.getBookmark(startBookmark);
Zack Rusinac92a212011-09-06 18:25:34 -0400199 numOfCalls = 0;
200 }
Zack Rusinac92a212011-09-06 18:25:34 -0400201 delete call;
202 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400203
Zack Rusinac92a212011-09-06 18:25:34 -0400204 if (numOfCalls) {
José Fonseca61e61f72011-09-11 16:53:34 +0100205 //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
206 FrameBookmark frameBookmark(startBookmark);
207 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400208
Zack Rusinac92a212011-09-06 18:25:34 -0400209 currentFrame = new ApiTraceFrame();
210 currentFrame->number = numOfFrames;
211 currentFrame->setNumChildren(numOfCalls);
212 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400213
José Fonseca61e61f72011-09-11 16:53:34 +0100214 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400215 ++numOfFrames;
216 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400217
Zack Rusinac92a212011-09-06 18:25:34 -0400218 emit parsed(100);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400219
Zack Rusinac92a212011-09-06 18:25:34 -0400220 emit framesLoaded(frames);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400221}
222
223void TraceLoader::parseTrace()
224{
Zack Rusinac92a212011-09-06 18:25:34 -0400225 QList<ApiTraceFrame*> frames;
226 ApiTraceFrame *currentFrame = 0;
227 int frameCount = 0;
228 QVector<ApiTraceCall*> calls;
229 quint64 binaryDataSize = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400230
Zack Rusinac92a212011-09-06 18:25:34 -0400231 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400232
Zack Rusinac92a212011-09-06 18:25:34 -0400233 Trace::Call *call = m_parser.parse_call();
234 while (call) {
235 //std::cout << *call;
236 if (!currentFrame) {
237 currentFrame = new ApiTraceFrame();
238 currentFrame->number = frameCount;
239 ++frameCount;
240 }
241 ApiTraceCall *apiCall =
242 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
243 calls.append(apiCall);
244 if (apiCall->hasBinaryData()) {
245 QByteArray data =
246 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
247 binaryDataSize += data.size();
248 }
249 if (ApiTrace::isCallAFrameMarker(apiCall,
250 m_frameMarker)) {
251 calls.squeeze();
252 currentFrame->setCalls(calls, binaryDataSize);
253 calls.clear();
254 frames.append(currentFrame);
255 currentFrame = 0;
256 binaryDataSize = 0;
257 if (frames.count() >= FRAMES_TO_CACHE) {
258 emit framesLoaded(frames);
259 frames.clear();
260 }
261 if (m_parser.percentRead() - lastPercentReport >= 5) {
262 emit parsed(m_parser.percentRead());
263 lastPercentReport = m_parser.percentRead();
264 }
265 }
266 delete call;
267 call = m_parser.parse_call();
268 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400269
Zack Rusinac92a212011-09-06 18:25:34 -0400270 //last frames won't have markers
271 // it's just a bunch of Delete calls for every object
272 // after the last SwapBuffers
273 if (currentFrame) {
274 calls.squeeze();
275 currentFrame->setCalls(calls, binaryDataSize);
276 frames.append(currentFrame);
277 currentFrame = 0;
278 }
279 if (frames.count()) {
280 emit framesLoaded(frames);
281 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400282}
283
284
Zack Rusinebf971e2011-09-06 17:44:43 -0400285ApiTraceCallSignature * TraceLoader::signature(unsigned id)
286{
287 if (id >= m_signatures.count()) {
288 m_signatures.resize(id + 1);
289 return NULL;
290 } else {
291 return m_signatures[id];
292 }
293}
294
295void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
296{
297 m_signatures[id] = signature;
298}
299
300ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
301{
302 if (id >= m_enumSignatures.count()) {
303 m_enumSignatures.resize(id + 1);
304 return NULL;
305 } else {
306 return m_enumSignatures[id];
307 }
308}
309
310void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
311{
312 m_enumSignatures[id] = signature;
313}
314
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400315#include "traceloader.moc"