aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp')
-rw-r--r--src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp311
1 files changed, 311 insertions, 0 deletions
diff --git a/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp b/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp
new file mode 100644
index 0000000000..cb61bbf07e
--- /dev/null
+++ b/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "scenegraphtimelinemodel.h"
+#include "qmldebug/qmlprofilereventtypes.h"
+#include "qmlprofiler/qmlprofilermodelmanager.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+
+namespace QmlProfilerExtension {
+namespace Internal {
+
+using namespace QmlProfiler;
+
+static const char *ThreadLabels[] = {
+ QT_TRANSLATE_NOOP("MainView", "GUI Thread"),
+ QT_TRANSLATE_NOOP("MainView", "Render Thread"),
+ QT_TRANSLATE_NOOP("MainView", "Render Thread Details")
+};
+
+static const char *StageLabels[] = {
+ QT_TRANSLATE_NOOP("MainView", "Polish"),
+ QT_TRANSLATE_NOOP("MainView", "Wait"),
+ QT_TRANSLATE_NOOP("MainView", "GUI Thread Sync"),
+ QT_TRANSLATE_NOOP("MainView", "Animations"),
+ QT_TRANSLATE_NOOP("MainView", "Render Thread Sync"),
+ QT_TRANSLATE_NOOP("MainView", "Render"),
+ QT_TRANSLATE_NOOP("MainView", "Swap"),
+ QT_TRANSLATE_NOOP("MainView", "Render Preprocess"),
+ QT_TRANSLATE_NOOP("MainView", "Render Update"),
+ QT_TRANSLATE_NOOP("MainView", "Render Bind"),
+ QT_TRANSLATE_NOOP("MainView", "Render Render"),
+ QT_TRANSLATE_NOOP("MainView", "Material Compile"),
+ QT_TRANSLATE_NOOP("MainView", "Glyph Render"),
+ QT_TRANSLATE_NOOP("MainView", "Glyph Upload"),
+ QT_TRANSLATE_NOOP("MainView", "Texture Bind"),
+ QT_TRANSLATE_NOOP("MainView", "Texture Convert"),
+ QT_TRANSLATE_NOOP("MainView", "Texture Swizzle"),
+ QT_TRANSLATE_NOOP("MainView", "Texture Upload"),
+ QT_TRANSLATE_NOOP("MainView", "Texture Mipmap"),
+ QT_TRANSLATE_NOOP("MainView", "Texture Delete")
+};
+
+enum SceneGraphCategoryType {
+ SceneGraphGUIThread,
+ SceneGraphRenderThread,
+ SceneGraphRenderThreadDetails,
+
+ MaximumSceneGraphCategoryType
+};
+
+Q_STATIC_ASSERT(sizeof(StageLabels) ==
+ SceneGraphTimelineModel::MaximumSceneGraphStage * sizeof(const char *));
+
+SceneGraphTimelineModel::SceneGraphTimelineModel(QmlProfilerModelManager *manager,
+ QObject *parent) :
+ QmlProfilerTimelineModel(manager, QmlDebug::SceneGraphFrame, QmlDebug::MaximumRangeType,
+ QmlDebug::ProfileSceneGraph, parent)
+{
+}
+
+int SceneGraphTimelineModel::expandedRow(int index) const
+{
+ return selectionId(index) + 1;
+}
+
+int SceneGraphTimelineModel::collapsedRow(int index) const
+{
+ return m_data[index].rowNumberCollapsed;
+}
+
+int SceneGraphTimelineModel::typeId(int index) const
+{
+ return m_data[index].typeId;
+}
+
+QColor SceneGraphTimelineModel::color(int index) const
+{
+ return colorBySelectionId(index);
+}
+
+QVariantList SceneGraphTimelineModel::labels() const
+{
+ QVariantList result;
+
+ for (SceneGraphStage i = MinimumSceneGraphStage; i < MaximumSceneGraphStage;
+ i = static_cast<SceneGraphStage>(i + 1)) {
+ QVariantMap element;
+ element.insert(QLatin1String("displayName"), tr(threadLabel(i)));
+ element.insert(QLatin1String("description"), tr(StageLabels[i]));
+ element.insert(QLatin1String("id"), i);
+ result << element;
+ }
+
+ return result;
+}
+
+QVariantMap SceneGraphTimelineModel::details(int index) const
+{
+ QVariantMap result;
+ const SceneGraphStage stage = static_cast<SceneGraphStage>(selectionId(index));
+
+ result.insert(QLatin1String("displayName"), tr(threadLabel(stage)));
+ result.insert(tr("Stage"), tr(StageLabels[stage]));
+ result.insert(tr("Duration"), QmlProfilerDataModel::formatTime(duration(index)));
+
+ const int glyphCount = m_data[index].glyphCount;
+ if (glyphCount >= 0)
+ result.insert(tr("Glyphs"), QString::number(glyphCount));
+
+ return result;
+}
+
+void SceneGraphTimelineModel::loadData()
+{
+ QmlProfilerDataModel *simpleModel = modelManager()->qmlModel();
+ if (simpleModel->isEmpty())
+ return;
+
+ // combine the data of several eventtypes into two rows
+ const QVector<QmlProfilerDataModel::QmlEventTypeData> &types = simpleModel->getEventTypes();
+ foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) {
+ const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()];
+ if (!accepted(type))
+ continue;
+
+ switch ((QmlDebug::SceneGraphFrameType)type.detailType) {
+ case QmlDebug::SceneGraphRendererFrame: {
+ // Breakdown of render times. We repeat "render" here as "net" render time. It would
+ // look incomplete if that was left out as the printf profiler lists it, too, and people
+ // are apparently comparing that. Unfortunately it is somewhat redundant as the other
+ // parts of the breakdown are usually very short.
+ qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) -
+ event.numericData(2) - event.numericData(3);
+ startTime += insert(startTime, event.numericData(0), event.typeIndex(), RenderPreprocess);
+ startTime += insert(startTime, event.numericData(1), event.typeIndex(), RenderUpdate);
+ startTime += insert(startTime, event.numericData(2), event.typeIndex(), RenderBind);
+ insert(startTime, event.numericData(3), event.typeIndex(), RenderRender);
+ break;
+ }
+ case QmlDebug::SceneGraphAdaptationLayerFrame: {
+ qint64 startTime = event.startTime() - event.numericData(1) - event.numericData(2);
+ startTime += insert(startTime, event.numericData(1), event.typeIndex(), GlyphRender,
+ event.numericData(0));
+ insert(startTime, event.numericData(2), event.typeIndex(), GlyphStore, event.numericData(0));
+ break;
+ }
+ case QmlDebug::SceneGraphContextFrame: {
+ insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(),
+ Material);
+ break;
+ }
+ case QmlDebug::SceneGraphRenderLoopFrame: {
+ qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) -
+ event.numericData(2);
+ startTime += insert(startTime, event.numericData(0), event.typeIndex(),
+ RenderThreadSync);
+ startTime += insert(startTime, event.numericData(1), event.typeIndex(),
+ Render);
+ insert(startTime, event.numericData(2), event.typeIndex(), Swap);
+ break;
+ }
+ case QmlDebug::SceneGraphTexturePrepare: {
+ qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) -
+ event.numericData(2) - event.numericData(3) - event.numericData(4);
+ startTime += insert(startTime, event.numericData(0), event.typeIndex(), TextureBind);
+ startTime += insert(startTime, event.numericData(1), event.typeIndex(), TextureConvert);
+ startTime += insert(startTime, event.numericData(2), event.typeIndex(), TextureSwizzle);
+ startTime += insert(startTime, event.numericData(3), event.typeIndex(), TextureUpload);
+ insert(startTime, event.numericData(4), event.typeIndex(), TextureMipmap);
+ break;
+ }
+ case QmlDebug::SceneGraphTextureDeletion: {
+ insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(),
+ TextureDeletion);
+ break;
+ }
+ case QmlDebug::SceneGraphPolishAndSync: {
+ qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) -
+ event.numericData(2) - event.numericData(3);
+
+ startTime += insert(startTime, event.numericData(0), event.typeIndex(), Polish);
+ startTime += insert(startTime, event.numericData(1), event.typeIndex(), Wait);
+ startTime += insert(startTime, event.numericData(2), event.typeIndex(), GUIThreadSync);
+ insert(startTime, event.numericData(3), event.typeIndex(), Animations);
+ break;
+ }
+ case QmlDebug::SceneGraphWindowsAnimations: {
+ // GUI thread, separate animations stage
+ insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(),
+ Animations);
+ break;
+ }
+ case QmlDebug::SceneGraphPolishFrame: {
+ // GUI thread, separate polish stage
+ insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(),
+ Polish);
+ break;
+ }
+ default: break;
+ }
+
+ updateProgress(count(), simpleModel->getEvents().count());
+ }
+
+ computeNesting();
+ flattenLoads();
+ updateProgress(1, 1);
+}
+
+void SceneGraphTimelineModel::flattenLoads()
+{
+ int collapsedRowCount = 0;
+
+ // computes "compressed row"
+ QVector <qint64> eventEndTimes;
+
+ for (int i = 0; i < count(); i++) {
+ SceneGraphEvent &event = m_data[i];
+ int stage = selectionId(i);
+ // Don't try to put render thread events in GUI row and vice versa.
+ // Rows below those are free for all.
+ if (stage < MaximumGUIThreadStage)
+ event.rowNumberCollapsed = SceneGraphGUIThread;
+ else if (stage < MaximumRenderThreadStage)
+ event.rowNumberCollapsed = SceneGraphRenderThread;
+ else
+ event.rowNumberCollapsed = SceneGraphRenderThreadDetails;
+
+ while (eventEndTimes.count() > event.rowNumberCollapsed &&
+ eventEndTimes[event.rowNumberCollapsed] > startTime(i))
+ ++event.rowNumberCollapsed;
+
+ while (eventEndTimes.count() <= event.rowNumberCollapsed)
+ eventEndTimes << 0; // increase stack length, proper value added below
+ eventEndTimes[event.rowNumberCollapsed] = endTime(i);
+
+ // readjust to account for category empty row
+ event.rowNumberCollapsed++;
+ if (event.rowNumberCollapsed > collapsedRowCount)
+ collapsedRowCount = event.rowNumberCollapsed;
+ }
+
+ // Starting from 0, count is maxIndex+1
+ setCollapsedRowCount(collapsedRowCount + 1);
+ setExpandedRowCount(MaximumSceneGraphStage + 1);
+}
+
+/*!
+ * Inserts an event characterized by \a start time, \a duration, \a typeIndex, \a stage and possibly
+ * \a glyphCount (if it's a \c GlyphRender or \c GlyphStore event) into the scene graph model if its
+ * \a duration is greater than 0. Returns \a duration in that case; otherwise returns 0.
+ */
+qint64 SceneGraphTimelineModel::insert(qint64 start, qint64 duration, int typeIndex,
+ SceneGraphStage stage, int glyphCount)
+{
+ if (duration <= 0)
+ return 0;
+
+ m_data.insert(QmlProfilerTimelineModel::insert(start, duration, stage),
+ SceneGraphEvent(typeIndex, glyphCount));
+ return duration;
+}
+
+const char *SceneGraphTimelineModel::threadLabel(SceneGraphStage stage)
+{
+ if (stage < MaximumGUIThreadStage)
+ return ThreadLabels[SceneGraphGUIThread];
+ else if (stage < MaximumRenderThreadStage)
+ return ThreadLabels[SceneGraphRenderThread];
+ else
+ return ThreadLabels[SceneGraphRenderThreadDetails];
+
+}
+
+void SceneGraphTimelineModel::clear()
+{
+ m_data.clear();
+ QmlProfilerTimelineModel::clear();
+}
+
+SceneGraphTimelineModel::SceneGraphEvent::SceneGraphEvent(int typeId, int glyphCount) :
+ typeId(typeId), rowNumberCollapsed(-1), glyphCount(glyphCount)
+{
+}
+
+} // namespace Internal
+} // namespace QmlProfilerExtension