mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
checkpoint
This commit is contained in:
parent
97898a1ad1
commit
42a1ee353e
4 changed files with 82 additions and 70 deletions
|
@ -1095,6 +1095,21 @@ void Application::paintGL() {
|
|||
_inPaint = true;
|
||||
Finally clearFlagLambda([this] { _inPaint = false; });
|
||||
|
||||
_lastInstantaneousFps = instantaneousFps;
|
||||
// Time between previous paintGL call and this one, which can vary not only with vSync misses, but also with QT timing.
|
||||
// This is not the same as update(deltaTime), because the latter attempts to throttle to 60hz and also clamps to 1/4 second.
|
||||
// Note that _lastPaintWait (stored at end of last call) is for the same paint cycle.
|
||||
const float actualPeriod = diff / (float)USECS_PER_SECOND; // same as 1/instantaneousFps but easier for compiler to optimize
|
||||
const float targetPeriod = isHMDMode() ? 1.0f / 75.0f : 1.0f / 60.0f;
|
||||
const float nSyncsByFrameRate = round(actualPeriod / targetPeriod);
|
||||
const float accuracyAllowance = 0.0005f; // sometimes paint goes over and it isn't reflected in actualPeriod
|
||||
const float nSyncsByPaintWait = floor((_lastPaintWait + accuracyAllowance) / targetPeriod);
|
||||
const float nSyncs = nSyncsByFrameRate + nSyncsByPaintWait;
|
||||
const float modularPeriod = ((nSyncs - 1) * targetPeriod) + actualPeriod;
|
||||
const float deducedNonVSyncPeriod = modularPeriod - _lastPaintWait;
|
||||
_lastDeducedNonVSyncFps = 1.0f / deducedNonVSyncPeriod;
|
||||
|
||||
|
||||
auto displayPlugin = getActiveDisplayPlugin();
|
||||
displayPlugin->preRender();
|
||||
_offscreenContext->makeCurrent();
|
||||
|
@ -1342,18 +1357,8 @@ void Application::paintGL() {
|
|||
displayPlugin->finishFrame();
|
||||
}
|
||||
uint64_t displayEnd = usecTimestampNow();
|
||||
// Store together, without Application::idle happening in between setting fps and period.
|
||||
_lastInstantaneousFps = instantaneousFps;
|
||||
const float displayPeriodUsec = (float)(displayEnd - displayStart); // usecs
|
||||
_lastPaintWait = displayPeriodUsec / (float)USECS_PER_SECOND;
|
||||
const float targetPeriod = isHMDMode() ? 1.0f/75.0f : 1.0f/60.0f;
|
||||
const float actualPeriod = 1.0f / instantaneousFps;
|
||||
const float nSyncsByFrameRate = round(actualPeriod / targetPeriod);
|
||||
const float accuracyAllowance = 0.0005;
|
||||
const float nSyncsByPaintWait = floor((_lastPaintWait + accuracyAllowance) / targetPeriod); // sometimes paint goes over and it isn't reflected in actualPeriod
|
||||
const float modularPeriod = (nSyncsByFrameRate + nSyncsByPaintWait) * targetPeriod;
|
||||
const float deducedNonVSyncPeriod = modularPeriod - _lastPaintWait;
|
||||
_lastDeducedNonVSyncFps = 1.0f / deducedNonVSyncPeriod;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -61,34 +61,12 @@ void AvatarManager::registerMetaTypes(QScriptEngine* engine) {
|
|||
qScriptRegisterSequenceMetaType<QVector<AvatarManager::LocalLight> >(engine);
|
||||
}
|
||||
|
||||
#define TARGET_FPS 60.0f
|
||||
#define TARGET_PERIOD_MS (1000.0f / TARGET_FPS)
|
||||
AvatarManager::AvatarManager(QObject* parent) :
|
||||
_avatarFades()
|
||||
{
|
||||
// register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar
|
||||
qRegisterMetaType<QWeakPointer<Node> >("NodeWeakPointer");
|
||||
_myAvatar = std::make_shared<MyAvatar>(std::make_shared<AvatarRig>());
|
||||
_renderDistanceController.setMeasuredValueSetpoint(TARGET_FPS); //FIXME
|
||||
const float TREE_SCALE = 32768.0f; // Not in shared library, alas.
|
||||
const float SMALLEST_REASONABLE_HORIZON = 0.5f; // FIXME 5
|
||||
_renderDistanceController.setControlledValueHighLimit(1.0f/SMALLEST_REASONABLE_HORIZON);
|
||||
_renderDistanceController.setControlledValueLowLimit(1.0f/TREE_SCALE);
|
||||
|
||||
// Advice for tuning parameters:
|
||||
// See PIDController.h. There's a sectionon tuning in the reference.
|
||||
// Turn off HYSTERESIS_PROPORTION and extra logging by defining PID_TUNING in Avatar.cpp.
|
||||
// Turn on logging with the following:
|
||||
_renderDistanceController.setHistorySize("avatar render", TARGET_FPS * 4); // FIXME
|
||||
// KP is usually tuned by setting the other constants to zero, finding the maximum value that doesn't oscillate,
|
||||
// and taking about 0.6 of that. A typical osciallation would be with error=37fps with avatars 10m away, so
|
||||
// KP*37=1/10 => KP(oscillating)=0.1/37 = 0.0027
|
||||
_renderDistanceController.setKP(0.0012f);
|
||||
// alt:
|
||||
// Our anti-windup limits accumulated error to 10*targetFrameRate, so the sanity check on KI is
|
||||
// KI*750=controlledValueHighLimit=1 => KI=1/750.
|
||||
_renderDistanceController.setKI(0.001);
|
||||
_renderDistanceController.setKD(0.0001); // a touch of kd increases the speed by which we get there
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::BulkAvatarData, this, "processAvatarDataPacket");
|
||||
|
@ -112,6 +90,29 @@ void AvatarManager::init() {
|
|||
_myAvatar->addToScene(_myAvatar, scene, pendingChanges);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
|
||||
const float target_fps = 75.0f; // qApp->isHMDMode() ? 75.0f : 60.0f;
|
||||
_renderDistanceController.setMeasuredValueSetpoint(target_fps);
|
||||
const float TREE_SCALE = 32768.0f; // Not in shared library, alas.
|
||||
const float SMALLEST_REASONABLE_HORIZON = 0.5f; // FIXME 5
|
||||
_renderDistanceController.setControlledValueHighLimit(1.0f / SMALLEST_REASONABLE_HORIZON);
|
||||
_renderDistanceController.setControlledValueLowLimit(1.0f / TREE_SCALE);
|
||||
|
||||
// Advice for tuning parameters:
|
||||
// See PIDController.h. There's a sectionon tuning in the reference.
|
||||
// Turn off HYSTERESIS_PROPORTION and extra logging by defining PID_TUNING in Avatar.cpp.
|
||||
// Turn on logging with the following:
|
||||
_renderDistanceController.setHistorySize("avatar render", target_fps * 4); // FIXME
|
||||
// KP is usually tuned by setting the other constants to zero, finding the maximum value that doesn't oscillate,
|
||||
// and taking about 0.6 of that. A typical osciallation would be with error=37fps with avatars 10m away, so
|
||||
// KP*37=1/10 => KP(oscillating)=0.1/37 = 0.0027
|
||||
_renderDistanceController.setKP(0.0015f);
|
||||
// alt:
|
||||
// Our anti-windup limits accumulated error to 10*targetFrameRate, so the sanity check on KI is
|
||||
// KI*750=controlledValueHighLimit=1 => KI=1/750.
|
||||
_renderDistanceController.setKI(0.001f);
|
||||
_renderDistanceController.setKD(0.0001f); // a touch of kd increases the speed by which we get there
|
||||
|
||||
}
|
||||
|
||||
void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||
|
@ -142,14 +143,10 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
const float FEED_FORWARD_RANGE = 2;
|
||||
const float fps = qApp->getLastInstanteousFps();
|
||||
const float paintWait = qApp->getLastPaintWait();
|
||||
//const float modularizedPeriod = floor((1000.0f / std::min(fps, TARGET_FPS)) / TARGET_PERIOD_MS) * TARGET_PERIOD_MS;
|
||||
// measured value: 1) bigger => more desirable plant activity (i.e., more rendering), 2) setpoint=TARGET_PERIOD_MS=13.333
|
||||
// single vsync: no load=>1or2. high load=>12or13
|
||||
// over vsync: just over: 13. way over: 14...15...16
|
||||
//const float effective = ((1000.0f / fps) < TARGET_PERIOD_MS) ? (TARGET_PERIOD_MS - paintWait) : ((2.0f * TARGET_PERIOD_MS) - paintWait);
|
||||
const float deduced = qApp->getLastDeducedNonVSyncFps();
|
||||
const bool isAtSetpoint = false; //FIXME fabsf(effectiveFps - _renderDistanceController.getMeasuredValueSetpoint()) < FEED_FORWARD_RANGE;
|
||||
const float distance = 1.0f / _renderDistanceController.update(deduced + (isAtSetpoint ? _renderFeedForward : 0.0f), deltaTime, isAtSetpoint, fps, paintWait);
|
||||
//const float distance = 1.0f / _renderDistanceController.update(deduced + (isAtSetpoint ? _renderFeedForward : 0.0f), deltaTime, isAtSetpoint, fps, paintWait);
|
||||
const float distance = 1.0f / _renderDistanceController.update(deduced, deltaTime, isAtSetpoint, fps, paintWait);
|
||||
|
||||
const float RENDER_DISTANCE_DEADBAND = 0.0f; //FIXME 0.3f; // meters
|
||||
if (fabsf(distance - _renderDistance) > RENDER_DISTANCE_DEADBAND) {
|
||||
|
|
|
@ -31,41 +31,49 @@ float PIDController::update(float measuredValue, float dt, bool resetAccumulator
|
|||
getControlledValueLowLimit(),
|
||||
getControlledValueHighLimit());
|
||||
|
||||
if (_history.capacity()) { // THIS SECTION ONLY FOR LOGGING
|
||||
// Don't report each update(), as the I/O messes with the results a lot.
|
||||
// Instead, add to history, and then dump out at once when full.
|
||||
// Typically, the first few values reported in each batch should be ignored.
|
||||
const int n = _history.size();
|
||||
_history.resize(n + 1);
|
||||
Row& next = _history[n];
|
||||
next.measured = measuredValue;
|
||||
next.FIXME1 = FIXME1;
|
||||
next.FIXME2 = FIXME2;
|
||||
next.dt = dt;
|
||||
next.error = error;
|
||||
next.accumulated = accumulatedError;
|
||||
next.changed = changeInError;
|
||||
next.p = p;
|
||||
next.i = i;
|
||||
next.d = d;
|
||||
next.computed = computedValue;
|
||||
if (_history.size() == _history.capacity()) { // report when buffer is full
|
||||
qCDebug(shared) << _label << "measured dt FIXME || error accumulated changed || p i d controlled";
|
||||
for (int i = 0; i < _history.size(); i++) {
|
||||
Row& row = _history[i];
|
||||
qCDebug(shared) << row.measured << row.dt << row.FIXME1 << row.FIXME2 <<
|
||||
"||" << row.error << row.accumulated << row.changed <<
|
||||
"||" << row.p << row.i << row.d << row.computed;
|
||||
}
|
||||
qCDebug(shared) << "Limits: accumulate" << getAccumulatedValueLowLimit() << getAccumulatedValueHighLimit() <<
|
||||
"controlled" << getControlledValueLowLimit() << getControlledValueHighLimit() <<
|
||||
"kp/ki/kd/bias" << getKP() << getKI() << getKD() << getBias();
|
||||
_history.resize(0);
|
||||
}
|
||||
}
|
||||
if (_history.capacity()) { // if logging/reporting
|
||||
updateHistory(measuredValue, dt, error, accumulatedError, changeInError, p, i, d, computedValue, FIXME1, FIXME2);
|
||||
}
|
||||
|
||||
// update state for next time
|
||||
_lastError = error;
|
||||
_lastAccumulation = accumulatedError;
|
||||
return computedValue;
|
||||
}
|
||||
|
||||
// Just for logging/reporting. Used when picking/verifying the operational parameters.
|
||||
void PIDController::updateHistory(float measuredValue, float dt, float error, float accumulatedError, float changeInError, float p, float i, float d, float computedValue, float FIXME1, float FIXME2) {
|
||||
// Don't report each update(), as the I/O messes with the results a lot.
|
||||
// Instead, add to history, and then dump out at once when full.
|
||||
// Typically, the first few values reported in each batch should be ignored.
|
||||
const int n = _history.size();
|
||||
_history.resize(n + 1);
|
||||
Row& next = _history[n];
|
||||
next.measured = measuredValue;
|
||||
next.FIXME1 = FIXME1;
|
||||
next.FIXME2 = FIXME2;
|
||||
next.dt = dt;
|
||||
next.error = error;
|
||||
next.accumulated = accumulatedError;
|
||||
next.changed = changeInError;
|
||||
next.p = p;
|
||||
next.i = i;
|
||||
next.d = d;
|
||||
next.computed = computedValue;
|
||||
if (_history.size() == _history.capacity()) { // report when buffer is full
|
||||
reportHistory();
|
||||
_history.resize(0);
|
||||
}
|
||||
}
|
||||
void PIDController::reportHistory() {
|
||||
qCDebug(shared) << _label << "measured dt FIXME || error accumulated changed || p i d controlled";
|
||||
for (int i = 0; i < _history.size(); i++) {
|
||||
Row& row = _history[i];
|
||||
qCDebug(shared) << row.measured << (row.dt * 1000) << row.FIXME1 << (row.FIXME2 * 1000) <<
|
||||
"||" << row.error << row.accumulated << row.changed <<
|
||||
"||" << row.p << row.i << row.d << row.computed;
|
||||
}
|
||||
qCDebug(shared) << "Limits: setpoint" << getMeasuredValueSetpoint() << "accumulate" << getAccumulatedValueLowLimit() << getAccumulatedValueHighLimit() <<
|
||||
"controlled" << getControlledValueLowLimit() << getControlledValueHighLimit() <<
|
||||
"kp/ki/kd/bias" << getKP() << getKI() << getKD() << getBias();
|
||||
}
|
|
@ -70,6 +70,8 @@ public:
|
|||
float computed;
|
||||
};
|
||||
protected:
|
||||
void reportHistory();
|
||||
void updateHistory(float measured, float dt, float error, float accumulatedError, float changeInErro, float p, float i, float d, float computedValue, float FIXME1, float FIXME2);
|
||||
float _measuredValueSetpoint { 0.0f };
|
||||
float _controlledValueLowLimit { 0.0f };
|
||||
float _controlledValueHighLimit { std::numeric_limits<float>::max() };
|
||||
|
|
Loading…
Reference in a new issue