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