From 11a240e2db79671bbd1a41b4a3909034afc1d83f Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 18 Jun 2018 12:47:13 -0700 Subject: [PATCH] Exploring the performance profile of the render engine --- interface/src/SecondaryCamera.cpp | 4 +- libraries/task/src/task/Config.h | 6 +- scripts/developer/utilities/lib/jet/jet.js | 114 ++++++++++++++ .../utilities/lib/jet/qml/TaskListView.qml | 128 ++++++++-------- .../lib/jet/qml/TaskTimeFrameView.qml | 141 ++++++++++++++++++ .../developer/utilities/lib/jet/qml/qmldir | 3 +- .../utilities/render/engineInspector.js | 10 +- .../utilities/render/engineInspector.qml | 3 +- 8 files changed, 338 insertions(+), 71 deletions(-) create mode 100644 scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index b9a767f700..766c64043d 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -196,11 +196,13 @@ public: void run(const render::RenderContextPointer& renderContext, const RenderArgsPointer& cachedArgs) { auto args = renderContext->args; + if (cachedArgs) { args->_blitFramebuffer = cachedArgs->_blitFramebuffer; args->_viewport = cachedArgs->_viewport; - args->popViewFrustum(); args->_displayMode = cachedArgs->_displayMode; args->_renderMode = cachedArgs->_renderMode; + } + args->popViewFrustum(); gpu::doInBatch("EndSecondaryCameraFrame::run", args->_context, [&](gpu::Batch& batch) { batch.restoreContextStereo(); diff --git a/libraries/task/src/task/Config.h b/libraries/task/src/task/Config.h index 00fa01808b..c94ed5f8ce 100644 --- a/libraries/task/src/task/Config.h +++ b/libraries/task/src/task/Config.h @@ -98,10 +98,10 @@ public: JobConfig() = default; JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {} - bool isEnabled() { return alwaysEnabled || enabled; } - void setEnabled(bool enable) { enabled = alwaysEnabled || enable; emit dirtyEnabled(); } + bool isEnabled() { return /*alwaysEnabled ||*/ enabled; } + void setEnabled(bool enable) { enabled = /*alwaysEnabled ||*/ enable; emit dirtyEnabled(); } - bool alwaysEnabled{ true }; + bool alwaysEnabled{ false }; bool enabled{ true }; virtual void setPresetList(const QJsonObject& object); diff --git a/scripts/developer/utilities/lib/jet/jet.js b/scripts/developer/utilities/lib/jet/jet.js index 16840e59bd..041be0f8a6 100644 --- a/scripts/developer/utilities/lib/jet/jet.js +++ b/scripts/developer/utilities/lib/jet/jet.js @@ -73,6 +73,120 @@ function job_print_functor(printout, showProps, maxDepth) { } } +// Use this function to create a functor that will build a tree datastructure of the Job visited + +function job_tree_model_array_functor(jobTreeArray, newNodeFunctor) { + var jobsRoot; + var numJobs = 0; + var jobTreePath = [] + if (newNodeFunctor === undefined) newNodeFunctor = function (node) {} + + return function (job, depth, index) { + var id = numJobs + var newItem = {"name": job.objectName, "level": depth, "index": index, "id": id, "subNode": [], "path": ""} + if (depth == 0) { + newNodeFunctor(newItem) + jobTreeArray.push(newItem) + numJobs++ + jobsRoot = jobTreeArray[0].subNode; + } else { + if (jobTreePath.length < depth) { + var node = jobsRoot; + var path; + for (var n = 0; n < jobTreePath.length; n++) { + newItem.path += (n > 0 ? "." : "") + node[jobTreePath[n]].name + node = node[jobTreePath[n]].subNode + } + + newNodeFunctor(newItem) + node.push((newItem)) + numJobs++ + jobTreePath.push(0); + } else if (jobTreePath.length >= depth) { + var node = jobsRoot; + for (var n = 0; n < (depth - 1); n++) { + newItem.path += (n > 0 ? "." : "") + node[jobTreePath[n]].name + node = node[jobTreePath[n]].subNode + } + + newNodeFunctor(newItem) + node.push((newItem)) + numJobs++ + jobTreePath[depth-1] = index; + while (jobTreePath.length > depth) { + jobTreePath.pop(); + } + } + } + return true; + } +} + +function job_tree_model_functor(jobTreeModel, maxLevel, newNodeFunctor) { + var jobsRoot; + var numJobs = 0; + var jobTreePath = [] + if (newNodeFunctor === undefined) newNodeFunctor = function (node) {} + + return function (job, depth, index) { + var id = numJobs + var newItem = {"name": job.objectName, "level": depth, "index": index, "id": id, "subNode": [], "path": "", "init": (depth < maxLevel), "ud": {}} + if (depth == 0) { + newNodeFunctor(newItem) + jobTreeModel.append(newItem) + numJobs++ + jobsRoot = jobTreeModel.get(0).subNode; + } else { + if (jobTreePath.length < depth) { + var node = jobsRoot; + var path; + for (var n = 0; n < jobTreePath.length; n++) { + newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name + node = node.get(jobTreePath[n]).subNode + } + + newNodeFunctor(newItem) + node.append((newItem)) + numJobs++ + jobTreePath.push(0); + } else if (jobTreePath.length >= depth) { + var node = jobsRoot; + for (var n = 0; n < (depth - 1); n++) { + newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name + node = node.get(jobTreePath[n]).subNode + } + + newNodeFunctor(newItem) + node.append((newItem)) + numJobs++ + jobTreePath[depth-1] = index; + while (jobTreePath.length > depth) { + jobTreePath.pop(); + } + } + } + return true; + } +} + + +// Traverse the jobTreenode data structure created above +function job_traverseTreeNode(root, functor, depth) { + // if (root.subNode.length) { + depth++; + for (var i = 0; i 0 ? "." : "") + node.get(jobTreePath[n]).name - node = node.get(jobTreePath[n]).subNode - } - node.append(newItem) - jobTreePath.push(0); - } else if (jobTreePath.length >= depth) { - var node = jobsRoot; - for (var n = 0; n < (depth - 1); n++) { - newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name - node = node.get(jobTreePath[n]).subNode - } - node.append(newItem) - jobTreePath[depth-1] = index; - while (jobTreePath.length > depth) { - jobTreePath.pop(); - } - } - } - return true; - } - + //var functor = Jet.job_tree_model_functor(jobsModel) + /* var functor = Jet.job_tree_model_functor(jobsModel, 1, function(node) { + node["cpuT"] = 0.0 + }) Jet.task_traverseTree(rootConfig, functor); - } + */ + + var tfunctor = Jet.job_tree_model_array_functor(jobsModel.engineJobItemModel, function(node) { + node["init"] = (node.level < 3) + node["fullpath"] = (node.path + "." + node.name) + node["cpuT"] = 0.0 + }) + + Jet.task_traverseTree(rootConfig, tfunctor); + + // var currentParentStach = [] + // currentParentStach.push(jobsModel); + + + Jet.job_traverseTreeNodeRoot(jobsModel.engineJobItemModel[0], function(node, depth, index) { + print(node.name + depth + " - " + index) + return true + }) + } + ListModel { id: jobsModel + property var engineJobItemModel : [] } Component { @@ -77,30 +64,49 @@ Rectangle { id: objRecursiveColumn clip: true visible: model.init - - MouseArea { - width: objRow.implicitWidth - height: objRow.implicitHeight - onDoubleClicked: { - for(var i = 1; i < parent.children.length - 1; ++i) { - parent.children[i].visible = !parent.children[i].visible - } - } - Row { - id: objRow - Item { - height: 1 - width: model.level * 15 - } - HifiControls.CheckBox { - property var config: root.rootConfig.getConfig(model.path + "." + model.name); - text: (objRecursiveColumn.children.length > 2 ? - objRecursiveColumn.children[1].visible ? - qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + " ms=" + config.cpuRunTime.toFixed(2) - checked: config.enabled - } + // visible: (node.level < 2) + + function switchFold() { + for(var i = 1; i < children.length - 1; ++i) { + children[i].visible = !children[i].visible } } + + Row { + id: objRow + Item { + height: 1 + width: model.level * 15 + } + + HifiControls.CheckBox { + id: objCheck + property var config: root.rootConfig.getConfig(model.path + "." + model.name); + text: " " + checked: config.enabled + onCheckedChanged: { config.enabled = checked } + } + + MouseArea { + width: objLabel.implicitWidth + height: objLabel.implicitHeight + onDoubleClicked: { + parent.parent.switchFold() + } + + HifiControls.Label { + id: objLabel + colorScheme: hifi.colorSchemes.dark + // property var config: root.rootConfig.getConfig(model.path + "." + model.name); + text: (objRecursiveColumn.children.length > 2 ? + objRecursiveColumn.children[1].visible ? + qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + + " ms=" + root.rootConfig.getConfig(model.path + "." + model.name).cpuRunTime.toFixed(3) + + " id=" + model.id + } + } + } + Repeater { model: subNode delegate: objRecursiveDelegate diff --git a/scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml b/scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml new file mode 100644 index 0000000000..ed1649a47a --- /dev/null +++ b/scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml @@ -0,0 +1,141 @@ +// +// jet/TaskTimeFrameView.qml +// +// Created by Sam Gateau, 2018/06/15 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 +import QtQuick.Controls 1.4 as Original +import QtQuick.Controls.Styles 1.4 + +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls + +import "../jet.js" as Jet + +Rectangle { + HifiConstants { id: hifi;} + color: hifi.colors.baseGray; + id: root; + + property var rootConfig : Workload + + property var jobsTree + property var jobsArray + + Component.onCompleted: { + if (!jobsTree) { jobsTree = new Array(); } + if (!jobsArray) { jobsArray = new Array(); } + + var tfunctor = Jet.job_tree_model_array_functor(jobsTree, function(node) { + var job = { "fullpath": (node.path + "." + node.name), "cpuT": 0.0, "depth": node.level } + jobsArray.push(job) + }) + Jet.task_traverseTree(rootConfig, tfunctor); + + for (var j = 0; j 0) { + + var rangeStack =new Array() + var frameDuration = Math.max(jobsArray[0].cpuT, 1) + rangeStack.push( { "b": 0.0, "e": frameDuration } ) + var timeScale = width * 0.9 / frameDuration; + + drawJob(ctx, 0, 0, jobsArray[0].cpuT, 0, timeScale) + + for (var i = 1; i lastDepth) { + timeOffset = rangeStack[lastDepth].b + while(rangeStack.length <= depth) { + rangeStack.push( { "b": timeOffset, "e": duration } ) + } + + } else { + if (depth < lastDepth) { + while(rangeStack.length != (depth + 1)) { + rangeStack.pop() + } + } + + timeOffset = rangeStack[depth].e + rangeStack[depth].b = timeOffset + rangeStack[depth].e = timeOffset + duration + } + + print("j " + i + " depth " + depth + " lastDepth " + lastDepth + " off " + timeOffset + " dur " + duration) + drawJob(ctx, depth, i, duration, timeOffset, timeScale) + } + } + } + } + } +} \ No newline at end of file diff --git a/scripts/developer/utilities/lib/jet/qml/qmldir b/scripts/developer/utilities/lib/jet/qml/qmldir index 3134545625..930641b10b 100644 --- a/scripts/developer/utilities/lib/jet/qml/qmldir +++ b/scripts/developer/utilities/lib/jet/qml/qmldir @@ -1,2 +1,3 @@ TaskList 1.0 TaskList.qml -TaskViewList 1.0 TaskViewList.qml \ No newline at end of file +TaskViewList 1.0 TaskViewList.qml +TaskTimeFrameView 1.0 TaskTimeFrameView.qml \ No newline at end of file diff --git a/scripts/developer/utilities/render/engineInspector.js b/scripts/developer/utilities/render/engineInspector.js index dcf13157b5..348ae8f54f 100644 --- a/scripts/developer/utilities/render/engineInspector.js +++ b/scripts/developer/utilities/render/engineInspector.js @@ -4,10 +4,12 @@ var window = new OverlayWindow({ title: 'Render Engine', source: qml, - width: 300, - height: 400 + width: 500, + height: 100 }); window.setPosition(200, 50); - //window.closed.connect(function() { Script.stop(); }); + window.closed.connect(function() { Script.stop(); }); } - openEngineTaskView(); \ No newline at end of file + openEngineTaskView(); + + \ No newline at end of file diff --git a/scripts/developer/utilities/render/engineInspector.qml b/scripts/developer/utilities/render/engineInspector.qml index 1b9941e64e..d2a6e01524 100644 --- a/scripts/developer/utilities/render/engineInspector.qml +++ b/scripts/developer/utilities/render/engineInspector.qml @@ -23,7 +23,8 @@ Item { property var mainViewTask: Render.getConfig("RenderMainView") - Jet.TaskListView { + //Jet.TaskListView { + Jet.TaskTimeFrameView { rootConfig: Render anchors.fill: render }