From 70664b64eb1becb11ddbee7bc221af8ef832ccd2 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 25 Jan 2017 10:59:49 -0800 Subject: [PATCH 01/17] Attempt to account for sparse texture memory overhead --- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 27 +-- .../src/gpu/gl45/GL45BackendTexture.cpp | 177 ++---------------- 2 files changed, 21 insertions(+), 183 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index c338d6e641..2242bba5d9 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -48,39 +48,18 @@ public: void update(); uvec3 getPageCounts(const uvec3& dimensions) const; uint32_t getPageCount(const uvec3& dimensions) const; + uint32_t getSize() const; GL45Texture& texture; bool sparse { false }; uvec3 pageDimensions { DEFAULT_PAGE_DIMENSION }; GLuint maxSparseLevel { DEFAULT_MAX_SPARSE_LEVEL }; + uint32_t allocatedPages { 0 }; uint32_t maxPages { 0 }; uint32_t pageBytes { 0 }; GLint pageDimensionsIndex { 0 }; }; -#if INCREMENTAL_TRANSFER - struct TransferState { - TransferState(GL45Texture& texture); - uvec3 currentPageSize() const; - void updateMip(); - void populatePage(std::vector& dest); - bool increment(); - - GL45Texture& texture; - GLTexelFormat texelFormat; - uint8_t face { 0 }; - uint16_t mipLevel { 0 }; - uint32_t bytesPerLine { 0 }; - uint32_t bytesPerPixel { 0 }; - uint32_t bytesPerPage { 0 }; - uvec3 mipDimensions; - uvec3 mipOffset; - const uint8_t* srcPointer { nullptr }; - }; - protected: - TransferState _transferState; -#endif - protected: void updateMips() override; void stripToMip(uint16_t newMinMip); @@ -98,8 +77,6 @@ public: void derez(); SparseInfo _sparseInfo; - uint32_t _allocatedPages { 0 }; - uint32_t _lastMipAllocatedPages { 0 }; uint16_t _mipOffset { 0 }; friend class GL45Backend; }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 9b16908244..6632bf936e 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -116,6 +116,8 @@ void SparseInfo::maybeMakeSparse() { } } +#define SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE 1.3f + // This can only be called after we've established our storage size void SparseInfo::update() { if (!sparse) { @@ -124,6 +126,9 @@ void SparseInfo::update() { glGetTextureParameterIuiv(texture._id, GL_NUM_SPARSE_LEVELS_ARB, &maxSparseLevel); pageBytes = texture._gpuObject.getTexelFormat().getSize(); pageBytes *= pageDimensions.x * pageDimensions.y * pageDimensions.z; + // Testing with a simple texture allocating app shows an estimated 20% GPU memory overhead for + // sparse textures as compared to non-sparse, so we acount for that here. + pageBytes = (uint32_t)(pageBytes * SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE); for (uint16_t mipLevel = 0; mipLevel <= maxSparseLevel; ++mipLevel) { auto mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel); @@ -146,6 +151,11 @@ uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const { return pageCounts.x * pageCounts.y * pageCounts.z; } + +uint32_t SparseInfo::getSize() const { + return allocatedPages * pageBytes; +} + void GL45Backend::initTextureManagementStage() { // enable the Sparse Texture on gl45 _textureManagement._sparseCapable = true; @@ -160,93 +170,6 @@ void GL45Backend::initTextureManagementStage() { } } -#if INCREMENTAL_TRANSFER - -using TransferState = GL45Backend::GL45Texture::TransferState; - -TransferState::TransferState(GL45Texture& texture) : texture(texture) { -} - -void TransferState::updateMip() { - mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel); - mipOffset = uvec3(); - if (!texture._gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { - srcPointer = nullptr; - return; - } - - auto mip = texture._gpuObject.accessStoredMipFace(mipLevel, face); - texelFormat = gl::GLTexelFormat::evalGLTexelFormat(texture._gpuObject.getTexelFormat(), mip->getFormat()); - srcPointer = mip->readData(); - bytesPerLine = (uint32_t)mip->getSize() / mipDimensions.y; - bytesPerPixel = bytesPerLine / mipDimensions.x; -} - -bool TransferState::increment() { - const SparseInfo& sparse = texture._sparseInfo; - if ((mipOffset.x + sparse.pageDimensions.x) < mipDimensions.x) { - mipOffset.x += sparse.pageDimensions.x; - return true; - } - - if ((mipOffset.y + sparse.pageDimensions.y) < mipDimensions.y) { - mipOffset.x = 0; - mipOffset.y += sparse.pageDimensions.y; - return true; - } - - if (mipOffset.z + sparse.pageDimensions.z < mipDimensions.z) { - mipOffset.x = 0; - mipOffset.y = 0; - ++mipOffset.z; - return true; - } - - // Done with this mip?, move on to the next mip - if (mipLevel + 1 < texture.usedMipLevels()) { - mipOffset = uvec3(0); - ++mipLevel; - updateMip(); - return true; - } - - uint8_t maxFace = (uint8_t)((texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); - uint8_t nextFace = face + 1; - // Done with this face? Move on to the next - if (nextFace < maxFace) { - ++face; - mipOffset = uvec3(0); - mipLevel = 0; - updateMip(); - return true; - } - - return false; -} - -void TransferState::populatePage(std::vector& buffer) { - uvec3 pageSize = currentPageSize(); - auto bytesPerPageLine = bytesPerPixel * pageSize.x; - if (0 != (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)) { - bytesPerPageLine += DEFAULT_GL_PIXEL_ALIGNMENT - (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT); - assert(0 == (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)); - } - auto totalPageSize = bytesPerPageLine * pageSize.y; - if (totalPageSize > buffer.size()) { - buffer.resize(totalPageSize); - } - uint8_t* dst = &buffer[0]; - for (uint32_t y = 0; y < pageSize.y; ++y) { - uint32_t srcOffset = (bytesPerLine * (mipOffset.y + y)) + (bytesPerPixel * mipOffset.x); - uint32_t dstOffset = bytesPerPageLine * y; - memcpy(dst + dstOffset, srcPointer + srcOffset, pageSize.x * bytesPerPixel); - } -} - -uvec3 TransferState::currentPageSize() const { - return glm::clamp(mipDimensions - mipOffset, uvec3(1), texture._sparseInfo.pageDimensions); -} -#endif GLuint GL45Texture::allocate(const Texture& texture) { GLuint result; @@ -260,17 +183,11 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, GLuint externalId) : GLTexture(backend, texture, externalId), _sparseInfo(*this) -#if INCREMENTAL_TRANSFER -, _transferState(*this) -#endif { } GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this) -#if INCREMENTAL_TRANSFER -, _transferState(*this) -#endif { auto theBackend = _backend.lock(); @@ -316,12 +233,12 @@ GL45Texture::~GL45Texture() { }); auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; - assert(deallocatedPages <= _allocatedPages); - _allocatedPages -= deallocatedPages; + assert(deallocatedPages <= _sparseInfo.allocatedPages); + _sparseInfo.allocatedPages -= deallocatedPages; } - if (0 != _allocatedPages) { - qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _allocatedPages; + if (0 != _sparseInfo.allocatedPages) { + qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _sparseInfo.allocatedPages; } auto size = _size; @@ -365,9 +282,9 @@ void GL45Texture::updateSize() const { } if (_transferrable && _sparseInfo.sparse) { - auto size = _allocatedPages * _sparseInfo.pageBytes; + auto size = _sparseInfo.getSize(); Backend::updateTextureGPUSparseMemoryUsage(_size, size); - setSize(_allocatedPages * _sparseInfo.pageBytes); + setSize(size); } else { setSize(_gpuObject.evalTotalSize(_mipOffset)); } @@ -376,20 +293,16 @@ void GL45Texture::updateSize() const { void GL45Texture::startTransfer() { Parent::startTransfer(); _sparseInfo.update(); -#if INCREMENTAL_TRANSFER - _transferState.updateMip(); -#endif } bool GL45Texture::continueTransfer() { -#if !INCREMENTAL_TRANSFER size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1; for (uint8_t face = 0; face < maxFace; ++face) { for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) { auto size = _gpuObject.evalMipDimensions(mipLevel); if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) { glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE); - _allocatedPages += _sparseInfo.getPageCount(size); + _sparseInfo.allocatedPages += _sparseInfo.getPageCount(size); } if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); @@ -413,58 +326,6 @@ bool GL45Texture::continueTransfer() { } } return false; -#else - static std::vector buffer; - if (buffer.empty()) { - buffer.resize(DEFAULT_PAGE_BUFFER_SIZE); - } - const uvec3 pageSize = _transferState.currentPageSize(); - const uvec3& offset = _transferState.mipOffset; - - if (_sparseInfo.sparse && _transferState.mipLevel <= _sparseInfo.maxSparseLevel) { - if (_allocatedPages > _sparseInfo.maxPages) { - qCWarning(gpugl45logging) << "Exceeded max page allocation!"; - } - glTexturePageCommitmentEXT(_id, _transferState.mipLevel, - offset.x, offset.y, _transferState.face, - pageSize.x, pageSize.y, pageSize.z, - GL_TRUE); - ++_allocatedPages; - } - - if (_transferState.srcPointer) { - // Transfer the mip data - _transferState.populatePage(buffer); - if (GL_TEXTURE_2D == _target) { - glTextureSubImage2D(_id, _transferState.mipLevel, - offset.x, offset.y, - pageSize.x, pageSize.y, - _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]); - } else if (GL_TEXTURE_CUBE_MAP == _target) { - auto target = CUBE_FACE_LAYOUT[_transferState.face]; - // DSA ARB does not work on AMD, so use EXT - // glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); - glTextureSubImage2DEXT(_id, target, _transferState.mipLevel, - offset.x, offset.y, - pageSize.x, pageSize.y, - _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]); - } - } - - serverWait(); - auto currentMip = _transferState.mipLevel; - auto result = _transferState.increment(); - if (_sparseInfo.sparse && _transferState.mipLevel != currentMip && currentMip <= _sparseInfo.maxSparseLevel) { - auto mipDimensions = _gpuObject.evalMipDimensions(currentMip); - auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions); - auto newPages = _allocatedPages - _lastMipAllocatedPages; - if (newPages != mipExpectedPages) { - qCWarning(gpugl45logging) << "Unexpected page allocation size... " << newPages << " " << mipExpectedPages; - } - _lastMipAllocatedPages = _allocatedPages; - } - return result; -#endif } void GL45Texture::finishTransfer() { @@ -545,8 +406,8 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { }); auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; - assert(deallocatedPages < _allocatedPages); - _allocatedPages -= deallocatedPages; + assert(deallocatedPages < _sparseInfo.allocatedPages); + _sparseInfo.allocatedPages -= deallocatedPages; } _minMip = newMinMip; } else { From 08bba5f45f221ea9d0ec3cce11a8d8526abfd08b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 19 Jan 2017 17:31:29 -0800 Subject: [PATCH 02/17] add and remove some profile data points --- interface/src/avatar/Avatar.cpp | 44 ++++++++++++++-------------- libraries/animation/src/Rig.cpp | 1 + libraries/render-utils/src/Model.cpp | 2 -- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 6061812d2a..a3eaeab46a 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -308,6 +308,7 @@ void Avatar::setShouldDie() { } void Avatar::simulate(float deltaTime) { + PROFILE_RANGE(simulation, "simulate"); PerformanceTimer perfTimer("simulate"); if (!isDead() && !_motionState) { @@ -317,8 +318,8 @@ void Avatar::simulate(float deltaTime) { bool avatarInView = false; { // update the shouldAnimate flag to match whether or not we will render the avatar. - PerformanceTimer perfTimer("cull"); { + PROFILE_RANGE(simulation, "cull"); // simple frustum check PerformanceTimer perfTimer("inView"); ViewFrustum viewFrustum; @@ -326,7 +327,7 @@ void Avatar::simulate(float deltaTime) { avatarInView = viewFrustum.sphereIntersectsFrustum(getPosition(), getBoundingRadius()) || viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound()); } - PerformanceTimer lodPerfTimer("LOD"); + PROFILE_RANGE(simulation, "LOD"); if (avatarInView) { const float MINIMUM_VISIBILITY_FOR_ON = 0.4f; const float MAXIMUM_VISIBILITY_FOR_OFF = 0.6f; @@ -346,19 +347,17 @@ void Avatar::simulate(float deltaTime) { } } - uint64_t start = usecTimestampNow(); - // CRUFT? _shouldSkipRender is never set 'true' - if (_shouldAnimate && avatarInView && !_shouldSkipRender) { - { - PerformanceTimer perfTimer("skeleton"); + { + PROFILE_RANGE(simulation, "updateJoints"); + uint64_t start = usecTimestampNow(); + // CRUFT? _shouldSkipRender is never set 'true' + if (_shouldAnimate && avatarInView && !_shouldSkipRender) { _skeletonModel->getRig()->copyJointsFromJointData(_jointData); _skeletonModel->simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations); locationChanged(); // joints changed, so if there are any children, update them. _hasNewJointRotations = false; _hasNewJointTranslations = false; - } - { - PerformanceTimer perfTimer("head"); + glm::vec3 headPosition = getPosition(); if (!_skeletonModel->getHeadPosition(headPosition)) { headPosition = getPosition(); @@ -367,15 +366,14 @@ void Avatar::simulate(float deltaTime) { head->setPosition(headPosition); head->setScale(getUniformScale()); head->simulate(deltaTime, false, !_shouldAnimate); + } else { + // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. + getHead()->setPosition(getPosition()); + _skeletonModel->simulate(deltaTime, false); } - } else { - // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. - getHead()->setPosition(getPosition()); - PerformanceTimer perfTimer("skeleton"); - _skeletonModel->simulate(deltaTime, false); + timeProcessingJoints += usecTimestampNow() - start; + numJointsProcessed += _jointData.size(); } - timeProcessingJoints += usecTimestampNow() - start; - numJointsProcessed += _jointData.size(); // update animation for display name fade in/out if ( _displayNameTargetAlpha != _displayNameAlpha) { @@ -394,11 +392,13 @@ void Avatar::simulate(float deltaTime) { _displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha; } - measureMotionDerivatives(deltaTime); - - simulateAttachments(deltaTime); - updatePalms(); - updateAvatarEntities(); + { + PROFILE_RANGE(simulation, "misc"); + measureMotionDerivatives(deltaTime); + simulateAttachments(deltaTime); + updatePalms(); + updateAvatarEntities(); + } } bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index fdeeb01739..ac16b16c1d 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1269,6 +1269,7 @@ void Rig::copyJointsIntoJointData(QVector& jointDataVec) const { void Rig::copyJointsFromJointData(const QVector& jointDataVec) { PerformanceTimer perfTimer("copyJoints"); + PROFILE_RANGE(simulation_animation_detail, "copyJoints"); if (_animSkeleton && jointDataVec.size() == (int)_internalPoseSet._relativePoses.size()) { // make a vector of rotations in absolute-geometry-frame const AnimPoseVec& absoluteDefaultPoses = _animSkeleton->getAbsoluteDefaultPoses(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b79e69a9b7..d3fddc96d9 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -272,8 +272,6 @@ void Model::reset() { } bool Model::updateGeometry() { - PROFILE_RANGE(render_detail, __FUNCTION__); - PerformanceTimer perfTimer("Model::updateGeometry"); bool needFullUpdate = false; if (!isLoaded()) { From 88bf12616833f8be17b121a0af20126b81c488d4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 20 Jan 2017 14:22:13 -0800 Subject: [PATCH 03/17] remove old avatar culling and LOD logic --- interface/src/avatar/Avatar.cpp | 50 ++++++-------------------- interface/src/avatar/Avatar.h | 6 +--- interface/src/avatar/AvatarManager.cpp | 6 ++-- libraries/avatars/src/AvatarData.cpp | 9 +++-- libraries/avatars/src/AvatarData.h | 3 +- 5 files changed, 21 insertions(+), 53 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a3eaeab46a..73c8a7553b 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -307,7 +307,7 @@ void Avatar::setShouldDie() { _owningAvatarMixer.clear(); } -void Avatar::simulate(float deltaTime) { +void Avatar::simulate(float deltaTime, bool inView) { PROFILE_RANGE(simulation, "simulate"); PerformanceTimer perfTimer("simulate"); @@ -316,47 +316,18 @@ void Avatar::simulate(float deltaTime) { } animateScaleChanges(deltaTime); - bool avatarInView = false; - { // update the shouldAnimate flag to match whether or not we will render the avatar. - { - PROFILE_RANGE(simulation, "cull"); - // simple frustum check - PerformanceTimer perfTimer("inView"); - ViewFrustum viewFrustum; - qApp->copyDisplayViewFrustum(viewFrustum); - avatarInView = viewFrustum.sphereIntersectsFrustum(getPosition(), getBoundingRadius()) - || viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound()); - } - PROFILE_RANGE(simulation, "LOD"); - if (avatarInView) { - const float MINIMUM_VISIBILITY_FOR_ON = 0.4f; - const float MAXIMUM_VISIBILITY_FOR_OFF = 0.6f; - ViewFrustum viewFrustum; - qApp->copyViewFrustum(viewFrustum); - float visibility = calculateRenderAccuracy(viewFrustum.getPosition(), - getBounds(), DependencyManager::get()->getOctreeSizeScale()); - if (!_shouldAnimate) { - if (visibility > MINIMUM_VISIBILITY_FOR_ON) { - _shouldAnimate = true; - qCDebug(interfaceapp) << "Restoring" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility; - } - } else if (visibility < MAXIMUM_VISIBILITY_FOR_OFF) { - _shouldAnimate = false; - qCDebug(interfaceapp) << "Optimizing" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility; - } - } - } - { PROFILE_RANGE(simulation, "updateJoints"); uint64_t start = usecTimestampNow(); - // CRUFT? _shouldSkipRender is never set 'true' - if (_shouldAnimate && avatarInView && !_shouldSkipRender) { + if (inView) { + // adebug BOOKMARK: can avoid copying duplicate joint data + // - can avoid some work when transform not changed (see SkeletonModel::simulate() and Model::setTranslation()) + // - can maybe use _hasNewFoo instead of AvatarData::_jointDataVersion + // - can maybe avoid stuff if blendShapes haven't changed _skeletonModel->getRig()->copyJointsFromJointData(_jointData); - _skeletonModel->simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations); + _skeletonModel->simulate(deltaTime, _hasNewJointData); locationChanged(); // joints changed, so if there are any children, update them. - _hasNewJointRotations = false; - _hasNewJointTranslations = false; + _hasNewJointData = false; glm::vec3 headPosition = getPosition(); if (!_skeletonModel->getHeadPosition(headPosition)) { @@ -365,7 +336,8 @@ void Avatar::simulate(float deltaTime) { Head* head = getHead(); head->setPosition(headPosition); head->setScale(getUniformScale()); - head->simulate(deltaTime, false, !_shouldAnimate); + const bool useBillboard = false; // HACK + head->simulate(deltaTime, false, useBillboard); } else { // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. getHead()->setPosition(getPosition()); @@ -1106,7 +1078,7 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) { if (_moving && _motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); } - if (_moving || _hasNewJointRotations || _hasNewJointTranslations) { + if (_moving || _hasNewJointData) { locationChanged(); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index d370402865..75af330452 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -68,7 +68,7 @@ public: void init(); void updateAvatarEntities(); - void simulate(float deltaTime); + void simulate(float deltaTime, bool inView); virtual void simulateAttachments(float deltaTime); virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition); @@ -141,8 +141,6 @@ public: Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; } - Q_INVOKABLE bool getShouldRender() 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; @@ -265,8 +263,6 @@ private: int _rightPointerGeometryID { 0 }; int _nameRectGeometryID { 0 }; bool _initialized; - bool _shouldAnimate { true }; - bool _shouldSkipRender { false }; bool _isLookAtTarget { false }; bool _inScene { false }; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index b0dc9922ff..4ba3cbdc1a 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -165,7 +165,8 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { ++avatarIterator; } else { avatar->ensureInScene(avatar); - avatar->simulate(deltaTime); + const bool inView = true; // HACK + avatar->simulate(deltaTime, inView); ++avatarIterator; avatar->updateRenderItem(pendingChanges); @@ -210,7 +211,8 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { ++fadingIterator; } } else { - avatar->simulate(deltaTime); + const bool inView = true; // HACK + avatar->simulate(deltaTime, inView); ++fadingIterator; } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1fb68fce14..1aacb00c04 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -120,8 +120,7 @@ AvatarData::AvatarData() : _handState(0), _keyState(NO_KEY_DOWN), _forceFaceTrackerConnected(false), - _hasNewJointRotations(true), - _hasNewJointTranslations(true), + _hasNewJointData(true), _headData(NULL), _displayNameTargetAlpha(1.0f), _displayNameAlpha(1.0f), @@ -553,7 +552,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { glm::vec3 newEulerAngles(pitch, yaw, roll); glm::quat newOrientation = glm::quat(glm::radians(newEulerAngles)); if (currentOrientation != newOrientation) { - _hasNewJointRotations = true; + _hasNewJointData = true; setLocalOrientation(newOrientation); } @@ -680,7 +679,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { JointData& data = _jointData[i]; if (validRotations[i]) { sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); - _hasNewJointRotations = true; + _hasNewJointData = true; data.rotationSet = true; } } @@ -715,7 +714,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { JointData& data = _jointData[i]; if (validTranslations[i]) { sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); - _hasNewJointTranslations = true; + _hasNewJointData = true; data.translationSet = true; } } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index db06d52092..a3c9e537ca 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -427,8 +427,7 @@ protected: KeyState _keyState; bool _forceFaceTrackerConnected; - bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar - bool _hasNewJointTranslations; // set in AvatarData, cleared in Avatar + bool _hasNewJointData; // set in AvatarData, cleared in Avatar HeadData* _headData; From d8a10320d1377652d8e7281a6c93047be6558843 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 14:04:24 -0800 Subject: [PATCH 04/17] fix warning about implicit cast --- libraries/shared/src/ViewFrustum.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index b4ed462639..a0b7d17e46 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -729,7 +729,7 @@ void ViewFrustum::evalProjectionMatrix(glm::mat4& proj) const { glm::mat4 ViewFrustum::evalProjectionMatrixRange(float rangeNear, float rangeFar) const { // make sure range near far make sense - assert(rangeNear > 0.0); + assert(rangeNear > 0.0f); assert(rangeFar > rangeNear); // recreate a projection matrix for only a range of depth of this frustum. @@ -738,7 +738,7 @@ glm::mat4 ViewFrustum::evalProjectionMatrixRange(float rangeNear, float rangeFar glm::mat4 rangeProj = _projection; float A = -(rangeFar + rangeNear) / (rangeFar - rangeNear); - float B = -2 * rangeFar*rangeNear / ((rangeFar - rangeNear)); + float B = -2.0f * rangeFar*rangeNear / ((rangeFar - rangeNear)); rangeProj[2][2] = A; rangeProj[3][2] = B; From 09707217ec40c64470583c2e58adc397629d583a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 14:04:33 -0800 Subject: [PATCH 05/17] remove Model::simulateInternal() --- libraries/render-utils/src/Model.cpp | 10 +++------- libraries/render-utils/src/Model.h | 1 - 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d3fddc96d9..1e83a874dc 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1126,7 +1126,9 @@ void Model::simulate(float deltaTime, bool fullUpdate) { if (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint) { snapToRegistrationPoint(); } - simulateInternal(deltaTime); + // update the world space transforms for all joints + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); + updateRig(deltaTime, parentTransform); } } @@ -1136,12 +1138,6 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->updateAnimations(deltaTime, parentTransform); } -void Model::simulateInternal(float deltaTime) { - // update the world space transforms for all joints - glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); - updateRig(deltaTime, parentTransform); -} - // virtual void Model::updateClusterMatrices() { PerformanceTimer perfTimer("Model::updateClusterMatrices"); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 246d67180e..3f673b0250 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -312,7 +312,6 @@ protected: void scaleToFit(); void snapToRegistrationPoint(); - void simulateInternal(float deltaTime); virtual void updateRig(float deltaTime, glm::mat4 parentTransform); /// Restores the indexed joint to its default position. From e3634239921cc09c20096195203cd5d7114e8929 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 14:05:25 -0800 Subject: [PATCH 06/17] compute priority of avatar and sort before update --- interface/src/avatar/Avatar.cpp | 5 +- interface/src/avatar/Avatar.h | 4 ++ interface/src/avatar/AvatarManager.cpp | 87 +++++++++++++++++++------- 3 files changed, 69 insertions(+), 27 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 73c8a7553b..260373bf50 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -127,6 +127,7 @@ Avatar::Avatar(RigPointer rig) : _nameRectGeometryID = geometryCache->allocateID(); _leftPointerGeometryID = geometryCache->allocateID(); _rightPointerGeometryID = geometryCache->allocateID(); + _lastRenderUpdateTime = usecTimestampNow(); } Avatar::~Avatar() { @@ -320,10 +321,6 @@ void Avatar::simulate(float deltaTime, bool inView) { PROFILE_RANGE(simulation, "updateJoints"); uint64_t start = usecTimestampNow(); if (inView) { - // adebug BOOKMARK: can avoid copying duplicate joint data - // - can avoid some work when transform not changed (see SkeletonModel::simulate() and Model::setTranslation()) - // - can maybe use _hasNewFoo instead of AvatarData::_jointDataVersion - // - can maybe avoid stuff if blendShapes haven't changed _skeletonModel->getRig()->copyJointsFromJointData(_jointData); _skeletonModel->simulate(deltaTime, _hasNewJointData); locationChanged(); // joints changed, so if there are any children, update them. diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 75af330452..3276eaff47 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -177,6 +177,9 @@ public: glm::vec3 getUncachedRightPalmPosition() const; glm::quat getUncachedRightPalmRotation() const; + uint64_t getLastRenderUpdateTime() const { return _lastRenderUpdateTime; } + void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; } + Q_INVOKABLE void setShouldDie(); public slots: @@ -259,6 +262,7 @@ protected: void ensureInScene(AvatarSharedPointer self); private: + uint64_t _lastRenderUpdateTime { 0 }; int _leftPointerGeometryID { 0 }; int _rightPointerGeometryID { 0 }; int _nameRectGeometryID { 0 }; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 4ba3cbdc1a..e3d3164b68 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -132,53 +132,94 @@ void AvatarManager::updateMyAvatar(float deltaTime) { Q_LOGGING_CATEGORY(trace_simulation_avatar, "trace.simulation.avatar"); +class AvatarPriority { +public: + AvatarPriority(AvatarSharedPointer a, float p) : avatar(a), priority(p) {} + AvatarSharedPointer avatar; + float priority; + // NOTE: we invert the less-than operator to sort high priorities to front + bool operator<(const AvatarPriority& other) const { return priority > other.priority; } +}; + void AvatarManager::updateOtherAvatars(float deltaTime) { // lock the hash for read to check the size QReadLocker lock(&_hashLock); - if (_avatarHash.size() < 2 && _avatarFades.isEmpty()) { return; } - lock.unlock(); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); PerformanceTimer perfTimer("otherAvatars"); - render::PendingChanges pendingChanges; - // simulate avatars - auto hashCopy = getHashCopy(); + auto avatarMap = getHashCopy(); + QList avatarList = avatarMap.values(); + uint64_t now = usecTimestampNow(); + ViewFrustum cameraView; + qApp->copyDisplayViewFrustum(cameraView); + glm::vec3 frustumCenter = cameraView.getPosition(); - uint64_t start = usecTimestampNow(); - AvatarHash::iterator avatarIterator = hashCopy.begin(); - while (avatarIterator != hashCopy.end()) { - auto avatar = std::static_pointer_cast(avatarIterator.value()); + const float OUT_OF_VIEW_PENALTY = -10.0; + std::priority_queue sortedAvatars; + for (int32_t i = 0; i < avatarList.size(); ++i) { + const auto& avatar = std::static_pointer_cast(avatarList.at(i)); if (avatar == _myAvatar || !avatar->isInitialized()) { // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. // DO NOT update or fade out uninitialized Avatars - ++avatarIterator; - } else if (avatar->shouldDie()) { - removeAvatar(avatarIterator.key()); - ++avatarIterator; - } else { - avatar->ensureInScene(avatar); - const bool inView = true; // HACK - avatar->simulate(deltaTime, inView); - ++avatarIterator; - - avatar->updateRenderItem(pendingChanges); + continue; } + if (avatar->shouldDie()) { + removeAvatar(avatar->getID()); + continue; + } + + // priority = weighted linear combination of: + // (a) apparentSize + // (b) proximity to center of view, and + // (c) time since last update + glm::vec3 avatarPosition = avatar->getPosition(); + glm::vec3 offset = avatarPosition - frustumCenter; + float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero + float radius = avatar->getBoundingRadius(); + const glm::vec3& forward = cameraView.getDirection(); + float apparentSize = radius / distance; + float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance; + float age = (float)(now - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND); + float priority = 2.0f * apparentSize + 0.25f * cosineAngle + age; + + // decrement priority of avatars outside keyhole + if (distance > cameraView.getCenterRadius()) { + if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) { + priority += OUT_OF_VIEW_PENALTY; + } + } + sortedAvatars.push(AvatarPriority(avatar, priority)); + } + + render::PendingChanges pendingChanges; + const uint64_t AVATAR_RENDER_UPDATE_TIME_BUDGET = 2 * USECS_PER_MSEC; + uint64_t expiry = now + AVATAR_RENDER_UPDATE_TIME_BUDGET; + while (!sortedAvatars.empty()) { + const AvatarPriority& sortData = sortedAvatars.top(); + const auto& avatar = std::static_pointer_cast(sortData.avatar); + avatar->ensureInScene(avatar); + const bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; + avatar->simulate(deltaTime, inView); + if (expiry > usecTimestampNow()) { + avatar->updateRenderItem(pendingChanges); + avatar->setLastRenderUpdateTime(now); + } + sortedAvatars.pop(); } qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges); - // simulate avatar fades simulateAvatarFades(deltaTime); - PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", - { { "NumAvatarsPerSec", (float)(size() * USECS_PER_SECOND) / (float)(usecTimestampNow() - start) } }); + //PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", + // { { "NumAvatarsPerSec", (float)((size() - sortedAvatars.size()) * USECS_PER_SECOND) / (float)(usecTimestampNow() - now) } }); PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } }); } From e65d9309b3592e2b97b3861bf1cf6511985b2c73 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 14:56:10 -0800 Subject: [PATCH 07/17] remove cruft: Avatar::setShouldDie() --- interface/src/avatar/Avatar.cpp | 6 +++--- interface/src/avatar/Avatar.h | 2 +- libraries/avatars/src/AvatarData.h | 4 ---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 260373bf50..c5c5dacfc6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -303,9 +303,9 @@ void Avatar::updateAvatarEntities() { } } -void Avatar::setShouldDie() { - // This will cause the avatar to be shrunk away and removed (the actual Avatar gets removed), but then it comes back. - _owningAvatarMixer.clear(); +bool Avatar::shouldDie() const { + const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND; + return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; } void Avatar::simulate(float deltaTime, bool inView) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 3276eaff47..d6f588c47e 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -180,7 +180,7 @@ public: uint64_t getLastRenderUpdateTime() const { return _lastRenderUpdateTime; } void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; } - Q_INVOKABLE void setShouldDie(); + bool shouldDie() const; public slots: diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a3c9e537ca..093530235b 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -81,8 +81,6 @@ const quint32 AVATAR_MOTION_DEFAULTS = const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; -const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND; - // Bitset of state flags - we store the key state, hand state, Faceshift, eye tracking, and existence of // referential data in this bit set. The hand state is an octal, but is split into two sections to maintain // backward compatibility. The bits are ordered as such (0-7 left to right). @@ -371,8 +369,6 @@ public: const glm::vec3& getTargetVelocity() const { return _targetVelocity; } - bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; } - void clearRecordingBasis(); TransformPointer getRecordingBasis() const; void setRecordingBasis(TransformPointer recordingBasis = TransformPointer()); From b8afc87ad976513f6bfa6025887081de523237d4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 16:12:36 -0800 Subject: [PATCH 08/17] remove cruft --- interface/src/ui/PreferencesDialog.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 5 ----- libraries/avatars/src/AvatarData.h | 3 +-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index a4cb62cc13..828e2e772d 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -157,7 +157,7 @@ void setupPreferences() { } { auto getter = [=]()->float { return myAvatar->getUniformScale(); }; - auto setter = [=](float value) { myAvatar->setTargetScaleVerbose(value); }; // The hell? + auto setter = [=](float value) { myAvatar->setTargetScale(value); }; auto preference = new SpinnerPreference(AVATAR_TUNING, "Avatar scale (default is 1.0)", getter, setter); preference->setMin(0.01f); preference->setMax(99.9f); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1aacb00c04..701fae1b2b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -179,11 +179,6 @@ void AvatarData::setTargetScale(float targetScale) { _targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); } -void AvatarData::setTargetScaleVerbose(float targetScale) { - setTargetScale(targetScale); - qCDebug(avatars) << "Changed scale to " << _targetScale; -} - glm::vec3 AvatarData::getHandPosition() const { return getOrientation() * _handPosition + getPosition(); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 093530235b..f07d9a2ba6 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -262,8 +262,7 @@ public: // Scale float getTargetScale() const; - void setTargetScale(float targetScale); - void setTargetScaleVerbose(float targetScale); + virtual void setTargetScale(float targetScale); float getDomainLimitedScale() const { return glm::clamp(_targetScale, _domainMinimumScale, _domainMaximumScale); } void setDomainMinimumScale(float domainMinimumScale) From 69a7b1ef76c4892f7ee28b4080c132f392d074b1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 16:12:47 -0800 Subject: [PATCH 09/17] move some stuff out of Avatar::simulate() call it explicity in AvatarManager::updateOtherAvatars() --- interface/src/avatar/Avatar.cpp | 28 +++++++++++++++----------- interface/src/avatar/Avatar.h | 5 +++-- interface/src/avatar/AvatarManager.cpp | 22 ++++++++++++++++++++ interface/src/avatar/AvatarManager.h | 2 +- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index c5c5dacfc6..208d265dcd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -188,25 +188,35 @@ AABox Avatar::getBounds() const { } void Avatar::animateScaleChanges(float deltaTime) { - float currentScale = getUniformScale(); - auto desiredScale = getDomainLimitedScale(); - if (currentScale != desiredScale) { + if (_isAnimatingScale) { + float currentScale = getUniformScale(); + float desiredScale = getDomainLimitedScale(); + // use exponential decay toward the domain limit clamped scale const float SCALE_ANIMATION_TIMESCALE = 0.5f; float blendFactor = glm::clamp(deltaTime / SCALE_ANIMATION_TIMESCALE, 0.0f, 1.0f); float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * desiredScale; // snap to the end when we get close enough - const float MIN_RELATIVE_SCALE_ERROR = 0.03f; - if (fabsf(desiredScale - currentScale) / desiredScale < MIN_RELATIVE_SCALE_ERROR) { + const float MIN_RELATIVE_ERROR = 0.03f; + float relativeError = fabsf(desiredScale - currentScale) / desiredScale; + if (relativeError < MIN_RELATIVE_ERROR) { animatedScale = desiredScale; + _isAnimatingScale = false; } - setScale(glm::vec3(animatedScale)); // avatar scale is uniform + + // TODO: rebuilding the shape constantly is somehwat expensive. + // We should only rebuild after significant change. rebuildCollisionShape(); } } +void Avatar::setTargetScale(float targetScale) { + AvatarData::setTargetScale(targetScale); + _isAnimatingScale = true; +} + void Avatar::updateAvatarEntities() { PerformanceTimer perfTimer("attachments"); // - if queueEditEntityMessage sees clientOnly flag it does _myAvatar->updateAvatarEntity() @@ -311,12 +321,6 @@ bool Avatar::shouldDie() const { void Avatar::simulate(float deltaTime, bool inView) { PROFILE_RANGE(simulation, "simulate"); PerformanceTimer perfTimer("simulate"); - - if (!isDead() && !_motionState) { - DependencyManager::get()->addAvatarToSimulation(this); - } - animateScaleChanges(deltaTime); - { PROFILE_RANGE(simulation, "updateJoints"); uint64_t start = usecTimestampNow(); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index d6f588c47e..a6c5bbf16f 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -181,6 +181,8 @@ public: void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; } bool shouldDie() const; + void animateScaleChanges(float deltaTime); + void setTargetScale(float targetScale) override; public slots: @@ -231,8 +233,6 @@ protected: // protected methods... bool isLookingAtMe(AvatarSharedPointer avatar) const; - virtual void animateScaleChanges(float deltaTime); - glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } @@ -269,6 +269,7 @@ private: bool _initialized; bool _isLookAtTarget { false }; bool _inScene { false }; + bool _isAnimatingScale { false }; float getBoundingRadius() const; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e3d3164b68..fa2ee2190c 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -175,6 +175,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { removeAvatar(avatar->getID()); continue; } + if (avatar->isDead()) { + continue; + } // priority = weighted linear combination of: // (a) apparentSize @@ -205,7 +208,24 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { while (!sortedAvatars.empty()) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); + + // for ALL avatars... avatar->ensureInScene(avatar); + if (!avatar->getMotionState()) { + ShapeInfo shapeInfo; + avatar->computeShapeInfo(shapeInfo); + btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); + if (shape) { + // don't add to the simulation now, instead put it on a list to be added later + AvatarMotionState* motionState = new AvatarMotionState(avatar.get(), shape); + avatar->setMotionState(motionState); + _motionStatesToAddToPhysics.insert(motionState); + _motionStatesThatMightUpdate.insert(motionState); + } + } + avatar->animateScaleChanges(deltaTime); + + // for avatars in view... const bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; avatar->simulate(deltaTime, inView); if (expiry > usecTimestampNow()) { @@ -429,6 +449,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } } +/* void AvatarManager::addAvatarToSimulation(Avatar* avatar) { assert(!avatar->getMotionState()); @@ -443,6 +464,7 @@ void AvatarManager::addAvatarToSimulation(Avatar* avatar) { _motionStatesThatMightUpdate.insert(motionState); } } +*/ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { if (DependencyManager::get()->shouldRenderAvatars()) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index a423e34f8f..efb01e071f 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -69,7 +69,7 @@ public: void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); - void addAvatarToSimulation(Avatar* avatar); + //void addAvatarToSimulation(Avatar* avatar); Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), From 887707426eb7e383604ff1964a37bc37b8811da3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 17:03:26 -0800 Subject: [PATCH 10/17] remove cruft: Head::getScalePivot() --- interface/src/avatar/Head.cpp | 4 ---- interface/src/avatar/Head.h | 2 -- 2 files changed, 6 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 928f46facb..66beafcdd8 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -378,10 +378,6 @@ glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const { return rotationBetween(orientation * IDENTITY_FRONT, lookAtDelta + glm::length(lookAtDelta) * _saccade) * orientation; } -glm::vec3 Head::getScalePivot() const { - return _position; -} - void Head::setFinalPitch(float finalPitch) { _deltaPitch = glm::clamp(finalPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH) - _basePitch; } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 29cd06865c..b1ea36df3d 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -70,8 +70,6 @@ public: bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) float getAverageLoudness() const { return _averageLoudness; } - /// \return the point about which scaling occurs. - glm::vec3 getScalePivot() const; void setDeltaPitch(float pitch) { _deltaPitch = pitch; } float getDeltaPitch() const { return _deltaPitch; } From d3dcc2b41559e5c122fd7abb18f2857e94525fa6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 17:28:54 -0800 Subject: [PATCH 11/17] remove cruft: billboard option for Head::simulate() --- interface/src/avatar/Head.cpp | 6 +++--- interface/src/avatar/Head.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 66beafcdd8..d7bf2b79bf 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -70,7 +70,7 @@ void Head::reset() { _baseYaw = _basePitch = _baseRoll = 0.0f; } -void Head::simulate(float deltaTime, bool isMine, bool billboard) { +void Head::simulate(float deltaTime, bool isMine) { // Update audio trailing average for rendering facial animations const float AUDIO_AVERAGING_SECS = 0.05f; const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; @@ -117,7 +117,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } } - if (!(_isFaceTrackerConnected || billboard)) { + if (!_isFaceTrackerConnected) { if (!_isEyeTrackerConnected) { // Update eye saccades @@ -220,7 +220,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _leftEyePosition = _rightEyePosition = getPosition(); _eyePosition = getPosition(); - if (!billboard && _owningAvatar) { + if (_owningAvatar) { auto skeletonModel = static_cast(_owningAvatar)->getSkeletonModel(); if (skeletonModel) { skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition); diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index b1ea36df3d..3d25c79087 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -31,7 +31,7 @@ public: void init(); void reset(); - void simulate(float deltaTime, bool isMine, bool billboard = false); + void simulate(float deltaTime, bool isMine); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } From ac180758ad87dab53efd4747c237f99f0fe58fba Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Jan 2017 10:36:42 -0800 Subject: [PATCH 12/17] sort, optimize, and timebox process avatar updates --- interface/src/avatar/Avatar.cpp | 15 ++-- interface/src/avatar/AvatarManager.cpp | 112 ++++++++++++++----------- interface/src/avatar/SkeletonModel.cpp | 18 ++-- 3 files changed, 83 insertions(+), 62 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 208d265dcd..cdf9323ace 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -323,10 +323,13 @@ void Avatar::simulate(float deltaTime, bool inView) { PerformanceTimer perfTimer("simulate"); { PROFILE_RANGE(simulation, "updateJoints"); - uint64_t start = usecTimestampNow(); - if (inView) { + if (inView && _hasNewJointData) { + uint64_t start = usecTimestampNow(); _skeletonModel->getRig()->copyJointsFromJointData(_jointData); - _skeletonModel->simulate(deltaTime, _hasNewJointData); + _skeletonModel->simulate(deltaTime, true); + timeProcessingJoints += usecTimestampNow() - start; + numJointsProcessed += _jointData.size(); + locationChanged(); // joints changed, so if there are any children, update them. _hasNewJointData = false; @@ -337,15 +340,11 @@ void Avatar::simulate(float deltaTime, bool inView) { Head* head = getHead(); head->setPosition(headPosition); head->setScale(getUniformScale()); - const bool useBillboard = false; // HACK - head->simulate(deltaTime, false, useBillboard); + head->simulate(deltaTime, false); } else { // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. - getHead()->setPosition(getPosition()); _skeletonModel->simulate(deltaTime, false); } - timeProcessingJoints += usecTimestampNow() - start; - numJointsProcessed += _jointData.size(); } // update animation for display name fade in/out diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index fa2ee2190c..73f3fb0f38 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -149,14 +149,11 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } lock.unlock(); - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); - PerformanceTimer perfTimer("otherAvatars"); + uint64_t startTime = usecTimestampNow(); auto avatarMap = getHashCopy(); QList avatarList = avatarMap.values(); - uint64_t now = usecTimestampNow(); ViewFrustum cameraView; qApp->copyDisplayViewFrustum(cameraView); glm::vec3 frustumCenter = cameraView.getPosition(); @@ -164,47 +161,56 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { const float OUT_OF_VIEW_PENALTY = -10.0; std::priority_queue sortedAvatars; - for (int32_t i = 0; i < avatarList.size(); ++i) { - const auto& avatar = std::static_pointer_cast(avatarList.at(i)); - if (avatar == _myAvatar || !avatar->isInitialized()) { - // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. - // DO NOT update or fade out uninitialized Avatars - continue; - } - if (avatar->shouldDie()) { - removeAvatar(avatar->getID()); - continue; - } - if (avatar->isDead()) { - continue; - } - - // priority = weighted linear combination of: - // (a) apparentSize - // (b) proximity to center of view, and - // (c) time since last update - glm::vec3 avatarPosition = avatar->getPosition(); - glm::vec3 offset = avatarPosition - frustumCenter; - float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero - float radius = avatar->getBoundingRadius(); - const glm::vec3& forward = cameraView.getDirection(); - float apparentSize = radius / distance; - float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance; - float age = (float)(now - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND); - float priority = 2.0f * apparentSize + 0.25f * cosineAngle + age; - - // decrement priority of avatars outside keyhole - if (distance > cameraView.getCenterRadius()) { - if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) { - priority += OUT_OF_VIEW_PENALTY; + { + PROFILE_RANGE(simulation, "sort"); + for (int32_t i = 0; i < avatarList.size(); ++i) { + const auto& avatar = std::static_pointer_cast(avatarList.at(i)); + if (avatar == _myAvatar || !avatar->isInitialized()) { + // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. + // DO NOT update or fade out uninitialized Avatars + continue; } + if (avatar->shouldDie()) { + removeAvatar(avatar->getID()); + continue; + } + if (avatar->isDead()) { + continue; + } + + // priority = weighted linear combination of: + // (a) apparentSize + // (b) proximity to center of view + // (c) time since last update + // (d) TIME_PENALTY to help recently updated entries sort toward back + glm::vec3 avatarPosition = avatar->getPosition(); + glm::vec3 offset = avatarPosition - frustumCenter; + float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero + float radius = avatar->getBoundingRadius(); + const glm::vec3& forward = cameraView.getDirection(); + float apparentSize = radius / distance; + float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance; + const float TIME_PENALTY = 0.080f; // seconds + float age = (float)(startTime - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND) - TIME_PENALTY; + float priority = apparentSize + 0.25f * cosineAngle + age; + + // decrement priority of avatars outside keyhole + if (distance > cameraView.getCenterRadius()) { + if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) { + priority += OUT_OF_VIEW_PENALTY; + } + } + sortedAvatars.push(AvatarPriority(avatar, priority)); } - sortedAvatars.push(AvatarPriority(avatar, priority)); } render::PendingChanges pendingChanges; - const uint64_t AVATAR_RENDER_UPDATE_TIME_BUDGET = 2 * USECS_PER_MSEC; - uint64_t expiry = now + AVATAR_RENDER_UPDATE_TIME_BUDGET; + // NOTE: the copy of hash and sort above takes about 300 usec + const uint64_t RENDER_UPDATE_BUDGET = 1500; // usec + const uint64_t MAX_UPDATE_BUDGET = 2000; // usec + uint64_t renderExpiry = startTime + RENDER_UPDATE_BUDGET; + uint64_t maxExpiry = startTime + MAX_UPDATE_BUDGET; + size_t numAvatarsProcessed = sortedAvatars.size(); while (!sortedAvatars.empty()) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); @@ -225,12 +231,23 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } avatar->animateScaleChanges(deltaTime); - // for avatars in view... - const bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; - avatar->simulate(deltaTime, inView); - if (expiry > usecTimestampNow()) { + uint64_t now = usecTimestampNow(); + if (now < renderExpiry) { + // we're within budget + bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; + avatar->simulate(deltaTime, inView); avatar->updateRenderItem(pendingChanges); - avatar->setLastRenderUpdateTime(now); + avatar->setLastRenderUpdateTime(startTime); + } else if (now < maxExpiry) { + // we've spent most of our time budget, but we still simulate() the avatar as it if were out of view + // --> some avatars may freeze until their priority trickles up + const bool inView = false; + avatar->simulate(deltaTime, inView); + } else { + // we've spent ALL of our time budget --> bail on the rest of the avatar updates + // --> some scale or fade animations may glitch + // --> some avatar velocity measurements may be a little off + break; } sortedAvatars.pop(); } @@ -238,8 +255,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { simulateAvatarFades(deltaTime); - //PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", - // { { "NumAvatarsPerSec", (float)((size() - sortedAvatars.size()) * USECS_PER_SECOND) / (float)(usecTimestampNow() - now) } }); + numAvatarsProcessed -= sortedAvatars.size(); + float numAvatarsPerSec = (float)(numAvatarsProcessed * USECS_PER_SECOND) / (float)(usecTimestampNow() - startTime); + PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", { { "NumAvatarsPerSec", numAvatarsPerSec } }); PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } }); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 54f6682191..4b77323bba 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -220,15 +220,19 @@ void SkeletonModel::updateAttitude() { // Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), // but just before head has been simulated. void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { - updateAttitude(); - setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); + if (fullUpdate) { + updateAttitude(); + setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); - Model::simulate(deltaTime, fullUpdate); + Model::simulate(deltaTime, fullUpdate); - // let rig compute the model offset - glm::vec3 registrationPoint; - if (_rig->getModelRegistrationPoint(registrationPoint)) { - setOffset(registrationPoint); + // let rig compute the model offset + glm::vec3 registrationPoint; + if (_rig->getModelRegistrationPoint(registrationPoint)) { + setOffset(registrationPoint); + } + } else { + Model::simulate(deltaTime, fullUpdate); } if (!isActive() || !_owningAvatar->isMyAvatar()) { From 01e14eec471cb65eb6aa8bb97851b69e52c490d5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Jan 2017 12:09:03 -0800 Subject: [PATCH 13/17] remove commented out cruft --- interface/src/avatar/AvatarManager.cpp | 17 ----------------- interface/src/avatar/AvatarManager.h | 2 -- 2 files changed, 19 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 73f3fb0f38..fe0b49728b 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -467,23 +467,6 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } } -/* -void AvatarManager::addAvatarToSimulation(Avatar* avatar) { - assert(!avatar->getMotionState()); - - ShapeInfo shapeInfo; - avatar->computeShapeInfo(shapeInfo); - btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); - if (shape) { - // we don't add to the simulation now, we put it on a list to be added later - AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); - avatar->setMotionState(motionState); - _motionStatesToAddToPhysics.insert(motionState); - _motionStatesThatMightUpdate.insert(motionState); - } -} -*/ - void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { if (DependencyManager::get()->shouldRenderAvatars()) { for (auto avatarData : _avatarHash) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index efb01e071f..817a3e580f 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -69,8 +69,6 @@ public: void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); - //void addAvatarToSimulation(Avatar* avatar); - Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), const QScriptValue& avatarIdsToDiscard = QScriptValue()); From 0f09e60acdcc8dc872609cad7ca88fc7366fe0e1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Jan 2017 12:13:01 -0800 Subject: [PATCH 14/17] remove unhelpful comment --- interface/src/avatar/AvatarManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index fe0b49728b..ff7180f95e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -205,7 +205,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } render::PendingChanges pendingChanges; - // NOTE: the copy of hash and sort above takes about 300 usec const uint64_t RENDER_UPDATE_BUDGET = 1500; // usec const uint64_t MAX_UPDATE_BUDGET = 2000; // usec uint64_t renderExpiry = startTime + RENDER_UPDATE_BUDGET; From 2264c2960443fd6591007ec06277e69b6709cd89 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Jan 2017 14:22:39 -0800 Subject: [PATCH 15/17] less magic --- interface/src/avatar/AvatarManager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index ff7180f95e..4eac5bc2a4 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -192,6 +192,10 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance; const float TIME_PENALTY = 0.080f; // seconds float age = (float)(startTime - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND) - TIME_PENALTY; + // NOTE: we are adding values of different units to get a single measure of "priority". + // Thus we multiply each component by a conversion "weight" that scales its units + // relative to the others. These weights are pure magic tuning and are hard coded in the + // relation below: (hint: unitary weights are not explicityly shown) float priority = apparentSize + 0.25f * cosineAngle + age; // decrement priority of avatars outside keyhole @@ -233,7 +237,8 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { uint64_t now = usecTimestampNow(); if (now < renderExpiry) { // we're within budget - bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; + const float OUT_OF_VIEW_THRESHOLD = 0.5f * OUT_OF_VIEW_PENALTY; + bool inView = sortData.priority > OUT_OF_VIEW_THRESHOLD; avatar->simulate(deltaTime, inView); avatar->updateRenderItem(pendingChanges); avatar->setLastRenderUpdateTime(startTime); From 82f52b9658e3dd41f1014b2f24ab23f13c53ffd8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 25 Jan 2017 10:52:12 -0800 Subject: [PATCH 16/17] fix bug: Avatar instance not getting deleted --- interface/src/avatar/AvatarManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 4eac5bc2a4..658ee8ed97 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -285,6 +285,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); + avatar->animateScaleChanges(deltaTime); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); // only remove from _avatarFades if we're sure its motionState has been removed from PhysicsEngine From 5783db910bc20098469d23fd59e856540fe8690e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 25 Jan 2017 10:57:48 -0800 Subject: [PATCH 17/17] remove some unhelpful trace profiling data --- interface/src/avatar/Avatar.cpp | 16 ---------------- interface/src/avatar/Avatar.h | 2 -- interface/src/avatar/AvatarManager.cpp | 6 ------ 3 files changed, 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index cdf9323ace..7ab1e7e8bd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -85,19 +85,6 @@ namespace render { } } -static uint64_t timeProcessingJoints = 0; -static int32_t numJointsProcessed = 0; - -float Avatar::getNumJointsProcessedPerSecond() { - float rate = 0.0f; - if (timeProcessingJoints > 0) { - rate = (float)(numJointsProcessed * USECS_PER_SECOND) / (float)timeProcessingJoints; - } - timeProcessingJoints = 0; - numJointsProcessed = 0; - return rate; -} - Avatar::Avatar(RigPointer rig) : AvatarData(), _skeletonOffset(0.0f), @@ -324,11 +311,8 @@ void Avatar::simulate(float deltaTime, bool inView) { { PROFILE_RANGE(simulation, "updateJoints"); if (inView && _hasNewJointData) { - uint64_t start = usecTimestampNow(); _skeletonModel->getRig()->copyJointsFromJointData(_jointData); _skeletonModel->simulate(deltaTime, true); - timeProcessingJoints += usecTimestampNow() - start; - numJointsProcessed += _jointData.size(); locationChanged(); // joints changed, so if there are any children, update them. _hasNewJointData = false; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index a6c5bbf16f..8f2b0817c1 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -58,8 +58,6 @@ class Avatar : public AvatarData { Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: - static float getNumJointsProcessedPerSecond(); - explicit Avatar(RigPointer rig = nullptr); ~Avatar(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 658ee8ed97..2d0860b355 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -213,7 +213,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { const uint64_t MAX_UPDATE_BUDGET = 2000; // usec uint64_t renderExpiry = startTime + RENDER_UPDATE_BUDGET; uint64_t maxExpiry = startTime + MAX_UPDATE_BUDGET; - size_t numAvatarsProcessed = sortedAvatars.size(); while (!sortedAvatars.empty()) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); @@ -258,11 +257,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges); simulateAvatarFades(deltaTime); - - numAvatarsProcessed -= sortedAvatars.size(); - float numAvatarsPerSec = (float)(numAvatarsProcessed * USECS_PER_SECOND) / (float)(usecTimestampNow() - startTime); - PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", { { "NumAvatarsPerSec", numAvatarsPerSec } }); - PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } }); } void AvatarManager::postUpdate(float deltaTime) {