]> git.cworth.org Git - apitrace/blobdiff - gui/apitrace.cpp
gui: Fix crash on trigger actions without loaded trace-file.
[apitrace] / gui / apitrace.cpp
index 723fad37be2918cac32d9a3ab2dcc4b4ae150deb..a69ce2fff0ef25a2f0293e392e273f9b4ecc1b4d 100644 (file)
@@ -1,95 +1,94 @@
 #include "apitrace.h"
 
-#include "loaderthread.h"
+#include "traceloader.h"
 #include "saverthread.h"
 
+#include <QDebug>
 #include <QDir>
+#include <QThread>
 
 ApiTrace::ApiTrace()
-    : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
-      m_needsSaving(false)
+    : m_needsSaving(false)
 {
-    m_loader = new LoaderThread(this);
-    connect(m_loader, SIGNAL(parsedFrames(const QList<ApiTraceFrame*>)),
+    m_loader = new TraceLoader();
+
+    connect(this, SIGNAL(loadTrace(QString)),
+            m_loader, SLOT(loadTrace(QString)));
+    connect(this, SIGNAL(requestFrame(ApiTraceFrame*)),
+            m_loader, SLOT(loadFrame(ApiTraceFrame*)));
+    connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
             this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
-    connect(m_loader, SIGNAL(started()),
+    connect(m_loader,
+            SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)),
+            this,
+            SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)));
+    connect(m_loader, SIGNAL(guessedApi(int)),
+            this, SLOT(guessedApi(int)));
+    connect(m_loader, SIGNAL(finishedParsing()),
+            this, SLOT(finishedParsing()));
+    connect(this, SIGNAL(loaderSearch(ApiTrace::SearchRequest)),
+            m_loader, SLOT(search(ApiTrace::SearchRequest)));
+    connect(m_loader,
+            SIGNAL(searchResult(ApiTrace::SearchRequest,ApiTrace::SearchResult,ApiTraceCall*)),
+            this,
+            SLOT(loaderSearchResult(ApiTrace::SearchRequest,ApiTrace::SearchResult,ApiTraceCall*)));
+    connect(this, SIGNAL(loaderFindFrameStart(ApiTraceFrame*)),
+            m_loader, SLOT(findFrameStart(ApiTraceFrame*)));
+    connect(this, SIGNAL(loaderFindFrameEnd(ApiTraceFrame*)),
+            m_loader, SLOT(findFrameEnd(ApiTraceFrame*)));
+    connect(m_loader, SIGNAL(foundFrameStart(ApiTraceFrame*)),
+            this, SIGNAL(foundFrameStart(ApiTraceFrame*)));
+    connect(m_loader, SIGNAL(foundFrameEnd(ApiTraceFrame*)),
+            this, SIGNAL(foundFrameEnd(ApiTraceFrame*)));
+    connect(this, SIGNAL(loaderFindCallIndex(int)),
+            m_loader, SLOT(findCallIndex(int)));
+    connect(m_loader, SIGNAL(foundCallIndex(ApiTraceCall*)),
+            this, SIGNAL(foundCallIndex(ApiTraceCall*)));
+
+
+    connect(m_loader, SIGNAL(startedParsing()),
             this, SIGNAL(startedLoadingTrace()));
-    connect(m_loader, SIGNAL(finished()),
+    connect(m_loader, SIGNAL(parsed(int)),
+            this, SIGNAL(loaded(int)));
+    connect(m_loader, SIGNAL(finishedParsing()),
             this, SIGNAL(finishedLoadingTrace()));
 
+
     m_saver = new SaverThread(this);
     connect(m_saver, SIGNAL(traceSaved()),
             this, SLOT(slotSaved()));
     connect(m_saver, SIGNAL(traceSaved()),
             this, SIGNAL(saved()));
+
+    m_loaderThread = new QThread();
+    m_loader->moveToThread(m_loaderThread);
+    m_loaderThread->start();
 }
 
 ApiTrace::~ApiTrace()
 {
-    qDeleteAll(m_calls);
+    m_loaderThread->quit();
+    m_loaderThread->deleteLater();
     qDeleteAll(m_frames);
     delete m_loader;
     delete m_saver;
 }
 
-bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
-                                  ApiTrace::FrameMarker marker)
-{
-    if (!call)
-        return false;
-
-    switch (marker) {
-    case FrameMarker_SwapBuffers:
-        return call->name().contains(QLatin1String("SwapBuffers")) ||
-               call->name() == QLatin1String("CGLFlushDrawable") ||
-               call->name() == QLatin1String("glFrameTerminatorGREMEDY");
-    case FrameMarker_Flush:
-        return call->name() == QLatin1String("glFlush");
-    case FrameMarker_Finish:
-        return call->name() == QLatin1String("glFinish");
-    case FrameMarker_Clear:
-        return call->name() == QLatin1String("glClear");
-    }
-
-    Q_ASSERT(!"unknown frame marker");
-
-    return false;
-}
-
 bool ApiTrace::isEmpty() const
 {
-    return m_calls.isEmpty();
+    return m_frames.isEmpty();
 }
 
 QString ApiTrace::fileName() const
 {
-    if (edited())
+    if (edited()) {
         return m_tempFileName;
+    }
 
     return m_fileName;
 }
 
-ApiTrace::FrameMarker ApiTrace::frameMarker() const
-{
-    return m_frameMarker;
-}
-
-QList<ApiTraceCall*> ApiTrace::calls() const
-{
-    return m_calls;
-}
-
-ApiTraceCall * ApiTrace::callAt(int idx) const
-{
-    return m_calls.value(idx);
-}
-
-int ApiTrace::numCalls() const
-{
-    return m_calls.count();
-}
-
-QList<ApiTraceFrame*> ApiTrace::frames() const
+const QList<ApiTraceFrame*> & ApiTrace::frames() const
 {
     return m_frames;
 }
