scenegraphtimelinemodel.cpp 11.6 KB
Newer Older
1 2
/****************************************************************************
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
5
**
6
** This file is part of Qt Creator.
7
**
8 9 10
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
11
** Software or, alternatively, in accordance with the terms contained in
12 13 14
** 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.
15
**
16 17 18 19 20 21 22
** 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.
23 24 25 26
**
****************************************************************************/

#include "scenegraphtimelinemodel.h"
27
#include "qmlprofilermodelmanager.h"
28
#include "qmlprofilereventtypes.h"
29

30 31
#include <timeline/timelineformattime.h>

Kai Koehne's avatar
Kai Koehne committed
32
#include <QCoreApplication>
33 34
#include <QDebug>

35
namespace QmlProfiler {
36 37
namespace Internal {

38
static const char *ThreadLabels[] = {
39 40 41
    QT_TRANSLATE_NOOP("MainView", "GUI Thread"),
    QT_TRANSLATE_NOOP("MainView", "Render Thread"),
    QT_TRANSLATE_NOOP("MainView", "Render Thread Details")
42 43 44
};

static const char *StageLabels[] = {
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
    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"),
63 64
    QT_TRANSLATE_NOOP("MainView", "Texture Mipmap"),
    QT_TRANSLATE_NOOP("MainView", "Texture Delete")
65 66 67 68
};

enum SceneGraphCategoryType {
    SceneGraphGUIThread,
69
    SceneGraphRenderThread,
70
    SceneGraphRenderThreadDetails,
71 72 73 74

    MaximumSceneGraphCategoryType
};

75 76
Q_STATIC_ASSERT(sizeof(StageLabels) ==
                SceneGraphTimelineModel::MaximumSceneGraphStage * sizeof(const char *));
77

78 79
SceneGraphTimelineModel::SceneGraphTimelineModel(QmlProfilerModelManager *manager,
                                                 QObject *parent) :
80
    QmlProfilerTimelineModel(manager, SceneGraphFrame, MaximumRangeType, ProfileSceneGraph, parent)
81
{
82 83
}

84
int SceneGraphTimelineModel::expandedRow(int index) const
85
{
86 87 88 89 90 91
    return selectionId(index) + 1;
}

int SceneGraphTimelineModel::collapsedRow(int index) const
{
    return m_data[index].rowNumberCollapsed;
92 93
}

94
int SceneGraphTimelineModel::typeId(int index) const
95
{
96
    return m_data[index].typeId;
97 98
}

99
QRgb SceneGraphTimelineModel::color(int index) const
100
{
101
    return colorBySelectionId(index);
102 103
}

104
QVariantList SceneGraphTimelineModel::labels() const
105 106 107
{
    QVariantList result;

108 109 110 111 112 113 114
    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;
115 116 117 118 119
    }

    return result;
}

Ulf Hermann's avatar
Ulf Hermann committed
120
QVariantMap SceneGraphTimelineModel::details(int index) const
121
{
Ulf Hermann's avatar
Ulf Hermann committed
122
    QVariantMap result;
123
    const SceneGraphStage stage = static_cast<SceneGraphStage>(selectionId(index));
124

125 126
    result.insert(QLatin1String("displayName"), tr(threadLabel(stage)));
    result.insert(tr("Stage"), tr(StageLabels[stage]));
127
    result.insert(tr("Duration"), Timeline::formatTime(duration(index)));
128 129 130 131

    const int glyphCount = m_data[index].glyphCount;
    if (glyphCount >= 0)
        result.insert(tr("Glyphs"), QString::number(glyphCount));
132 133 134 135

    return result;
}

136
void SceneGraphTimelineModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
137 138
{
    // combine the data of several eventtypes into two rows
139
    switch ((SceneGraphFrameType)type.detailType()) {
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    case 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.timestamp() - event.number<qint64>(0) - event.number<qint64>(1) -
                event.number<qint64>(2) - event.number<qint64>(3);
        startTime += insert(startTime, event.number<qint64>(0), event.typeIndex(),
                            RenderPreprocess);
        startTime += insert(startTime, event.number<qint64>(1), event.typeIndex(), RenderUpdate);
        startTime += insert(startTime, event.number<qint64>(2), event.typeIndex(), RenderBind);
        insert(startTime, event.number<qint64>(3), event.typeIndex(), RenderRender);
        break;
    }
    case SceneGraphAdaptationLayerFrame: {
        qint64 startTime = event.timestamp() - event.number<qint64>(1) - event.number<qint64>(2);
        startTime += insert(startTime, event.number<qint64>(1), event.typeIndex(), GlyphRender,
                            event.number<qint64>(0));
        insert(startTime, event.number<qint64>(2), event.typeIndex(), GlyphStore,
               event.number<qint64>(0));
        break;
    }
    case SceneGraphContextFrame: {
        insert(event.timestamp() - event.number<qint64>(0), event.number<qint64>(0),
               event.typeIndex(), Material);
        break;
    }
    case SceneGraphRenderLoopFrame: {
        qint64 startTime = event.timestamp() - event.number<qint64>(0) - event.number<qint64>(1) -
                event.number<qint64>(2);
        startTime += insert(startTime, event.number<qint64>(0), event.typeIndex(),
                               RenderThreadSync);
        startTime += insert(startTime, event.number<qint64>(1), event.typeIndex(),
                               Render);
        insert(startTime, event.number<qint64>(2), event.typeIndex(), Swap);
        break;
    }
    case SceneGraphTexturePrepare: {
        qint64 startTime = event.timestamp() - event.number<qint64>(0) - event.number<qint64>(1) -
                event.number<qint64>(2) - event.number<qint64>(3) - event.number<qint64>(4);
        startTime += insert(startTime, event.number<qint64>(0), event.typeIndex(), TextureBind);
        startTime += insert(startTime, event.number<qint64>(1), event.typeIndex(), TextureConvert);
        startTime += insert(startTime, event.number<qint64>(2), event.typeIndex(), TextureSwizzle);
        startTime += insert(startTime, event.number<qint64>(3), event.typeIndex(), TextureUpload);
        insert(startTime, event.number<qint64>(4), event.typeIndex(), TextureMipmap);
        break;
    }
    case SceneGraphTextureDeletion: {
        insert(event.timestamp() - event.number<qint64>(0), event.number<qint64>(0),
               event.typeIndex(), TextureDeletion);
        break;
191
    }
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    case SceneGraphPolishAndSync: {
        qint64 startTime = event.timestamp() - event.number<qint64>(0) - event.number<qint64>(1) -
                event.number<qint64>(2) - event.number<qint64>(3);

        startTime += insert(startTime, event.number<qint64>(0), event.typeIndex(), Polish);
        startTime += insert(startTime, event.number<qint64>(1), event.typeIndex(), Wait);
        startTime += insert(startTime, event.number<qint64>(2), event.typeIndex(), GUIThreadSync);
        insert(startTime, event.number<qint64>(3), event.typeIndex(), Animations);
        break;
    }
    case SceneGraphWindowsAnimations: {
        // GUI thread, separate animations stage
        insert(event.timestamp() - event.number<qint64>(0), event.number<qint64>(0),
               event.typeIndex(), Animations);
        break;
    }
    case SceneGraphPolishFrame: {
        // GUI thread, separate polish stage
        insert(event.timestamp() - event.number<qint64>(0), event.number<qint64>(0),
               event.typeIndex(), Polish);
        break;
    }
    default: break;
    }
}
217

