Rebuild on a new branch after original stopped building.

This commit is contained in:
Howard Stearns 2015-11-17 20:06:25 -08:00
parent 9a651c6194
commit fee13d4375
9 changed files with 127 additions and 5 deletions

View file

@ -40,7 +40,7 @@ Item {
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
text: "Avatars: " + root.avatarCount
text: "Avatars: " + root.avatarCount + ", " + root.avatarRenderedCount + " w/in " + root.avatarRenderDistance + "m"
}
Text {
color: root.fontColor;

View file

@ -1061,8 +1061,10 @@ void Application::paintGL() {
uint64_t now = usecTimestampNow();
static uint64_t lastPaintBegin{ now };
uint64_t diff = now - lastPaintBegin;
float instantaneousFps = 0.0f;
if (diff != 0) {
_framesPerSecond.updateAverage((float)USECS_PER_SECOND / (float)diff);
instantaneousFps = (float)USECS_PER_SECOND / (float)diff;
_framesPerSecond.updateAverage(_lastInstantaneousFps);
}
lastPaintBegin = now;
@ -1326,6 +1328,7 @@ void Application::paintGL() {
// Ensure all operations from the previous context are complete before we try to read the fbo
glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
glDeleteSync(sync);
uint64_t displayStart = usecTimestampNow();
{
PROFILE_RANGE(__FUNCTION__ "/pluginDisplay");
@ -1338,6 +1341,20 @@ void Application::paintGL() {
PerformanceTimer perfTimer("bufferSwap");
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;
}
{

View file

@ -159,6 +159,9 @@ public:
bool isForeground() const { return _isForeground; }
float getFps() const { return _fps; }
float getLastInstanteousFps() const { return _lastInstantaneousFps; }
float getLastPaintWait() const { return _lastPaintWait; };
float getLastDeducedNonVSyncFps() const { return _lastDeducedNonVSyncFps; }
float getFieldOfView() { return _fieldOfView.get(); }
void setFieldOfView(float fov);
@ -430,6 +433,9 @@ private:
float _fps;
QElapsedTimer _timerStart;
QElapsedTimer _lastTimeUpdated;
float _lastInstantaneousFps { 0.0f };
float _lastPaintWait { 0.0f };
float _lastDeducedNonVSyncFps { 0.0f };
ShapeManager _shapeManager;
PhysicalEntitySimulation _entitySimulation;

View file

@ -97,6 +97,7 @@ Avatar::Avatar(RigPointer rig) :
_moving(false),
_initialized(false),
_shouldRenderBillboard(true),
_shouldSkipRender(true),
_voiceSphereID(GeometryCache::UNKNOWN_ID)
{
// we may have been created in the network thread, but we live in the main thread
@ -114,7 +115,7 @@ Avatar::~Avatar() {
}
}
const float BILLBOARD_LOD_DISTANCE = 40.0f;
/*const fixme*/ float BILLBOARD_LOD_DISTANCE = 40.0f;
void Avatar::init() {
getHead()->init();
@ -181,12 +182,36 @@ void Avatar::simulate(float deltaTime) {
// update the billboard render flag
const float BILLBOARD_HYSTERESIS_PROPORTION = 0.1f;
BILLBOARD_LOD_DISTANCE = DependencyManager::get<AvatarManager>()->getFIXMEupdate();
if (_shouldRenderBillboard) {
if (getLODDistance() < BILLBOARD_LOD_DISTANCE * (1.0f - BILLBOARD_HYSTERESIS_PROPORTION)) {
_shouldRenderBillboard = false;
qCDebug(interfaceapp) << "Unbillboarding" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for LOD" << getLODDistance();
}
} else if (getLODDistance() > BILLBOARD_LOD_DISTANCE * (1.0f + BILLBOARD_HYSTERESIS_PROPORTION)) {
_shouldRenderBillboard = true;
qCDebug(interfaceapp) << "Billboarding" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for LOD" << getLODDistance();
}
#define PID_TUNING 1
#ifdef PID_TUNING
const float SKIP_HYSTERESIS_PROPORTION = 0.0f;
#else
const float SKIP_HYSTERESIS_PROPORTION = BILLBOARD_HYSTERESIS_PROPORTION;
#endif
float renderDistance = DependencyManager::get<AvatarManager>()->getRenderDistance();
float distance = glm::distance(qApp->getCamera()->getPosition(), _position);
if (_shouldSkipRender) {
if (distance < renderDistance * (1.0f - SKIP_HYSTERESIS_PROPORTION)) {
_shouldSkipRender = false;
#ifndef PID_TUNING
qCDebug(interfaceapp) << "Rerendering" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for LOD" << getLODDistance();
#endif
}
} else if (distance > renderDistance * (1.0f + SKIP_HYSTERESIS_PROPORTION)) {
_shouldSkipRender = true;
#ifndef PID_TUNING
qCDebug(interfaceapp) << "Unrendering" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for LOD" << getLODDistance();
#endif
}
// simple frustum check
@ -199,7 +224,7 @@ void Avatar::simulate(float deltaTime) {
getHand()->simulate(deltaTime, false);
}
if (!_shouldRenderBillboard && inViewFrustum) {
if (!_shouldRenderBillboard && !_shouldSkipRender && inViewFrustum) {
{
PerformanceTimer perfTimer("skeleton");
for (int i = 0; i < _jointData.size(); i++) {
@ -585,10 +610,13 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
}
void Avatar::fixupModelsInScene() {
// check to see if when we added our models to the scene they were ready, if they were not ready, then
// fix them up in the scene
render::ScenePointer scene = qApp->getMain3DScene();
_skeletonModel.setVisibleInScene(!_shouldSkipRender, scene);
if (_shouldSkipRender) {
return;
}
render::PendingChanges pendingChanges;
if (_skeletonModel.isRenderable() && _skeletonModel.needsFixupInScene()) {
_skeletonModel.removeFromScene(scene, pendingChanges);

View file

@ -140,6 +140,8 @@ public:
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
Q_INVOKABLE bool getShouldSkipRendering() const { return _shouldSkipRender; }
/// Scales a world space position vector relative to the avatar position and scale
/// \param vector position to be scaled. Will store the result
void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const;
@ -226,6 +228,7 @@ private:
bool _initialized;
NetworkTexturePointer _billboardTexture;
bool _shouldRenderBillboard;
bool _shouldSkipRender { false };
bool _isLookAtTarget;
void renderBillboard(RenderArgs* renderArgs);

View file

@ -61,12 +61,34 @@ 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");
@ -117,9 +139,26 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
PerformanceTimer perfTimer("otherAvatars");
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 RENDER_DISTANCE_DEADBAND = 0.0f; //FIXME 0.3f; // meters
if (fabsf(distance - _renderDistance) > RENDER_DISTANCE_DEADBAND) {
_renderDistance = distance;
}
// simulate avatars
AvatarHash::iterator avatarIterator = _avatarHash.begin();
int renderableCount = 0;
while (avatarIterator != _avatarHash.end()) {
auto avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value());
@ -135,10 +174,14 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
} else {
avatar->startUpdate();
avatar->simulate(deltaTime);
if (!avatar->getShouldSkipRendering()) {
renderableCount++;
}
avatar->endUpdate();
++avatarIterator;
}
}
_renderedAvatarCount = renderableCount;
// simulate avatar fades
simulateAvatarFades(deltaTime);

View file

@ -18,6 +18,7 @@
#include <AvatarHashMap.h>
#include <PhysicsEngine.h>
#include <PIDController.h>
#include "Avatar.h"
#include "AvatarMotionState.h"
@ -43,6 +44,7 @@ public:
void clearOtherAvatars();
bool shouldShowReceiveStats() const { return _shouldShowReceiveStats; }
PIDController& getRenderDistanceController() { return _renderDistanceController; }
class LocalLight {
public:
@ -64,6 +66,17 @@ public:
void handleCollisionEvents(const CollisionEvents& collisionEvents);
void updateAvatarPhysicsShape(const QUuid& id);
Q_INVOKABLE int getNumberRendered() { return _renderedAvatarCount; }
Q_INVOKABLE float getRenderDistance() { return _renderDistance; }
Q_INVOKABLE float getFIXMEupdate() { return _fixmeUpdate; }
Q_INVOKABLE void setFIXMEupdate(float f) { _fixmeUpdate = f; }
Q_INVOKABLE void setFIXMEkp(float f) { _renderDistanceController.setKP(f); }
Q_INVOKABLE void setFIXMEki(float f) { _renderDistanceController.setKI(f); }
Q_INVOKABLE void setFIXMEkd(float f) { _renderDistanceController.setKD(f); }
Q_INVOKABLE void setFIXMEbias(float f) { _renderDistanceController.setBias(f); }
Q_INVOKABLE void setFIXMElow(float f) { _renderDistanceController.setControlledValueLowLimit(f); }
Q_INVOKABLE void setFIXMEhigh(float f) { _renderDistanceController.setControlledValueHighLimit(f); }
Q_INVOKABLE void setFIXMEfeedForward(float f) { _renderFeedForward = f; }
public slots:
void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; }
@ -88,6 +101,12 @@ private:
QVector<AvatarManager::LocalLight> _localLights;
bool _shouldShowReceiveStats = false;
float _fixmeUpdate = 40.0f;
float _renderDistance { 40.0f };
float _renderFeedForward { 5.0f };
int _renderedAvatarCount {0};
PIDController _renderDistanceController {};
SetOfAvatarMotionStates _avatarMotionStates;
SetOfMotionStates _motionStatesToAdd;

View file

@ -115,6 +115,8 @@ void Stats::updateStats(bool force) {
auto avatarManager = DependencyManager::get<AvatarManager>();
// we need to take one avatar out so we don't include ourselves
STAT_UPDATE(avatarCount, avatarManager->size() - 1);
STAT_UPDATE(avatarRenderedCount, avatarManager->getNumberRendered());
STAT_UPDATE(avatarRenderDistance, (int) round(avatarManager->getRenderDistance())); // deliberately truncating
STAT_UPDATE(serverCount, nodeList->size());
STAT_UPDATE(framerate, (int)qApp->getFps());
STAT_UPDATE(simrate, (int)qApp->getAverageSimsPerSecond());

View file

@ -36,6 +36,8 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, simrate, 0)
STATS_PROPERTY(int, avatarSimrate, 0)
STATS_PROPERTY(int, avatarCount, 0)
STATS_PROPERTY(int, avatarRenderedCount, 0)
STATS_PROPERTY(int, avatarRenderDistance, 0)
STATS_PROPERTY(int, packetInCount, 0)
STATS_PROPERTY(int, packetOutCount, 0)
STATS_PROPERTY(float, mbpsIn, 0)
@ -117,6 +119,8 @@ signals:
void simrateChanged();
void avatarSimrateChanged();
void avatarCountChanged();
void avatarRenderedCountChanged();
void avatarRenderDistanceChanged();
void packetInCountChanged();
void packetOutCountChanged();
void mbpsInChanged();