X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=gui%2Fapitrace.cpp;h=671fc683887fa35fbbbda15bde9b92cae1df5b43;hb=caa8428eb4c4292d3ea53405d4dc9c3c3f21f10a;hp=4d7a17c427d2df8ad268c628f2afe4d6884260a4;hpb=de4ea4197df6ba442beae0d52651fc4606e78417;p=apitrace diff --git a/gui/apitrace.cpp b/gui/apitrace.cpp index 4d7a17c..671fc68 100644 --- a/gui/apitrace.cpp +++ b/gui/apitrace.cpp @@ -1,173 +1,507 @@ #include "apitrace.h" -#include "loaderthread.h" +#include "traceloader.h" +#include "saverthread.h" + +#include +#include +#include ApiTrace::ApiTrace() - : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers) + : m_needsSaving(false) { - m_loader = new LoaderThread(this); - connect(m_loader, SIGNAL(parsedFrames(const QList)), + 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)), this, SLOT(addFrames(const QList))); - connect(m_loader, SIGNAL(started()), + connect(m_loader, + SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector,quint64)), + this, + SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector,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) +bool ApiTrace::isEmpty() const { - if (!call) - return false; + return m_frames.isEmpty(); +} - switch (marker) { - case FrameMarker_SwapBuffers: - return call->name.contains(QLatin1String("SwapBuffers")); - case FrameMarker_Flush: - return call->name == QLatin1String("glFlush"); - case FrameMarker_Finish: - return call->name == QLatin1String("glFinish"); - case FrameMarker_Clear: - return call->name == QLatin1String("glClear"); +QString ApiTrace::fileName() const +{ + if (edited()) { + return m_tempFileName; } - Q_ASSERT(!"unknown frame marker"); + return m_fileName; +} - return false; +const QList & ApiTrace::frames() const +{ + return m_frames; } -bool ApiTrace::isEmpty() const +ApiTraceFrame * ApiTrace::frameAt(int idx) const { - return m_calls.isEmpty(); + return m_frames.value(idx); } -QString ApiTrace::fileName() const +int ApiTrace::numFrames() const { - return m_fileName; + return m_frames.count(); +} + +int ApiTrace::numCallsInFrame(int idx) const +{ + const ApiTraceFrame *frame = frameAt(idx); + if (frame) { + return frame->numChildren(); + } else { + return 0; + } +} + +void ApiTrace::setFileName(const QString &name) +{ + if (m_fileName != name) { + m_fileName = name; + m_tempFileName = QString(); + + m_frames.clear(); + m_errors.clear(); + m_editedCalls.clear(); + m_queuedErrors.clear(); + m_needsSaving = false; + emit invalidated(); + + emit loadTrace(m_fileName); + } } -ApiTrace::FrameMarker ApiTrace::frameMarker() const +void ApiTrace::addFrames(const QList &frames) { - return m_frameMarker; + int currentFrames = m_frames.count(); + int numNewFrames = frames.count(); + + emit beginAddingFrames(currentFrames, numNewFrames); + + m_frames += frames; + + foreach(ApiTraceFrame *frame, frames) { + frame->setParentTrace(this); + } + + emit endAddingFrames(); } -QList ApiTrace::calls() const +ApiTraceCall * ApiTrace::callWithIndex(int idx) const { - return m_calls; + for (int i = 0; i < m_frames.count(); ++i) { + ApiTraceCall *call = m_frames[i]->callWithIndex(idx); + if (call) { + return call; + } + } + return NULL; } -ApiTraceCall * ApiTrace::callAt(int idx) const +ApiTraceState ApiTrace::defaultState() const { - return m_calls.value(idx); + ApiTraceFrame *frame = frameAt(0); + if (!frame || !frame->isLoaded() || frame->isEmpty()) { + return ApiTraceState(); + } + + ApiTraceCall *firstCall = frame->calls().first(); + if (!firstCall->hasState()) { + return ApiTraceState(); + } + + return *firstCall->state(); } -int ApiTrace::numCalls() const +void ApiTrace::callEdited(ApiTraceCall *call) { - return m_calls.count(); + if (!m_editedCalls.contains(call)) { + //lets generate a temp filename + QString tempPath = QDir::tempPath(); + m_tempFileName = QString::fromLatin1("%1/%2.edited") + .arg(tempPath) + .arg(m_fileName); + } + m_editedCalls.insert(call); + m_needsSaving = true; + + emit changed(call); } -QList ApiTrace::frames() const +void ApiTrace::callReverted(ApiTraceCall *call) { - return m_frames; + m_editedCalls.remove(call); + + if (m_editedCalls.isEmpty()) { + m_needsSaving = false; + } + emit changed(call); } -ApiTraceFrame * ApiTrace::frameAt(int idx) const +bool ApiTrace::edited() const { - return m_frames.value(idx); + return !m_editedCalls.isEmpty(); } -int ApiTrace::numFrames() const +bool ApiTrace::needsSaving() const { - return m_frames.count(); + return m_needsSaving; } -int ApiTrace::numCallsInFrame(int idx) const +void ApiTrace::save() { - const ApiTraceFrame *frame = frameAt(idx); - if (frame) - return frame->calls.count(); - else - return 0; + QFileInfo fi(m_tempFileName); + QDir dir; + emit startedSaving(); + dir.mkpath(fi.absolutePath()); + m_saver->saveFile(m_tempFileName, + m_fileName, + m_editedCalls); } -void ApiTrace::setFileName(const QString &name) +void ApiTrace::slotSaved() { - if (m_fileName != name) { - m_fileName = name; + m_needsSaving = false; +} + +bool ApiTrace::isSaving() const +{ + return m_saver->isRunning(); +} - if (m_loader->isRunning()) { - m_loader->terminate(); - m_loader->wait(); +bool ApiTrace::hasErrors() const +{ + return !m_errors.isEmpty() || !m_queuedErrors.isEmpty(); +} + +void ApiTrace::loadFrame(ApiTraceFrame *frame) +{ + if (!isFrameLoading(frame)) { + Q_ASSERT(!frame->isLoaded()); + m_loadingFrames.insert(frame); + emit requestFrame(frame); + } +} + +void ApiTrace::guessedApi(int api) +{ + m_api = static_cast(api); +} + +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); } - emit invalidated(); + } +} + +void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame, + const QVector &calls, + quint64 binaryDataSize) +{ + 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 >::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; + } - m_loader->loadFile(m_fileName); + 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::setFrameMarker(FrameMarker marker) +void ApiTrace::findNext(ApiTraceFrame *frame, + ApiTraceCall *from, + const QString &str, + Qt::CaseSensitivity sensitivity) { - if (m_frameMarker != marker) { - emit framesInvalidated(); + ApiTraceCall *foundCall = 0; + int frameIdx = m_frames.indexOf(frame); + SearchRequest request(SearchRequest::Next, + frame, from, str, sensitivity); - qDeleteAll(m_frames); - m_frames.clear(); - detectFrames(); + 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::addFrames(const QList &frames) +void ApiTrace::findPrev(ApiTraceFrame *frame, + ApiTraceCall *from, + const QString &str, + Qt::CaseSensitivity sensitivity) { - int currentFrames = m_frames.count(); - int numNewFrames = frames.count(); - m_frames += frames; + ApiTraceCall *foundCall = 0; + int frameIdx = m_frames.indexOf(frame); + SearchRequest request(SearchRequest::Prev, + frame, from, str, sensitivity); - int currentCalls = m_calls.count(); - int numNewCalls = 0; - foreach(ApiTraceFrame *frame, frames) { - numNewCalls += frame->calls.count(); - m_calls += frame->calls; + 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); +} - emit framesAdded(currentFrames, numNewFrames); - emit callsAdded(currentCalls, numNewCalls); +void ApiTrace::loaderSearchResult(const ApiTrace::SearchRequest &request, + ApiTrace::SearchResult result, + ApiTraceCall *call) +{ + //qDebug()<<"Search result = "<