218 219
void SceneGraphTimelineModel::finalize()
{
220
    computeNesting();
221
    flattenLoads();
222 223
}

224
void SceneGraphTimelineModel::flattenLoads()
225
{
226
    int collapsedRowCount = 0;
227 228 229 230

    // computes "compressed row"
    QVector <qint64> eventEndTimes;

231 232
    for (int i = 0; i < count(); i++) {
        SceneGraphEvent &event = m_data[i];
233
        int stage = selectionId(i);
234 235
        // Don't try to put render thread events in GUI row and vice versa.
        // Rows below those are free for all.
236
        if (stage < MaximumGUIThreadStage)
237
            event.rowNumberCollapsed = SceneGraphGUIThread;
238
        else if (stage < MaximumRenderThreadStage)
239 240 241 242
            event.rowNumberCollapsed = SceneGraphRenderThread;
        else
            event.rowNumberCollapsed = SceneGraphRenderThreadDetails;

243
        while (eventEndTimes.count() > event.rowNumberCollapsed &&
244
               eventEndTimes[event.rowNumberCollapsed] > startTime(i))
245 246 247 248
            ++event.rowNumberCollapsed;

        while (eventEndTimes.count() <= event.rowNumberCollapsed)
            eventEndTimes << 0; // increase stack length, proper value added below
249
        eventEndTimes[event.rowNumberCollapsed] = endTime(i);
250 251 252 253 254 255 256 257

        // readjust to account for category empty row
        event.rowNumberCollapsed++;
        if (event.rowNumberCollapsed > collapsedRowCount)
            collapsedRowCount = event.rowNumberCollapsed;
    }

    // Starting from 0, count is maxIndex+1
258 259
    setCollapsedRowCount(collapsedRowCount + 1);
    setExpandedRowCount(MaximumSceneGraphStage + 1);
260 261
}

262 263 264 265 266
/*!
 * 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.
 */
267 268
qint64 SceneGraphTimelineModel::insert(qint64 start, qint64 duration, int typeIndex,
                                       SceneGraphStage stage, int glyphCount)
269 270 271 272
{
    if (duration <= 0)
        return 0;

273
    m_data.insert(QmlProfilerTimelineModel::insert(start, duration, stage),
274
                  SceneGraphEvent(typeIndex, glyphCount));
275 276 277
    return duration;
}

278
const char *SceneGraphTimelineModel::threadLabel(SceneGraphStage stage)
279 280 281 282 283 284 285 286 287 288
{
    if (stage < MaximumGUIThreadStage)
        return ThreadLabels[SceneGraphGUIThread];
    else if (stage < MaximumRenderThreadStage)
        return ThreadLabels[SceneGraphRenderThread];
    else
        return ThreadLabels[SceneGraphRenderThreadDetails];

}

289 290
void SceneGraphTimelineModel::clear()
{
291
    m_data.clear();
292
    QmlProfilerTimelineModel::clear();
293 294
}

295 296
SceneGraphTimelineModel::SceneGraphEvent::SceneGraphEvent(int typeId, int glyphCount) :
    typeId(typeId), rowNumberCollapsed(-1), glyphCount(glyphCount)
297 298 299
{
}

300
} // namespace Internal
301
} // namespace QmlProfiler