]> git.cworth.org Git - apitrace/blob - gui/traceloader.cpp
Encapsulate on parser state in structure.
[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 FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
67
68             m_parser.setBookmark(frameBookmark.start);
69
70             Trace::Call *call;
71             int parsedCalls = 0;
72             while ((call = m_parser.parse_call())) {
73                 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                 }
84
85                 ++parsedCalls;
86
87                 delete call;
88
89                 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
90                     break;
91                 }
92
93             }
94             assert(parsedCalls == numOfCalls);
95             Q_ASSERT(parsedCalls == calls.size());
96             Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
97             calls.squeeze();
98             currentFrame->setCalls(calls, binaryDataSize);
99             emit frameLoaded(currentFrame);
100         }
101     }
102 }
103
104 void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
105 {
106     m_frameMarker = marker;
107 }
108
109 bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
110 {
111     std::string name = call->name();
112
113     switch (m_frameMarker) {
114     case ApiTrace::FrameMarker_SwapBuffers:
115         return  name.find("SwapBuffers") != std::string::npos ||
116                 name == "CGLFlushDrawable" ||
117                 name == "glFrameTerminatorGREMEDY";
118         break;
119     case ApiTrace::FrameMarker_Flush:
120         return name == "glFlush";
121         break;
122     case ApiTrace::FrameMarker_Finish:
123         return name == "glFinish";
124         break;
125     case ApiTrace::FrameMarker_Clear:
126         return name == "glClear";
127         break;
128     }
129     return false;
130 }
131
132 int TraceLoader::numberOfFrames() const
133 {
134     return m_frameBookmarks.size();
135 }
136
137 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
138 {
139     if (frameIdx > m_frameBookmarks.size()) {
140         return 0;
141     }
142     FrameBookmarks::const_iterator itr =
143             m_frameBookmarks.find(frameIdx);
144     return itr->numberOfCalls;
145 }
146
147 void TraceLoader::loadHelpFile()
148 {
149     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();
164 }
165
166 void TraceLoader::scanTrace()
167 {
168     QList<ApiTraceFrame*> frames;
169     ApiTraceFrame *currentFrame = 0;
170
171     Trace::Call *call;
172     Trace::ParseBookmark startBookmark;
173     int numOfFrames = 0;
174     int numOfCalls = 0;
175     int lastPercentReport = 0;
176
177     m_parser.getBookmark(startBookmark);
178
179     while ((call = m_parser.scan_call())) {
180         ++numOfCalls;
181
182         if (isCallAFrameMarker(call)) {
183             FrameBookmark frameBookmark(startBookmark);
184             frameBookmark.numberOfCalls = numOfCalls;
185
186             currentFrame = new ApiTraceFrame();
187             currentFrame->number = numOfFrames;
188             currentFrame->setNumChildren(numOfCalls);
189             frames.append(currentFrame);
190
191             m_frameBookmarks[numOfFrames] = frameBookmark;
192             ++numOfFrames;
193
194             if (m_parser.percentRead() - lastPercentReport >= 5) {
195                 emit parsed(m_parser.percentRead());
196                 lastPercentReport = m_parser.percentRead();
197             }
198             m_parser.getBookmark(startBookmark);
199             numOfCalls = 0;
200         }
201         delete call;
202     }
203
204     if (numOfCalls) {
205         //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
206         FrameBookmark frameBookmark(startBookmark);
207         frameBookmark.numberOfCalls = numOfCalls;
208
209         currentFrame = new ApiTraceFrame();
210         currentFrame->number = numOfFrames;
211         currentFrame->setNumChildren(numOfCalls);
212         frames.append(currentFrame);
213
214         m_frameBookmarks[numOfFrames] = frameBookmark;
215         ++numOfFrames;
216     }
217
218     emit parsed(100);
219
220     emit framesLoaded(frames);
221 }
222
223 void TraceLoader::parseTrace()
224 {
225     QList<ApiTraceFrame*> frames;
226     ApiTraceFrame *currentFrame = 0;
227     int frameCount = 0;
228     QVector<ApiTraceCall*> calls;
229     quint64 binaryDataSize = 0;
230
231     int lastPercentReport = 0;
232
233     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     }
269
270     //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     }
282 }
283
284
285 ApiTraceCallSignature * 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
295 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
296 {
297     m_signatures[id] = signature;
298 }
299
300 ApiTraceEnumSignature * 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
310 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
311 {
312     m_enumSignatures[id] = signature;
313 }
314
315 #include "traceloader.moc"