]> git.cworth.org Git - apitrace/blob - gui/traceloader.cpp
First working on demand loading!
[apitrace] / gui / traceloader.cpp
1 #include "traceloader.h"
2
3 #include "apitrace.h"
4 #include <QDebug>
5 #include <QFile>
6
7 #define FRAMES_TO_CACHE 100
8
9 static ApiTraceCall *
10 apiCallFromTraceCall(const Trace::Call *call,
11                      const QHash<QString, QUrl> &helpHash,
12                      ApiTraceFrame *frame,
13                      TraceLoader *loader)
14 {
15     ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
16
17     apiCall->setHelpUrl(helpHash.value(apiCall->name()));
18
19     return apiCall;
20 }
21
22 TraceLoader::TraceLoader(QObject *parent)
23     : QObject(parent),
24       m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
25 {
26 }
27
28 TraceLoader::~TraceLoader()
29 {
30     m_parser.close();
31 }
32
33 void 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     }
43     qDebug()<<"load trace with "<<filename;
44     emit startedParsing();
45
46     qDebug() <<"\t support offsets = "<<m_parser.supportsOffsets();
47     if (m_parser.supportsOffsets()) {
48         scanTrace();
49     } else {
50         //Load the entire file into memory
51         parseTrace();
52     }
53
54     emit finishedParsing();
55 }
56
57 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
58 {
59     if (m_parser.supportsOffsets()) {
60         unsigned frameIdx = currentFrame->number;
61         int numOfCalls = numberOfCallsInFrame(frameIdx);
62
63         if (numOfCalls) {
64             quint64 binaryDataSize = 0;
65             QVector<ApiTraceCall*> calls(numOfCalls);
66             const FrameOffset &frameOffset = m_frameOffsets[frameIdx];
67
68             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())) {
74                 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                 }
85
86                 ++parsedCalls;
87
88                 delete call;
89
90                 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
91                     break;
92                 }
93
94             }
95             assert(parsedCalls == numOfCalls);
96             Q_ASSERT(parsedCalls == calls.size());
97             Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
98             calls.squeeze();
99             currentFrame->setCalls(calls, binaryDataSize);
100             emit frameLoaded(currentFrame);
101         }
102     }
103 }
104
105 void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
106 {
107     m_frameMarker = marker;
108 }
109
110 bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
111 {
112     std::string name = call->name();
113
114     switch (m_frameMarker) {
115     case ApiTrace::FrameMarker_SwapBuffers:
116         return  name.find("SwapBuffers") != std::string::npos ||
117                 name == "CGLFlushDrawable" ||
118                 name == "glFrameTerminatorGREMEDY";
119         break;
120     case ApiTrace::FrameMarker_Flush:
121         return name == "glFlush";
122         break;
123     case ApiTrace::FrameMarker_Finish:
124         return name == "glFinish";
125         break;
126     case ApiTrace::FrameMarker_Clear:
127         return name == "glClear";
128         break;
129     }
130     return false;
131 }
132
133 int TraceLoader::numberOfFrames() const
134 {
135     return m_frameOffsets.size();
136 }
137
138 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
139 {
140     if (frameIdx > m_frameOffsets.size()) {
141         return 0;
142     }
143     FrameOffsets::const_iterator itr =
144             m_frameOffsets.find(frameIdx);
145     return itr->numberOfCalls;
146 }
147
148 void TraceLoader::loadHelpFile()
149 {
150     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();
165 }
166
167 void TraceLoader::scanTrace()
168 {
169     QList<ApiTraceFrame*> frames;
170     ApiTraceFrame *currentFrame = 0;
171
172     Trace::Call *call;
173     Trace::File::Offset startOffset;
174     int numOfFrames = 0;
175     int numOfCalls = 0;
176     unsigned callNum = 0;
177     int lastPercentReport = 0;
178
179     startOffset = m_parser.currentOffset();
180     callNum = m_parser.currentCallNumber();
181
182     while ((call = m_parser.scan_call())) {
183         ++numOfCalls;
184
185         if (isCallAFrameMarker(call)) {
186             Trace::File::Offset endOffset = m_parser.currentOffset();
187             FrameOffset frameOffset(startOffset);
188             frameOffset.numberOfCalls = numOfCalls;
189             frameOffset.callNumber = callNum;
190
191             currentFrame = new ApiTraceFrame();
192             currentFrame->number = numOfFrames;
193             currentFrame->setNumChildren(numOfCalls);
194             frames.append(currentFrame);
195
196             m_frameOffsets[numOfFrames] = frameOffset;
197             ++numOfFrames;
198
199             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         }
207         delete call;
208     }
209
210     if (numOfCalls) {
211         //Trace::File::Offset endOffset = m_parser.currentOffset();
212         FrameOffset frameOffset(startOffset);
213         frameOffset.numberOfCalls = numOfCalls;
214         frameOffset.callNumber = callNum;
215
216         currentFrame = new ApiTraceFrame();
217         currentFrame->number = numOfFrames;
218         currentFrame->setNumChildren(numOfCalls);
219         frames.append(currentFrame);
220
221         m_frameOffsets[numOfFrames] = frameOffset;
222         ++numOfFrames;
223     }
224
225     emit parsed(100);
226
227     emit framesLoaded(frames);
228 }
229
230 void TraceLoader::parseTrace()
231 {
232     QList<ApiTraceFrame*> frames;
233     ApiTraceFrame *currentFrame = 0;
234     int frameCount = 0;
235     QVector<ApiTraceCall*> calls;
236     quint64 binaryDataSize = 0;
237
238     int lastPercentReport = 0;
239
240     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     }
276
277     //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     }
289 }
290
291
292 ApiTraceCallSignature * 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
302 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
303 {
304     m_signatures[id] = signature;
305 }
306
307 ApiTraceEnumSignature * 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
317 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
318 {
319     m_enumSignatures[id] = signature;
320 }
321
322 #include "traceloader.moc"