@@ -107,46 +106,32 @@ int ApiTrace::numFrames() const
 int ApiTrace::numCallsInFrame(int idx) const
 {
     const ApiTraceFrame *frame = frameAt(idx);
-    if (frame)
+    if (frame) {
         return frame->numChildren();
-    else
+    } else {
         return 0;
+    }
 }
 
 void ApiTrace::setFileName(const QString &name)
 {
     if (m_fileName != name) {
         m_fileName = name;
+        m_tempFileName = QString();
 
-        if (m_loader->isRunning()) {
-            m_loader->terminate();
-            m_loader->wait();
-        }
         m_frames.clear();
-        m_calls.clear();
         m_errors.clear();
         m_editedCalls.clear();
+        m_queuedErrors.clear();
         m_needsSaving = false;
         emit invalidated();
 
-        m_loader->loadFile(m_fileName);
-    }
-}
-
-void ApiTrace::setFrameMarker(FrameMarker marker)
-{
-    if (m_frameMarker != marker) {
-        emit framesInvalidated();
-
-        qDeleteAll(m_frames);
-        m_frames.clear();
-        detectFrames();
+        emit loadTrace(m_fileName);
     }
 }
 
 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
 {
-    QList<ApiTraceCall*> calls;
     int currentFrames = m_frames.count();
     int numNewFrames = frames.count();
 
@@ -154,57 +139,20 @@ void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
 
     m_frames += frames;
 
-    int currentCalls = m_calls.count();
-    int numNewCalls = 0;
     foreach(ApiTraceFrame *frame, frames) {
-        Q_ASSERT(this == frame->parentTrace());
-        numNewCalls += frame->numChildren();
-        calls += frame->calls();
+        frame->setParentTrace(this);
     }
-    m_calls.reserve(m_calls.count() + calls.count());
-    m_calls += calls;
 
     emit endAddingFrames();
-    emit callsAdded(currentCalls, numNewCalls);
-}
-
-void ApiTrace::detectFrames()
-{
-    if (m_calls.isEmpty())
-        return;
-
-    emit beginAddingFrames(0, m_frames.count());
-
-    ApiTraceFrame *currentFrame = 0;
-    foreach(ApiTraceCall *apiCall, m_calls) {
-        if (!currentFrame) {
-            currentFrame = new ApiTraceFrame(this);
-            currentFrame->number = m_frames.count();
-        }
-        apiCall->setParentFrame(currentFrame);
-        currentFrame->addCall(apiCall);
-        if (ApiTrace::isCallAFrameMarker(apiCall,
-                                         m_frameMarker)) {
-            m_frames.append(currentFrame);
-            currentFrame = 0;
-        }
-    }
-    //last frames won't have markers
-    //  it's just a bunch of Delete calls for every object
-    //  after the last SwapBuffers
-    if (currentFrame) {
-        m_frames.append(currentFrame);
-        currentFrame = 0;
-    }
-    emit endAddingFrames();
 }
 
 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
 {
-    for (int i = 0; i < m_calls.count(); ++i) {
-        ApiTraceCall *call = m_calls[i];
-        if (call->index() == idx)
+    for (int i = 0; i < m_frames.count(); ++i) {
+        ApiTraceCall *call = m_frames[i]->callWithIndex(idx);
+        if (call) {
             return call;
+        }
     }
     return NULL;
 }
@@ -212,10 +160,16 @@ ApiTraceCall * ApiTrace::callWithIndex(int idx) const
 ApiTraceState ApiTrace::defaultState() const
 {
     ApiTraceFrame *frame = frameAt(0);
-    if (!frame || !frame->hasState())
+    if (!frame || !frame->isLoaded() || frame->isEmpty()) {
         return ApiTraceState();
+    }
+
+    ApiTraceCall *firstCall = frame->calls().first();
+    if (!firstCall->hasState()) {
+        return ApiTraceState();
+    }
 
-    return *frame->state();
+    return *firstCall->state();
 }
 
 void ApiTrace::callEdited(ApiTraceCall *call)
@@ -259,7 +213,9 @@ void ApiTrace::save()
     QDir dir;
     emit startedSaving();
     dir.mkpath(fi.absolutePath());
-    m_saver->saveFile(m_tempFileName, m_calls);
+    m_saver->saveFile(m_tempFileName,
+                      m_fileName,
+                      m_editedCalls);
 }
 
 void ApiTrace::slotSaved()
@@ -272,51 +228,280 @@ bool ApiTrace::isSaving() const
     return m_saver->isRunning();
 }
 
-void ApiTrace::callError(ApiTraceCall *call)
+bool ApiTrace::hasErrors() const
 {
-    Q_ASSERT(call);
+    return !m_errors.isEmpty() || !m_queuedErrors.isEmpty();
+}
 
-    if (call->hasError())
-        m_errors.insert(call);
-    else
-        m_errors.remove(call);
+void ApiTrace::loadFrame(ApiTraceFrame *frame)
+{
+    if (!isFrameLoading(frame)) {
+        Q_ASSERT(!frame->isLoaded());
+        m_loadingFrames.insert(frame);
+        emit requestFrame(frame);
+    }
+}
 
-    emit changed(call);
+void ApiTrace::guessedApi(int api)
+{
+    m_api = static_cast<trace::API>(api);
 }
 
