aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/qmlprofilerextended/scenegraphtimelinemodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/qmlprofilerextended/scenegraphtimelinemodel.cpp')
-rw-r--r--plugins/qmlprofilerextended/scenegraphtimelinemodel.cpp467
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