--- /dev/null
+#include "traceloader.h"
+
+#include <QDebug>
+#include <QFile>
+
+#define FRAMES_TO_CACHE 100
+
+static ApiTraceCall *
+apiCallFromTraceCall(const Trace::Call *call,
+ const QHash<QString, QUrl> &helpHash,
+ ApiTraceFrame *frame)
+{
+ ApiTraceCall *apiCall = new ApiTraceCall(frame, call);
+
+ apiCall->setHelpUrl(helpHash.value(apiCall->name()));
+
+ return apiCall;
+}
+
+TraceLoader::TraceLoader(ApiTrace *parent)
+ : QObject(parent),
+ m_trace(parent),
+ m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
+{
+}
+
+TraceLoader::~TraceLoader()
+{
+ m_parser.close();
+}
+
+void TraceLoader::loadTrace(const QString &filename)
+{
+ if (m_helpHash.isEmpty()) {
+ loadHelpFile();
+ }
+
+ if (!m_parser.open(filename.toLatin1())) {
+ qDebug() << "error: failed to open " << filename;
+ return;
+ }
+
+ emit startedParsing();
+
+ if (m_parser.supportsOffsets()) {
+ scanTrace();
+ } else {
+ //Load the entire file into memory
+ parseTrace();
+ }
+
+ emit finishedParsing();
+}
+
+void TraceLoader::loadFrame(int frameIdx)
+{
+ if (m_parser.supportsOffsets()) {
+ int numOfCalls = numberOfCallsInFrame(frameIdx);
+ if (numOfCalls) {
+ const FrameOffset &frameOffset = m_frameOffsets[frameIdx];
+ std::vector<Trace::Call*> calls(numOfCalls);
+ m_parser.setCurrentOffset(frameOffset.start);
+ m_parser.setCurrentCallNumber(frameOffset.callNumber);
+
+ Trace::Call *call;
+ int parsedCalls = 0;
+ while ((call = m_parser.parse_call())) {
+
+ calls[parsedCalls] = call;
+ ++parsedCalls;
+
+ if (isCallAFrameMarker(call)) {
+ break;
+ }
+
+ }
+ assert(parsedCalls == numOfCalls);
+// emit parsedFrame();
+ }
+ }
+}
+
+void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
+{
+ m_frameMarker = marker;
+}
+
+bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
+{
+ std::string name = call->name();
+
+ switch (m_frameMarker) {
+ case ApiTrace::FrameMarker_SwapBuffers:
+ return name.find("SwapBuffers") != std::string::npos ||
+ name == "CGLFlushDrawable" ||
+ name == "glFrameTerminatorGREMEDY";
+ break;
+ case ApiTrace::FrameMarker_Flush:
+ return name == "glFlush";
+ break;
+ case ApiTrace::FrameMarker_Finish:
+ return name == "glFinish";
+ break;
+ case ApiTrace::FrameMarker_Clear:
+ return name == "glClear";
+ break;
+ }
+ return false;
+}
+
+int TraceLoader::numberOfFrames() const
+{
+ return m_frameOffsets.size();
+}
+
+int TraceLoader::numberOfCallsInFrame(int frameIdx) const
+{
+ if (frameIdx > m_frameOffsets.size()) {
+ return 0;
+ }
+ FrameOffsets::const_iterator itr =
+ m_frameOffsets.find(frameIdx);
+ return itr->numberOfCalls;
+}
+
+void TraceLoader::loadHelpFile()
+{
+ QFile file(":/resources/glreference.tsv");
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QString line;
+ while (!file.atEnd()) {
+ line = file.readLine();
+ QString function = line.section('\t', 0, 0).trimmed();
+ QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
+ //qDebug()<<"function = "<<function<<", url = "<<url.toString();
+ m_helpHash.insert(function, url);
+ }
+ } else {
+ qWarning() << "Couldn't open reference file "
+ << file.fileName();
+ }
+ file.close();
+}
+
+void TraceLoader::scanTrace()
+{
+ QList<ApiTraceFrame*> frames;
+ ApiTraceFrame *currentFrame = 0;
+
+ Trace::Call *call;
+ Trace::File::Offset startOffset;
+ int numOfFrames = 0;
+ int numOfCalls = 0;
+ unsigned callNum = 0;
+ int lastPercentReport = 0;
+
+ startOffset = m_parser.currentOffset();
+ callNum = m_parser.currentCallNumber();
+
+ while ((call = m_parser.scan_call())) {
+ ++numOfCalls;
+
+ if (isCallAFrameMarker(call)) {
+ Trace::File::Offset endOffset = m_parser.currentOffset();
+ FrameOffset frameOffset(startOffset);
+ frameOffset.numberOfCalls = numOfCalls;
+ frameOffset.callNumber = callNum;
+
+ currentFrame = new ApiTraceFrame(m_trace);
+ currentFrame->number = numOfFrames;
+ currentFrame->setNumChildren(numOfCalls);
+ frames.append(currentFrame);
+
+ m_frameOffsets[numOfFrames] = frameOffset;
+ ++numOfFrames;
+
+ if (m_parser.percentRead() - lastPercentReport >= 5) {
+ emit parsed(m_parser.percentRead());
+ lastPercentReport = m_parser.percentRead();
+ }
+ startOffset = endOffset;
+ callNum = m_parser.currentCallNumber();
+ numOfCalls = 0;
+ }
+ //call->dump(std::cout, color);
+ delete call;
+ }
+
+ if (numOfCalls) {
+// Trace::File::Offset endOffset = m_parser.currentOffset();
+ FrameOffset frameOffset(startOffset);
+ frameOffset.numberOfCalls = numOfCalls;
+ frameOffset.callNumber = callNum;
+
+ currentFrame = new ApiTraceFrame(m_trace);
+ currentFrame->number = numOfFrames;
+ currentFrame->setNumChildren(numOfCalls);
+ frames.append(currentFrame);
+
+ m_frameOffsets[numOfFrames] = frameOffset;
+ ++numOfFrames;
+ }
+
+ emit parsed(100);
+
+ emit framesLoaded(frames);
+}
+
+void TraceLoader::parseTrace()
+{
+ QList<ApiTraceFrame*> frames;
+ ApiTraceFrame *currentFrame = 0;
+ int frameCount = 0;
+ QVector<ApiTraceCall*> calls;
+ quint64 binaryDataSize = 0;
+
+ int lastPercentReport = 0;
+
+ Trace::Call *call = m_parser.parse_call();
+ while (call) {
+ //std::cout << *call;
+ if (!currentFrame) {
+ currentFrame = new ApiTraceFrame(m_trace);
+ currentFrame->number = frameCount;
+ ++frameCount;
+ }
+ ApiTraceCall *apiCall =
+ apiCallFromTraceCall(call, m_helpHash, currentFrame);
+ calls.append(apiCall);
+ if (apiCall->hasBinaryData()) {
+ QByteArray data =
+ apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
+ binaryDataSize += data.size();
+ }
+ if (ApiTrace::isCallAFrameMarker(apiCall,
+ m_frameMarker)) {
+ calls.squeeze();
+ currentFrame->setCalls(calls, binaryDataSize);
+ calls.clear();
+ frames.append(currentFrame);
+ currentFrame = 0;
+ binaryDataSize = 0;
+ if (frames.count() >= FRAMES_TO_CACHE) {
+ emit framesLoaded(frames);
+ frames.clear();
+ }
+ if (m_parser.percentRead() - lastPercentReport >= 5) {
+ emit parsed(m_parser.percentRead());
+ lastPercentReport = m_parser.percentRead();
+ }
+ }
+ delete call;
+ call = m_parser.parse_call();
+ }
+
+ //last frames won't have markers
+ // it's just a bunch of Delete calls for every object
+ // after the last SwapBuffers
+ if (currentFrame) {
+ if (!frames.count()) {
+ calls.squeeze();
+ currentFrame->setCalls(calls, binaryDataSize);
+ }
+ frames.append(currentFrame);
+ currentFrame = 0;
+ }
+ if (frames.count()) {
+ emit framesLoaded(frames);
+ }
+}
+
+
+#include "traceloader.moc"