Fine tuning a LOD regulator PV that works

This commit is contained in:
Sam Gateau 2018-08-29 22:56:44 -07:00
parent 8f4419de30
commit 6c502e79e3
4 changed files with 139 additions and 137 deletions

View file

@ -66,14 +66,23 @@ void LODManager::setRenderTimes(float presentTime, float engineRunTime, float ba
} }
void LODManager::autoAdjustLOD(float realTimeDelta) { void LODManager::autoAdjustLOD(float realTimeDelta) {
// float maxRenderTime = glm::max(glm::max(_presentTime, _engineRunTime), _gpuTime); // The "render time" is the worse of:
float maxRenderTime = glm::max(glm::max(_presentTime, _engineRunTime), _gpuTime); // - 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 // compute time-weighted running average maxRenderTime
// Note: we MUST clamp the blend to 1.0 for stability // 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; float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxRenderTime; // msec _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 _smoothRenderTime = (1.0f - smoothBlend) * _smoothRenderTime + smoothBlend * maxRenderTime; // msec
@ -87,24 +96,29 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
float oldSolidAngle = getLODAngleDeg(); float oldSolidAngle = getLODAngleDeg();
float targetFPS = 0.5 * (getLODDecreaseFPS() + getLODIncreaseFPS()); float targetFPS = 0.5 * (getLODDecreaseFPS() + getLODIncreaseFPS());
// float targetFPS = (getLODDecreaseFPS());
float targetPeriod = 1.0f / targetFPS; float targetPeriod = 1.0f / targetFPS;
float currentFPS = (float)MSECS_PER_SECOND / _avgRenderTime; 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_error = _pidHistory.x;
auto previous_integral = _pidHistory.y; auto previous_integral = _pidHistory.y;
auto error = (targetFPS - currentFPS) / targetFPS; auto smoothError = (targetFPS - currentSmoothFPS);
error = glm::clamp(error, -1.0f, 1.0f);
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; auto integral = previous_integral + error * dt;
glm::clamp(integral, -1.0f, 1.0f); glm::clamp(integral, -1.0f, 1.0f);
@ -131,59 +145,6 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
setLODAngleDeg(newSolidAngle); 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) { if (oldOctreeSizeScale != _octreeSizeScale) {
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog(); auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
if (lodToolsDialog) { if (lodToolsDialog) {
@ -325,6 +286,11 @@ void LODManager::saveSettings() {
hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS()); hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS());
} }
void LODManager::setSmoothScale(float t) {
_smoothScale = glm::max(1.0f, t);
}
void LODManager::setWorldDetailQuality(float quality) { void LODManager::setWorldDetailQuality(float quality) {
static const float MAX_DESKTOP_FPS = 60; static const float MAX_DESKTOP_FPS = 60;
@ -414,7 +380,7 @@ float LODManager::getPidKi() const {
float LODManager::getPidKd() const { float LODManager::getPidKd() const {
return _pidCoefs.z; return _pidCoefs.z;
} }
float LODManager::getPidT() const { float LODManager::getPidKv() const {
return _pidCoefs.w; return _pidCoefs.w;
} }
void LODManager::setPidKp(float k) { void LODManager::setPidKp(float k) {
@ -426,7 +392,7 @@ void LODManager::setPidKi(float k) {
void LODManager::setPidKd(float k) { void LODManager::setPidKd(float k) {
_pidCoefs.z = k; _pidCoefs.z = k;
} }
void LODManager::setPidT(float t) { void LODManager::setPidKv(float t) {
_pidCoefs.w = t; _pidCoefs.w = t;
} }

View file

@ -67,6 +67,7 @@ class LODManager : public QObject, public Dependency {
Q_PROPERTY(float smoothRenderTime READ getSmoothRenderTime) Q_PROPERTY(float smoothRenderTime READ getSmoothRenderTime)
Q_PROPERTY(float smoothFPS READ getSmoothFPS) 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 lodLevel READ getLODLevel WRITE setLODLevel NOTIFY LODChanged)
Q_PROPERTY(float lodDecreaseFPS READ getLODDecreaseFPS) 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 pidKp READ getPidKp WRITE setPidKp)
Q_PROPERTY(float pidKi READ getPidKi WRITE setPidKi) Q_PROPERTY(float pidKi READ getPidKi WRITE setPidKi)
Q_PROPERTY(float pidKd READ getPidKd WRITE setPidKd) 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 pidOp READ getPidOp)
Q_PROPERTY(float pidOi READ getPidOi) Q_PROPERTY(float pidOi READ getPidOi)
@ -195,6 +196,9 @@ public:
void saveSettings(); void saveSettings();
void resetLODAdjust(); void resetLODAdjust();
void setSmoothScale(float t);
float getSmoothScale() const { return _smoothScale; }
float getAverageRenderTime() const { return _avgRenderTime; }; float getAverageRenderTime() const { return _avgRenderTime; };
float getMaxTheoreticalFPS() const { return (float)MSECS_PER_SECOND / _avgRenderTime; }; float getMaxTheoreticalFPS() const { return (float)MSECS_PER_SECOND / _avgRenderTime; };
@ -216,12 +220,12 @@ public:
float getPidKp() const; float getPidKp() const;
float getPidKi() const; float getPidKi() const;
float getPidKd() const; float getPidKd() const;
float getPidT() const; float getPidKv() const;
void setPidKp(float k); void setPidKp(float k);
void setPidKi(float k); void setPidKi(float k);
void setPidKd(float k); void setPidKd(float k);
void setPidT(float t); void setPidKv(float t);
float getPidOp() const; float getPidOp() const;
float getPidOi() const; float getPidOi() const;
float getPidOd() const; float getPidOd() const;
@ -254,6 +258,7 @@ private:
float _batchTime{ 0.0f }; // msec float _batchTime{ 0.0f }; // msec
float _gpuTime { 0.0f }; // msec float _gpuTime { 0.0f }; // msec
float _smoothScale{ 8.0f };
float _avgRenderTime { 0.0f }; // msec float _avgRenderTime { 0.0f }; // msec
float _smoothRenderTime{ 0.0f }; float _smoothRenderTime{ 0.0f };
float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME }; float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME };
@ -262,7 +267,7 @@ private:
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
int _boundaryLevelAdjust = 0; 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 _pidHistory{ 0.0f };
glm::vec4 _pidOutputs{ 0.0f }; glm::vec4 _pidOutputs{ 0.0f };

View file

@ -217,9 +217,9 @@ Item {
function displayTitle(ctx, text, maxVal) { function displayTitle(ctx, text, maxVal) {
ctx.fillStyle = "grey"; ctx.fillStyle = "grey";
ctx.textAlign = "right"; 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.fillStyle = "white";
ctx.textAlign = "left"; ctx.textAlign = "left";
@ -245,7 +245,6 @@ Item {
ctx.strokeStyle= "LightSlateGray"; ctx.strokeStyle= "LightSlateGray";
ctx.lineWidth="1"; ctx.lineWidth="1";
// ctx.strokeStyle= "grey";
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(0, maxY); ctx.moveTo(0, maxY);
ctx.lineTo(width, maxY); ctx.lineTo(width, maxY);
@ -254,7 +253,6 @@ Item {
if (_displayMinValue != 0) { if (_displayMinValue != 0) {
var zeroY = pixelFromVal(0); var zeroY = pixelFromVal(0);
var minY = pixelFromVal(_displayMinValue); var minY = pixelFromVal(_displayMinValue);
// ctx.strokeStyle= "DarkRed";
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(0, zeroY); ctx.moveTo(0, zeroY);
ctx.lineTo(width, zeroY); ctx.lineTo(width, zeroY);

View file

@ -53,18 +53,26 @@ Item {
min: 0.25 min: 0.25
integral: false integral: false
anchors.left: autoLOD.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
} }
HifiControls.CheckBox { Row {
id: autoLOD HifiControls.CheckBox {
boxSize: 20 id: autoLOD
text: "Auto LOD" boxSize: 20
checked: LODManager.automaticLODAdjust text: "Auto LOD"
onCheckedChanged: { LODManager.automaticLODAdjust = (checked) } checked: LODManager.automaticLODAdjust
onCheckedChanged: { LODManager.automaticLODAdjust = (checked) }
}
HifiControls.CheckBox {
id: showLODRegulatorDetails
visible: LODManager.automaticLODAdjust
boxSize: 20
text: "Show LOD Details"
}
} }
RichSlider { RichSlider {
visible: !LODManager.automaticLODAdjust visible: !LODManager.automaticLODAdjust
showLabel: true showLabel: true
@ -78,67 +86,85 @@ Item {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
} }
Column {
RichSlider { id: lodRegulatorDetails
visible: LODManager.automaticLODAdjust visible: LODManager.automaticLODAdjust && showLODRegulatorDetails.checked
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
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
} RichSlider {
RichSlider { visible: lodRegulatorDetails.visible
visible: LODManager.automaticLODAdjust showLabel: true
showLabel: true label: "LOD Kp"
label: "LOD PID Ki" valueVar: LODManager["pidKp"]
valueVar: LODManager["pidKi"] valueVarSetter: (function (v) { LODManager["pidKp"] = v })
valueVarSetter: (function (v) { LODManager["pidKi"] = v }) max: 2.0
max: 0.1 min: 0.0
min: 0.0 integral: false
integral: false numDigits: 3
numDigits: 8
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
} }
RichSlider { RichSlider {
visible: LODManager.automaticLODAdjust visible: false && lodRegulatorDetails.visible
showLabel: true showLabel: true
label: "LOD PID Kd" label: "LOD Ki"
valueVar: LODManager["pidKd"] valueVar: LODManager["pidKi"]
valueVarSetter: (function (v) { LODManager["pidKd"] = v }) valueVarSetter: (function (v) { LODManager["pidKi"] = v })
max: 10.0 max: 0.1
min: 0.0 min: 0.0
integral: false integral: false
numDigits: 3 numDigits: 8
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
} }
RichSlider { RichSlider {
visible: LODManager.automaticLODAdjust visible: false && lodRegulatorDetails.visible
showLabel: true showLabel: true
label: "LOD PID Num T" label: "LOD Kd"
valueVar: LODManager["pidT"] valueVar: LODManager["pidKd"]
valueVarSetter: (function (v) { LODManager["pidT"] = v }) valueVarSetter: (function (v) { LODManager["pidKd"] = v })
max: 10.0 max: 10.0
min: 0.0 min: 0.0
integral: true integral: false
numDigits: 3
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right 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 { Column {
id: stats id: stats
spacing: 8 spacing: 4
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
anchors.top: topHeader.bottom anchors.top: topHeader.bottom
@ -146,7 +172,8 @@ Item {
function evalEvenHeight() { function evalEvenHeight() {
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ? // 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 { Separator {
@ -226,6 +253,7 @@ Item {
] ]
} }
PlotPerf { PlotPerf {
// visible: lodRegulatorDetails.visible
title: "PID Output" title: "PID Output"
height: parent.evalEvenHeight() height: parent.evalEvenHeight()
object: LODManager object: LODManager
@ -248,6 +276,11 @@ Item {
prop: "pidOd", prop: "pidOd",
label: "Od", label: "Od",
color: "#FF6666" color: "#FF6666"
},
{
prop: "pidO",
label: "Output",
color: "#66FF66"
} }
] ]
} }