-bool ApiTrace::hasErrors() const
+trace::API ApiTrace::api() const
+{
+    return m_api;
+}
+
+void ApiTrace::finishedParsing()
+{
+    if (!m_frames.isEmpty()) {
+        ApiTraceFrame *firstFrame = m_frames[0];
+        if (firstFrame && !firstFrame->isLoaded()) {
+            loadFrame(firstFrame);
+        }
+    }
+}
+
+void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
+                                 const QVector<ApiTraceCall*> &calls,
+                                 quint64 binaryDataSize)
 {
-    return !m_errors.isEmpty();
+    Q_ASSERT(frame->numChildrenToLoad() == calls.size());
+
+    if (!frame->isLoaded()) {
+        emit beginLoadingFrame(frame, calls.size());
+        frame->setCalls(calls, binaryDataSize);
+        emit endLoadingFrame(frame);
+        m_loadingFrames.remove(frame);
+    }
+
+    if (!m_queuedErrors.isEmpty()) {
+        QList< QPair<ApiTraceFrame*, ApiTraceError> >::iterator itr;
+        for (itr = m_queuedErrors.begin(); itr != m_queuedErrors.end();
+             ++itr) {
+            const ApiTraceError &error = (*itr).second;
+            if ((*itr).first == frame) {
+                ApiTraceCall *call = frame->callWithIndex(error.callIndex);
+
+                if (!call) {
+                    continue;
+                }
+
+                call->setError(error.message);
+                m_queuedErrors.erase(itr);
+
+                if (call->hasError()) {
+                    m_errors.insert(call);
+                } else {
+                    m_errors.remove(call);
+                }
+                emit changed(call);
+            }
+        }
+    }
+}
+
+void ApiTrace::findNext(ApiTraceFrame *frame,
+                        ApiTraceCall *from,
+                        const QString &str,
+                        Qt::CaseSensitivity sensitivity)
+{
+    ApiTraceCall *foundCall = 0;
+    int frameIdx = m_frames.indexOf(frame);
+    SearchRequest request(SearchRequest::Next,
+                          frame, from, str, sensitivity);
+
+    if (frame->isLoaded()) {
+        foundCall = frame->findNextCall(from, str, sensitivity);
+        if (foundCall) {
+            emit findResult(request, SearchResult_Found, foundCall);
+            return;
+        }
+
+        //if the frame is loaded we already searched it above
+        // so skip it
+        frameIdx += 1;
+    }
+
+    //for the rest of the frames we search from beginning
+    request.from = 0;
+    for (int i = frameIdx; i < m_frames.count(); ++i) {
+        ApiTraceFrame *frame = m_frames[i];
+        request.frame = frame;
+        if (!frame->isLoaded()) {
+            emit loaderSearch(request);
+            return;
+        } else {
+            ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
+            if (call) {
+                emit findResult(request, SearchResult_Found, call);
+                return;
+            }
+        }
+    }
+    emit findResult(request, SearchResult_Wrapped, 0);
+}
+
+void ApiTrace::findPrev(ApiTraceFrame *frame,
+                        ApiTraceCall *from,
+                        const QString &str,
+                        Qt::CaseSensitivity sensitivity)
+{
+    ApiTraceCall *foundCall = 0;
+    int frameIdx = m_frames.indexOf(frame);
+    SearchRequest request(SearchRequest::Prev,
+                          frame, from, str, sensitivity);
+
+    if (frame->isLoaded()) {
+        foundCall = frame->findPrevCall(from, str, sensitivity);
+        if (foundCall) {
+            emit findResult(request, SearchResult_Found, foundCall);
+            return;
+        }
+
+        //if the frame is loaded we already searched it above
+        // so skip it
+        frameIdx -= 1;
+    }
+
+    request.from = 0;
+    for (int i = frameIdx; i >= 0; --i) {
+        ApiTraceFrame *frame = m_frames[i];
+        request.frame = frame;
+        if (!frame->isLoaded()) {
+            emit loaderSearch(request);
+            return;
+        } else {
+            ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
+            if (call) {
+                emit findResult(request, SearchResult_Found, call);
+                return;
+            }
+        }
+    }
+    emit findResult(request, SearchResult_Wrapped, 0);
+}
+
+void ApiTrace::loaderSearchResult(const ApiTrace::SearchRequest &request,
+                                  ApiTrace::SearchResult result,
+                                  ApiTraceCall *call)
+{
+    //qDebug()<<"Search result = "<<result
+    //       <<", call is = "<<call;
+    emit findResult(request, result, call);
+}
+
+void ApiTrace::findFrameStart(ApiTraceFrame *frame)
+{
+    if (!frame)
+        return;
+
+    if (frame->isLoaded()) {
+        emit foundFrameStart(frame);
+    } else {
+        emit loaderFindFrameStart(frame);
+    }
 }
 
