diff options
Diffstat (limited to 'plugins/qmlprofilerextended/scenegraphtimelinemodel.cpp')
-rw-r--r-- | plugins/qmlprofilerextended/scenegraphtimelinemodel.cpp | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/plugins/qmlprofilerextended/scenegraphtimelinemodel.cpp b/plugins/qmlprofilerextended/scenegraphtimelinemodel.cpp new file mode 100644 index 0000000000..7446638c55 --- /dev/null +++ b/plugins/qmlprofilerextended/scenegraphtimelinemodel.cpp @@ -0,0 +1,467 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +****************************************************************************/ + +#include "scenegraphtimelinemodel.h" +#include "qmldebug/qmlprofilereventtypes.h" +#include "qmlprofiler/qmlprofilermodelmanager.h" + +#include <QDebug> + +namespace QmlProfilerExtended { +namespace Internal { + +using namespace QmlProfiler::Internal; + +enum SceneGraphEventType { + SceneGraphRendererFrame, + SceneGraphAdaptationLayerFrame, + SceneGraphContextFrame, + SceneGraphRenderLoopFrame, + SceneGraphTexturePrepare, + SceneGraphTextureDeletion, + SceneGraphPolishAndSync, + SceneGraphWindowsRenderShow, + SceneGraphWindowsAnimations, + SceneGraphWindowsPolishFrame, + + MaximumSceneGraphFrameType +}; + +enum SceneGraphCategoryType { + SceneGraphRenderThread, + SceneGraphGUIThread, + + MaximumSceneGraphCategoryType +}; + +class SceneGraphTimelineModel::SceneGraphTimelineModelPrivate { +public: + SceneGraphTimelineModelPrivate(SceneGraphTimelineModel *qq):q(qq) {} + ~SceneGraphTimelineModelPrivate(); + + SceneGraphTimelineModel *q; + + QVector < SceneGraphTimelineModel::SceneGraphEvent > eventList; + bool isExpanded; + QString displayTime(double time); + void addVP(QVariantList &l, QString label, qint64 time); +}; + +SceneGraphTimelineModel::SceneGraphTimelineModel(QObject *parent) + : AbstractTimelineModel(parent), d(new SceneGraphTimelineModelPrivate(this)) +{ +} + +SceneGraphTimelineModel::~SceneGraphTimelineModel() +{ +} + +int SceneGraphTimelineModel::categories() const +{ + return 1; +} + +QStringList SceneGraphTimelineModel::categoryTitles() const +{ + QStringList retString; + retString << categoryLabel(0); + return retString; +} + +QString SceneGraphTimelineModel::name() const +{ + return QLatin1String("SceneGraphTimeLineModel"); +} + +int SceneGraphTimelineModel::count() const +{ + return d->eventList.count(); +} + +bool SceneGraphTimelineModel::isEmpty() const +{ + return d->eventList.isEmpty(); +} + +bool SceneGraphTimelineModel::eventAccepted(const QmlProfiler::Internal::QmlProfilerSimpleModel::QmlEventData &event) const +{ + return (event.eventType == QmlDebug::SceneGraphFrameEvent); +} + +qint64 SceneGraphTimelineModel::lastTimeMark() const +{ + return d->eventList.last().startTime; +} + +void SceneGraphTimelineModel::setExpanded(int category, bool expanded) +{ + // TODO: uncomment this for PixMap + //if (category == QmlDebug::SceneGraphFrameEvent) + d->isExpanded = expanded; +} + +int SceneGraphTimelineModel::categoryDepth(int categoryIndex) const +{ + // TODO + if (isEmpty()) + return 1; + return 3; + + if (categoryIndex == QmlDebug::SceneGraphFrameEvent) + return 11; + return 1; +} + +int SceneGraphTimelineModel::categoryCount() const +{ + return 1; +} + +const QString SceneGraphTimelineModel::categoryLabel(int categoryIndex) const +{ + Q_UNUSED(categoryIndex); + return QLatin1String("SceneGraph"); +} + +int SceneGraphTimelineModel::findFirstIndex(qint64 startTime) const +{ + // TODO properly + int candidate = -2; + for (int i=0; i < d->eventList.count(); i++) + if (d->eventList[i].startTime + d->eventList[i].duration > startTime) { + candidate = i; + break; + } + + if (candidate == -1) + return 0; + if (candidate == -2) + return d->eventList.count() - 1; + + return candidate; +} + +int SceneGraphTimelineModel::findFirstIndexNoParents(qint64 startTime) const +{ + // TODO properly + return findFirstIndex(startTime); + +// int candidate = -1; +// // in the "endtime" list, find the first event that ends after startTime +// if (d->endTimeData.isEmpty()) +// return 0; // -1 +// if (d->endTimeData.count() == 1 || d->endTimeData.first().endTime >= startTime) +// candidate = 0; +// else +// if (d->endTimeData.last().endTime <= startTime) +// return 0; // -1 + +// if (candidate == -1) { +// int fromIndex = 0; +// int toIndex = d->endTimeData.count()-1; +// while (toIndex - fromIndex > 1) { +// int midIndex = (fromIndex + toIndex)/2; +// if (d->endTimeData[midIndex].endTime < startTime) +// fromIndex = midIndex; +// else +// toIndex = midIndex; +// } + +// candidate = toIndex; +// } + +// int ndx = d->endTimeData[candidate].startTimeIndex; + +// return ndx; +} + +int SceneGraphTimelineModel::findLastIndex(qint64 endTime) const +{ + // TODO properly + int candidate = 0; + for (int i = d->eventList.count()-1; i >= 0; i--) + if (d->eventList[i].startTime < endTime) { + candidate = i; + break; + } + return candidate; +} + +int SceneGraphTimelineModel::getEventType(int index) const +{ + // TODO fix + return QmlDebug::PixmapCacheEvent; + //return QmlDebug::SceneGraphFrameEvent; +// return 0; +} + +int SceneGraphTimelineModel::getEventRow(int index) const +{ + return d->eventList[index].sgEventType + 1; + if (d->isExpanded) + return d->eventList[index].sgEventType + 1; + else + return 0; +} + +qint64 SceneGraphTimelineModel::getDuration(int index) const +{ + return d->eventList[index].duration; +} + +qint64 SceneGraphTimelineModel::getStartTime(int index) const +{ + return d->eventList[index].startTime; +} + +qint64 SceneGraphTimelineModel::getEndTime(int index) const +{ + return getStartTime(index)+getDuration(index); +} + +int SceneGraphTimelineModel::getEventId(int index) const +{ + return d->eventList[index].sgEventType; +} + +QColor SceneGraphTimelineModel::getColor(int index) const +{ + // get duration in seconds + double eventDuration = getDuration(index) / 1e9; + + // supposedly never above 60 frames per second + // limit it in that case + if (eventDuration < 1/60.0) + eventDuration = 1/60.0; + + // generate hue based on fraction of the 60fps + double fpsFraction = 1 / (eventDuration * 60.0); + if (fpsFraction > 1.0) + fpsFraction = 1.0; + return QColor::fromHsl((fpsFraction*96)+10, 76, 166); +} + +float SceneGraphTimelineModel::getHeight(int index) const +{ + return 1.0f; +} + +QString labelForSGType(int t) +{ + switch ((SceneGraphCategoryType)t) { + case SceneGraphRenderThread: return QLatin1String("Renderer Thread"); + case SceneGraphGUIThread: return QLatin1String("GUI Thread"); + } +} + +const QVariantList SceneGraphTimelineModel::getLabelsForCategory(int category) const +{ + QVariantList result; + + for (int i = 0; i < MaximumSceneGraphCategoryType; i++) { + QVariantMap element; + element.insert(QLatin1String("displayName"), QVariant(labelForSGType(i))); + element.insert(QLatin1String("description"), QVariant(labelForSGType(i))); + element.insert(QLatin1String("id"), QVariant(i)); + result << element; + } + + return result; +} + + + +QString SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::displayTime(double time) +{ + if (time < 1e6) + return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s"); + if (time < 1e9) + return QString::number(time/1e6,'f',3) + tr(" ms"); + + return QString::number(time/1e9,'f',3) + tr(" s"); +} + +void SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::addVP(QVariantList &l, QString label, qint64 time) +{ + if (time > 0) { + QVariantMap res; + res.insert(label, QVariant(displayTime(time))); + l << res; + } +} + + +const QVariantList SceneGraphTimelineModel::getEventDetails(int index) const +{ + QVariantList result; + SceneGraphEvent *ev = &d->eventList[index]; + + { + QVariantMap res; + res.insert(tr("title"), QVariant(labelForSGType(ev->sgEventType))); + result << res; + } + + d->addVP(result, tr("duration"), ev->duration ); + + if (ev->sgEventType == SceneGraphRenderThread) { + d->addVP(result, tr("polish"), ev->timing[14]); + d->addVP(result, tr("sync"), ev->timing[0]); + d->addVP(result, tr("preprocess"), ev->timing[1]); + d->addVP(result, tr("upload"), ev->timing[2]); + d->addVP(result, tr("swizzle"), ev->timing[3]); + d->addVP(result, tr("convert"), ev->timing[4]); + d->addVP(result, tr("mipmap"), ev->timing[5]); + d->addVP(result, tr("bind"), ev->timing[6]); + d->addVP(result, tr("material"), ev->timing[7]); + d->addVP(result, tr("glyph render"), ev->timing[8]); + d->addVP(result, tr("glyph store"), ev->timing[9]); + d->addVP(result, tr("update"), ev->timing[10]); + d->addVP(result, tr("binding"), ev->timing[11]); + d->addVP(result, tr("render"), ev->timing[12]); + d->addVP(result, tr("swap"), ev->timing[13]); + d->addVP(result, tr("animations"), ev->timing[15]); + } + if (ev->sgEventType == SceneGraphGUIThread) { + d->addVP(result, tr("polish"), ev->timing[0]); + d->addVP(result, tr("wait"), ev->timing[1]); + d->addVP(result, tr("sync"), ev->timing[2]); + d->addVP(result, tr("animations"), ev->timing[3]); + } + + return result; +} + +bool compareStartTimes(const SceneGraphTimelineModel::SceneGraphEvent&t1, const SceneGraphTimelineModel::SceneGraphEvent &t2) +{ + return t1.startTime < t2.startTime; +} + +void SceneGraphTimelineModel::loadData() +{ + clear(); + QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel(); + if (simpleModel->isEmpty()) + return; + + int lastRenderEvent = -1; + + // combine the data of several eventtypes into two rows + foreach (const QmlProfilerSimpleModel::QmlEventData &event, simpleModel->getEvents()) { + if (!eventAccepted(event)) + continue; + + if (event.bindingType == SceneGraphRenderLoopFrame) { + SceneGraphEvent newEvent; + newEvent.sgEventType = SceneGraphRenderThread; + newEvent.duration = event.numericData1 + event.numericData2 + event.numericData3; + newEvent.startTime = event.startTime - newEvent.duration; + for (int i=0; i < timingFieldCount; i++) + newEvent.timing[i] = 0; + + d->eventList << newEvent; + lastRenderEvent = d->eventList.count()-1; + } + + if (lastRenderEvent >= 0) { + switch ((SceneGraphEventType)event.bindingType) { + case SceneGraphRendererFrame: { + d->eventList[lastRenderEvent].timing[1] = event.numericData1; + d->eventList[lastRenderEvent].timing[10] = event.numericData2; + d->eventList[lastRenderEvent].timing[11] = event.numericData3; + d->eventList[lastRenderEvent].timing[12] = event.numericData4; + break; + } + case SceneGraphAdaptationLayerFrame: { + d->eventList[lastRenderEvent].timing[8] = event.numericData2; + d->eventList[lastRenderEvent].timing[9] = event.numericData3; + break; + } + case SceneGraphContextFrame: { + d->eventList[lastRenderEvent].timing[7] = event.numericData1; + break; + } + case SceneGraphRenderLoopFrame: { + d->eventList[lastRenderEvent].timing[0] = event.numericData1; + d->eventList[lastRenderEvent].timing[13] = event.numericData3; + + break; + } + case SceneGraphTexturePrepare: { + d->eventList[lastRenderEvent].timing[2] = event.numericData4; + d->eventList[lastRenderEvent].timing[3] = event.numericData3; + d->eventList[lastRenderEvent].timing[4] = event.numericData2; + d->eventList[lastRenderEvent].timing[5] = event.numericData5; + d->eventList[lastRenderEvent].timing[6] = event.numericData1; + break; + } + case SceneGraphPolishAndSync: { + // GUI thread + SceneGraphEvent newEvent; + newEvent.sgEventType = SceneGraphGUIThread; + newEvent.duration = event.numericData1 + event.numericData2 + event.numericData3 + event.numericData4; + newEvent.startTime = event.startTime - newEvent.duration; + for (int i=0; i < timingFieldCount; i++) + newEvent.timing[i] = 0; + + newEvent.timing[0] = event.numericData1; + newEvent.timing[1] = event.numericData2; + newEvent.timing[2] = event.numericData3; + newEvent.timing[3] = event.numericData4; + + d->eventList << newEvent; + break; + } + case SceneGraphWindowsAnimations: { + d->eventList[lastRenderEvent].timing[14] = event.numericData1; + break; + } + case SceneGraphWindowsPolishFrame: { + d->eventList[lastRenderEvent].timing[15] = event.numericData1; + break; + } + } + } + } + + qSort(d->eventList.begin(), d->eventList.end(), compareStartTimes); +} + +void SceneGraphTimelineModel::clear() +{ + d->eventList.clear(); +} + +void SceneGraphTimelineModel::dataChanged() +{ + if (m_modelManager->state() == QmlProfilerDataState::Done) + loadData(); + + if (m_modelManager->state() == QmlProfilerDataState::Empty) + clear(); + + emit stateChanged(); + emit dataAvailable(); + emit emptyChanged(); + return; +} + + + + +} // namespace Internal +} // namespace QmlProfilerExtended |