Merge pull request from AndrewMeadows/faster-update-renderables

Faster renderables update
This commit is contained in:
Brad Hefta-Gaub 2017-10-20 13:43:08 -07:00 committed by GitHub
commit d6ad389dab
15 changed files with 183 additions and 95 deletions

View file

@ -25,7 +25,7 @@ The above dependencies will be downloaded, built, linked and included automatica
These are not placed in your normal build tree when doing an out of source build so that they do not need to be re-downloaded and re-compiled every time the CMake build folder is cleared. Should you want to force a re-download and re-compile of a specific external, you can simply remove that directory from the appropriate subfolder in `build/ext`. Should you want to force a re-download and re-compile of all externals, just remove the `build/ext` folder.
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE_LOCAL_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE\_LOCAL\_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
### OS Specific Build Guides

View file

@ -2392,8 +2392,8 @@ void Application::initializeUi() {
}
void Application::updateCamera(RenderArgs& renderArgs) {
PROFILE_RANGE(render, "/updateCamera");
PerformanceTimer perfTimer("CameraUpdates");
PROFILE_RANGE(render, __FUNCTION__);
PerformanceTimer perfTimer("updateCamera");
glm::vec3 boomOffset;
auto myAvatar = getMyAvatar();
@ -2609,7 +2609,7 @@ void Application::resizeGL() {
}
void Application::handleSandboxStatus(QNetworkReply* reply) {
PROFILE_RANGE(render, "HandleSandboxStatus");
PROFILE_RANGE(render, __FUNCTION__);
bool sandboxIsRunning = SandboxUtils::readStatus(reply->readAll());
qDebug() << "HandleSandboxStatus" << sandboxIsRunning;
@ -4638,7 +4638,6 @@ void Application::updateDialogs(float deltaTime) const {
static bool domainLoadingInProgress = false;
void Application::update(float deltaTime) {
PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_renderFrameCount + 1);
if (!_physicsEnabled) {
@ -4833,11 +4832,11 @@ void Application::update(float deltaTime) {
QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
{
PROFILE_RANGE_EX(simulation_physics, "Physics", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation_physics, "Physics");
PerformanceTimer perfTimer("physics");
if (_physicsEnabled) {
{
PROFILE_RANGE_EX(simulation_physics, "UpdateStates", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation_physics, "PreStep");
PerformanceTimer perfTimer("updateStates)");
static VectorOfMotionStates motionStates;
@ -4871,14 +4870,14 @@ void Application::update(float deltaTime) {
});
}
{
PROFILE_RANGE_EX(simulation_physics, "StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation_physics, "Step");
PerformanceTimer perfTimer("stepSimulation");
getEntities()->getTree()->withWriteLock([&] {
_physicsEngine->stepSimulation();
});
}
{
PROFILE_RANGE_EX(simulation_physics, "HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation_physics, "PostStep");
PerformanceTimer perfTimer("harvestChanges");
if (_physicsEngine->hasOutgoingChanges()) {
// grab the collision events BEFORE handleOutgoingChanges() because at this point
@ -4886,6 +4885,7 @@ void Application::update(float deltaTime) {
auto& collisionEvents = _physicsEngine->getCollisionEvents();
getEntities()->getTree()->withWriteLock([&] {
PROFILE_RANGE(simulation_physics, "Harvest");
PerformanceTimer perfTimer("handleOutgoingChanges");
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
@ -4898,18 +4898,25 @@ void Application::update(float deltaTime) {
if (!_aboutToQuit) {
// handleCollisionEvents() AFTER handleOutgoinChanges()
PerformanceTimer perfTimer("entities");
avatarManager->handleCollisionEvents(collisionEvents);
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
// deadlock.)
_entitySimulation->handleCollisionEvents(collisionEvents);
{
PROFILE_RANGE(simulation_physics, "CollisionEvents");
PerformanceTimer perfTimer("entities");
avatarManager->handleCollisionEvents(collisionEvents);
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
// deadlock.)
_entitySimulation->handleCollisionEvents(collisionEvents);
}
PROFILE_RANGE(simulation_physics, "UpdateEntities");
// NOTE: the getEntities()->update() call below will wait for lock
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
getEntities()->update(true); // update the models...
}
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
{
PROFILE_RANGE(simulation_physics, "MyAvatar");
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
}
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) {
@ -4928,13 +4935,13 @@ void Application::update(float deltaTime) {
// AvatarManager update
{
{
PROFILE_RANGE(simulation, "OtherAvatars");
PerformanceTimer perfTimer("otherAvatars");
PROFILE_RANGE_EX(simulation, "OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
avatarManager->updateOtherAvatars(deltaTime);
}
{
PROFILE_RANGE_EX(simulation, "MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation, "MyAvatar");
PerformanceTimer perfTimer("MyAvatar");
qApp->updateMyAvatarLookAtPosition();
avatarManager->updateMyAvatar(deltaTime);

View file

@ -32,6 +32,7 @@
#include "AnimUtil.h"
#include "IKTarget.h"
static int nextRigId = 1;
static std::map<int, Rig*> rigRegistry;
static std::mutex rigRegistryMutex;
@ -999,14 +1000,13 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
}
void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, const glm::mat4& rigToWorldTransform) {
PROFILE_RANGE_EX(simulation_animation_detail, __FUNCTION__, 0xffff00ff, 0);
PerformanceTimer perfTimer("updateAnimations");
DETAILED_PROFILE_RANGE_EX(simulation_animation_detail, __FUNCTION__, 0xffff00ff, 0);
DETAILED_PERFORMANCE_TIMER("updateAnimations");
setModelOffset(rootTransform);
if (_animNode && _enabledAnimations) {
PerformanceTimer perfTimer("handleTriggers");
DETAILED_PERFORMANCE_TIMER("handleTriggers");
updateAnimationStateHandlers();
_animVars.setRigToGeometryTransform(_rigToGeometryTransform);
@ -1658,7 +1658,7 @@ bool Rig::getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const
}
void Rig::applyOverridePoses() {
PerformanceTimer perfTimer("override");
DETAILED_PERFORMANCE_TIMER("override");
if (_numOverrides == 0 || !_animSkeleton) {
return;
}
@ -1675,7 +1675,7 @@ void Rig::applyOverridePoses() {
}
void Rig::buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut) {
PerformanceTimer perfTimer("buildAbsolute");
DETAILED_PERFORMANCE_TIMER("buildAbsolute");
if (!_animSkeleton) {
return;
}
@ -1730,8 +1730,9 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
}
void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
PerformanceTimer perfTimer("copyJoints");
PROFILE_RANGE(simulation_animation_detail, "copyJoints");
DETAILED_PROFILE_RANGE(simulation_animation_detail, "copyJoints");
DETAILED_PERFORMANCE_TIMER("copyJoints");
if (!_animSkeleton) {
return;
}

View file

@ -160,6 +160,8 @@ void EntityTreeRenderer::shutdown() {
}
void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction) {
PROFILE_RANGE_EX(simulation_physics, "Add", 0xffff00ff, (uint64_t)_entitiesToAdd.size());
PerformanceTimer pt("add");
// Clear any expired entities
// FIXME should be able to use std::remove_if, but it fails due to some
// weird compilation error related to EntityItemID assignment operators
@ -203,6 +205,8 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
}
void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction) {
PROFILE_RANGE_EX(simulation_physics, "Change", 0xffff00ff, (uint64_t)_changedEntities.size());
PerformanceTimer pt("change");
std::unordered_set<EntityItemID> changedEntities;
_changedEntitiesGuard.withWriteLock([&] {
#if 0
@ -223,6 +227,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
}
if (!_renderablesToUpdate.empty()) {
PROFILE_RANGE_EX(simulation_physics, "UpdateRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size());
for (const auto& entry : _renderablesToUpdate) {
const auto& renderable = entry.second;
renderable->updateInScene(scene, transaction);
@ -232,6 +237,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
}
void EntityTreeRenderer::update(bool simulate) {
PROFILE_RANGE(simulation_physics, "ETR::update");
PerformanceTimer perfTimer("ETRupdate");
if (_tree && !_shuttingDown) {
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
@ -239,22 +245,14 @@ void EntityTreeRenderer::update(bool simulate) {
// Update the rendereable entities as needed
{
PROFILE_RANGE(simulation_physics, "Scene");
PerformanceTimer sceneTimer("scene");
auto scene = _viewState->getMain3DScene();
if (scene) {
render::Transaction transaction;
{
PerformanceTimer pt("add");
addPendingEntities(scene, transaction);
}
{
PerformanceTimer pt("change");
updateChangedEntities(scene, transaction);
}
{
PerformanceTimer pt("enqueue");
scene->enqueueTransaction(transaction);
}
addPendingEntities(scene, transaction);
updateChangedEntities(scene, transaction);
scene->enqueueTransaction(transaction);
}
}
@ -336,7 +334,8 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityIt
}
bool EntityTreeRenderer::checkEnterLeaveEntities() {
PerformanceTimer perfTimer("checkEnterLeaveEntities");
PROFILE_RANGE(simulation_physics, "EnterLeave");
PerformanceTimer perfTimer("enterLeave");
auto now = usecTimestampNow();
bool didUpdate = false;

View file

@ -26,6 +26,7 @@
#include "RenderableWebEntityItem.h"
#include "RenderableZoneEntityItem.h"
using namespace render;
using namespace render::entities;
@ -271,6 +272,7 @@ void EntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& tra
}
void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& transaction) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
if (!isValidRenderItem()) {
return;
}
@ -330,6 +332,7 @@ bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity
}
void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
withWriteLock([&] {
auto transparent = isTransparent();
if (_prevIsTransparent && !transparent) {

View file

@ -34,6 +34,7 @@
#include "EntityTreeRenderer.h"
#include "EntitiesRendererLogging.h"
static CollisionRenderMeshCache collisionMeshCache;
void ModelEntityWrapper::setModel(const ModelPointer& model) {
@ -107,6 +108,7 @@ QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextu
}
void RenderableModelEntityItem::doInitialModelSimulation() {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
ModelPointer model = getModel();
if (!model) {
return;
@ -123,11 +125,11 @@ void RenderableModelEntityItem::doInitialModelSimulation() {
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
model->setRotation(getRotation());
model->setTranslation(getPosition());
{
PerformanceTimer perfTimer("model->simulate");
if (_needsInitialSimulation) {
model->simulate(0.0f);
_needsInitialSimulation = false;
}
_needsInitialSimulation = false;
}
void RenderableModelEntityItem::autoResizeJointArrays() {
@ -138,6 +140,7 @@ void RenderableModelEntityItem::autoResizeJointArrays() {
}
bool RenderableModelEntityItem::needsUpdateModelBounds() const {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
ModelPointer model = getModel();
if (!hasModel() || !model) {
return false;
@ -151,7 +154,7 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
return true;
}
if (isMovingRelativeToParent() || isAnimatingSomething()) {
if (isAnimatingSomething()) {
return true;
}
@ -178,13 +181,61 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
}
}
return false;
return model->needsReload();
}
void RenderableModelEntityItem::updateModelBounds() {
if (needsUpdateModelBounds()) {
doInitialModelSimulation();
DETAILED_PROFILE_RANGE(simulation_physics, "updateModelBounds");
if (!_dimensionsInitialized || !hasModel()) {
return;
}
ModelPointer model = getModel();
if (!model || !model->isLoaded()) {
return;
}
bool updateRenderItems = false;
if (model->needsReload()) {
model->updateGeometry();
updateRenderItems = true;
}
if (model->getScaleToFitDimensions() != getDimensions() ||
model->getRegistrationPoint() != getRegistrationPoint()) {
// The machinery for updateModelBounds will give existing models the opportunity to fix their
// translation/rotation/scale/registration. The first two are straightforward, but the latter two
// have guards to make sure they don't happen after they've already been set. Here we reset those guards.
// This doesn't cause the entity values to change -- it just allows the model to match once it comes in.
model->setScaleToFit(false, getDimensions());
model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
// now recalculate the bounds and registration
model->setScaleToFit(true, getDimensions());
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
updateRenderItems = true;
}
bool success;
auto transform = getTransform(success);
if (success && (model->getTranslation() != transform.getTranslation() ||
model->getRotation() != transform.getRotation())) {
model->setTransformNoUpdateRenderItems(transform);
updateRenderItems = true;
}
if (_needsInitialSimulation || _needsJointSimulation || isAnimatingSomething()) {
// NOTE: on isAnimatingSomething() we need to call Model::simulate() which calls Rig::updateRig()
// TODO: there is opportunity to further optimize the isAnimatingSomething() case.
model->simulate(0.0f);
_needsInitialSimulation = false;
_needsJointSimulation = false;
updateRenderItems = true;
}
if (updateRenderItems) {
model->updateRenderItems();
}
}
@ -293,7 +344,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() const {
// we have both URLs AND both geometries AND they are both fully loaded.
if (_needsInitialSimulation) {
// the _model's offset will be wrong until _needsInitialSimulation is false
PerformanceTimer perfTimer("_model->simulate");
DETAILED_PERFORMANCE_TIMER("_model->simulate");
const_cast<RenderableModelEntityItem*>(this)->doInitialModelSimulation();
}
return true;
@ -839,7 +890,7 @@ void RenderableModelEntityItem::setJointTranslationsSet(const QVector<bool>& tra
}
void RenderableModelEntityItem::locationChanged(bool tellPhysics) {
PerformanceTimer pertTimer("locationChanged");
DETAILED_PERFORMANCE_TIMER("locationChanged");
EntityItem::locationChanged(tellPhysics);
auto model = getModel();
if (model && model->isLoaded()) {
@ -880,7 +931,6 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
return;
}
// relay any inbound joint changes from scripts/animation/network to the model/rig
_jointDataLock.withWriteLock([&] {
for (int index = 0; index < _localJointData.size(); ++index) {
@ -897,10 +947,6 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
});
}
bool RenderableModelEntityItem::isAnimatingSomething() const {
return !getAnimationURL().isEmpty() && getAnimationIsPlaying() && getAnimationFPS() != 0.0f;
}
using namespace render;
using namespace render::entities;
@ -1124,6 +1170,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
}
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
if (_hasModel != entity->hasModel()) {
_hasModel = entity->hasModel();
}
@ -1202,9 +1249,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
}
if (entity->needsUpdateModelBounds()) {
entity->updateModelBounds();
}
entity->updateModelBounds();
if (model->isVisible() != _visible) {
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
@ -1212,13 +1257,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
// so most of the time we don't do anything in this function.
model->setVisibleInScene(_visible, scene);
}
// TODO? early exit here when not visible?
//entity->doInitialModelSimulation();
if (model->needsFixupInScene()) {
model->removeFromScene(scene, transaction);
render::Item::Status::Getters statusGetters;
makeStatusGetters(entity, statusGetters);
model->addToScene(scene, transaction, statusGetters);
{
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
if (model->needsFixupInScene()) {
model->removeFromScene(scene, transaction);
render::Item::Status::Getters statusGetters;
makeStatusGetters(entity, statusGetters);
model->addToScene(scene, transaction, statusGetters);
}
}
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
@ -1227,16 +1275,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
model->updateRenderItems();
}
// make a copy of the animation properites
auto newAnimationProperties = entity->getAnimationProperties();
if (newAnimationProperties != _renderAnimationProperties) {
withWriteLock([&] {
_renderAnimationProperties = newAnimationProperties;
_currentFrame = _renderAnimationProperties.getCurrentFrame();
});
{
DETAILED_PROFILE_RANGE(simulation_physics, "CheckAnimation");
// make a copy of the animation properites
auto newAnimationProperties = entity->getAnimationProperties();
if (newAnimationProperties != _renderAnimationProperties) {
withWriteLock([&] {
_renderAnimationProperties = newAnimationProperties;
_currentFrame = _renderAnimationProperties.getCurrentFrame();
});
}
}
if (_animating) {
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
if (!jointsMapped()) {
mapJoints(entity, model->getJointNames());
}
@ -1247,8 +1299,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
void ModelEntityRenderer::doRender(RenderArgs* args) {
PROFILE_RANGE(render_detail, "MetaModelRender");
PerformanceTimer perfTimer("RMEIrender");
DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender");
DETAILED_PERFORMANCE_TIMER("RMEIrender");
ModelPointer model;
withReadLock([&]{

View file

@ -108,7 +108,6 @@ public:
private:
bool needsUpdateModelBounds() const;
bool isAnimatingSomething() const;
void autoResizeJointArrays();
void copyAnimationJointDataToModel();

View file

@ -9,9 +9,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <AACube.h>
#include "EntitySimulation.h"
#include <AACube.h>
#include <Profile.h>
#include "EntitiesLogging.h"
#include "MovingEntitiesOperator.h"
@ -27,6 +29,7 @@ void EntitySimulation::setEntityTree(EntityTreePointer tree) {
}
void EntitySimulation::updateEntities() {
PROFILE_RANGE(simulation_physics, "ES::updateEntities");
QMutexLocker lock(&_mutex);
quint64 now = usecTimestampNow();
@ -35,8 +38,12 @@ void EntitySimulation::updateEntities() {
callUpdateOnEntitiesThatNeedIt(now);
moveSimpleKinematics(now);
updateEntitiesInternal(now);
PerformanceTimer perfTimer("sortingEntities");
sortEntitiesThatMoved();
{
PROFILE_RANGE(simulation_physics, "Sort");
PerformanceTimer perfTimer("sortingEntities");
sortEntitiesThatMoved();
}
}
void EntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) {
@ -258,6 +265,7 @@ void EntitySimulation::clearEntities() {
}
void EntitySimulation::moveSimpleKinematics(const quint64& now) {
PROFILE_RANGE_EX(simulation_physics, "Kinematics", 0xffff00ff, (uint64_t)_simpleKinematicEntities.size());
SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin();
while (itemItr != _simpleKinematicEntities.end()) {
EntityItemPointer entity = *itemItr;

View file

@ -15,8 +15,9 @@
#include <QtScript/QScriptEngine>
#include <PerfStat.h>
#include <Extents.h>
#include <PerfStat.h>
#include <Profile.h>
#include "EntitySimulation.h"
#include "VariantMapToScriptValue.h"
@ -1370,6 +1371,7 @@ void EntityTree::entityChanged(EntityItemPointer entity) {
void EntityTree::fixupNeedsParentFixups() {
PROFILE_RANGE(simulation_physics, "FixupParents");
MovingEntitiesOperator moveOperator;
QWriteLocker locker(&_needsParentFixupLock);
@ -1459,6 +1461,7 @@ void EntityTree::addToNeedsParentFixupList(EntityItemPointer entity) {
}
void EntityTree::update(bool simulate) {
PROFILE_RANGE(simulation_physics, "ET::update");
fixupNeedsParentFixups();
if (simulate && _simulation) {
withWriteLock([&] {

View file

@ -557,12 +557,6 @@ void ModelEntityItem::setAnimationLoop(bool loop) {
});
}
bool ModelEntityItem::getAnimationLoop() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getLoop();
});
}
void ModelEntityItem::setAnimationHold(bool hold) {
withWriteLock([&] {
_animationProperties.setHold(hold);
@ -610,8 +604,10 @@ float ModelEntityItem::getAnimationCurrentFrame() const {
});
}
float ModelEntityItem::getAnimationFPS() const {
bool ModelEntityItem::isAnimatingSomething() const {
return resultWithReadLock<float>([&] {
return _animationProperties.getFPS();
});
return !_animationProperties.getURL().isEmpty() &&
_animationProperties.getRunning() &&
(_animationProperties.getFPS() != 0.0f);
});
}

View file

@ -90,7 +90,6 @@ public:
bool getAnimationAllowTranslation() const { return _animationProperties.getAllowTranslation(); };
void setAnimationLoop(bool loop);
bool getAnimationLoop() const;
void setAnimationHold(bool hold);
bool getAnimationHold() const;
@ -101,10 +100,9 @@ public:
void setAnimationLastFrame(float lastFrame);
float getAnimationLastFrame() const;
bool getAnimationIsPlaying() const;
float getAnimationCurrentFrame() const;
float getAnimationFPS() const;
bool isAnimatingSomething() const;
static const QString DEFAULT_TEXTURES;
const QString getTextures() const;
@ -123,7 +121,6 @@ public:
QVector<bool> getJointRotationsSet() const;
QVector<glm::vec3> getJointTranslations() const;
QVector<bool> getJointTranslationsSet() const;
bool isAnimatingSomething() const;
private:
void setAnimationSettings(const QString& value); // only called for old bitstream format

View file

@ -121,8 +121,6 @@ bool Model::needsFixupInScene() const {
return (_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded();
}
// TODO?: should we combine translation and rotation into single method to avoid double-work?
// (figure out where we call these)
void Model::setTranslation(const glm::vec3& translation) {
_translation = translation;
updateRenderItems();
@ -133,6 +131,14 @@ void Model::setRotation(const glm::quat& rotation) {
updateRenderItems();
}
// temporary HACK: set transform while avoiding implicit calls to updateRenderItems()
// TODO: make setRotation() and friends set flag to be used later to decide to updateRenderItems()
void Model::setTransformNoUpdateRenderItems(const Transform& transform) {
_translation = transform.getTranslation();
_rotation = transform.getRotation();
// DO NOT call updateRenderItems() here!
}
Transform Model::getTransform() const {
if (_spatiallyNestableOverride) {
bool success;
@ -957,7 +963,7 @@ Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointe
}
void Blender::run() {
PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
QVector<glm::vec3> vertices, normals;
if (_model) {
int offset = 0;
@ -1078,8 +1084,7 @@ void Model::snapToRegistrationPoint() {
}
void Model::simulate(float deltaTime, bool fullUpdate) {
PROFILE_RANGE(simulation_detail, __FUNCTION__);
PerformanceTimer perfTimer("Model::simulate");
DETAILED_PROFILE_RANGE(simulation_detail, __FUNCTION__);
fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit)
|| (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);
@ -1117,7 +1122,7 @@ void Model::computeMeshPartLocalBounds() {
// virtual
void Model::updateClusterMatrices() {
PerformanceTimer perfTimer("Model::updateClusterMatrices");
DETAILED_PERFORMANCE_TIMER("Model::updateClusterMatrices");
if (!_needsUpdateClusterMatrices || !isLoaded()) {
return;

View file

@ -206,6 +206,7 @@ public:
void setTranslation(const glm::vec3& translation);
void setRotation(const glm::quat& rotation);
void setTransformNoUpdateRenderItems(const Transform& transform); // temporary HACK
const glm::vec3& getTranslation() const { return _translation; }
const glm::quat& getRotation() const { return _rotation; }

View file

@ -97,5 +97,12 @@ private:
static QMap<QString, PerformanceTimerRecord> _records;
};
// uncomment WANT_DETAILED_PERFORMANCE_TIMERS definition to enable performance timers in high-frequency contexts
//#define WANT_DETAILED_PERFORMANCE_TIMERS
#ifdef WANT_DETAILED_PERFORMANCE_TIMERS
#define DETAILED_PERFORMANCE_TIMER(name) PerformanceTimer detailedPerformanceTimer(name);
#else // WANT_DETAILED_PERFORMANCE_TIMERS
#define DETAILED_PERFORMANCE_TIMER(name) ; // no-op
#endif // WANT_DETAILED_PERFORMANCE_TIMERS
#endif // hifi_PerfStat_h

View file

@ -108,4 +108,14 @@ inline void metadata(const QString& metadataType, const QVariantMap& args) {
#define SAMPLE_PROFILE_COUNTER(chance, category, name, ...) if (randFloat() <= chance) { PROFILE_COUNTER(category, name, ##__VA_ARGS__); }
#define SAMPLE_PROFILE_INSTANT(chance, category, name, ...) if (randFloat() <= chance) { PROFILE_INSTANT(category, name, ##__VA_ARGS__); }
// uncomment WANT_DETAILED_PROFILING definition to enable profiling in high-frequency contexts
//#define WANT_DETAILED_PROFILING
#ifdef WANT_DETAILED_PROFILING
#define DETAILED_PROFILE_RANGE(category, name) Duration profileRangeThis(trace_##category(), name);
#define DETAILED_PROFILE_RANGE_EX(category, name, argbColor, payload, ...) Duration profileRangeThis(trace_##category(), name, argbColor, (uint64_t)payload, ##__VA_ARGS__);
#else // WANT_DETAILED_PROFILING
#define DETAILED_PROFILE_RANGE(category, name) ; // no-op
#define DETAILED_PROFILE_RANGE_EX(category, name, argbColor, payload, ...) ; // no-op
#endif // WANT_DETAILED_PROFILING
#endif