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) {
// 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<DialogsManager>()->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;
}

View file

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

View file

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

View file

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