diff options
-rw-r--r-- | plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp | 376 | ||||
-rw-r--r-- | plugins/qmlprofilerextension/scenegraphtimelinemodel.h | 8 |
2 files changed, 209 insertions, 175 deletions
diff --git a/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp b/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp index ccb27cb7b4..b6eb1a263e 100644 --- a/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp +++ b/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp @@ -30,19 +30,30 @@ namespace Internal { using namespace QmlProfiler; -enum SceneGraphEventType { - SceneGraphRendererFrame, - SceneGraphAdaptationLayerFrame, - SceneGraphContextFrame, - SceneGraphRenderLoopFrame, - SceneGraphTexturePrepare, - SceneGraphTextureDeletion, - SceneGraphPolishAndSync, - SceneGraphWindowsRenderShow, - SceneGraphWindowsAnimations, - SceneGraphWindowsPolishFrame, - - MaximumSceneGraphFrameType +static const char *ThreadLabels[] = { + "GUI Thread", + "Render Thread" +}; + +static const char *StageLabels[] = { + "Polish", + "Wait", + "Sync", + "Animations", + "Sync", + "Swap", + "Material Compile", + "Render Preprocess", + "Render Update", + "Render Bind", + "Render", + "Glyph Render", + "Glyph Upload", + "Texture Bind", + "Texture Convert", + "Texture Swizzle", + "Texture Upload", + "Texture Mipmap" }; enum SceneGraphCategoryType { @@ -52,23 +63,63 @@ enum SceneGraphCategoryType { MaximumSceneGraphCategoryType }; +enum SceneGraphStage { + Polish = 0, + Wait, + GUIThreadSync, + Animations, + MaximumGUIThreadStage, + + RenderThreadSync = MaximumGUIThreadStage, + Swap, + Material, + MaximumRenderThreadStage, + + RenderPreprocess = MaximumRenderThreadStage, + RenderUpdate, + RenderBind, + RenderRender, + MaximumRenderStage, + + GlyphRender = MaximumRenderStage, + GlyphStore, + MaximumGlyphStage, + + TextureBind = MaximumGlyphStage, + TextureConvert, + TextureSwizzle, + TextureUpload, + TextureMipmap, + MaximumTextureStage, + + MaximumSceneGraphStage = MaximumTextureStage +}; + + +Q_STATIC_ASSERT(sizeof(StageLabels) == MaximumSceneGraphStage * sizeof(const char *)); + class SceneGraphTimelineModel::SceneGraphTimelineModelPrivate : public SortedTimelineModel<SceneGraphTimelineModel::SceneGraphEvent, AbstractTimelineModel::AbstractTimelineModelPrivate> { public: - void addVP(QVariantMap &result, QString label, qint64 time) const; + SceneGraphTimelineModelPrivate(); + int collapsedRowCount; + void flattenLoads(); + private: - bool seenPolishAndSync; Q_DECLARE_PUBLIC(SceneGraphTimelineModel) }; +SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::SceneGraphTimelineModelPrivate() : + collapsedRowCount(1) +{ +} + SceneGraphTimelineModel::SceneGraphTimelineModel(QObject *parent) : AbstractTimelineModel(new SceneGraphTimelineModelPrivate, tr("Scene Graph"), QmlDebug::SceneGraphFrame, QmlDebug::MaximumRangeType, parent) { - Q_D(SceneGraphTimelineModel); - d->seenPolishAndSync = false; } int SceneGraphTimelineModel::rowCount() const @@ -76,47 +127,24 @@ int SceneGraphTimelineModel::rowCount() const Q_D(const SceneGraphTimelineModel); if (isEmpty()) return 1; - return d->seenPolishAndSync ? 3 : 2; + return expanded() ? (MaximumSceneGraphStage + 1) : d->collapsedRowCount; } int SceneGraphTimelineModel::row(int index) const { Q_D(const SceneGraphTimelineModel); - return d->seenPolishAndSync ? d->range(index).sgEventType + 1 : 1; + return expanded() ? (d->range(index).stage + 1) : d->range(index).rowNumberCollapsed; } int SceneGraphTimelineModel::eventId(int index) const { Q_D(const SceneGraphTimelineModel); - return d->seenPolishAndSync ? d->range(index).sgEventType : SceneGraphGUIThread; + return d->range(index).stage; } QColor SceneGraphTimelineModel::color(int index) const { - // get duration in seconds - double eventDuration = duration(index) / 1e9; - - // supposedly never above 60 frames per second - // limit it in that case - if (eventDuration < 1/60.0) - eventDuration = 1/60.0; - - // generate hue based on fraction of the 60fps - double fpsFraction = 1 / (eventDuration * 60.0); - if (fpsFraction > 1.0) - fpsFraction = 1.0; - return colorByFraction(fpsFraction); -} - -QString labelForSGType(int t) -{ - switch ((SceneGraphCategoryType)t) { - case SceneGraphRenderThread: - return QCoreApplication::translate("SceneGraphTimelineModel", "Render Thread"); - case SceneGraphGUIThread: - return QCoreApplication::translate("SceneGraphTimelineModel", "GUI Thread"); - default: return QString(); - } + return colorByEventId(eventId(index)); } QVariantList SceneGraphTimelineModel::labels() const @@ -124,20 +152,13 @@ QVariantList SceneGraphTimelineModel::labels() const Q_D(const SceneGraphTimelineModel); QVariantList result; - static QVariant renderThreadLabel(labelForSGType(SceneGraphRenderThread)); - static QVariant guiThreadLabel(labelForSGType(SceneGraphGUIThread)); - if (d->expanded && !isEmpty()) { - { + for (int i = 0; i < MaximumSceneGraphStage; ++i) { QVariantMap element; - element.insert(QLatin1String("description"), guiThreadLabel); - element.insert(QLatin1String("id"), SceneGraphGUIThread); - result << element; - } - if (d->seenPolishAndSync) { - QVariantMap element; - element.insert(QLatin1String("description"), renderThreadLabel); - element.insert(QLatin1String("id"), SceneGraphRenderThread); + element.insert(QLatin1String("displayName"), tr(ThreadLabels[i < MaximumGUIThreadStage ? + SceneGraphGUIThread : SceneGraphRenderThread])); + element.insert(QLatin1String("description"), tr(StageLabels[i])); + element.insert(QLatin1String("id"), i); result << element; } } @@ -145,15 +166,6 @@ QVariantList SceneGraphTimelineModel::labels() const return result; } -void SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::addVP(QVariantMap &result, - QString label, - qint64 time) const -{ - if (time > 0) - result.insert(label, QmlProfilerBaseModel::formatTime(time)); -} - - QVariantMap SceneGraphTimelineModel::details(int index) const { Q_D(const SceneGraphTimelineModel); @@ -162,34 +174,12 @@ QVariantMap SceneGraphTimelineModel::details(int index) const AbstractTimelineModel::AbstractTimelineModelPrivate>::Range *ev = &d->range(index); - result.insert(QLatin1String("displayName"), labelForSGType( - d->seenPolishAndSync ? ev->sgEventType : SceneGraphGUIThread)); - d->addVP(result, tr("Duration"), ev->duration ); - - if (ev->sgEventType == SceneGraphRenderThread) { - d->addVP(result, tr("Polish"), ev->timing[14]); - d->addVP(result, tr("Sync"), ev->timing[0]); - d->addVP(result, tr("Preprocess"), ev->timing[1]); - d->addVP(result, tr("Upload"), ev->timing[2]); - d->addVP(result, tr("Swizzle"), ev->timing[3]); - d->addVP(result, tr("Convert"), ev->timing[4]); - d->addVP(result, tr("Mipmap"), ev->timing[5]); - d->addVP(result, tr("Bind"), ev->timing[6]); - d->addVP(result, tr("Material"), ev->timing[7]); - d->addVP(result, tr("Glyph Render"), ev->timing[8]); - d->addVP(result, tr("Glyph Store"), ev->timing[9]); - d->addVP(result, tr("Update"), ev->timing[10]); - d->addVP(result, tr("Binding"), ev->timing[11]); - d->addVP(result, tr("Render"), ev->timing[12]); - d->addVP(result, tr("Swap"), ev->timing[13]); - d->addVP(result, tr("Animations"), ev->timing[15]); - } - if (ev->sgEventType == SceneGraphGUIThread) { - d->addVP(result, tr("Polish"), ev->timing[0]); - d->addVP(result, tr("Wait"), ev->timing[1]); - d->addVP(result, tr("Sync"), ev->timing[2]); - d->addVP(result, tr("Animations"), ev->timing[3]); - } + result.insert(QLatin1String("displayName"), tr(ThreadLabels[ev->stage < MaximumGUIThreadStage ? + SceneGraphGUIThread : SceneGraphRenderThread])); + result.insert(tr("Stage"), tr(StageLabels[ev->stage])); + result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(ev->duration)); + if (ev->glyphCount >= 0) + result.insert(tr("Glyph Count"), QString::number(ev->glyphCount)); return result; } @@ -202,8 +192,6 @@ void SceneGraphTimelineModel::loadData() if (simpleModel->isEmpty()) return; - int lastRenderEvent = -1; - // combine the data of several eventtypes into two rows const QVector<QmlProfilerDataModel::QmlEventTypeData> &types = simpleModel->getEventTypes(); foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { @@ -211,99 +199,145 @@ void SceneGraphTimelineModel::loadData() if (!accepted(type)) continue; - if (type.detailType == SceneGraphRenderLoopFrame) { - SceneGraphEvent newEvent; - newEvent.sgEventType = SceneGraphRenderThread; - qint64 duration = event.numericData1 + event.numericData2 + event.numericData3; - qint64 startTime = event.startTime - duration; - for (int i=0; i < timingFieldCount; i++) - newEvent.timing[i] = 0; - - // Filter out events with incorrect timings due to interrupted thread on server side - if (duration > 0 && startTime > 0) - lastRenderEvent = d->insert(startTime, duration, newEvent); + switch ((QmlDebug::SceneGraphFrameType)type.detailType) { + case QmlDebug::SceneGraphRendererFrame: { + qint64 startTime = event.startTime - event.numericData1 - event.numericData2 - + event.numericData3 - event.numericData4; + d->insert(startTime, event.numericData1, SceneGraphEvent(RenderPreprocess)); + startTime += event.numericData1; + d->insert(startTime, event.numericData2, SceneGraphEvent(RenderUpdate)); + startTime += event.numericData2; + d->insert(startTime, event.numericData3, SceneGraphEvent(RenderBind)); + startTime += event.numericData3; + d->insert(startTime, event.numericData4, SceneGraphEvent(RenderRender)); + break; } - - if (lastRenderEvent >= 0) { - qint64 *timing = d->data(lastRenderEvent).timing; - switch ((SceneGraphEventType)type.detailType) { - case SceneGraphRendererFrame: { - timing[1] = event.numericData1; - timing[10] = event.numericData2; - timing[11] = event.numericData3; - timing[12] = event.numericData4; - break; - } - case SceneGraphAdaptationLayerFrame: { - timing[8] = event.numericData2; - timing[9] = event.numericData3; - break; - } - case SceneGraphContextFrame: { - timing[7] = event.numericData1; - break; - } - case SceneGraphRenderLoopFrame: { - timing[0] = event.numericData1; - timing[13] = event.numericData3; - break; - } - case SceneGraphTexturePrepare: { - timing[2] = event.numericData4; - timing[3] = event.numericData3; - timing[4] = event.numericData2; - timing[5] = event.numericData5; - timing[6] = event.numericData1; - break; - } - case SceneGraphPolishAndSync: { - d->seenPolishAndSync = true; - // GUI thread - SceneGraphEvent newEvent; - newEvent.sgEventType = SceneGraphGUIThread; - qint64 duration = event.numericData1 + event.numericData2 + event.numericData3 + event.numericData4; - qint64 startTime = event.startTime - duration; - for (int i=0; i < timingFieldCount; i++) - newEvent.timing[i] = 0; - - newEvent.timing[0] = event.numericData1; - newEvent.timing[1] = event.numericData2; - newEvent.timing[2] = event.numericData3; - newEvent.timing[3] = event.numericData4; - - // Filter out events with incorrect timings due to interrupted thread on server side - if (duration > 0 && startTime > 0) - d->insert(startTime, duration, newEvent); - - break; - } - case SceneGraphWindowsAnimations: { - timing[15] = event.numericData1; - break; - } - case SceneGraphWindowsPolishFrame: { - timing[14] = event.numericData1; - break; - } - default: break; - } + case QmlDebug::SceneGraphAdaptationLayerFrame: { + qint64 startTime = event.startTime - event.numericData2 - event.numericData3; + d->insert(startTime, event.numericData2, + SceneGraphEvent(GlyphRender, event.numericData1)); + startTime += event.numericData2; + d->insert(startTime, event.numericData3, + SceneGraphEvent(GlyphStore, event.numericData1)); + break; + } + case QmlDebug::SceneGraphContextFrame: { + d->insert(event.startTime - event.numericData1, event.numericData1, + SceneGraphEvent(Material)); + break; + } + case QmlDebug::SceneGraphRenderLoopFrame: { + qint64 startTime = event.startTime - event.numericData1 - event.numericData2 - + event.numericData3; + d->insert(startTime, event.numericData1, SceneGraphEvent(RenderThreadSync)); + startTime += event.numericData1 + event.numericData2; + // Skip actual rendering. We get a SceneGraphRendererFrame for that + d->insert(startTime, event.numericData3, SceneGraphEvent(Swap)); + break; + } + case QmlDebug::SceneGraphTexturePrepare: { + qint64 startTime = event.startTime - event.numericData1 - event.numericData2 - + event.numericData3 - event.numericData4 - event.numericData5; + + d->insert(startTime, event.numericData1, SceneGraphEvent(TextureBind)); + startTime += event.numericData1; + d->insert(startTime, event.numericData2, SceneGraphEvent(TextureConvert)); + startTime += event.numericData2; + d->insert(startTime, event.numericData3, SceneGraphEvent(TextureSwizzle)); + startTime += event.numericData3; + d->insert(startTime, event.numericData4, SceneGraphEvent(TextureUpload)); + startTime += event.numericData4; + d->insert(startTime, event.numericData4, SceneGraphEvent(TextureMipmap)); + break; + } + case QmlDebug::SceneGraphPolishAndSync: { + qint64 startTime = event.startTime - event.numericData1 - event.numericData2 - + event.numericData3 - event.numericData4; + + d->insert(startTime, event.numericData1, SceneGraphEvent(Polish)); + startTime += event.numericData1; + d->insert(startTime, event.numericData2, SceneGraphEvent(Wait)); + startTime += event.numericData2; + d->insert(startTime, event.numericData3, SceneGraphEvent(GUIThreadSync)); + startTime += event.numericData3; + d->insert(startTime, event.numericData4, SceneGraphEvent(Animations)); + break; + } + case QmlDebug::SceneGraphWindowsAnimations: { + // GUI thread, separate animations stage + d->insert(event.startTime - event.numericData1, event.numericData1, + SceneGraphEvent(Animations)); + break; + } + case QmlDebug::SceneGraphPolishFrame: { + // GUI thread, separate polish stage + d->insert(event.startTime - event.numericData1, event.numericData1, + SceneGraphEvent(Polish)); + break; + } + default: break; } d->modelManager->modelProxyCountUpdated(d->modelId, d->count(), simpleModel->getEvents().count()); } d->computeNesting(); + d->flattenLoads(); d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1); } +void SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::flattenLoads() +{ + collapsedRowCount = 0; + + // computes "compressed row" + QVector <qint64> eventEndTimes; + + for (int i = 0; i < count(); i++) { + SceneGraphEvent &event = data(i); + const Range &start = range(i); + // Don't try to put render thread events in GUI row and vice versa. + // Rows below those are free for all. + event.rowNumberCollapsed = (event.stage < MaximumGUIThreadStage ? SceneGraphGUIThread : + SceneGraphRenderThread); + while (eventEndTimes.count() > event.rowNumberCollapsed && + eventEndTimes[event.rowNumberCollapsed] > start.start) { + ++event.rowNumberCollapsed; + if (event.stage < MaximumGUIThreadStage) { + if (event.rowNumberCollapsed == SceneGraphRenderThread) + ++event.rowNumberCollapsed; + } else if (event.rowNumberCollapsed == SceneGraphGUIThread) { + ++event.rowNumberCollapsed; + } + } + + while (eventEndTimes.count() <= event.rowNumberCollapsed) + eventEndTimes << 0; // increase stack length, proper value added below + eventEndTimes[event.rowNumberCollapsed] = start.start + start.duration; + + // readjust to account for category empty row + event.rowNumberCollapsed++; + if (event.rowNumberCollapsed > collapsedRowCount) + collapsedRowCount = event.rowNumberCollapsed; + } + + // Starting from 0, count is maxIndex+1 + collapsedRowCount++; +} + void SceneGraphTimelineModel::clear() { Q_D(SceneGraphTimelineModel); d->clear(); - d->seenPolishAndSync = false; d->expanded = false; + d->collapsedRowCount = 1; d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1); } +SceneGraphTimelineModel::SceneGraphEvent::SceneGraphEvent(int stage, int glyphCount) : + stage(stage), rowNumberCollapsed(-1), glyphCount(glyphCount) +{ +} + } // namespace Internal } // namespace QmlProfilerExtension diff --git a/plugins/qmlprofilerextension/scenegraphtimelinemodel.h b/plugins/qmlprofilerextension/scenegraphtimelinemodel.h index 6a9ebfd76c..71ef32d20a 100644 --- a/plugins/qmlprofilerextension/scenegraphtimelinemodel.h +++ b/plugins/qmlprofilerextension/scenegraphtimelinemodel.h @@ -29,16 +29,16 @@ namespace QmlProfilerExtension { namespace Internal { -#define timingFieldCount 16 - class SceneGraphTimelineModel : public QmlProfiler::AbstractTimelineModel { Q_OBJECT public: struct SceneGraphEvent { - int sgEventType; - qint64 timing[timingFieldCount]; + SceneGraphEvent(int stage = -1, int glyphCount = -1); + int stage; + int rowNumberCollapsed; + int glyphCount; // only used for one event type }; SceneGraphTimelineModel(QObject *parent = 0); |