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
|
|
|
|
|
|
|
|
enum SceneGraphEventType {
|
|
|
|
|
SceneGraphRendererFrame,
|
|
|
|
|
SceneGraphAdaptationLayerFrame,
|
|
|
|
|
SceneGraphContextFrame,
|
|
|
|
|
SceneGraphRenderLoopFrame,
|
|
|
|
|
SceneGraphTexturePrepare,
|
|
|
|
|
SceneGraphTextureDeletion,
|
|
|
|
|
SceneGraphPolishAndSync,
|
|
|
|
|
SceneGraphWindowsRenderShow,
|
|
|
|
|
SceneGraphWindowsAnimations,
|
|
|
|
|
SceneGraphWindowsPolishFrame,
|
|
|
|
|
|
|
|
|
|
MaximumSceneGraphFrameType
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum SceneGraphCategoryType {
|
|
|
|
|
SceneGraphGUIThread,
|
2014-06-03 19:06:34 +02:00
|
|
|
SceneGraphRenderThread,
|
2013-06-11 15:13:33 +02:00
|
|
|
|
|
|
|
|
MaximumSceneGraphCategoryType
|
|
|
|
|
};
|
|
|
|
|
|
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-02-14 16:34:22 +01:00
|
|
|
void addVP(QVariantList &l, QString label, qint64 time) const;
|
|
|
|
|
private:
|
2014-06-03 19:06:34 +02:00
|
|
|
bool seenPolishAndSync;
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_DECLARE_PUBLIC(SceneGraphTimelineModel)
|
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-03 19:06:34 +02:00
|
|
|
Q_D(SceneGraphTimelineModel);
|
|
|
|
|
d->seenPolishAndSync = false;
|
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-03 19:06:34 +02:00
|
|
|
return d->seenPolishAndSync ? 3 : 2;
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SceneGraphTimelineModel::getEventRow(int index) const
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const SceneGraphTimelineModel);
|
2014-06-03 19:06:34 +02:00
|
|
|
return d->seenPolishAndSync ? d->range(index).sgEventType + 1 : 1;
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SceneGraphTimelineModel::getEventId(int index) const
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const SceneGraphTimelineModel);
|
2014-06-03 19:06:34 +02:00
|
|
|
return d->seenPolishAndSync ? d->range(index).sgEventType : SceneGraphGUIThread;
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2014-02-26 17:44:58 +01:00
|
|
|
return getFractionColor(fpsFraction);
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString labelForSGType(int t)
|
|
|
|
|
{
|
|
|
|
|
switch ((SceneGraphCategoryType)t) {
|
2013-06-18 16:06:12 +02:00
|
|
|
case SceneGraphRenderThread:
|
2014-03-10 16:02:57 +01:00
|
|
|
return QCoreApplication::translate("SceneGraphTimelineModel", "Render Thread");
|
2013-06-18 16:06:12 +02:00
|
|
|
case SceneGraphGUIThread:
|
2013-06-20 10:11:52 +02:00
|
|
|
return QCoreApplication::translate("SceneGraphTimelineModel", "GUI Thread");
|
2013-06-18 16:06:12 +02:00
|
|
|
default: return QString();
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-12 13:27:41 +02:00
|
|
|
const QVariantList SceneGraphTimelineModel::getLabels() 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-06-03 19:06:34 +02:00
|
|
|
static QVariant renderThreadLabel(labelForSGType(SceneGraphRenderThread));
|
|
|
|
|
static QVariant guiThreadLabel(labelForSGType(SceneGraphGUIThread));
|
|
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
if (d->expanded && !isEmpty()) {
|
2014-06-03 19:06:34 +02:00
|
|
|
{
|
2013-06-13 13:05:14 +02:00
|
|
|
QVariantMap element;
|
2014-06-03 19:06:34 +02:00
|
|
|
element.insert(QLatin1String("description"), guiThreadLabel);
|
|
|
|
|
element.insert(QLatin1String("id"), SceneGraphGUIThread);
|
|
|
|
|
result << element;
|
|
|
|
|
}
|
|
|
|
|
if (d->seenPolishAndSync) {
|
|
|
|
|
QVariantMap element;
|
|
|
|
|
element.insert(QLatin1String("description"), renderThreadLabel);
|
|
|
|
|
element.insert(QLatin1String("id"), SceneGraphRenderThread);
|
2013-06-13 13:05:14 +02:00
|
|
|
result << element;
|
|
|
|
|
}
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
void SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::addVP(QVariantList &l, QString label, qint64 time) const
|
2013-06-11 15:13:33 +02:00
|
|
|
{
|
|
|
|
|
if (time > 0) {
|
|
|
|
|
QVariantMap res;
|
2014-02-18 18:34:43 +01:00
|
|
|
res.insert(label, QVariant(QmlProfilerBaseModel::formatTime(time)));
|
2013-06-11 15:13:33 +02:00
|
|
|
l << res;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const QVariantList SceneGraphTimelineModel::getEventDetails(int index) const
|
|
|
|
|
{
|
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
|
|
|
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
|
|
|
|
|
|
|
|
{
|
|
|
|
|
QVariantMap res;
|
2014-08-11 15:33:03 +02:00
|
|
|
res.insert(QLatin1String("displayName"), QVariant(labelForSGType(
|
2014-06-03 19:06:34 +02:00
|
|
|
d->seenPolishAndSync ? ev->sgEventType : SceneGraphGUIThread)));
|
2013-06-11 15:13:33 +02:00
|
|
|
result << res;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-14 15:50:55 +02:00
|
|
|
d->addVP(result, tr("Duration"), ev->duration );
|
2013-06-11 15:13:33 +02:00
|
|
|
|
|
|
|
|
if (ev->sgEventType == SceneGraphRenderThread) {
|
2013-06-14 15:50:55 +02:00
|
|
|
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]);
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
if (ev->sgEventType == SceneGraphGUIThread) {
|
2013-06-14 15:50:55 +02:00
|
|
|
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]);
|
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;
|
|
|
|
|
|
|
|
|
|
int lastRenderEvent = -1;
|
|
|
|
|
|
|
|
|
|
// 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];
|
|
|
|
|
if (!eventAccepted(type))
|
2013-06-11 15:13:33 +02:00
|
|
|
continue;
|
|
|
|
|
|
2014-06-13 16:56:46 +02:00
|
|
|
if (type.detailType == SceneGraphRenderLoopFrame) {
|
2013-06-11 15:13:33 +02:00
|
|
|
SceneGraphEvent newEvent;
|
|
|
|
|
newEvent.sgEventType = SceneGraphRenderThread;
|
2013-12-06 15:38:22 +01:00
|
|
|
qint64 duration = event.numericData1 + event.numericData2 + event.numericData3;
|
|
|
|
|
qint64 startTime = event.startTime - duration;
|
2013-06-11 15:13:33 +02:00
|
|
|
for (int i=0; i < timingFieldCount; i++)
|
|
|
|
|
newEvent.timing[i] = 0;
|
|
|
|
|
|
2013-08-07 15:46:15 +02:00
|
|
|
// Filter out events with incorrect timings due to interrupted thread on server side
|
2013-12-06 15:38:22 +01:00
|
|
|
if (duration > 0 && startTime > 0)
|
|
|
|
|
lastRenderEvent = d->insert(startTime, duration, newEvent);
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lastRenderEvent >= 0) {
|
2013-12-06 15:38:22 +01:00
|
|
|
qint64 *timing = d->data(lastRenderEvent).timing;
|
2014-06-13 16:56:46 +02:00
|
|
|
switch ((SceneGraphEventType)type.detailType) {
|
2013-06-11 15:13:33 +02:00
|
|
|
case SceneGraphRendererFrame: {
|
2013-12-06 15:38:22 +01:00
|
|
|
timing[1] = event.numericData1;
|
|
|
|
|
timing[10] = event.numericData2;
|
|
|
|
|
timing[11] = event.numericData3;
|
|
|
|
|
timing[12] = event.numericData4;
|
2013-06-11 15:13:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SceneGraphAdaptationLayerFrame: {
|
2013-12-06 15:38:22 +01:00
|
|
|
timing[8] = event.numericData2;
|
|
|
|
|
timing[9] = event.numericData3;
|
2013-06-11 15:13:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SceneGraphContextFrame: {
|
2013-12-06 15:38:22 +01:00
|
|
|
timing[7] = event.numericData1;
|
2013-06-11 15:13:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SceneGraphRenderLoopFrame: {
|
2013-12-06 15:38:22 +01:00
|
|
|
timing[0] = event.numericData1;
|
|
|
|
|
timing[13] = event.numericData3;
|
2013-06-11 15:13:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SceneGraphTexturePrepare: {
|
2013-12-06 15:38:22 +01:00
|
|
|
timing[2] = event.numericData4;
|
|
|
|
|
timing[3] = event.numericData3;
|
|
|
|
|
timing[4] = event.numericData2;
|
|
|
|
|
timing[5] = event.numericData5;
|
|
|
|
|
timing[6] = event.numericData1;
|
2013-06-11 15:13:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SceneGraphPolishAndSync: {
|
2014-06-03 19:06:34 +02:00
|
|
|
d->seenPolishAndSync = true;
|
2013-06-11 15:13:33 +02:00
|
|
|
// GUI thread
|
|
|
|
|
SceneGraphEvent newEvent;
|
|
|
|
|
newEvent.sgEventType = SceneGraphGUIThread;
|
2013-12-06 15:38:22 +01:00
|
|
|
qint64 duration = event.numericData1 + event.numericData2 + event.numericData3 + event.numericData4;
|
|
|
|
|
qint64 startTime = event.startTime - duration;
|
2013-06-11 15:13:33 +02:00
|
|
|
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;
|
|
|
|
|
|
2013-08-07 15:46:15 +02:00
|
|
|
// Filter out events with incorrect timings due to interrupted thread on server side
|
2013-12-06 15:38:22 +01:00
|
|
|
if (duration > 0 && startTime > 0)
|
|
|
|
|
d->insert(startTime, duration, newEvent);
|
2013-08-07 15:46:15 +02:00
|
|
|
|
2013-06-11 15:13:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SceneGraphWindowsAnimations: {
|
2014-06-30 12:47:49 +02:00
|
|
|
timing[15] = event.numericData1;
|
2013-06-11 15:13:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SceneGraphWindowsPolishFrame: {
|
2014-06-30 12:47:49 +02:00
|
|
|
timing[14] = event.numericData1;
|
2013-06-11 15:13:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2013-06-20 16:29:37 +02:00
|
|
|
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-02-14 16:34:22 +01:00
|
|
|
d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1);
|
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-06-03 19:06:34 +02:00
|
|
|
d->seenPolishAndSync = false;
|
2014-02-14 16:34:22 +01:00
|
|
|
d->expanded = false;
|
|
|
|
|
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
|
2013-06-11 15:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
2013-06-24 14:17:43 +02:00
|
|
|
} // namespace QmlProfilerExtension
|