mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-08 07:02:25 +02:00
Fine tuning a LOD regulator PV that works
This commit is contained in:
parent
8f4419de30
commit
6c502e79e3
4 changed files with 139 additions and 137 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue