]> git.cworth.org Git - apitrace/blobdiff - gui/traceloader.cpp
readme: Provide a GLEW_KHR_debug example instead of GLEW_GREMEDY_string_marker.
[apitrace] / gui / traceloader.cpp
index 0fee815ff6a811bbac9a58e9099453de6aa71fa5..27886dc65607adb59b69789dca962af957a6ca98 100644 (file)
@@ -3,16 +3,23 @@
 #include "apitrace.h"
 #include <QDebug>
 #include <QFile>
+#include <QStack>
 
 #define FRAMES_TO_CACHE 100
 
 static ApiTraceCall *
-apiCallFromTraceCall(const Trace::Call *call,
+apiCallFromTraceCall(const trace::Call *call,
                      const QHash<QString, QUrl> &helpHash,
                      ApiTraceFrame *frame,
+                     ApiTraceCall *parentCall,
                      TraceLoader *loader)
 {
-    ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
+    ApiTraceCall *apiCall;
+
+    if (parentCall)
+        apiCall = new ApiTraceCall(parentCall, loader, call);
+    else
+        apiCall = new ApiTraceCall(frame, loader, call);
 
     apiCall->setHelpUrl(helpHash.value(apiCall->name()));
 
@@ -20,8 +27,7 @@ apiCallFromTraceCall(const Trace::Call *call,
 }
 
 TraceLoader::TraceLoader(QObject *parent)
-    : QObject(parent),
-      m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
+    : QObject(parent)
 {
 }
 
@@ -38,6 +44,16 @@ void TraceLoader::loadTrace(const QString &filename)
         loadHelpFile();
     }
 
+    if (!m_frameBookmarks.isEmpty()) {
+        qDeleteAll(m_signatures);
+        qDeleteAll(m_enumSignatures);
+        m_signatures.clear();
+        m_enumSignatures.clear();
+        m_frameBookmarks.clear();
+        m_createdFrames.clear();
+        m_parser.close();
+    }
+
     if (!m_parser.open(filename.toLatin1())) {
         qDebug() << "error: failed to open " << filename;
         return;
@@ -51,7 +67,7 @@ void TraceLoader::loadTrace(const QString &filename)
         //Load the entire file into memory
         parseTrace();
     }
-
+    emit guessedApi(static_cast<int>(m_parser.api));
     emit finishedParsing();
 }
 
@@ -60,34 +76,6 @@ void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
     fetchFrameContents(currentFrame);
 }
 
-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_frameBookmarks.size();
@@ -95,7 +83,7 @@ int TraceLoader::numberOfFrames() const
 
 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
 {
-    if (frameIdx > m_frameBookmarks.size()) {
+    if (frameIdx >= m_frameBookmarks.size()) {
         return 0;
     }
     FrameBookmarks::const_iterator itr =
@@ -127,8 +115,8 @@ void TraceLoader::scanTrace()
     QList<ApiTraceFrame*> frames;
     ApiTraceFrame *currentFrame = 0;
 
-    Trace::Call *call;
-    Trace::ParseBookmark startBookmark;
+    trace::Call *call;
+    trace::ParseBookmark startBookmark;
     int numOfFrames = 0;
     int numOfCalls = 0;
     int lastPercentReport = 0;
@@ -138,7 +126,7 @@ void TraceLoader::scanTrace()
     while ((call = m_parser.scan_call())) {
         ++numOfCalls;
 
-        if (isCallAFrameMarker(call)) {
+        if (call->flags & trace::CALL_FLAG_END_FRAME) {
             FrameBookmark frameBookmark(startBookmark);
             frameBookmark.numberOfCalls = numOfCalls;
 
@@ -163,7 +151,7 @@ void TraceLoader::scanTrace()
     }
 
     if (numOfCalls) {
-        //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
+        //trace::File::Bookmark endBookmark = m_parser.currentBookmark();
         FrameBookmark frameBookmark(startBookmark);
         frameBookmark.numberOfCalls = numOfCalls;
 
@@ -187,12 +175,14 @@ void TraceLoader::parseTrace()
     QList<ApiTraceFrame*> frames;
     ApiTraceFrame *currentFrame = 0;
     int frameCount = 0;
-    QVector<ApiTraceCall*> calls;
+    QStack<ApiTraceCall*> groups;
+    QVector<ApiTraceCall*> topLevelItems;
+    QVector<ApiTraceCall*> allCalls;
     quint64 binaryDataSize = 0;
 
     int lastPercentReport = 0;
 
-    Trace::Call *call = m_parser.parse_call();
+    trace::Call *call = m_parser.parse_call();
     while (call) {
         //std::cout << *call;
         if (!currentFrame) {
@@ -201,18 +191,36 @@ void TraceLoader::parseTrace()
             ++frameCount;
         }
         ApiTraceCall *apiCall =
-                apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
-        calls.append(apiCall);
+            apiCallFromTraceCall(call, m_helpHash, currentFrame, groups.isEmpty() ? 0 : groups.top(), this);
+        allCalls.append(apiCall);
+        if (groups.count() == 0) {
+            topLevelItems.append(apiCall);
+        }
+        if (call->flags & trace::CALL_FLAG_MARKER_PUSH) {
+            groups.push(apiCall);
+        } else if (call->flags & trace::CALL_FLAG_MARKER_POP) {
+            groups.top()->finishedAddingChildren();
+            groups.pop();
+        }
+        if (!groups.isEmpty()) {
+            groups.top()->addChild(apiCall);
+        }
         if (apiCall->hasBinaryData()) {
             QByteArray data =
-                    apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
+                apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
             binaryDataSize += data.size();
         }
-        if (ApiTrace::isCallAFrameMarker(apiCall,
-                                         m_frameMarker)) {
-            calls.squeeze();
-            currentFrame->setCalls(calls, binaryDataSize);
-            calls.clear();
+        if (call->flags & trace::CALL_FLAG_END_FRAME) {
+            allCalls.squeeze();
+            topLevelItems.squeeze();
+            if (topLevelItems.count() == allCalls.count()) {
+                currentFrame->setCalls(allCalls, allCalls, binaryDataSize);
+            } else {
+                currentFrame->setCalls(topLevelItems, allCalls, binaryDataSize);
+            }
+            allCalls.clear();
+            groups.clear();
+            topLevelItems.clear();
             frames.append(currentFrame);
             currentFrame = 0;
             binaryDataSize = 0;
@@ -233,8 +241,12 @@ void TraceLoader::parseTrace()
     //  it's just a bunch of Delete calls for every object
     //  after the last SwapBuffers
     if (currentFrame) {
-        calls.squeeze();
-        currentFrame->setCalls(calls, binaryDataSize);
+        allCalls.squeeze();
+        if (topLevelItems.count() == allCalls.count()) {
+            currentFrame->setCalls(allCalls, allCalls, binaryDataSize);
+        } else {
+            currentFrame->setCalls(topLevelItems, allCalls, binaryDataSize);
+        }
         frames.append(currentFrame);
         currentFrame = 0;
     }
@@ -274,25 +286,25 @@ void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature
     m_enumSignatures[id] = signature;
 }
 
-void TraceLoader::searchNext(int startFrame,
-                             const QString &str,
-                             Qt::CaseSensitivity sensitivity)
+void TraceLoader::searchNext(const ApiTrace::SearchRequest &request)
 {
     Q_ASSERT(m_parser.supportsOffsets());
     if (m_parser.supportsOffsets()) {
+        int startFrame = m_createdFrames.indexOf(request.frame);
         const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
         m_parser.setBookmark(frameBookmark.start);
-        Trace::Call *call = 0;
+        trace::Call *call = 0;
         while ((call = m_parser.parse_call())) {
 
-            if (callContains(call, str, sensitivity)) {
+            if (callContains(call, request.text, request.cs)) {
                 unsigned frameIdx = callInFrame(call->no);
                 ApiTraceFrame *frame = m_createdFrames[frameIdx];
                 const QVector<ApiTraceCall*> calls =
                         fetchFrameContents(frame);
                 for (int i = 0; i < calls.count(); ++i) {
                     if (calls[i]->index() == call->no) {
-                        emit searchResult(ApiTrace::SearchResult_Found, calls[i]);
+                        emit searchResult(request, ApiTrace::SearchResult_Found,
+                                          calls[i]);
                         break;
                     }
                 }
@@ -303,17 +315,16 @@ void TraceLoader::searchNext(int startFrame,
             delete call;
         }
     }
-    emit searchResult(ApiTrace::SearchResult_NotFound, 0);
+    emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
 }
 
-void TraceLoader::searchPrev(int startFrame,
-                             const QString &str,
-                             Qt::CaseSensitivity sensitivity)
+void TraceLoader::searchPrev(const ApiTrace::SearchRequest &request)
 {
     Q_ASSERT(m_parser.supportsOffsets());
     if (m_parser.supportsOffsets()) {
-        Trace::Call *call = 0;
-        QList<Trace::Call*> frameCalls;
+        int startFrame = m_createdFrames.indexOf(request.frame);
+        trace::Call *call = 0;
+        QList<trace::Call*> frameCalls;
         int frameIdx = startFrame;
 
         const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
@@ -328,7 +339,7 @@ void TraceLoader::searchPrev(int startFrame,
             if (numCallsToParse == 0) {
                 bool foundCall = searchCallsBackwards(frameCalls,
                                                       frameIdx,
-                                                      str, sensitivity);
+                                                      request);
 
                 qDeleteAll(frameCalls);
                 frameCalls.clear();
@@ -347,23 +358,24 @@ void TraceLoader::searchPrev(int startFrame,
             }
         }
     }
-    emit searchResult(ApiTrace::SearchResult_NotFound, 0);
+    emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
 }
 
-bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
+bool TraceLoader::searchCallsBackwards(const QList<trace::Call*> &calls,
                                        int frameIdx,
-                                       const QString &str,
-                                       Qt::CaseSensitivity sensitivity)
+                                       const ApiTrace::SearchRequest &request)
 {
     for (int i = calls.count() - 1; i >= 0; --i) {
-        Trace::Call *call = calls[i];
-        if (callContains(call, str, sensitivity)) {
+        trace::Call *call = calls[i];
+        if (callContains(call, request.text, request.cs)) {
             ApiTraceFrame *frame = m_createdFrames[frameIdx];
             const QVector<ApiTraceCall*> apiCalls =
                     fetchFrameContents(frame);
             for (int i = 0; i < apiCalls.count(); ++i) {
                 if (apiCalls[i]->index() == call->no) {
-                    emit searchResult(ApiTrace::SearchResult_Found, apiCalls[i]);
+                    emit searchResult(request,
+                                      ApiTrace::SearchResult_Found,
+                                      apiCalls[i]);
                     break;
                 }
             }
@@ -377,7 +389,7 @@ int TraceLoader::callInFrame(int callIdx) const
 {
     unsigned numCalls = 0;
 
-    for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) {
+    for (int frameIdx = 0; frameIdx < m_frameBookmarks.size(); ++frameIdx) {
         const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
         unsigned firstCall = numCalls;
         unsigned endCall = numCalls + frameBookmark.numberOfCalls;
@@ -390,15 +402,15 @@ int TraceLoader::callInFrame(int callIdx) const
     return 0;
 }
 
-bool TraceLoader::callContains(Trace::Call *call,
+bool TraceLoader::callContains(trace::Call *call,
                                const QString &str,
                                Qt::CaseSensitivity sensitivity)
 {
     /*
-     * FIXME: do string comparison directly on Trace::Call
+     * FIXME: do string comparison directly on trace::Call
      */
     ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
-                                                 0, this);
+                                                 0, 0, this);
     bool result = apiCall->contains(str, sensitivity);
     delete apiCall;
     return result;
@@ -419,19 +431,34 @@ TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
 
         if (numOfCalls) {
             quint64 binaryDataSize = 0;
-            QVector<ApiTraceCall*> calls(numOfCalls);
+            QStack<ApiTraceCall*> groups;
+            QVector<ApiTraceCall*> topLevelItems;
+            QVector<ApiTraceCall*> allCalls(numOfCalls);
             const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
 
             m_parser.setBookmark(frameBookmark.start);
 
-            Trace::Call *call;
+            trace::Call *call;
             int parsedCalls = 0;
             while ((call = m_parser.parse_call())) {
                 ApiTraceCall *apiCall =
                     apiCallFromTraceCall(call, m_helpHash,
-                                         currentFrame, this);
-                calls[parsedCalls] = apiCall;
-                Q_ASSERT(calls[parsedCalls]);
+                                         currentFrame, groups.isEmpty() ? 0 : groups.top(), this);
+                Q_ASSERT(apiCall);
+                Q_ASSERT(parsedCalls < allCalls.size());
+                allCalls[parsedCalls++] = apiCall;
+                if (groups.count() == 0) {
+                    topLevelItems.append(apiCall);
+                }
+                if (!groups.isEmpty()) {
+                    groups.top()->addChild(apiCall);
+                }
+                if (call->flags & trace::CALL_FLAG_MARKER_PUSH) {
+                    groups.push(apiCall);
+                } else if (call->flags & trace::CALL_FLAG_MARKER_POP) {
+                    groups.top()->finishedAddingChildren();
+                    groups.pop();
+                }
                 if (apiCall->hasBinaryData()) {
                     QByteArray data =
                         apiCall->arguments()[
@@ -439,23 +466,29 @@ TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
                     binaryDataSize += data.size();
                 }
 
-                ++parsedCalls;
-
                 delete call;
 
-                if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
+                if (apiCall->flags() & trace::CALL_FLAG_END_FRAME) {
                     break;
                 }
 
             }
-            assert(parsedCalls == numOfCalls);
-            Q_ASSERT(parsedCalls == calls.size());
-            calls.squeeze();
-
-            Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
-            emit frameContentsLoaded(currentFrame,
-                                     calls, binaryDataSize);
-            return calls;
+            // There can be fewer parsed calls when call in different
+            // threads cross the frame boundary
+            Q_ASSERT(parsedCalls <= numOfCalls);
+            Q_ASSERT(parsedCalls <= allCalls.size());
+            allCalls.resize(parsedCalls);
+            allCalls.squeeze();
+
+            Q_ASSERT(parsedCalls <= currentFrame->numChildrenToLoad());
+            if (topLevelItems.count() == allCalls.count()) {
+                emit frameContentsLoaded(currentFrame, allCalls,
+                                         allCalls, binaryDataSize);
+            } else {
+                emit frameContentsLoaded(currentFrame, topLevelItems,
+                                         allCalls, binaryDataSize);
+            }
+            return allCalls;
         }
     }
     return QVector<ApiTraceCall*>();
@@ -489,8 +522,18 @@ void TraceLoader::findCallIndex(int index)
             call = *itr;
         }
     }
-    Q_ASSERT(call);
-    emit foundCallIndex(call);
+    if (call) {
+        emit foundCallIndex(call);
+    }
+}
+
+void TraceLoader::search(const ApiTrace::SearchRequest &request)
+{
+    if (request.direction == ApiTrace::SearchRequest::Next) {
+        searchNext(request);
+    } else {
+        searchPrev(request);
+    }
 }
 
 #include "traceloader.moc"