-ApiTraceCallSignature * ApiTrace::signature(unsigned id)
+void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
 {
-    if (id >= m_signatures.count()) {
-        m_signatures.resize(id + 1);
-        return NULL;
+    if (!frame)
+        return;
+
+    if (frame->isLoaded()) {
+        emit foundFrameEnd(frame);
     } else {
-        return m_signatures[id];
+        emit loaderFindFrameEnd(frame);
+    }
+}
+
+void ApiTrace::findCallIndex(int index)
+{
+    int frameIdx = callInFrame(index);
+    ApiTraceFrame *frame = 0;
+
+    if (frameIdx < 0) {
+        emit foundCallIndex(0);
+        return;
+    }
+
+    frame = m_frames[frameIdx];
+
+    if (frame) {
+        if (frame->isLoaded()) {
+            ApiTraceCall *call = frame->callWithIndex(index);
+            emit foundCallIndex(call);
+        } else {
+            emit loaderFindCallIndex(index);
+        }
     }
 }
 
-void ApiTrace::addSignature(unsigned id, ApiTraceCallSignature *signature)
+int ApiTrace::callInFrame(int callIdx) const
 {
-    m_signatures[id] = signature;
+    unsigned numCalls = 0;
+
+    for (int frameIdx = 0; frameIdx < m_frames.size(); ++frameIdx) {
+        const ApiTraceFrame *frame = m_frames[frameIdx];
+        unsigned numCallsInFrame =  frame->isLoaded()
+                ? frame->numChildren()
+                : frame->numChildrenToLoad();
+        unsigned firstCall = numCalls;
+        unsigned endCall = numCalls + numCallsInFrame;
+        if (firstCall <= callIdx && endCall > callIdx) {
+            return frameIdx;
+        }
+        numCalls = endCall;
+    }
+
+    return -1;
 }
 
-ApiTraceEnumSignature * ApiTrace::enumSignature(unsigned id)
+void ApiTrace::setCallError(const ApiTraceError &error)
 {
-    if (id >= m_signatures.count()) {
-        m_enumSignatures.resize(id + 1);
-        return NULL;
+    int frameIdx = callInFrame(error.callIndex);
+    ApiTraceFrame *frame = 0;
+
+    if (frameIdx < 0) {
+        return;
+    }
+    frame = m_frames[frameIdx];
+
+    if (frame->isLoaded()) {
+        ApiTraceCall *call = frame->callWithIndex(error.callIndex);
+        call->setError(error.message);
+        if (call->hasError()) {
+            m_errors.insert(call);
+        } else {
+            m_errors.remove(call);
+        }
+        emit changed(call);
     } else {
-        return m_enumSignatures[id];
+        loadFrame(frame);
+        m_queuedErrors.append(qMakePair(frame, error));
     }
 }
 
-void ApiTrace::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
+bool ApiTrace::isFrameLoading(ApiTraceFrame *frame) const
+{
+    return m_loadingFrames.contains(frame);
+}
+
+void ApiTrace::bindThumbnailsToFrames(const QList<QImage> &thumbnails)
 {
-    m_enumSignatures[id] = signature;
+    QList<ApiTraceFrame *> frames = m_frames;
+
+    QList<QImage>::const_iterator thumbnail = thumbnails.begin();
+
+    foreach (ApiTraceFrame *frame, frames) {
+        if (thumbnail != thumbnails.end()) {
+            frame->setThumbnail(*thumbnail);
+
+            ++thumbnail;
+
+            emit changed(frame);
+        }
+    }
 }
 
 #include "apitrace.moc"