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:
Antti Määttä
2022-08-11 12:28:56 +03:00
parent 33a8854b21
commit 19df320051
13 changed files with 1168 additions and 41 deletions

View File

@@ -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)

View File

@@ -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",
] ]
} }

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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;
} }

View 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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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