2013-06-11 15:13:33 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2013-06-20 12:34:02 +02:00
|
|
|
** Copyright (C) 2013 Digia Plc
|
|
|
|
|
** All rights reserved.
|
|
|
|
|
** For any questions to Digia, please use contact form at http://qt.digia.com <http://qt.digia.com/>
|
2013-06-11 15:13:33 +02:00
|
|
|
**
|
2013-06-20 12:34:02 +02:00
|
|
|
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
|
2013-06-11 15:13:33 +02:00
|
|
|
**
|
2013-06-20 12:34:02 +02:00
|
|
|
** Licensees holding valid Qt Enterprise licenses may use this file in
|
|
|
|
|
** accordance with the Qt Enterprise License Agreement provided with the
|
2013-06-11 15:13:33 +02:00
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2013-06-20 12:34:02 +02:00
|
|
|
** a written agreement between you and Digia.
|
|
|
|
|
**
|
|
|
|
|
** If you have questions regarding the use of this file, please use
|
|
|
|
|
** contact form at http://qt.digia.com <http://qt.digia.com/>
|
2013-06-11 15:13:33 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "scenegraphtimelinemodel.h"
|
|
|
|
|
#include "qmldebug/qmlprofilereventtypes.h"
|
|
|
|
|
#include "qmlprofiler/qmlprofilermodelmanager.h"
|
2013-12-06 15:38:22 +01:00
|
|
|
#include "qmlprofiler/sortedtimelinemodel.h"
|
2014-06-12 16:03:40 +02:00
|
|
|
#include "qmlprofiler/abstracttimelinemodel_p.h"
|
2013-06-11 15:13:33 +02:00
|
|
|
|
2013-06-20 10:11:52 +02:00
|
|
|
#include <QCoreApplication>
|
2013-06-11 15:13:33 +02:00
|
|
|
#include <QDebug>
|
|
|
|
|
|
2013-06-24 14:17:43 +02:00
|
|
|
namespace QmlProfilerExtension {
|
2013-06-11 15:13:33 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2013-08-12 11:44:35 +02:00
|
|
|
using namespace QmlProfiler;
|
2013-06-11 15:13:33 +02:00
|
|
|
|
2014-06-30 12:47:49 +02:00
|
|
|
static const char *ThreadLabels[] = {
|
|
|
|
|
"GUI Thread",
|
|
|
|
|
"Render Thread"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char *StageLabels[] = {
|
|
|
|
|
"Polish",
|
|
|
|
|
"Wait",
|
|
|
|
|
"Sync",
|
|
|
|
|
"Animations",
|
|
|
|
|
"Sync",
|
|
|
|
|
"Swap",
|
|
|
|
|
"Material Compile",
|
|
|
|
|
"Render Preprocess",
|
|
|
|
|
"Render Update",
|
|
|
|
|
"Render Bind",
|
|
|
|
|
"Render",
|
|
|
|
|
"Glyph Render",
|
|
|
|
|
"Glyph Upload",
|
|
|
|
|
"Texture Bind",
|
|
|
|
|
"Texture Convert",
|
|
|
|
|
"Texture Swizzle",
|
|
|
|
|
"Texture Upload",
|
|
|
|
|
"Texture Mipmap"
|
2013-06-11 15:13:33 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum SceneGraphCategoryType {
|
|
|
|
|
SceneGraphGUIThread,
|
2014-06-03 19:06:34 +02:00
|
|
|
SceneGraphRenderThread,
|
2013-06-11 15:13:33 +02:00
|
|
|
|
|
|
|
|
MaximumSceneGraphCategoryType
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-30 12:47:49 +02:00
|
|
|
enum SceneGraphStage {
|
|
|
|
|
Polish = 0,
|
|
|
|
|
Wait,
|
|
|
|
|
GUIThreadSync,
|
|
|
|
|
Animations,
|
|
|
|
|
MaximumGUIThreadStage,
|
|
|
|
|
|
|
|
|
|
RenderThreadSync = MaximumGUIThreadStage,
|
|
|
|
|
Swap,
|
|
|
|
|
Material,
|
|
|
|
|
MaximumRenderThreadStage,
|
|
|
|
|
|
|
|
|
|
RenderPreprocess = MaximumRenderThreadStage,
|
|
|
|
|
RenderUpdate,
|
|
|
|
|
RenderBind,
|
|
|
|
|
RenderRender,
|
|
|
|
|
MaximumRenderStage,
|
|
|
|
|
|
|
|
|
|
GlyphRender = MaximumRenderStage,
|
|
|
|
|
GlyphStore,
|
|
|
|
|
MaximumGlyphStage,
|
|
|
|
|
|
|
|
|
|
TextureBind = MaximumGlyphStage,
|
|
|
|
|
TextureConvert,
|
|
|
|
|
TextureSwizzle,
|
|
|
|
|
TextureUpload,
|
|
|
|
|
TextureMipmap,
|
|
|
|
|
MaximumTextureStage,
|
|
|
|
|
|
|
|
|
|
MaximumSceneGraphStage = MaximumTextureStage
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Q_STATIC_ASSERT(sizeof(StageLabels) == MaximumSceneGraphStage * sizeof(const char *));
|
|
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
class SceneGraphTimelineModel::SceneGraphTimelineModelPrivate :
|
|
|
|
|
public SortedTimelineModel<SceneGraphTimelineModel::SceneGraphEvent,
|
2014-06-12 16:03:40 +02:00
|
|
|
AbstractTimelineModel::AbstractTimelineModelPrivate>
|
2014-02-14 16:34:22 +01:00
|
|
|
{
|
2013-06-11 15:13:33 +02:00
|
|
|
public:
|
2014-06-30 12:47:49 +02:00
|
|
|
SceneGraphTimelineModelPrivate();
|
|
|
|
|
int collapsedRowCount;
|
|
|
|
|
void flattenLoads();
|
|
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
private:
|
|
|
|
|
Q_DECLARE_PUBLIC(SceneGraphTimelineModel)
|
2013-06-11 15:13:33 +02:00
|
|
|
};
|
|
|
|
|
|
2014-06-30 12:47:49 +02:00
|
|
|
SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::SceneGraphTimelineModelPrivate() :
|
|
|
|
|
collapsedRowCount(1)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-11 15:13:33 +02:00
|
|
|
SceneGraphTimelineModel::SceneGraphTimelineModel(QObject *parent)
|
2014-07-08 13:29:21 +02:00
|
|
|
: AbstractTimelineModel(new SceneGraphTimelineModelPrivate, tr("Scene Graph"),
|
|
|
|
|
QmlDebug::SceneGraphFrame, QmlDebug::MaximumRangeType, parent)
|
2013-06-11 15:13:33 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-12 13:27:41 +02:00
|
|
|
int SceneGraphTimelineModel::rowCount() const
|
2013-06-11 15:13:33 +02:00
|
|
|
{
|
2014-06-03 19:06:34 +02:00
|
|
|
Q_D(const SceneGraphTimelineModel);
|
2013-06-11 15:13:33 +02:00
|
|
|
if (isEmpty())
|
|
|
|
|
return 1;
|
2014-06-30 12:47:49 +02:00
|
|
|
return expanded() ? (MaximumSceneGraphStage + 1) : d->collapsedRowCount;
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-08 14:53:47 +02:00
|
|
|
int SceneGraphTimelineModel::row(int index) const
|
2013-06-11 15:13:33 +02:00
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const SceneGraphTimelineModel);
|
2014-06-30 12:47:49 +02:00
|
|
|
return expanded() ? (d->range(index).stage + 1) : d->range(index).rowNumberCollapsed;
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-08 14:53:47 +02:00
|
|
|
int SceneGraphTimelineModel::eventId(int index) const
|
2013-06-11 15:13:33 +02:00
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const SceneGraphTimelineModel);
|
2014-06-30 12:47:49 +02:00
|
|
|
return d->range(index).stage;
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-08 14:53:47 +02:00
|
|
|
QColor SceneGraphTimelineModel::color(int index) const
|
2013-06-11 15:13:33 +02:00
|
|
|
{
|
2014-06-30 12:47:49 +02:00
|
|
|
return colorByEventId(eventId(index));
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-08 14:53:47 +02:00
|
|
|
QVariantList SceneGraphTimelineModel::labels() const
|
2013-06-11 15:13:33 +02:00
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const SceneGraphTimelineModel);
|
2013-06-11 15:13:33 +02:00
|
|
|
QVariantList result;
|
|
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
if (d->expanded && !isEmpty()) {
|
2014-06-30 12:47:49 +02:00
|
|
|
for (int i = 0; i < MaximumSceneGraphStage; ++i) {
|
2013-06-13 13:05:14 +02:00
|
|
|
QVariantMap element;
|
2014-06-30 12:47:49 +02:00
|
|
|
element.insert(QLatin1String("displayName"), tr(ThreadLabels[i < MaximumGUIThreadStage ?
|
|
|
|
|
SceneGraphGUIThread : SceneGraphRenderThread]));
|
|
|
|
|
element.insert(QLatin1String("description"), tr(StageLabels[i]));
|
|
|
|
|
element.insert(QLatin1String("id"), i);
|
2013-06-13 13:05:14 +02:00
|
|
|
result << element;
|
|
|
|
|
}
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-07 14:41:44 +02:00
|
|
|
QVariantMap SceneGraphTimelineModel::details(int index) const
|
2013-06-11 15:13:33 +02:00
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const SceneGraphTimelineModel);
|
2014-07-07 14:41:44 +02:00
|
|
|
QVariantMap result;
|
2014-02-14 16:34:22 +01:00
|
|
|
const SortedTimelineModel<SceneGraphEvent,
|
2014-06-12 16:03:40 +02:00
|
|
|
AbstractTimelineModel::AbstractTimelineModelPrivate>::Range *ev =
|
2014-02-14 16:34:22 +01:00
|
|
|
&d->range(index);
|
2013-06-11 15:13:33 +02:00
|
|
|
|
2014-06-30 12:47:49 +02:00
|
|
|
result.insert(QLatin1String("displayName"), tr(ThreadLabels[ev->stage < MaximumGUIThreadStage ?
|
|
|
|
|
SceneGraphGUIThread : SceneGraphRenderThread]));
|
|
|
|
|
result.insert(tr("Stage"), tr(StageLabels[ev->stage]));
|
|
|
|
|
result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(ev->duration));
|
|
|
|
|
if (ev->glyphCount >= 0)
|
|
|
|
|
result.insert(tr("Glyph Count"), QString::number(ev->glyphCount));
|
2013-06-11 15:13:33 +02:00
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SceneGraphTimelineModel::loadData()
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(SceneGraphTimelineModel);
|
2013-06-11 15:13:33 +02:00
|
|
|
clear();
|
2014-02-18 18:34:43 +01:00
|
|
|
QmlProfilerDataModel *simpleModel = d->modelManager->qmlModel();
|
2013-06-11 15:13:33 +02:00
|
|
|
if (simpleModel->isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// combine the data of several eventtypes into two rows
|
2014-06-13 16:56:46 +02:00
|
|
|
const QVector<QmlProfilerDataModel::QmlEventTypeData> &types = simpleModel->getEventTypes();
|
2014-02-18 18:34:43 +01:00
|
|
|
foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) {
|
2014-06-13 16:56:46 +02:00
|
|
|
const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex];
|
2014-07-08 14:53:47 +02:00
|
|
|
if (!accepted(type))
|
2013-06-11 15:13:33 +02:00
|
|
|
continue;
|
|
|
|
|
|
2014-06-30 12:47:49 +02:00
|
|
|
switch ((QmlDebug::SceneGraphFrameType)type.detailType) {
|
|
|
|
|
case QmlDebug::SceneGraphRendererFrame: {
|
|
|
|
|
qint64 startTime = event.startTime - event.numericData1 - event.numericData2 -
|
|
|
|
|
event.numericData3 - event.numericData4;
|
|
|
|
|
d->insert(startTime, event.numericData1, SceneGraphEvent(RenderPreprocess));
|
|
|
|
|
startTime += event.numericData1;
|
|
|
|
|
d->insert(startTime, event.numericData2, SceneGraphEvent(RenderUpdate));
|
|
|
|
|
startTime += event.numericData2;
|
|
|
|
|
d->insert(startTime, event.numericData3, SceneGraphEvent(RenderBind));
|
|
|
|
|
startTime += event.numericData3;
|
|
|
|
|
d->insert(startTime, event.numericData4, SceneGraphEvent(RenderRender));
|
|
|
|
|
break;
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
2014-06-30 12:47:49 +02:00
|
|
|
case QmlDebug::SceneGraphAdaptationLayerFrame: {
|
|
|
|
|
qint64 startTime = event.startTime - event.numericData2 - event.numericData3;
|
|
|
|
|
d->insert(startTime, event.numericData2,
|
|
|
|
|
SceneGraphEvent(GlyphRender, event.numericData1));
|
|
|
|
|
startTime += event.numericData2;
|
|
|
|
|
d->insert(startTime, event.numericData3,
|
|
|
|
|
SceneGraphEvent(GlyphStore, event.numericData1));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case QmlDebug::SceneGraphContextFrame: {
|
|
|
|
|
d->insert(event.startTime - event.numericData1, event.numericData1,
|
|
|
|
|
SceneGraphEvent(Material));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case QmlDebug::SceneGraphRenderLoopFrame: {
|
|
|
|
|
qint64 startTime = event.startTime - event.numericData1 - event.numericData2 -
|
|
|
|
|
event.numericData3;
|
|
|
|
|
d->insert(startTime, event.numericData1, SceneGraphEvent(RenderThreadSync));
|
|
|
|
|
startTime += event.numericData1 + event.numericData2;
|
|
|
|
|
// Skip actual rendering. We get a SceneGraphRendererFrame for that
|
|
|
|
|
d->insert(startTime, event.numericData3, SceneGraphEvent(Swap));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case QmlDebug::SceneGraphTexturePrepare: {
|
|
|
|
|
qint64 startTime = event.startTime - event.numericData1 - event.numericData2 -
|
|
|
|
|
event.numericData3 - event.numericData4 - event.numericData5;
|
|
|
|
|
|
|
|
|
|
d->insert(startTime, event.numericData1, SceneGraphEvent(TextureBind));
|
|
|
|
|
startTime += event.numericData1;
|
|
|
|
|
d->insert(startTime, event.numericData2, SceneGraphEvent(TextureConvert));
|
|
|
|
|
startTime += event.numericData2;
|
|
|
|
|
d->insert(startTime, event.numericData3, SceneGraphEvent(TextureSwizzle));
|
|
|
|
|
startTime += event.numericData3;
|
|
|
|
|
d->insert(startTime, event.numericData4, SceneGraphEvent(TextureUpload));
|
|
|
|
|
startTime += event.numericData4;
|
|
|
|
|
d->insert(startTime, event.numericData4, SceneGraphEvent(TextureMipmap));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case QmlDebug::SceneGraphPolishAndSync: {
|
|
|
|
|
qint64 startTime = event.startTime - event.numericData1 - event.numericData2 -
|
|
|
|
|
event.numericData3 - event.numericData4;
|
|
|
|
|
|
|
|
|
|
d->insert(startTime, event.numericData1, SceneGraphEvent(Polish));
|
|
|
|
|
startTime += event.numericData1;
|
|
|
|
|
d->insert(startTime, event.numericData2, SceneGraphEvent(Wait));
|
|
|
|
|
startTime += event.numericData2;
|
|
|
|
|
d->insert(startTime, event.numericData3, SceneGraphEvent(GUIThreadSync));
|
|
|
|
|
startTime += event.numericData3;
|
|
|
|
|
d->insert(startTime, event.numericData4, SceneGraphEvent(Animations));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case QmlDebug::SceneGraphWindowsAnimations: {
|
|
|
|
|
// GUI thread, separate animations stage
|
|
|
|
|
d->insert(event.startTime - event.numericData1, event.numericData1,
|
|
|
|
|
SceneGraphEvent(Animations));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case QmlDebug::SceneGraphPolishFrame: {
|
|
|
|
|
// GUI thread, separate polish stage
|
|
|
|
|
d->insert(event.startTime - event.numericData1, event.numericData1,
|
|
|
|
|
SceneGraphEvent(Polish));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: break;
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
2013-07-25 17:29:22 +02:00
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
d->modelManager->modelProxyCountUpdated(d->modelId, d->count(), simpleModel->getEvents().count());
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
2013-12-06 15:38:22 +01:00
|
|
|
d->computeNesting();
|
2014-06-30 12:47:49 +02:00
|
|
|
d->flattenLoads();
|
2014-02-14 16:34:22 +01:00
|
|
|
d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1);
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-30 12:47:49 +02:00
|
|
|
void SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::flattenLoads()
|
|
|
|
|
{
|
|
|
|
|
collapsedRowCount = 0;
|
|
|
|
|
|
|
|
|
|
// computes "compressed row"
|
|
|
|
|
QVector <qint64> eventEndTimes;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < count(); i++) {
|
|
|
|
|
SceneGraphEvent &event = data(i);
|
|
|
|
|
const Range &start = range(i);
|
|
|
|
|
// Don't try to put render thread events in GUI row and vice versa.
|
|
|
|
|
// Rows below those are free for all.
|
|
|
|
|
event.rowNumberCollapsed = (event.stage < MaximumGUIThreadStage ? SceneGraphGUIThread :
|
|
|
|
|
SceneGraphRenderThread);
|
|
|
|
|
while (eventEndTimes.count() > event.rowNumberCollapsed &&
|
|
|
|
|
eventEndTimes[event.rowNumberCollapsed] > start.start) {
|
|
|
|
|
++event.rowNumberCollapsed;
|
|
|
|
|
if (event.stage < MaximumGUIThreadStage) {
|
|
|
|
|
if (event.rowNumberCollapsed == SceneGraphRenderThread)
|
|
|
|
|
++event.rowNumberCollapsed;
|
|
|
|
|
} else if (event.rowNumberCollapsed == SceneGraphGUIThread) {
|
|
|
|
|
++event.rowNumberCollapsed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (eventEndTimes.count() <= event.rowNumberCollapsed)
|
|
|
|
|
eventEndTimes << 0; // increase stack length, proper value added below
|
|
|
|
|
eventEndTimes[event.rowNumberCollapsed] = start.start + start.duration;
|
|
|
|
|
|
|
|
|
|
// readjust to account for category empty row
|
|
|
|
|
event.rowNumberCollapsed++;
|
|
|
|
|
if (event.rowNumberCollapsed > collapsedRowCount)
|
|
|
|
|
collapsedRowCount = event.rowNumberCollapsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Starting from 0, count is maxIndex+1
|
|
|
|
|
collapsedRowCount++;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-11 15:13:33 +02:00
|
|
|
void SceneGraphTimelineModel::clear()
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(SceneGraphTimelineModel);
|
2013-12-06 15:38:22 +01:00
|
|
|
d->clear();
|
2014-02-14 16:34:22 +01:00
|
|
|
d->expanded = false;
|
2014-06-30 12:47:49 +02:00
|
|
|
d->collapsedRowCount = 1;
|
2014-02-14 16:34:22 +01:00
|
|
|
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-30 12:47:49 +02:00
|
|
|
SceneGraphTimelineModel::SceneGraphEvent::SceneGraphEvent(int stage, int glyphCount) :
|
|
|
|
|
stage(stage), rowNumberCollapsed(-1), glyphCount(glyphCount)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-11 15:13:33 +02:00
|
|
|
} // namespace Internal
|
2013-06-24 14:17:43 +02:00
|
|
|
} // namespace QmlProfilerExtension
|