From 6c502e79e350924d5006d457c22ea85f8995d0d9 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Aug 2018 22:56:44 -0700 Subject: [PATCH] Fine tuning a LOD regulator PV that works --- interface/src/LODManager.cpp | 102 ++++-------- interface/src/LODManager.h | 15 +- .../utilities/lib/plotperf/PlotPerf.qml | 6 +- scripts/developer/utilities/render/lod.qml | 153 +++++++++++------- 4 files changed, 139 insertions(+), 137 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index df371f3a59..df3b9a9f69 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -66,14 +66,23 @@ void LODManager::setRenderTimes(float presentTime, float engineRunTime, float ba } void LODManager::autoAdjustLOD(float realTimeDelta) { - // float maxRenderTime = glm::max(glm::max(_presentTime, _engineRunTime), _gpuTime); - float maxRenderTime = glm::max(glm::max(_presentTime, _engineRunTime), _gpuTime); + // The "render time" is the worse of: + // - engineRunTime: Time spent in the render thread in the engine producing the gpu::Frame N + // - batchTime: Time spent in the present thread processing the batches of gpu::Frame N+1 + // - presentTime: Time spent in the present thread between the last 2 swap buffers considered the total time to submit gpu::Frame N+1 + // - gpuTime: Time spent in the GPU executing the gpu::Frame N + 2 + + // But Present time is in reality synched with the monitor/display refresh rate, it s always longer than batchTime. + // So if batchTime is fast enough relative to PResent Time we are using it, otherwise we are using presentTime. got it ? + auto presentTime = (_presentTime - _batchTime > 3.0f ? _batchTime + 3.0f : _presentTime); + float maxRenderTime = glm::max(glm::max(presentTime, _engineRunTime), _gpuTime); + // compute time-weighted running average maxRenderTime // Note: we MUST clamp the blend to 1.0 for stability float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f; _avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxRenderTime; // msec - float smoothBlend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE * _pidCoefs.w) ? realTimeDelta / (LOD_ADJUST_RUNNING_AVG_TIMESCALE * _pidCoefs.w) : 1.0f; + float smoothBlend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE * _smoothScale) ? realTimeDelta / (LOD_ADJUST_RUNNING_AVG_TIMESCALE * _smoothScale) : 1.0f; _smoothRenderTime = (1.0f - smoothBlend) * _smoothRenderTime + smoothBlend * maxRenderTime; // msec @@ -87,24 +96,29 @@ void LODManager::autoAdjustLOD(float realTimeDelta) { float oldSolidAngle = getLODAngleDeg(); float targetFPS = 0.5 * (getLODDecreaseFPS() + getLODIncreaseFPS()); - // float targetFPS = (getLODDecreaseFPS()); float targetPeriod = 1.0f / targetFPS; float currentFPS = (float)MSECS_PER_SECOND / _avgRenderTime; + float currentSmoothFPS = (float)MSECS_PER_SECOND / _smoothRenderTime; + float currentVarianceFPS = (currentSmoothFPS - currentFPS); + currentVarianceFPS *= currentVarianceFPS; - static uint64_t lastTime = usecTimestampNow(); + auto dt = realTimeDelta; - uint64_t now = usecTimestampNow(); - auto dt = (float) ((now - lastTime) / double(USECS_PER_MSEC)); - // if (dt < targetPeriod * _pidCoefs.w) return; - dt = realTimeDelta; - - lastTime = now; auto previous_error = _pidHistory.x; auto previous_integral = _pidHistory.y; - auto error = (targetFPS - currentFPS) / targetFPS; - error = glm::clamp(error, -1.0f, 1.0f); + auto smoothError = (targetFPS - currentSmoothFPS); + + auto fpsError = smoothError; + + auto errorSquare = smoothError * smoothError; + + auto noiseCoef = (errorSquare < _pidCoefs.w * currentVarianceFPS ? 0.0f : 1.0f); + + auto normalizedError = noiseCoef * smoothError / targetFPS; + + auto error = glm::clamp(normalizedError, -1.0f, 1.0f); auto integral = previous_integral + error * dt; glm::clamp(integral, -1.0f, 1.0f); @@ -131,59 +145,6 @@ void LODManager::autoAdjustLOD(float realTimeDelta) { setLODAngleDeg(newSolidAngle); - //newSolidAngle = std::max( 0.5f, std::min(newSolidAngle, 90.f)); - - //auto halTan = glm::tan(glm::radians(newSolidAngle * 0.5f)); - - //auto octreeSizeScale = TREE_SCALE * OCTREE_TO_MESH_RATIO / halTan; - // _octreeSizeScale = octreeSizeScale; -/* - if (currentFPS < getLODDecreaseFPS()) { - if (now > _decreaseFPSExpiry) { - _decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; - if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale *= LOD_AUTO_ADJUST_DECREMENT_FACTOR; - if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; - } - emit LODDecreased(); - emit LODChanged(); - // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime - // to provide an FPS just above the decrease threshold. It will drift close to its - // true value after a few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary. - _avgRenderTime = (float)MSECS_PER_SECOND / (getLODDecreaseFPS() + 1.0f); - } - _decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; - } - _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; - } else if (currentFPS > getLODIncreaseFPS()) { - if (now > _increaseFPSExpiry) { - _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; - if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { - if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; - } else { - _octreeSizeScale *= LOD_AUTO_ADJUST_INCREMENT_FACTOR; - } - if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; - } - emit LODIncreased(); - emit LODChanged(); - - // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime - // to provide an FPS just below the increase threshold. It will drift close to its - // true value after a few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary. - _avgRenderTime = (float)MSECS_PER_SECOND / (getLODIncreaseFPS() - 1.0f); - } - _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; - } - _decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; - } else { - _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; - _decreaseFPSExpiry = _increaseFPSExpiry; - } -*/ if (oldOctreeSizeScale != _octreeSizeScale) { auto lodToolsDialog = DependencyManager::get()->getLodToolsDialog(); if (lodToolsDialog) { @@ -325,6 +286,11 @@ void LODManager::saveSettings() { hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS()); } + +void LODManager::setSmoothScale(float t) { + _smoothScale = glm::max(1.0f, t); +} + void LODManager::setWorldDetailQuality(float quality) { static const float MAX_DESKTOP_FPS = 60; @@ -414,7 +380,7 @@ float LODManager::getPidKi() const { float LODManager::getPidKd() const { return _pidCoefs.z; } -float LODManager::getPidT() const { +float LODManager::getPidKv() const { return _pidCoefs.w; } void LODManager::setPidKp(float k) { @@ -426,7 +392,7 @@ void LODManager::setPidKi(float k) { void LODManager::setPidKd(float k) { _pidCoefs.z = k; } -void LODManager::setPidT(float t) { +void LODManager::setPidKv(float t) { _pidCoefs.w = t; } diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 167533a236..6843744d16 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -67,6 +67,7 @@ class LODManager : public QObject, public Dependency { Q_PROPERTY(float smoothRenderTime READ getSmoothRenderTime) Q_PROPERTY(float smoothFPS READ getSmoothFPS) + Q_PROPERTY(float smoothScale READ getSmoothScale WRITE setSmoothScale) Q_PROPERTY(float lodLevel READ getLODLevel WRITE setLODLevel NOTIFY LODChanged) Q_PROPERTY(float lodDecreaseFPS READ getLODDecreaseFPS) @@ -80,7 +81,7 @@ class LODManager : public QObject, public Dependency { Q_PROPERTY(float pidKp READ getPidKp WRITE setPidKp) Q_PROPERTY(float pidKi READ getPidKi WRITE setPidKi) Q_PROPERTY(float pidKd READ getPidKd WRITE setPidKd) - Q_PROPERTY(float pidT READ getPidT WRITE setPidT) + Q_PROPERTY(float pidKv READ getPidKv WRITE setPidKv) Q_PROPERTY(float pidOp READ getPidOp) Q_PROPERTY(float pidOi READ getPidOi) @@ -195,6 +196,9 @@ public: void saveSettings(); void resetLODAdjust(); + void setSmoothScale(float t); + float getSmoothScale() const { return _smoothScale; } + float getAverageRenderTime() const { return _avgRenderTime; }; float getMaxTheoreticalFPS() const { return (float)MSECS_PER_SECOND / _avgRenderTime; }; @@ -216,12 +220,12 @@ public: float getPidKp() const; float getPidKi() const; float getPidKd() const; - float getPidT() const; + float getPidKv() const; void setPidKp(float k); void setPidKi(float k); void setPidKd(float k); - void setPidT(float t); - + void setPidKv(float t); + float getPidOp() const; float getPidOi() const; float getPidOd() const; @@ -254,6 +258,7 @@ private: float _batchTime{ 0.0f }; // msec float _gpuTime { 0.0f }; // msec + float _smoothScale{ 8.0f }; float _avgRenderTime { 0.0f }; // msec float _smoothRenderTime{ 0.0f }; float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME }; @@ -262,7 +267,7 @@ private: float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; int _boundaryLevelAdjust = 0; - glm::vec4 _pidCoefs{ 1.0f, 0.0000000f, 0.f, 8.0f }; + glm::vec4 _pidCoefs{ 1.0f, 0.0f, 0.0f, 1.0f }; // Kp, Ki, Kd, Kv glm::vec4 _pidHistory{ 0.0f }; glm::vec4 _pidOutputs{ 0.0f }; diff --git a/scripts/developer/utilities/lib/plotperf/PlotPerf.qml b/scripts/developer/utilities/lib/plotperf/PlotPerf.qml index 27101a2867..f239cc010a 100644 --- a/scripts/developer/utilities/lib/plotperf/PlotPerf.qml +++ b/scripts/developer/utilities/lib/plotperf/PlotPerf.qml @@ -217,9 +217,9 @@ Item { function displayTitle(ctx, text, maxVal) { ctx.fillStyle = "grey"; ctx.textAlign = "right"; - ctx.fillText("max" + displayValue(_displayMaxValue, root.valueUnit), width, pixelFromVal(_displayMaxValue)); + ctx.fillText("max " + displayValue(_displayMaxValue, root.valueUnit), width, pixelFromVal(_displayMaxValue)); - ctx.fillText("min" + displayValue(_displayMinValue, root.valueUnit), width, pixelFromVal(_displayMinValue)); + ctx.fillText("min " + displayValue(_displayMinValue, root.valueUnit), width, pixelFromVal(_displayMinValue)); ctx.fillStyle = "white"; ctx.textAlign = "left"; @@ -245,7 +245,6 @@ Item { ctx.strokeStyle= "LightSlateGray"; ctx.lineWidth="1"; - // ctx.strokeStyle= "grey"; ctx.beginPath(); ctx.moveTo(0, maxY); ctx.lineTo(width, maxY); @@ -254,7 +253,6 @@ Item { if (_displayMinValue != 0) { var zeroY = pixelFromVal(0); var minY = pixelFromVal(_displayMinValue); - // ctx.strokeStyle= "DarkRed"; ctx.beginPath(); ctx.moveTo(0, zeroY); ctx.lineTo(width, zeroY); diff --git a/scripts/developer/utilities/render/lod.qml b/scripts/developer/utilities/render/lod.qml index d0562e1020..28cf744394 100644 --- a/scripts/developer/utilities/render/lod.qml +++ b/scripts/developer/utilities/render/lod.qml @@ -53,18 +53,26 @@ Item { min: 0.25 integral: false - anchors.left: autoLOD.left + anchors.left: parent.left anchors.right: parent.right } - HifiControls.CheckBox { - id: autoLOD - boxSize: 20 - text: "Auto LOD" - checked: LODManager.automaticLODAdjust - onCheckedChanged: { LODManager.automaticLODAdjust = (checked) } + Row { + HifiControls.CheckBox { + id: autoLOD + boxSize: 20 + text: "Auto LOD" + checked: LODManager.automaticLODAdjust + onCheckedChanged: { LODManager.automaticLODAdjust = (checked) } + } + HifiControls.CheckBox { + id: showLODRegulatorDetails + visible: LODManager.automaticLODAdjust + boxSize: 20 + text: "Show LOD Details" + } } - + RichSlider { visible: !LODManager.automaticLODAdjust showLabel: true @@ -78,67 +86,85 @@ Item { anchors.left: parent.left anchors.right: parent.right } - - RichSlider { - visible: LODManager.automaticLODAdjust - showLabel: true - label: "LOD PID Kp" - valueVar: LODManager["pidKp"] - valueVarSetter: (function (v) { LODManager["pidKp"] = v }) - max: 2.0 - min: 0.0 - integral: false - numDigits: 3 - + Column { + id: lodRegulatorDetails + visible: LODManager.automaticLODAdjust && showLODRegulatorDetails.checked anchors.left: parent.left anchors.right: parent.right - } - RichSlider { - visible: LODManager.automaticLODAdjust - showLabel: true - label: "LOD PID Ki" - valueVar: LODManager["pidKi"] - valueVarSetter: (function (v) { LODManager["pidKi"] = v }) - max: 0.1 - min: 0.0 - integral: false - numDigits: 8 + RichSlider { + visible: lodRegulatorDetails.visible + showLabel: true + label: "LOD Kp" + valueVar: LODManager["pidKp"] + valueVarSetter: (function (v) { LODManager["pidKp"] = v }) + max: 2.0 + min: 0.0 + integral: false + numDigits: 3 - anchors.left: parent.left - anchors.right: parent.right - } - RichSlider { - visible: LODManager.automaticLODAdjust - showLabel: true - label: "LOD PID Kd" - valueVar: LODManager["pidKd"] - valueVarSetter: (function (v) { LODManager["pidKd"] = v }) - max: 10.0 - min: 0.0 - integral: false - numDigits: 3 + anchors.left: parent.left + anchors.right: parent.right + } + RichSlider { + visible: false && lodRegulatorDetails.visible + showLabel: true + label: "LOD Ki" + valueVar: LODManager["pidKi"] + valueVarSetter: (function (v) { LODManager["pidKi"] = v }) + max: 0.1 + min: 0.0 + integral: false + numDigits: 8 - anchors.left: parent.left - anchors.right: parent.right - } - RichSlider { - visible: LODManager.automaticLODAdjust - showLabel: true - label: "LOD PID Num T" - valueVar: LODManager["pidT"] - valueVarSetter: (function (v) { LODManager["pidT"] = v }) - max: 10.0 - min: 0.0 - integral: true + anchors.left: parent.left + anchors.right: parent.right + } + RichSlider { + visible: false && lodRegulatorDetails.visible + showLabel: true + label: "LOD Kd" + valueVar: LODManager["pidKd"] + valueVarSetter: (function (v) { LODManager["pidKd"] = v }) + max: 10.0 + min: 0.0 + integral: false + numDigits: 3 - anchors.left: parent.left - anchors.right: parent.right + anchors.left: parent.left + anchors.right: parent.right + } + RichSlider { + visible: lodRegulatorDetails.visible + showLabel: true + label: "LOD Kv" + valueVar: LODManager["pidKv"] + valueVarSetter: (function (v) { LODManager["pidKv"] = v }) + max: 2.0 + min: 0.0 + integral: false + + anchors.left: parent.left + anchors.right: parent.right + } + RichSlider { + visible: lodRegulatorDetails.visible + showLabel: true + label: "LOD Smooth Scale" + valueVar: LODManager["smoothScale"] + valueVarSetter: (function (v) { LODManager["smoothScale"] = v }) + max: 20.0 + min: 1.0 + integral: true + + anchors.left: parent.left + anchors.right: parent.right + } } } Column { id: stats - spacing: 8 + spacing: 4 anchors.right: parent.right anchors.left: parent.left anchors.top: topHeader.bottom @@ -146,7 +172,8 @@ Item { function evalEvenHeight() { // Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ? - return (height - topLine.height - bottomLine.height - spacing * (children.length - 3)) / (children.length - 2) + var numPlots = (children.length + (lodRegulatorDetails.visible ? 1 : 0) - 2) + return (height - topLine.height - bottomLine.height - spacing * (numPlots - 1)) / (numPlots) } Separator { @@ -226,6 +253,7 @@ Item { ] } PlotPerf { + // visible: lodRegulatorDetails.visible title: "PID Output" height: parent.evalEvenHeight() object: LODManager @@ -248,6 +276,11 @@ Item { prop: "pidOd", label: "Od", color: "#FF6666" + }, + { + prop: "pidO", + label: "Output", + color: "#66FF66" } ] }