blob: 40609adef6ef2ca6d83f2deba811b40f467c061f [file] [log] [blame]
Zack Rusin20b1f6d2011-09-06 11:50:07 -04001#include "traceloader.h"
2
3#include <QDebug>
4#include <QFile>
5
6#define FRAMES_TO_CACHE 100
7
8static ApiTraceCall *
9apiCallFromTraceCall(const Trace::Call *call,
10 const QHash<QString, QUrl> &helpHash,
11 ApiTraceFrame *frame)
12{
13 ApiTraceCall *apiCall = new ApiTraceCall(frame, call);
14
15 apiCall->setHelpUrl(helpHash.value(apiCall->name()));
16
17 return apiCall;
18}
19
20TraceLoader::TraceLoader(ApiTrace *parent)
21 : QObject(parent),
22 m_trace(parent),
23 m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
24{
25}
26
27TraceLoader::~TraceLoader()
28{
29 m_parser.close();
30}
31
32void TraceLoader::loadTrace(const QString &filename)
33{
34 if (m_helpHash.isEmpty()) {
35 loadHelpFile();
36 }
37
38 if (!m_parser.open(filename.toLatin1())) {
39 qDebug() << "error: failed to open " << filename;
40 return;
41 }
42
43 emit startedParsing();
44
45 if (m_parser.supportsOffsets()) {
46 scanTrace();
47 } else {
48 //Load the entire file into memory
49 parseTrace();
50 }
51
52 emit finishedParsing();
53}
54
55void TraceLoader::loadFrame(int frameIdx)
56{
57 if (m_parser.supportsOffsets()) {
58 int numOfCalls = numberOfCallsInFrame(frameIdx);
59 if (numOfCalls) {
60 const FrameOffset &frameOffset = m_frameOffsets[frameIdx];
61 std::vector<Trace::Call*> calls(numOfCalls);
62 m_parser.setCurrentOffset(frameOffset.start);
63 m_parser.setCurrentCallNumber(frameOffset.callNumber);
64
65 Trace::Call *call;
66 int parsedCalls = 0;
67 while ((call = m_parser.parse_call())) {
68
69 calls[parsedCalls] = call;
70 ++parsedCalls;
71
72 if (isCallAFrameMarker(call)) {
73 break;
74 }
75
76 }
77 assert(parsedCalls == numOfCalls);
78// emit parsedFrame();
79 }
80 }
81}
82
83void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
84{
85 m_frameMarker = marker;
86}
87
88bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
89{
90 std::string name = call->name();
91
92 switch (m_frameMarker) {
93 case ApiTrace::FrameMarker_SwapBuffers:
94 return name.find("SwapBuffers") != std::string::npos ||
95 name == "CGLFlushDrawable" ||
96 name == "glFrameTerminatorGREMEDY";
97 break;
98 case ApiTrace::FrameMarker_Flush:
99 return name == "glFlush";
100 break;
101 case ApiTrace::FrameMarker_Finish:
102 return name == "glFinish";
103 break;
104 case ApiTrace::FrameMarker_Clear:
105 return name == "glClear";
106 break;
107 }
108 return false;
109}
110
111int TraceLoader::numberOfFrames() const
112{
113 return m_frameOffsets.size();
114}
115
116int TraceLoader::numberOfCallsInFrame(int frameIdx) const
117{
118 if (frameIdx > m_frameOffsets.size()) {
119 return 0;
120 }
121 FrameOffsets::const_iterator itr =
122 m_frameOffsets.find(frameIdx);
123 return itr->numberOfCalls;
124}
125
126void TraceLoader::loadHelpFile()
127{
128 QFile file(":/resources/glreference.tsv");
129 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
130 QString line;
131 while (!file.atEnd()) {
132 line = file.readLine();
133 QString function = line.section('\t', 0, 0).trimmed();
134 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
135 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
136 m_helpHash.insert(function, url);
137 }
138 } else {
139 qWarning() << "Couldn't open reference file "
140 << file.fileName();
141 }
142 file.close();
143}
144
145void TraceLoader::scanTrace()
146{
147 QList<ApiTraceFrame*> frames;
148 ApiTraceFrame *currentFrame = 0;
149
150 Trace::Call *call;
151 Trace::File::Offset startOffset;
152 int numOfFrames = 0;
153 int numOfCalls = 0;
154 unsigned callNum = 0;
155 int lastPercentReport = 0;
156
157 startOffset = m_parser.currentOffset();
158 callNum = m_parser.currentCallNumber();
159
160 while ((call = m_parser.scan_call())) {
161 ++numOfCalls;
162
163 if (isCallAFrameMarker(call)) {
164 Trace::File::Offset endOffset = m_parser.currentOffset();
165 FrameOffset frameOffset(startOffset);
166 frameOffset.numberOfCalls = numOfCalls;
167 frameOffset.callNumber = callNum;
168
169 currentFrame = new ApiTraceFrame(m_trace);
170 currentFrame->number = numOfFrames;
171 currentFrame->setNumChildren(numOfCalls);
172 frames.append(currentFrame);
173
174 m_frameOffsets[numOfFrames] = frameOffset;
175 ++numOfFrames;
176
177 if (m_parser.percentRead() - lastPercentReport >= 5) {
178 emit parsed(m_parser.percentRead());
179 lastPercentReport = m_parser.percentRead();
180 }
181 startOffset = endOffset;
182 callNum = m_parser.currentCallNumber();
183 numOfCalls = 0;
184 }
185 //call->dump(std::cout, color);
186 delete call;
187 }
188
189 if (numOfCalls) {
190// Trace::File::Offset endOffset = m_parser.currentOffset();
191 FrameOffset frameOffset(startOffset);
192 frameOffset.numberOfCalls = numOfCalls;
193 frameOffset.callNumber = callNum;
194
195 currentFrame = new ApiTraceFrame(m_trace);
196 currentFrame->number = numOfFrames;
197 currentFrame->setNumChildren(numOfCalls);
198 frames.append(currentFrame);
199
200 m_frameOffsets[numOfFrames] = frameOffset;
201 ++numOfFrames;
202 }
203
204 emit parsed(100);
205
206 emit framesLoaded(frames);
207}
208
209void TraceLoader::parseTrace()
210{
211 QList<ApiTraceFrame*> frames;
212 ApiTraceFrame *currentFrame = 0;
213 int frameCount = 0;
214 QVector<ApiTraceCall*> calls;
215 quint64 binaryDataSize = 0;
216
217 int lastPercentReport = 0;
218
219 Trace::Call *call = m_parser.parse_call();
220 while (call) {
221 //std::cout << *call;
222 if (!currentFrame) {
223 currentFrame = new ApiTraceFrame(m_trace);
224 currentFrame->number = frameCount;
225 ++frameCount;
226 }
227 ApiTraceCall *apiCall =
228 apiCallFromTraceCall(call, m_helpHash, currentFrame);
229 calls.append(apiCall);
230 if (apiCall->hasBinaryData()) {
231 QByteArray data =
232 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
233 binaryDataSize += data.size();
234 }
235 if (ApiTrace::isCallAFrameMarker(apiCall,
236 m_frameMarker)) {
237 calls.squeeze();
238 currentFrame->setCalls(calls, binaryDataSize);
239 calls.clear();
240 frames.append(currentFrame);
241 currentFrame = 0;
242 binaryDataSize = 0;
243 if (frames.count() >= FRAMES_TO_CACHE) {
244 emit framesLoaded(frames);
245 frames.clear();
246 }
247 if (m_parser.percentRead() - lastPercentReport >= 5) {
248 emit parsed(m_parser.percentRead());
249 lastPercentReport = m_parser.percentRead();
250 }
251 }
252 delete call;
253 call = m_parser.parse_call();
254 }
255
256 //last frames won't have markers
257 // it's just a bunch of Delete calls for every object
258 // after the last SwapBuffers
259 if (currentFrame) {
260 if (!frames.count()) {
261 calls.squeeze();
262 currentFrame->setCalls(calls, binaryDataSize);
263 }
264 frames.append(currentFrame);
265 currentFrame = 0;
266 }
267 if (frames.count()) {
268 emit framesLoaded(frames);
269 }
270}
271
272
273#include "traceloader.moc"