forked from qt-creator/qt-creator
Add support for new Quick3D profiling events
- Add support for the new RenderCall and RenderPass events. - Add support for more info from existing events. - Add quick3d frame view Task-number: QTBUG-105970 Task-number: QTBUG-105971 Change-Id: Ia1b6f466da5b195558fd5880b622084634c9090b Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
@@ -69,6 +69,8 @@ set(QMLPROFILER_CPP_SOURCES
|
|||||||
qmltypedevent.cpp qmltypedevent.h
|
qmltypedevent.cpp qmltypedevent.h
|
||||||
scenegraphtimelinemodel.cpp scenegraphtimelinemodel.h
|
scenegraphtimelinemodel.cpp scenegraphtimelinemodel.h
|
||||||
quick3dmodel.cpp quick3dmodel.h
|
quick3dmodel.cpp quick3dmodel.h
|
||||||
|
quick3dframeview.cpp quick3dframeview.h
|
||||||
|
quick3dframemodel.cpp quick3dframemodel.h
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Qt6 COMPONENTS ShaderTools QUIET)
|
find_package(Qt6 COMPONENTS ShaderTools QUIET)
|
||||||
|
@@ -60,6 +60,8 @@ QtcPlugin {
|
|||||||
"qmlprofilerviewmanager.cpp", "qmlprofilerviewmanager.h",
|
"qmlprofilerviewmanager.cpp", "qmlprofilerviewmanager.h",
|
||||||
"qmltypedevent.cpp", "qmltypedevent.h",
|
"qmltypedevent.cpp", "qmltypedevent.h",
|
||||||
"quick3dmodel.cpp", "quick3dmodel.h",
|
"quick3dmodel.cpp", "quick3dmodel.h",
|
||||||
|
"quick3dframeview.cpp", "quick3dframeview.h",
|
||||||
|
"quick3dframemodel.cpp", "quick3dframemodel.h",
|
||||||
"scenegraphtimelinemodel.cpp", "scenegraphtimelinemodel.h",
|
"scenegraphtimelinemodel.cpp", "scenegraphtimelinemodel.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -47,9 +47,10 @@ enum Quick3DEventType {
|
|||||||
Quick3DParticleUpdate,
|
Quick3DParticleUpdate,
|
||||||
Quick3DGenerateShader,
|
Quick3DGenerateShader,
|
||||||
Quick3DLoadShader,
|
Quick3DLoadShader,
|
||||||
|
Quick3DRenderCall,
|
||||||
|
Quick3DRenderPass,
|
||||||
|
Quick3DEventData,
|
||||||
MaximumQuick3DFrameType,
|
MaximumQuick3DFrameType,
|
||||||
NumQuick3DRenderThreadFrameTypes = Quick3DParticleUpdate,
|
|
||||||
NumQuick3DGUIThreadFrameTypes = MaximumQuick3DFrameType - NumQuick3DRenderThreadFrameTypes,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RangeType {
|
enum RangeType {
|
||||||
|
@@ -16,7 +16,7 @@ namespace QmlProfiler {
|
|||||||
|
|
||||||
inline auto qHash(const QmlEventType &type)
|
inline auto qHash(const QmlEventType &type)
|
||||||
{
|
{
|
||||||
return qHash(type.location())
|
return qHash(type.location()) ^ qHash(type.data())
|
||||||
^ (((type.message() << 12) & 0xf000) // 4 bits of message
|
^ (((type.message() << 12) & 0xf000) // 4 bits of message
|
||||||
| ((type.rangeType() << 24) & 0xf000000) // 4 bits of rangeType
|
| ((type.rangeType() << 24) & 0xf000000) // 4 bits of rangeType
|
||||||
| ((type.detailType() << 28) & 0xf0000000)); // 4 bits of detailType
|
| ((type.detailType() << 28) & 0xf0000000)); // 4 bits of detailType
|
||||||
@@ -25,7 +25,8 @@ inline auto qHash(const QmlEventType &type)
|
|||||||
inline bool operator==(const QmlEventType &type1, const QmlEventType &type2)
|
inline bool operator==(const QmlEventType &type1, const QmlEventType &type2)
|
||||||
{
|
{
|
||||||
return type1.message() == type2.message() && type1.rangeType() == type2.rangeType()
|
return type1.message() == type2.message() && type1.rangeType() == type2.rangeType()
|
||||||
&& type1.detailType() == type2.detailType() && type1.location() == type2.location();
|
&& type1.detailType() == type2.detailType() && type1.location() == type2.location()
|
||||||
|
&& type1.data() == type2.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!=(const QmlEventType &type1, const QmlEventType &type2)
|
inline bool operator!=(const QmlEventType &type1, const QmlEventType &type2)
|
||||||
|
@@ -66,15 +66,19 @@ void QmlProfilerViewManager::createViews()
|
|||||||
prepareEventsView(m_statisticsView);
|
prepareEventsView(m_statisticsView);
|
||||||
m_flameGraphView = new FlameGraphView(m_profilerModelManager);
|
m_flameGraphView = new FlameGraphView(m_profilerModelManager);
|
||||||
prepareEventsView(m_flameGraphView);
|
prepareEventsView(m_flameGraphView);
|
||||||
|
m_quick3dView = new Quick3DFrameView(m_profilerModelManager);
|
||||||
|
prepareEventsView(m_quick3dView);
|
||||||
|
|
||||||
QWidget *anchorDock = nullptr;
|
QWidget *anchorDock = nullptr;
|
||||||
if (m_traceView->isUsable()) {
|
if (m_traceView->isUsable()) {
|
||||||
anchorDock = m_traceView;
|
anchorDock = m_traceView;
|
||||||
m_perspective->addWindow(m_traceView, Perspective::SplitVertical, nullptr);
|
m_perspective->addWindow(m_traceView, Perspective::SplitVertical, nullptr);
|
||||||
m_perspective->addWindow(m_flameGraphView, Perspective::AddToTab, m_traceView);
|
m_perspective->addWindow(m_flameGraphView, Perspective::AddToTab, m_traceView);
|
||||||
|
m_perspective->addWindow(m_quick3dView, Perspective::AddToTab, m_flameGraphView);
|
||||||
} else {
|
} else {
|
||||||
anchorDock = m_flameGraphView;
|
anchorDock = m_flameGraphView;
|
||||||
m_perspective->addWindow(m_flameGraphView, Perspective::SplitVertical, nullptr);
|
m_perspective->addWindow(m_flameGraphView, Perspective::SplitVertical, nullptr);
|
||||||
|
m_perspective->addWindow(m_quick3dView, Perspective::AddToTab, m_flameGraphView);
|
||||||
}
|
}
|
||||||
m_perspective->addWindow(m_statisticsView, Perspective::AddToTab, anchorDock);
|
m_perspective->addWindow(m_statisticsView, Perspective::AddToTab, anchorDock);
|
||||||
m_perspective->addWindow(anchorDock, Perspective::Raise, nullptr);
|
m_perspective->addWindow(anchorDock, Perspective::Raise, nullptr);
|
||||||
@@ -87,6 +91,7 @@ QmlProfilerViewManager::~QmlProfilerViewManager()
|
|||||||
delete m_traceView;
|
delete m_traceView;
|
||||||
delete m_flameGraphView;
|
delete m_flameGraphView;
|
||||||
delete m_statisticsView;
|
delete m_statisticsView;
|
||||||
|
delete m_quick3dView;
|
||||||
delete m_perspective;
|
delete m_perspective;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "qmlprofilerstatisticsview.h"
|
#include "qmlprofilerstatisticsview.h"
|
||||||
#include "qmlprofilertraceview.h"
|
#include "qmlprofilertraceview.h"
|
||||||
|
#include "quick3dframeview.h"
|
||||||
#include "flamegraphview.h"
|
#include "flamegraphview.h"
|
||||||
|
|
||||||
namespace Utils { class Perspective; }
|
namespace Utils { class Perspective; }
|
||||||
@@ -25,6 +26,7 @@ public:
|
|||||||
QmlProfilerTraceView *traceView() const { return m_traceView; }
|
QmlProfilerTraceView *traceView() const { return m_traceView; }
|
||||||
QmlProfilerStatisticsView *statisticsView() const { return m_statisticsView; }
|
QmlProfilerStatisticsView *statisticsView() const { return m_statisticsView; }
|
||||||
FlameGraphView *flameGraphView() const { return m_flameGraphView; }
|
FlameGraphView *flameGraphView() const { return m_flameGraphView; }
|
||||||
|
Quick3DFrameView *quick3dView() const { return m_quick3dView; }
|
||||||
Utils::Perspective *perspective() const { return m_perspective; }
|
Utils::Perspective *perspective() const { return m_perspective; }
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
@@ -40,6 +42,7 @@ private:
|
|||||||
QmlProfilerTraceView *m_traceView = nullptr;
|
QmlProfilerTraceView *m_traceView = nullptr;
|
||||||
QmlProfilerStatisticsView *m_statisticsView = nullptr;
|
QmlProfilerStatisticsView *m_statisticsView = nullptr;
|
||||||
FlameGraphView *m_flameGraphView = nullptr;
|
FlameGraphView *m_flameGraphView = nullptr;
|
||||||
|
Quick3DFrameView *m_quick3dView = nullptr;
|
||||||
QmlProfilerStateManager *m_profilerState = nullptr;
|
QmlProfilerStateManager *m_profilerState = nullptr;
|
||||||
QmlProfilerModelManager *m_profilerModelManager = nullptr;
|
QmlProfilerModelManager *m_profilerModelManager = nullptr;
|
||||||
Utils::Perspective *m_perspective = nullptr;
|
Utils::Perspective *m_perspective = nullptr;
|
||||||
|
@@ -166,13 +166,19 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
|
|||||||
case Quick3DEvent: {
|
case Quick3DEvent: {
|
||||||
|
|
||||||
QVarLengthArray<qint64> params;
|
QVarLengthArray<qint64> params;
|
||||||
qint64 param;
|
qint64 param = 0;
|
||||||
|
QByteArray str;
|
||||||
while (!stream.atEnd()) {
|
if (subtype == Quick3DEventData) {
|
||||||
stream >> param;
|
stream >> str;
|
||||||
params.push_back(param);
|
} else {
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
stream >> param;
|
||||||
|
params.push_back(param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event.type = QmlEventType(static_cast<Message>(messageType), UndefinedRangeType, subtype);
|
event.type = QmlEventType(static_cast<Message>(messageType), UndefinedRangeType, subtype);
|
||||||
|
event.type.setData(QString::fromUtf8(str));
|
||||||
event.event.setNumbers<QVarLengthArray<qint64>, qint64>(params);
|
event.event.setNumbers<QVarLengthArray<qint64>, qint64>(params);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
528
src/plugins/qmlprofiler/quick3dframemodel.cpp
Normal file
528
src/plugins/qmlprofiler/quick3dframemodel.cpp
Normal file
@@ -0,0 +1,528 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 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 <tracing/timelineformattime.h>
|
||||||
|
#include "quick3dframemodel.h"
|
||||||
|
#include "quick3dmodel.h"
|
||||||
|
#include "qmlprofilermodelmanager.h"
|
||||||
|
#include "qmlprofilerconstants.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace QmlProfiler {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
Quick3DFrameModel::Quick3DFrameModel(QmlProfilerModelManager *modelManager)
|
||||||
|
: m_modelManager(modelManager)
|
||||||
|
{
|
||||||
|
m_acceptedDetailTypes << RenderFrame << SynchronizeFrame << PrepareFrame << RenderCall << RenderPass << EventData << TextureLoad << MeshLoad << CustomMeshLoad;
|
||||||
|
modelManager->registerFeatures(1ULL << ProfileQuick3D,
|
||||||
|
std::bind(&Quick3DFrameModel::loadEvent, this,
|
||||||
|
std::placeholders::_1, std::placeholders::_2),
|
||||||
|
std::bind(&Quick3DFrameModel::beginResetModel, this),
|
||||||
|
std::bind(&Quick3DFrameModel::finalize, this),
|
||||||
|
std::bind(&Quick3DFrameModel::clear, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DFrameModel::clear()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_data.clear();
|
||||||
|
m_stackBottom = {};
|
||||||
|
m_frameTimes.clear();
|
||||||
|
m_eventData.clear();
|
||||||
|
m_oldEvents = false;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Quick3DFrameModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (!parent.isValid())
|
||||||
|
return m_stackBottom.children.size();
|
||||||
|
int index = parent.internalId();
|
||||||
|
if (index >= 0) {
|
||||||
|
const Item &i = m_data[index];
|
||||||
|
return i.children.size();
|
||||||
|
} else {
|
||||||
|
return m_stackBottom.children.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Quick3DFrameModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent);
|
||||||
|
return MaxColumnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant Quick3DFrameModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
const Item &item = m_data[index.internalId()];
|
||||||
|
QString strData;
|
||||||
|
if (m_eventData.contains(item.eventData))
|
||||||
|
strData = m_modelManager->eventType(m_eventData[item.eventData]).data();
|
||||||
|
QVariant result;
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole: {
|
||||||
|
switch (index.column()) {
|
||||||
|
case Frame: {
|
||||||
|
switch (item.additionalType) {
|
||||||
|
case SynchronizeFrame: {
|
||||||
|
QString data = "Synchronize Frame: ";
|
||||||
|
if (item.data) {
|
||||||
|
quint32 w = item.data & 0xffffffff;
|
||||||
|
quint32 h = item.data >> 32;
|
||||||
|
data += ", Render target size: " + QString::number(w) + "x" + QString::number(h);
|
||||||
|
}
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case RenderFrame: {
|
||||||
|
QString data = "Render Frame: ";
|
||||||
|
if (item.data) {
|
||||||
|
quint32 calls = item.data & 0xffffffff;
|
||||||
|
quint32 passes = item.data >> 32;
|
||||||
|
data += "Render Calls: " + QString::number(calls) + ", Render Passes: " + QString::number(passes);
|
||||||
|
}
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case PrepareFrame: {
|
||||||
|
QString data = "Prepare Frame: ";
|
||||||
|
if (item.data) {
|
||||||
|
quint32 w = item.data & 0xffffffff;
|
||||||
|
quint32 h = item.data >> 32;
|
||||||
|
data += ", Render target size: " + QString::number(w) + "x" + QString::number(h);
|
||||||
|
}
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case RenderCall: {
|
||||||
|
QString data = "Render Call: ";
|
||||||
|
if (item.data) {
|
||||||
|
quint32 primitives = item.data & 0xffffffff;
|
||||||
|
quint32 instances = item.data >> 32;
|
||||||
|
data += "Primitives: " + QString::number(primitives) + ", Instances: " + QString::number(instances);
|
||||||
|
}
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case RenderPass: {
|
||||||
|
QString data = "Render Pass: " + strData;
|
||||||
|
if (item.data) {
|
||||||
|
quint32 w = item.data & 0xffffffff;
|
||||||
|
quint32 h = item.data >> 32;
|
||||||
|
data += ", Render target size: " + QString::number(w) + "x" + QString::number(h);
|
||||||
|
}
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case FrameGroup: {
|
||||||
|
QString data = "Frame " + QString::number(item.data);
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case TextureLoad: {
|
||||||
|
QString data = "Texture Load " + strData;
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case MeshLoad: {
|
||||||
|
QString data = "Mesh Load " + strData;
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case CustomMeshLoad: {
|
||||||
|
QString data = "Custom Mesh Load " + strData;
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case SubData: {
|
||||||
|
if (strData.contains(QLatin1String("Material")))
|
||||||
|
strData = QLatin1String("Material: ") + strData;
|
||||||
|
else if (strData.contains(QLatin1String("Model")))
|
||||||
|
strData = QLatin1String("Model: ") + strData;
|
||||||
|
else if (strData.contains(QLatin1String("Particle")))
|
||||||
|
strData = QLatin1String("Particle: ") + strData;
|
||||||
|
else
|
||||||
|
strData = QLatin1String("Object: ") + strData;
|
||||||
|
result = QVariant::fromValue(strData);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Timestamp: {
|
||||||
|
QString data = Timeline::formatTime(item.begin);
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case Duration: {
|
||||||
|
QString data = Timeline::formatTime(item.end - item.begin);
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
} break;
|
||||||
|
case FrameDelta: {
|
||||||
|
if (item.frameDelta) {
|
||||||
|
QString data = Timeline::formatTime(item.frameDelta);
|
||||||
|
result = QVariant::fromValue(data);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case View3D: {
|
||||||
|
// Don't show view3d object anywhere but FrameGroup
|
||||||
|
const bool isView3D = m_frameTimes.contains(item.eventData);
|
||||||
|
if (isView3D && item.additionalType == FrameGroup)
|
||||||
|
result = QVariant::fromValue(strData);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SortRole: {
|
||||||
|
switch (index.column()) {
|
||||||
|
case Frame:
|
||||||
|
if (item.additionalType == FrameGroup)
|
||||||
|
result = QVariant::fromValue(item.data);
|
||||||
|
else
|
||||||
|
result = QVariant::fromValue(item.index);
|
||||||
|
break;
|
||||||
|
case Timestamp:
|
||||||
|
result = QVariant::fromValue(item.begin);
|
||||||
|
break;
|
||||||
|
case Duration:
|
||||||
|
result = QVariant::fromValue(item.end - item.begin);
|
||||||
|
break;
|
||||||
|
case FrameDelta:
|
||||||
|
if (item.frameDelta)
|
||||||
|
result = QVariant::fromValue(item.frameDelta);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case IndexRole: {
|
||||||
|
result = QVariant::fromValue(item.index);
|
||||||
|
} break;
|
||||||
|
case FilterRole: {
|
||||||
|
const Item *group = findFrameGroup(&item);
|
||||||
|
if (group)
|
||||||
|
result = QVariant::fromValue(m_modelManager->eventType(m_eventData[group->eventData]).data());
|
||||||
|
} break;
|
||||||
|
case CompareRole: {
|
||||||
|
const Item *group = findFrameGroup(&item);
|
||||||
|
if (group && int(group->data) == m_filterFrame && (group->eventData == m_filterView3D || m_filterView3D == -1))
|
||||||
|
result = QVariant::fromValue(QString("+"));
|
||||||
|
else
|
||||||
|
result = QVariant::fromValue(QString("-"));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant Quick3DFrameModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
QVariant result;
|
||||||
|
if (orientation != Qt::Horizontal)
|
||||||
|
return QAbstractItemModel::headerData(section, orientation, role);
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
switch (section) {
|
||||||
|
case Frame:
|
||||||
|
result = QVariant::fromValue(tr("Frame"));
|
||||||
|
break;
|
||||||
|
case Duration:
|
||||||
|
result = QVariant::fromValue(tr("Duration"));
|
||||||
|
break;
|
||||||
|
case Timestamp:
|
||||||
|
result = QVariant::fromValue(tr("Timestamp"));
|
||||||
|
break;
|
||||||
|
case FrameDelta:
|
||||||
|
result = QVariant::fromValue(tr("Frame Delta"));
|
||||||
|
break;
|
||||||
|
case View3D:
|
||||||
|
result = QVariant::fromValue(tr("View3D"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Quick3DFrameModel::location(int index) const
|
||||||
|
{
|
||||||
|
if (index < 0)
|
||||||
|
return {};
|
||||||
|
const Item &item = m_data[index];
|
||||||
|
if (item.eventData == -1)
|
||||||
|
return {};
|
||||||
|
return m_modelManager->eventType(m_eventData[item.eventData]).data();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex Quick3DFrameModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (!hasIndex(row, column, parent))
|
||||||
|
return QModelIndex();
|
||||||
|
if (parent.isValid()) {
|
||||||
|
int parentIndex = parent.internalId();
|
||||||
|
if (parentIndex >= m_data.size())
|
||||||
|
return QModelIndex();
|
||||||
|
const Item *parentData = &m_stackBottom;
|
||||||
|
if (parentIndex >= 0)
|
||||||
|
parentData = &m_data[parentIndex];
|
||||||
|
return createIndex(row, column, parentData->children[row]);
|
||||||
|
} else {
|
||||||
|
return createIndex(row, column, row >= 0 ? m_stackBottom.children[row] : -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Quick3DFrameModel::parentRow(int index) const
|
||||||
|
{
|
||||||
|
const Item *item = &m_data[index];
|
||||||
|
const Item *parent = item->parent == -1 ? &m_stackBottom : &m_data[item->parent];
|
||||||
|
return parent->children.indexOf(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex Quick3DFrameModel::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (index.isValid()) {
|
||||||
|
int childIndex = index.internalId();
|
||||||
|
const Item *childData = &m_data[childIndex];
|
||||||
|
return childData->parent == -1 ? QModelIndex() : createIndex(parentRow(childData->parent), 0, childData->parent);
|
||||||
|
} else {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isParentOf(const Quick3DFrameModel::Item &child, const Quick3DFrameModel::Item &parent) {
|
||||||
|
return child.begin >= parent.begin && child.begin < parent.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Quick3DFrameModel::Item *Quick3DFrameModel::findFrameGroup(const Quick3DFrameModel::Item *item) const
|
||||||
|
{
|
||||||
|
while (item) {
|
||||||
|
if (item->additionalType == FrameGroup)
|
||||||
|
return item;
|
||||||
|
item = item->parent >= 0 ? &m_data[item->parent] : nullptr;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Quick3DFrameModel::Item *Quick3DFrameModel::findParent(int child)
|
||||||
|
{
|
||||||
|
const Item &ci = m_data[child];
|
||||||
|
if (ci.parent != -1)
|
||||||
|
return &m_data[ci.parent];
|
||||||
|
for (auto iter = m_data.begin(); iter != m_data.end(); iter++) {
|
||||||
|
if (ci.index == iter->index || iter->additionalType == SubData)
|
||||||
|
continue;
|
||||||
|
if (isParentOf(ci, *iter)) {
|
||||||
|
const Item *j = &m_data[iter->index];
|
||||||
|
bool allChecked = false;
|
||||||
|
while (!allChecked && j->hasChildren()) {
|
||||||
|
allChecked = true;
|
||||||
|
for (int i = 0; i < iter->children.size(); i++) {
|
||||||
|
const Item &k = m_data[iter->children[i]];
|
||||||
|
if (isParentOf(ci, k) && iter->additionalType != SubData) {
|
||||||
|
j = &k;
|
||||||
|
allChecked = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &m_data[j->index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DFrameModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
|
||||||
|
{
|
||||||
|
int detailType = type.detailType();
|
||||||
|
if (!m_acceptedDetailTypes.contains(detailType) || m_oldEvents)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (detailType == EventData){
|
||||||
|
m_eventData.insert(m_eventData.size() + 1, event.typeIndex());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<quint64> numbers = event.numbers<QList<quint64>>();
|
||||||
|
if (numbers.size() == 0)
|
||||||
|
return;
|
||||||
|
qint64 eventDuration = numbers[0];
|
||||||
|
qint64 eventTime = event.timestamp() - eventDuration;
|
||||||
|
quint64 data = numbers.size() > 1 ? numbers[1] : 0;
|
||||||
|
QList<int> eventData;
|
||||||
|
// The rest are pairs of event data id's
|
||||||
|
for (int i = 2; i < numbers.size(); i++) {
|
||||||
|
qint32 h = Quick3DModel::eventDataId(numbers[i] >> 32);
|
||||||
|
qint32 l = Quick3DModel::eventDataId(numbers[i] & 0xffffffff);
|
||||||
|
if (m_eventData.contains(h))
|
||||||
|
eventData.push_back(h);
|
||||||
|
if (m_eventData.contains(l))
|
||||||
|
eventData.push_back(l);
|
||||||
|
}
|
||||||
|
if (eventData.isEmpty() && detailType == SynchronizeFrame) {
|
||||||
|
m_oldEvents = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int index = m_data.size();
|
||||||
|
Item item = Item(index, -1, eventTime, event.timestamp(), detailType, data);
|
||||||
|
m_data.push_back(item);
|
||||||
|
if (detailType == RenderCall) {
|
||||||
|
for (int i = 0; i < eventData.size(); i++) {
|
||||||
|
Item child = Item(index + i + 1, item.index, eventTime, event.timestamp(), SubData);
|
||||||
|
child.eventData = eventData[i];
|
||||||
|
m_data.push_back(child);
|
||||||
|
m_data[index].children.push_back(child.index);
|
||||||
|
}
|
||||||
|
} else if (eventData.size()) {
|
||||||
|
m_data[index].eventData = eventData[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(detailType >= RenderFrame && detailType <= PrepareFrame))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int v3d = eventData[0];
|
||||||
|
if (!m_frameTimes.contains(v3d))
|
||||||
|
m_frameTimes[v3d] = {};
|
||||||
|
|
||||||
|
switch (detailType) {
|
||||||
|
case SynchronizeFrame:
|
||||||
|
if (m_frameTimes[v3d].inFrame)
|
||||||
|
qWarning () << "Previous frame was not ended correctly";
|
||||||
|
m_frameTimes[v3d].begin = eventTime - 1;
|
||||||
|
m_frameTimes[v3d].inFrame = true;
|
||||||
|
break;
|
||||||
|
case PrepareFrame:
|
||||||
|
if (!m_frameTimes[v3d].inFrame) {
|
||||||
|
qWarning () << "Synchronize frame missing";
|
||||||
|
m_frameTimes[v3d].begin = eventTime - 1;
|
||||||
|
m_frameTimes[v3d].inFrame = true;
|
||||||
|
}
|
||||||
|
m_frameTimes[v3d].prepareReceived = true;
|
||||||
|
break;
|
||||||
|
case RenderFrame:
|
||||||
|
int index = m_data.size();
|
||||||
|
if (!m_frameTimes[v3d].inFrame) {
|
||||||
|
qWarning () << "Render message received without Synchronize and Prepare messages";
|
||||||
|
} else {
|
||||||
|
if (!m_frameTimes[v3d].prepareReceived)
|
||||||
|
qWarning () << "Frame received without Prepare message";
|
||||||
|
item = Item(index, -1, m_frameTimes[v3d].begin, event.timestamp() + 1, FrameGroup, m_frameTimes[v3d].frameCount);
|
||||||
|
if (m_frameTimes[v3d].frameCount)
|
||||||
|
item.frameDelta = item.end - m_frameTimes[v3d].end;
|
||||||
|
item.eventData = v3d;
|
||||||
|
m_frameTimes[v3d].frameCount++;
|
||||||
|
m_frameTimes[v3d].end = item.end;
|
||||||
|
m_frameTimes[v3d].inFrame = false;
|
||||||
|
m_frameTimes[v3d].prepareReceived = false;
|
||||||
|
m_data.push_back(item);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList Quick3DFrameModel::view3DNames() const
|
||||||
|
{
|
||||||
|
QStringList ret;
|
||||||
|
for (auto value : m_frameTimes.keys())
|
||||||
|
ret << m_modelManager->eventType(m_eventData[value]).data();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<int> Quick3DFrameModel::frameIndices(const QString &view3DFilter) const
|
||||||
|
{
|
||||||
|
QList<int> ret;
|
||||||
|
int key = -1;
|
||||||
|
if (view3DFilter != tr("All")) {
|
||||||
|
for (int v3d : m_frameTimes.keys()) {
|
||||||
|
if (m_modelManager->eventType(m_eventData[v3d]).data() == view3DFilter) {
|
||||||
|
key = v3d;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto child : m_stackBottom.children) {
|
||||||
|
if (key == -1 || key == m_data[child].eventData)
|
||||||
|
ret << child;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList Quick3DFrameModel::frameNames(const QString &view3D) const
|
||||||
|
{
|
||||||
|
auto indices = frameIndices(view3D);
|
||||||
|
QStringList ret;
|
||||||
|
for (auto index : indices) {
|
||||||
|
const Item &item = m_data[index];
|
||||||
|
ret << QString(tr("Frame") + QLatin1Char(' ') + QString::number(item.data));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DFrameModel::setFilterFrame(const QString &frame)
|
||||||
|
{
|
||||||
|
if (frame == tr("None")) {
|
||||||
|
m_filterFrame = -1;
|
||||||
|
} else {
|
||||||
|
QString title = tr("Frame");
|
||||||
|
QString number = frame.right(frame.length() - title.length());
|
||||||
|
m_filterFrame = number.toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DFrameModel::setFilterView3D(const QString &view3D)
|
||||||
|
{
|
||||||
|
int key = -1;
|
||||||
|
if (view3D != tr("All")) {
|
||||||
|
for (int v3d : m_frameTimes.keys()) {
|
||||||
|
if (m_modelManager->eventType(m_eventData[v3d]).data() == view3D) {
|
||||||
|
key = v3d;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_filterView3D = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DFrameModel::finalize()
|
||||||
|
{
|
||||||
|
if (m_oldEvents) {
|
||||||
|
m_data.clear();
|
||||||
|
endResetModel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto &item : m_data) {
|
||||||
|
Item *parent = findParent(item.index);
|
||||||
|
if (parent) {
|
||||||
|
if (item.parent == -1) {
|
||||||
|
for (int i = 0; i < parent->children.size();) {
|
||||||
|
Item &j = m_data[parent->children[i]];
|
||||||
|
if (isParentOf(j, item) && j.additionalType != SubData) {
|
||||||
|
parent->children.removeOne(j.index);
|
||||||
|
item.children.push_back(j.index);
|
||||||
|
j.parent = item.index;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent->children.push_back(item.index);
|
||||||
|
item.parent = parent->index;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_stackBottom.children.push_back(item.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace QmlProfiler
|
151
src/plugins/qmlprofiler/quick3dframemodel.h
Normal file
151
src/plugins/qmlprofiler/quick3dframemodel.h
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qmlprofilereventtypes.h"
|
||||||
|
#include "qmlevent.h"
|
||||||
|
#include "qmleventtype.h"
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QStack>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
namespace QmlProfiler {
|
||||||
|
class QmlProfilerModelManager;
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class Quick3DFrameModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Item {
|
||||||
|
Item(int index = -1, int parent = -1, qint64 begin = 0, qint64 end = 0, int additionalType = 0, quint64 data = 0) :
|
||||||
|
index(index), parent(parent), additionalType(additionalType), begin(begin), end(end), data(data) {}
|
||||||
|
int index;
|
||||||
|
int parent;
|
||||||
|
int additionalType;
|
||||||
|
qint64 begin;
|
||||||
|
qint64 end;
|
||||||
|
quint64 data;
|
||||||
|
quint64 frameDelta = 0;
|
||||||
|
int eventData = -1;
|
||||||
|
QList<int> children;
|
||||||
|
bool hasChildren() const
|
||||||
|
{
|
||||||
|
return !children.isEmpty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct FrameTime
|
||||||
|
{
|
||||||
|
qint64 begin = 0;
|
||||||
|
qint64 end = 0;
|
||||||
|
int frameCount = 0;
|
||||||
|
bool inFrame = false;
|
||||||
|
bool prepareReceived = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MessageType
|
||||||
|
{
|
||||||
|
RenderFrame,
|
||||||
|
SynchronizeFrame,
|
||||||
|
PrepareFrame,
|
||||||
|
MeshLoad,
|
||||||
|
CustomMeshLoad,
|
||||||
|
TextureLoad,
|
||||||
|
GenerateShader,
|
||||||
|
LoadShader,
|
||||||
|
ParticleUpdate,
|
||||||
|
RenderCall,
|
||||||
|
RenderPass,
|
||||||
|
EventData,
|
||||||
|
// additional types
|
||||||
|
MeshMemoryConsumption,
|
||||||
|
TextureMemoryConsumption,
|
||||||
|
FrameGroup,
|
||||||
|
SubData
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ColumnType
|
||||||
|
{
|
||||||
|
Frame,
|
||||||
|
Duration,
|
||||||
|
FrameDelta,
|
||||||
|
Timestamp,
|
||||||
|
View3D,
|
||||||
|
MaxColumnType
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ItemRole {
|
||||||
|
SortRole = Qt::UserRole + 1, // Sort by data, not by displayed string
|
||||||
|
FilterRole,
|
||||||
|
CompareRole,
|
||||||
|
IndexRole,
|
||||||
|
};
|
||||||
|
|
||||||
|
Quick3DFrameModel(QmlProfilerModelManager *manager);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QModelIndex parent(const QModelIndex &index) const override;
|
||||||
|
QString location(int index) const;
|
||||||
|
|
||||||
|
QStringList view3DNames() const;
|
||||||
|
QStringList frameNames(const QString &view3D) const;
|
||||||
|
void setFilterView3D(const QString &view3D);
|
||||||
|
void setFilterFrame(const QString &frame);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<int> frameIndices(const QString &view3DFilter) const;
|
||||||
|
void loadEvent(const QmlEvent &event, const QmlEventType &type);
|
||||||
|
Item *findParent(int child);
|
||||||
|
const Item *findFrameGroup(const Item *item) const;
|
||||||
|
void finalize();
|
||||||
|
int parentRow(int index) const;
|
||||||
|
|
||||||
|
bool m_oldEvents = false;
|
||||||
|
QList<Item> m_data;
|
||||||
|
Item m_stackBottom;
|
||||||
|
QHash<int, FrameTime> m_frameTimes;
|
||||||
|
QHash<int, int> m_eventData;
|
||||||
|
QList<int> m_acceptedDetailTypes;
|
||||||
|
QPointer<QmlProfilerModelManager> m_modelManager;
|
||||||
|
int m_filterView3D = -1;
|
||||||
|
int m_filterFrame = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace QmlProfiler
|
173
src/plugins/qmlprofiler/quick3dframeview.cpp
Normal file
173
src/plugins/qmlprofiler/quick3dframeview.cpp
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 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 "quick3dframeview.h"
|
||||||
|
|
||||||
|
#include <coreplugin/minisplitter.h>
|
||||||
|
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QStringListModel>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
namespace QmlProfiler {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
Quick3DFrameView::Quick3DFrameView(QmlProfilerModelManager *profilerModelManager, QWidget *parent)
|
||||||
|
: QmlProfilerEventsView(parent)
|
||||||
|
{
|
||||||
|
setObjectName(QLatin1String("QmlProfiler.Quick3DFrame.Dock"));
|
||||||
|
setWindowTitle(tr("Quick3D Frame"));
|
||||||
|
|
||||||
|
auto model = new Quick3DFrameModel(profilerModelManager);
|
||||||
|
m_mainView.reset(new Quick3DMainView(model, false, this));
|
||||||
|
connect(m_mainView.get(), &Quick3DMainView::gotoSourceLocation,
|
||||||
|
this, &Quick3DFrameView::gotoSourceLocation);
|
||||||
|
|
||||||
|
m_compareFrameView.reset(new Quick3DMainView(model, true, this));
|
||||||
|
connect(m_compareFrameView.get(), &Quick3DMainView::gotoSourceLocation,
|
||||||
|
this, &Quick3DFrameView::gotoSourceLocation);
|
||||||
|
|
||||||
|
auto groupLayout = new QVBoxLayout(this);
|
||||||
|
groupLayout->setContentsMargins(0,0,0,0);
|
||||||
|
groupLayout->setSpacing(0);
|
||||||
|
auto hMainLayout = new QHBoxLayout(this);
|
||||||
|
hMainLayout->setContentsMargins(0,0,0,0);
|
||||||
|
hMainLayout->setSpacing(0);
|
||||||
|
auto hFrameLayout = new QHBoxLayout(this);
|
||||||
|
hFrameLayout->setContentsMargins(0,0,0,0);
|
||||||
|
hFrameLayout->setSpacing(0);
|
||||||
|
auto view3DComboBox = new QComboBox(this);
|
||||||
|
auto view3DComboModel = new QStringListModel(this);
|
||||||
|
auto frameComboBox = new QComboBox(this);
|
||||||
|
auto frameComboModel = new QStringListModel(this);
|
||||||
|
auto selectView3DLabel = new QLabel(tr("Select View3D"), this);
|
||||||
|
auto selectFrameLabel = new QLabel(tr("Compare Frame"), this);
|
||||||
|
view3DComboBox->setModel(view3DComboModel);
|
||||||
|
frameComboBox->setModel(frameComboModel);
|
||||||
|
hFrameLayout->addWidget(selectView3DLabel);
|
||||||
|
hFrameLayout->addWidget(view3DComboBox);
|
||||||
|
hFrameLayout->addWidget(selectFrameLabel);
|
||||||
|
hFrameLayout->addWidget(frameComboBox);
|
||||||
|
groupLayout->addLayout(hFrameLayout);
|
||||||
|
hMainLayout->addWidget(m_mainView.get());
|
||||||
|
hMainLayout->addWidget(m_compareFrameView.get());
|
||||||
|
groupLayout->addLayout(hMainLayout);
|
||||||
|
connect(model, &Quick3DFrameModel::modelReset, [model, view3DComboModel, frameComboModel](){
|
||||||
|
QStringList list;
|
||||||
|
list << tr("All");
|
||||||
|
list << model->view3DNames();
|
||||||
|
view3DComboModel->setStringList(list);
|
||||||
|
list.clear();
|
||||||
|
list << tr("None");
|
||||||
|
list << model->frameNames(tr("All"));
|
||||||
|
frameComboModel->setStringList(list);
|
||||||
|
});
|
||||||
|
connect(view3DComboBox, &QComboBox::currentTextChanged, [this, model, frameComboModel](const QString &text){
|
||||||
|
m_mainView->setFilterView3D(text);
|
||||||
|
model->setFilterView3D(text);
|
||||||
|
QStringList list;
|
||||||
|
list << tr("None");
|
||||||
|
list << model->frameNames(text);
|
||||||
|
frameComboModel->setStringList(list);
|
||||||
|
});
|
||||||
|
connect(frameComboBox, &QComboBox::currentTextChanged, [model, this](const QString &text){
|
||||||
|
model->setFilterFrame(text);
|
||||||
|
m_compareFrameView->setFilterFrame(text);
|
||||||
|
});
|
||||||
|
|
||||||
|
setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DFrameView::selectByTypeId(int)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DFrameView::onVisibleFeaturesChanged(quint64)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Quick3DMainView::Quick3DMainView(Quick3DFrameModel *model, bool compareView, QWidget *parent)
|
||||||
|
: Utils::TreeView(parent), m_model(model), m_compareView(compareView)
|
||||||
|
{
|
||||||
|
setObjectName("Quick3DMainView");
|
||||||
|
setFrameStyle(QFrame::NoFrame);
|
||||||
|
QHeaderView *h = header();
|
||||||
|
h->setSectionResizeMode(QHeaderView::Interactive);
|
||||||
|
h->setDefaultSectionSize(100);
|
||||||
|
h->setMinimumSectionSize(50);
|
||||||
|
|
||||||
|
auto sortModel = new QSortFilterProxyModel(this);
|
||||||
|
sortModel->setSourceModel(model);
|
||||||
|
sortModel->setSortRole(Quick3DFrameModel::SortRole);
|
||||||
|
sortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
sortModel->setFilterRole(compareView ? Quick3DFrameModel::CompareRole : Quick3DFrameModel::FilterRole);
|
||||||
|
if (m_compareView)
|
||||||
|
sortModel->setFilterFixedString("+");
|
||||||
|
setModel(sortModel);
|
||||||
|
|
||||||
|
connect(this, &QAbstractItemView::activated, this, [this](const QModelIndex &index) {
|
||||||
|
QString location = m_model->location(index.data(Quick3DFrameModel::IndexRole).toInt());
|
||||||
|
if (!location.isEmpty()) {
|
||||||
|
QString file, line;
|
||||||
|
int lineIdx = location.lastIndexOf(QStringLiteral(".qml:"));
|
||||||
|
int nameIdx = location.lastIndexOf(QStringLiteral(" "));
|
||||||
|
if (lineIdx < 0)
|
||||||
|
return;
|
||||||
|
lineIdx += 4;
|
||||||
|
file = location.mid(nameIdx + 1, lineIdx - nameIdx - 1);
|
||||||
|
line = location.right(location.length() - lineIdx - 1);
|
||||||
|
QUrl url(file);
|
||||||
|
emit gotoSourceLocation(url.fileName(), line.toInt(), 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
m_sortModel = sortModel;
|
||||||
|
|
||||||
|
setSortingEnabled(true);
|
||||||
|
sortByColumn(Quick3DFrameModel::FrameGroup, Qt::AscendingOrder);
|
||||||
|
|
||||||
|
setRootIsDecorated(true);
|
||||||
|
setColumnWidth(0, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DMainView::setFilterView3D(const QString &objectName)
|
||||||
|
{
|
||||||
|
if (objectName == tr("All"))
|
||||||
|
m_sortModel->setFilterFixedString("");
|
||||||
|
else
|
||||||
|
m_sortModel->setFilterFixedString(objectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DMainView::setFilterFrame(const QString &)
|
||||||
|
{
|
||||||
|
m_sortModel->setFilterFixedString("+");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace QmlProfiler
|
82
src/plugins/qmlprofiler/quick3dframeview.h
Normal file
82
src/plugins/qmlprofiler/quick3dframeview.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qmlprofilermodelmanager.h"
|
||||||
|
#include "quick3dframemodel.h"
|
||||||
|
#include "qmlprofilereventsview.h"
|
||||||
|
#include "qmlprofilereventtypes.h"
|
||||||
|
|
||||||
|
#include <utils/itemviews.h>
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace QmlProfiler {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class Quick3DMainView;
|
||||||
|
|
||||||
|
class Quick3DFrameView : public QmlProfilerEventsView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Quick3DFrameView(QmlProfilerModelManager *profilerModelManager,
|
||||||
|
QWidget *parent = nullptr);
|
||||||
|
~Quick3DFrameView() override = default;
|
||||||
|
|
||||||
|
void selectByTypeId(int typeIndex) override;
|
||||||
|
void onVisibleFeaturesChanged(quint64 features) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::unique_ptr<Quick3DMainView> m_mainView;
|
||||||
|
std::unique_ptr<Quick3DMainView> m_compareFrameView;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Quick3DMainView : public Utils::TreeView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Quick3DMainView(Quick3DFrameModel *model, bool compareView, QWidget *parent = nullptr);
|
||||||
|
~Quick3DMainView() override = default;
|
||||||
|
|
||||||
|
void setFilterView3D(const QString &objectName);
|
||||||
|
void setFilterFrame(const QString &objectName);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Quick3DFrameModel *m_model;
|
||||||
|
QSortFilterProxyModel *m_sortModel;
|
||||||
|
bool m_compareView;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace QmlProfiler
|
@@ -4,16 +4,23 @@
|
|||||||
#include "qmlprofilerconstants.h"
|
#include "qmlprofilerconstants.h"
|
||||||
#include "qmlprofilertr.h"
|
#include "qmlprofilertr.h"
|
||||||
#include "quick3dmodel.h"
|
#include "quick3dmodel.h"
|
||||||
|
|
||||||
#include <tracing/timelineformattime.h>
|
#include <tracing/timelineformattime.h>
|
||||||
|
|
||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
int Quick3DModel::eventDataId(int id)
|
||||||
|
{
|
||||||
|
static int ID_MASK = 0xff000000;
|
||||||
|
static int ID_MARKER = 0xed000000;
|
||||||
|
if ((id & ID_MASK) == ID_MARKER)
|
||||||
|
return id - ID_MARKER;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Quick3DModel::Quick3DModel(QmlProfilerModelManager *manager,
|
Quick3DModel::Quick3DModel(QmlProfilerModelManager *manager,
|
||||||
Timeline::TimelineModelAggregator *parent) :
|
Timeline::TimelineModelAggregator *parent) :
|
||||||
QmlProfilerTimelineModel(manager, Quick3DEvent, UndefinedRangeType, ProfileQuick3D, parent),
|
QmlProfilerTimelineModel(manager, Quick3DEvent, UndefinedRangeType, ProfileQuick3D, parent)
|
||||||
m_maximumMsgType(-1)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +39,9 @@ static const char *messageTypes[] = {
|
|||||||
QT_TRANSLATE_NOOP("QmlProfiler", "Generate Shader"),
|
QT_TRANSLATE_NOOP("QmlProfiler", "Generate Shader"),
|
||||||
QT_TRANSLATE_NOOP("QmlProfiler", "Load Shader"),
|
QT_TRANSLATE_NOOP("QmlProfiler", "Load Shader"),
|
||||||
QT_TRANSLATE_NOOP("QmlProfiler", "Particle Update"),
|
QT_TRANSLATE_NOOP("QmlProfiler", "Particle Update"),
|
||||||
|
QT_TRANSLATE_NOOP("QmlProfiler", "Render Call"),
|
||||||
|
QT_TRANSLATE_NOOP("QmlProfiler", "Render Pass"),
|
||||||
|
QT_TRANSLATE_NOOP("QmlProfiler", "Event Data"),
|
||||||
|
|
||||||
QT_TRANSLATE_NOOP("QmlProfiler", "Mesh Memory consumption"),
|
QT_TRANSLATE_NOOP("QmlProfiler", "Mesh Memory consumption"),
|
||||||
QT_TRANSLATE_NOOP("QmlProfiler", "Texture Memory consumption"),
|
QT_TRANSLATE_NOOP("QmlProfiler", "Texture Memory consumption"),
|
||||||
@@ -65,12 +75,12 @@ QString Quick3DModel::unloadMessageType(uint i)
|
|||||||
QVariantList Quick3DModel::labels() const
|
QVariantList Quick3DModel::labels() const
|
||||||
{
|
{
|
||||||
QVariantList result;
|
QVariantList result;
|
||||||
for (int i = 0; i <= m_maximumMsgType; ++i) {
|
for (int detailType : m_sortedTypes) {
|
||||||
QVariantMap element;
|
QVariantMap element;
|
||||||
element.insert(QLatin1String("displayName"),
|
element.insert(QLatin1String("displayName"),
|
||||||
i != ParticleUpdate ? Tr::tr("Render Thread") : Tr::tr("GUI Thread"));
|
detailType != ParticleUpdate ? Tr::tr("Render Thread") : Tr::tr("GUI Thread"));
|
||||||
element.insert(QLatin1String("description"), messageType(i));
|
element.insert(QLatin1String("description"), messageType(detailType));
|
||||||
element.insert(QLatin1String("id"), i);
|
element.insert(QLatin1String("id"), detailType);
|
||||||
result << element;
|
result << element;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -83,6 +93,8 @@ float Quick3DModel::relativeHeight(int index) const
|
|||||||
return qMin(1.0f, (float)m_data[index].data / (float)m_maxTextureSize);
|
return qMin(1.0f, (float)m_data[index].data / (float)m_maxTextureSize);
|
||||||
if (detailType == MeshMemoryConsumption)
|
if (detailType == MeshMemoryConsumption)
|
||||||
return qMin(1.0f, (float)m_data[index].data / (float)m_maxMeshSize);
|
return qMin(1.0f, (float)m_data[index].data / (float)m_maxMeshSize);
|
||||||
|
if (detailType == RenderPass)
|
||||||
|
return qMin(1.0f, (float)m_data[index].nests / (float)m_maxNestedRenderCalls);
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,9 +105,45 @@ qint64 Quick3DModel::rowMaxValue(int rowNumber) const
|
|||||||
return m_maxTextureSize;
|
return m_maxTextureSize;
|
||||||
if (index == MeshMemoryConsumption)
|
if (index == MeshMemoryConsumption)
|
||||||
return m_maxMeshSize;
|
return m_maxMeshSize;
|
||||||
|
if (index == RenderPass)
|
||||||
|
return m_maxNestedRenderCalls;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Quick3DModel::resolveType(const QString &object, int detailType, QString &type)
|
||||||
|
{
|
||||||
|
switch (detailType) {
|
||||||
|
case RenderFrame:
|
||||||
|
case SynchronizeFrame:
|
||||||
|
case PrepareFrame:
|
||||||
|
type = QLatin1String("View3D");
|
||||||
|
break;
|
||||||
|
case MeshLoad:
|
||||||
|
case CustomMeshLoad:
|
||||||
|
case TextureLoad:
|
||||||
|
case LoadShader:
|
||||||
|
case GenerateShader:
|
||||||
|
type = QLatin1String("URL");
|
||||||
|
break;
|
||||||
|
case ParticleUpdate:
|
||||||
|
type = QLatin1String("ParticleSystem");
|
||||||
|
break;
|
||||||
|
case RenderCall:
|
||||||
|
if (object.contains(QLatin1String("Material")))
|
||||||
|
type = QLatin1String("Material");
|
||||||
|
if (object.contains(QLatin1String("Model")))
|
||||||
|
type = QLatin1String("Model");
|
||||||
|
return !type.isEmpty();
|
||||||
|
break;
|
||||||
|
case RenderPass:
|
||||||
|
type = QLatin1String("Pass");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return !type.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap Quick3DModel::details(int index) const
|
QVariantMap Quick3DModel::details(int index) const
|
||||||
{
|
{
|
||||||
auto detailType = m_data[index].additionalType;
|
auto detailType = m_data[index].additionalType;
|
||||||
@@ -115,16 +163,41 @@ QVariantMap Quick3DModel::details(int index) const
|
|||||||
result.insert(Tr::tr("Draw Calls"), calls);
|
result.insert(Tr::tr("Draw Calls"), calls);
|
||||||
result.insert(Tr::tr("Render Passes"), passes);
|
result.insert(Tr::tr("Render Passes"), passes);
|
||||||
}
|
}
|
||||||
|
if ((detailType == RenderPass || detailType == PrepareFrame) && m_data[index].data) {
|
||||||
|
quint32 width = m_data[index].data & 0xffffffff;
|
||||||
|
quint32 height = m_data[index].data >> 32;
|
||||||
|
result.insert(tr("Width"), width);
|
||||||
|
result.insert(tr("Height"), height);
|
||||||
|
}
|
||||||
if ((detailType >= MeshLoad && detailType <= TextureLoad)
|
if ((detailType >= MeshLoad && detailType <= TextureLoad)
|
||||||
|| (detailType >= MeshMemoryConsumption && detailType <= TextureMemoryConsumption)) {
|
|| (detailType >= MeshMemoryConsumption && detailType <= TextureMemoryConsumption)) {
|
||||||
result.insert(Tr::tr("Total Memory Usage"), m_data[index].data);
|
result.insert(Tr::tr("Total Memory Usage"), m_data[index].data);
|
||||||
}
|
}
|
||||||
|
if (detailType == RenderCall) {
|
||||||
|
quint32 primitives = m_data[index].data & 0xffffffff;
|
||||||
|
quint32 instances = m_data[index].data >> 32;
|
||||||
|
result.insert(tr("Primitives"), primitives);
|
||||||
|
if (instances > 1)
|
||||||
|
result.insert(tr("Instances"), instances);
|
||||||
|
}
|
||||||
|
if (!m_data[index].eventData.isEmpty()) {
|
||||||
|
for (int i = 0; i < m_data[index].eventData.size(); i++) {
|
||||||
|
int p = m_data[index].eventData[i];
|
||||||
|
if (m_eventData.contains(p)) {
|
||||||
|
const QmlEventType &et = modelManager()->eventType(m_eventData[p]);
|
||||||
|
QString type;
|
||||||
|
if (resolveType(et.data(), detailType, type))
|
||||||
|
result.insert(type, et.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Quick3DModel::expandedRow(int index) const
|
int Quick3DModel::expandedRow(int index) const
|
||||||
{
|
{
|
||||||
return selectionId(index) + 1;
|
const Item &item = m_data[index];
|
||||||
|
return m_sortedTypes.indexOf(item.additionalType) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Quick3DModel::collapsedRow(int index) const
|
int Quick3DModel::collapsedRow(int index) const
|
||||||
@@ -138,64 +211,105 @@ void Quick3DModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
|
|||||||
int detailType = type.detailType();
|
int detailType = type.detailType();
|
||||||
if (detailType >= MaximumQuick3DFrameType)
|
if (detailType >= MaximumQuick3DFrameType)
|
||||||
return;
|
return;
|
||||||
qint64 eventDuration = event.number<qint64>(0);
|
if (detailType == EventData) {
|
||||||
qint64 eventTime = event.timestamp() - eventDuration;
|
m_eventData.insert(m_eventData.size() + 1, event.typeIndex());
|
||||||
QVector<quint64> numbers = event.numbers<QVector<quint64>>();
|
return;
|
||||||
quint64 data = numbers.size() > 1 ? event.number<quint64>(1) : 0;
|
}
|
||||||
|
|
||||||
int typeCount = detailType;
|
QList<quint64> numbers = event.numbers<QList<quint64>>();
|
||||||
|
if (numbers.size() == 0)
|
||||||
|
return;
|
||||||
|
qint64 eventDuration = numbers[0];
|
||||||
|
qint64 eventTime = event.timestamp() - eventDuration;
|
||||||
|
quint64 data = numbers.size() > 1 ? numbers[1] : 0;
|
||||||
|
QList<int> eventData;
|
||||||
|
// The rest are pairs of event data id's
|
||||||
|
for (int i = 2; i < numbers.size(); i++) {
|
||||||
|
qint32 h = eventDataId(numbers[i] >> 32);
|
||||||
|
qint32 l = eventDataId(numbers[i] & 0xffffffff);
|
||||||
|
if (m_eventData.contains(h))
|
||||||
|
eventData.push_back(h);
|
||||||
|
if (m_eventData.contains(l))
|
||||||
|
eventData.push_back(l);
|
||||||
|
}
|
||||||
|
m_types << detailType;
|
||||||
if (detailType == MeshLoad || detailType == CustomMeshLoad) {
|
if (detailType == MeshLoad || detailType == CustomMeshLoad) {
|
||||||
bool updatePrevValues = true;
|
bool updatePrevValues = true;
|
||||||
|
|
||||||
if (m_prevMeshStartTime != -1) {
|
if (m_prevMeshStartTime != -1) {
|
||||||
bool unload = m_prevMeshData > data;
|
bool unload = m_prevMeshData > data;
|
||||||
m_data.insert(insert(eventTime, eventDuration, detailType),
|
Item i = Item(detailType, data, unload);
|
||||||
Item(detailType, data, unload));
|
i.eventData = eventData;
|
||||||
|
m_data.insert(insert(eventTime, eventDuration, detailType), i);
|
||||||
if (m_prevMeshData != data) {
|
if (m_prevMeshData != data) {
|
||||||
m_data.insert(insert(m_prevMeshStartTime,
|
m_data.insert(insert(m_prevMeshStartTime,
|
||||||
eventTime - m_prevMeshStartTime, MeshMemoryConsumption),
|
eventTime - m_prevMeshStartTime, MeshMemoryConsumption),
|
||||||
Item(MeshMemoryConsumption, m_prevMeshData));
|
Item(MeshMemoryConsumption, m_prevMeshData));
|
||||||
|
m_types << MeshMemoryConsumption;
|
||||||
} else {
|
} else {
|
||||||
updatePrevValues = false;
|
updatePrevValues = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_data.insert(insert(eventTime, eventDuration, detailType),
|
Item i = Item(detailType, data);
|
||||||
Item(detailType, data));
|
i.eventData = eventData;
|
||||||
|
m_data.insert(insert(eventTime, eventDuration, detailType), i);
|
||||||
}
|
}
|
||||||
m_maxMeshSize = qMax(m_maxMeshSize, data);
|
m_maxMeshSize = qMax(m_maxMeshSize, data);
|
||||||
if (updatePrevValues) {
|
if (updatePrevValues) {
|
||||||
m_prevMeshStartTime = eventTime;
|
m_prevMeshStartTime = eventTime;
|
||||||
m_prevMeshData = data;
|
m_prevMeshData = data;
|
||||||
}
|
}
|
||||||
typeCount = MeshMemoryConsumption;
|
|
||||||
} else if (detailType == TextureLoad) {
|
} else if (detailType == TextureLoad) {
|
||||||
bool updatePrevValues = true;
|
bool updatePrevValues = true;
|
||||||
|
|
||||||
if (m_prevTexStartTime != -1) {
|
if (m_prevTexStartTime != -1) {
|
||||||
bool unload = m_prevTexData > data;
|
bool unload = m_prevTexData > data;
|
||||||
m_data.insert(insert(eventTime, eventDuration, detailType),
|
Item i = Item(detailType, data, unload);
|
||||||
Item(detailType, data, unload));
|
i.eventData = eventData;
|
||||||
|
m_data.insert(insert(eventTime, eventDuration, detailType), i);
|
||||||
if (m_prevTexData != data) {
|
if (m_prevTexData != data) {
|
||||||
m_data.insert(insert(m_prevTexStartTime,
|
m_data.insert(insert(m_prevTexStartTime,
|
||||||
eventTime - m_prevTexStartTime, TextureMemoryConsumption),
|
eventTime - m_prevTexStartTime, TextureMemoryConsumption),
|
||||||
Item(TextureMemoryConsumption, m_prevTexData));
|
Item(TextureMemoryConsumption, m_prevTexData));
|
||||||
|
m_types << TextureMemoryConsumption;
|
||||||
} else {
|
} else {
|
||||||
updatePrevValues = false;
|
updatePrevValues = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_data.insert(insert(eventTime, eventDuration, detailType),
|
Item i = Item(detailType, data, false);
|
||||||
Item(detailType, data));
|
i.eventData = eventData;
|
||||||
|
m_data.insert(insert(eventTime, eventDuration, detailType), i);
|
||||||
}
|
}
|
||||||
m_maxTextureSize = qMax(m_maxTextureSize, data);
|
m_maxTextureSize = qMax(m_maxTextureSize, data);
|
||||||
if (updatePrevValues) {
|
if (updatePrevValues) {
|
||||||
m_prevTexData = data;
|
m_prevTexData = data;
|
||||||
m_prevTexStartTime = eventTime;
|
m_prevTexStartTime = eventTime;
|
||||||
}
|
}
|
||||||
typeCount = TextureMemoryConsumption;
|
|
||||||
} else {
|
} else {
|
||||||
m_data.insert(insert(eventTime, eventDuration, detailType),
|
Item i = Item(detailType, data);
|
||||||
Item(detailType, data));
|
i.eventData = eventData;
|
||||||
|
auto index = insert(eventTime, eventDuration, detailType);
|
||||||
|
m_data.insert(index, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quick3DModel::calculateRenderPassNesting()
|
||||||
|
{
|
||||||
|
QList<qint64> nesting;
|
||||||
|
for (int item = 0; item < m_data.size(); item++) {
|
||||||
|
if (m_data[item].additionalType != RenderPass)
|
||||||
|
continue;
|
||||||
|
while (!nesting.isEmpty()) {
|
||||||
|
auto l = nesting.last();
|
||||||
|
if (l >= startTime(item))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
nesting.removeLast();
|
||||||
|
}
|
||||||
|
nesting.push_back(endTime(item));
|
||||||
|
m_data[item].nests = nesting.size();
|
||||||
|
m_maxNestedRenderCalls = qMax(m_maxNestedRenderCalls, nesting.size());
|
||||||
}
|
}
|
||||||
if (typeCount > m_maximumMsgType)
|
|
||||||
m_maximumMsgType = typeCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Quick3DModel::finalize()
|
void Quick3DModel::finalize()
|
||||||
@@ -204,22 +318,29 @@ void Quick3DModel::finalize()
|
|||||||
m_data.insert(insert(m_prevMeshStartTime, modelManager()->traceEnd() - m_prevMeshStartTime,
|
m_data.insert(insert(m_prevMeshStartTime, modelManager()->traceEnd() - m_prevMeshStartTime,
|
||||||
MeshMemoryConsumption),
|
MeshMemoryConsumption),
|
||||||
Item(MeshMemoryConsumption, m_prevMeshData));
|
Item(MeshMemoryConsumption, m_prevMeshData));
|
||||||
|
m_types << MeshMemoryConsumption;
|
||||||
}
|
}
|
||||||
if (m_prevTexStartTime != -1) {
|
if (m_prevTexStartTime != -1) {
|
||||||
m_data.insert(insert(m_prevTexStartTime, modelManager()->traceEnd() - m_prevTexStartTime,
|
m_data.insert(insert(m_prevTexStartTime, modelManager()->traceEnd() - m_prevTexStartTime,
|
||||||
TextureMemoryConsumption),
|
TextureMemoryConsumption),
|
||||||
Item(TextureMemoryConsumption, m_prevTexData));
|
Item(TextureMemoryConsumption, m_prevTexData));
|
||||||
|
m_types << TextureMemoryConsumption;
|
||||||
}
|
}
|
||||||
computeNesting();
|
computeNesting();
|
||||||
setCollapsedRowCount(Constants::QML_MIN_LEVEL + 1);
|
setCollapsedRowCount(Constants::QML_MIN_LEVEL + 1);
|
||||||
setExpandedRowCount(m_maximumMsgType + 2);
|
m_sortedTypes = m_types.values();
|
||||||
|
std::sort(m_sortedTypes.begin(), m_sortedTypes.end(), [](int a, int b){ return a < b;});
|
||||||
|
setExpandedRowCount(m_sortedTypes.size() + 1);
|
||||||
QmlProfilerTimelineModel::finalize();
|
QmlProfilerTimelineModel::finalize();
|
||||||
|
calculateRenderPassNesting();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Quick3DModel::clear()
|
void Quick3DModel::clear()
|
||||||
{
|
{
|
||||||
m_data.clear();
|
m_data.clear();
|
||||||
m_maximumMsgType = -1;
|
m_types.clear();
|
||||||
|
m_sortedTypes.clear();
|
||||||
m_prevTexStartTime = -1;
|
m_prevTexStartTime = -1;
|
||||||
m_prevMeshStartTime = -1;
|
m_prevMeshStartTime = -1;
|
||||||
m_maxMeshSize = 0;
|
m_maxMeshSize = 0;
|
||||||
@@ -227,10 +348,49 @@ void Quick3DModel::clear()
|
|||||||
QmlProfilerTimelineModel::clear();
|
QmlProfilerTimelineModel::clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantMap Quick3DModel::locationFromEvent(int index) const
|
||||||
|
{
|
||||||
|
QVariantMap ret;
|
||||||
|
for (auto e : m_data[index].eventData) {
|
||||||
|
if (m_eventData.contains(e)) {
|
||||||
|
const QmlEventType &et = modelManager()->eventType(m_eventData[e]);
|
||||||
|
const QString data = et.data();
|
||||||
|
QString file, line;
|
||||||
|
int lineIdx = data.lastIndexOf(QStringLiteral(".qml:"));
|
||||||
|
int nameIdx = data.lastIndexOf(QStringLiteral(" "));
|
||||||
|
if (lineIdx < 0)
|
||||||
|
return ret;
|
||||||
|
lineIdx += 4;
|
||||||
|
file = data.mid(nameIdx + 1, lineIdx - nameIdx - 1);
|
||||||
|
line = data.right(data.length() - lineIdx - 1);
|
||||||
|
QUrl url(file);
|
||||||
|
ret.insert(QStringLiteral("file"), url.fileName());
|
||||||
|
ret.insert(QStringLiteral("line"), line.toInt());
|
||||||
|
ret.insert(QStringLiteral("column"), 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap Quick3DModel::location(int index) const
|
QVariantMap Quick3DModel::location(int index) const
|
||||||
{
|
{
|
||||||
|
QVariantMap ret;
|
||||||
|
if (!m_data[index].eventData.isEmpty())
|
||||||
|
ret = locationFromEvent(index);
|
||||||
|
if (!ret.isEmpty())
|
||||||
|
return ret;
|
||||||
return locationFromTypeId(index);
|
return locationFromTypeId(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Quick3DModel::typeId(int index) const
|
||||||
|
{
|
||||||
|
for (auto ed : m_data[index].eventData) {
|
||||||
|
if (m_eventData.contains(ed))
|
||||||
|
return m_eventData[ed];
|
||||||
|
}
|
||||||
|
return QmlProfilerTimelineModel::typeId(index);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace QmlProfiler
|
} // namespace QmlProfiler
|
||||||
|
@@ -17,8 +17,10 @@ public:
|
|||||||
Item(int additionalType, quint64 data, bool unload = false) :
|
Item(int additionalType, quint64 data, bool unload = false) :
|
||||||
additionalType(additionalType), data(data), unload(unload) {}
|
additionalType(additionalType), data(data), unload(unload) {}
|
||||||
int additionalType = 0;
|
int additionalType = 0;
|
||||||
|
int nests = 0;
|
||||||
quint64 data = 0;
|
quint64 data = 0;
|
||||||
bool unload = false;
|
bool unload = false;
|
||||||
|
QList<int> eventData;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MessageType
|
enum MessageType
|
||||||
@@ -32,7 +34,9 @@ public:
|
|||||||
GenerateShader,
|
GenerateShader,
|
||||||
LoadShader,
|
LoadShader,
|
||||||
ParticleUpdate,
|
ParticleUpdate,
|
||||||
|
RenderCall,
|
||||||
|
RenderPass,
|
||||||
|
EventData,
|
||||||
// additional types
|
// additional types
|
||||||
MeshMemoryConsumption,
|
MeshMemoryConsumption,
|
||||||
TextureMemoryConsumption
|
TextureMemoryConsumption
|
||||||
@@ -51,19 +55,28 @@ public:
|
|||||||
void finalize() override;
|
void finalize() override;
|
||||||
void clear() override;
|
void clear() override;
|
||||||
QVariantMap location(int index) const override;
|
QVariantMap location(int index) const override;
|
||||||
|
int typeId(int index) const override;
|
||||||
|
|
||||||
|
static int eventDataId(int id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QString messageType(uint i);
|
static QString messageType(uint i);
|
||||||
static QString unloadMessageType(uint i);
|
static QString unloadMessageType(uint i);
|
||||||
|
static bool resolveType(const QString &object, int detailType, QString &type);
|
||||||
|
QVariantMap locationFromEvent(int poid) const;
|
||||||
|
void calculateRenderPassNesting();
|
||||||
|
|
||||||
int m_maximumMsgType = 0;
|
QSet<int> m_types;
|
||||||
|
QList<int> m_sortedTypes;
|
||||||
qint64 m_prevTexStartTime = -1;
|
qint64 m_prevTexStartTime = -1;
|
||||||
qint64 m_prevMeshStartTime = -1;
|
qint64 m_prevMeshStartTime = -1;
|
||||||
quint64 m_prevMeshData = 0;
|
quint64 m_prevMeshData = 0;
|
||||||
quint64 m_prevTexData = 0;
|
quint64 m_prevTexData = 0;
|
||||||
quint64 m_maxMeshSize = 0;
|
quint64 m_maxMeshSize = 0;
|
||||||
quint64 m_maxTextureSize = 0;
|
quint64 m_maxTextureSize = 0;
|
||||||
|
int m_maxNestedRenderCalls = 1;
|
||||||
QVector<Item> m_data;
|
QVector<Item> m_data;
|
||||||
|
QHash<int, int> m_eventData;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
Reference in New Issue
Block a user