Merge pull request #281 from HifiExperiments/parenting2

Improve performance of MyAvatar::simulate when you have lots of descendants
This commit is contained in:
kasenvr 2020-05-31 14:47:22 -04:00 committed by GitHub
commit 4cca7f6f75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 27 deletions

View file

@ -972,7 +972,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
recorder->recordFrame(FRAME_TYPE, toFrame(*this));
}
locationChanged(true, false);
locationChanged(true, true);
// if a entity-child of this avatar has moved outside of its queryAACube, update the cube and tell the entity server.
auto entityTreeRenderer = qApp->getEntities();
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
@ -981,16 +981,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
entityTree->withWriteLock([&] {
zoneInteractionProperties = entityTreeRenderer->getZoneInteractionProperties();
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
forEachDescendant([&](SpatiallyNestablePointer object) {
locationChanged(true, false);
// we need to update attached queryAACubes in our own local tree so point-select always works
// however we don't want to flood the update pipeline with AvatarEntity updates, so we assume
// others have all info required to properly update queryAACube of AvatarEntities on their end
EntityItemPointer entity = std::dynamic_pointer_cast<EntityItem>(object);
bool iShouldTellServer = !(entity && entity->isAvatarEntity());
const bool force = false;
entityTree->updateEntityQueryAACube(object, packetSender, force, iShouldTellServer);
});
entityTree->updateEntityQueryAACube(shared_from_this(), packetSender, false, true);
});
bool isPhysicsEnabled = qApp->isPhysicsEnabled();
bool zoneAllowsFlying = zoneInteractionProperties.first;

View file

@ -3194,21 +3194,30 @@ glm::vec3 EntityTree::getUnscaledDimensionsForID(const QUuid& id) {
return glm::vec3(1.0f);
}
void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,
AACube EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,
MovingEntitiesOperator& moveOperator, bool force, bool tellServer) {
glm::vec3 min(FLT_MAX);
glm::vec3 max(-FLT_MAX);
// if the queryBox has changed, tell the entity-server
EntityItemPointer entity = std::dynamic_pointer_cast<EntityItem>(object);
if (entity) {
bool queryAACubeChanged = false;
if (!entity->hasChildren()) {
// updateQueryAACube will also update all ancestors' AACubes, so we only need to call this for leaf nodes
queryAACubeChanged = entity->updateQueryAACube();
queryAACubeChanged = entity->updateQueryAACube(false);
AACube entityAACube = entity->getQueryAACube();
min = glm::min(min, entityAACube.getMinimumPoint());
max = glm::max(max, entityAACube.getMaximumPoint());
} else {
AACube oldCube = entity->getQueryAACube();
object->forEachChild([&](SpatiallyNestablePointer descendant) {
updateEntityQueryAACubeWorker(descendant, packetSender, moveOperator, force, tellServer);
AACube entityAACube = updateEntityQueryAACubeWorker(descendant, packetSender, moveOperator, force, tellServer);
min = glm::min(min, entityAACube.getMinimumPoint());
max = glm::max(max, entityAACube.getMaximumPoint());
});
queryAACubeChanged = oldCube != entity->getQueryAACube();
queryAACubeChanged = entity->updateQueryAACubeWithDescendantAACube(AACube(Extents(min, max)), false);
AACube newCube = entity->getQueryAACube();
min = glm::min(min, newCube.getMinimumPoint());
max = glm::max(max, newCube.getMaximumPoint());
}
if (queryAACubeChanged || force) {
@ -3217,9 +3226,10 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object,
if (success) {
moveOperator.addEntityToMoveList(entity, newCube);
}
// send an edit packet to update the entity-server about the queryAABox. We do this for domain-hosted
// entities as well as for avatar-entities; the packet-sender will route the update accordingly
if (tellServer && packetSender && (entity->isDomainEntity() || entity->isAvatarEntity())) {
// send an edit packet to update the entity-server about the queryAABox. We only do this for domain-hosted
// entities, as we don't want to flood the update pipeline with AvatarEntity updates, so we assume
// others have all info required to properly update queryAACube of AvatarEntities on their end
if (tellServer && packetSender && entity->isDomainEntity()) {
quint64 now = usecTimestampNow();
EntityItemProperties properties = entity->getProperties();
properties.setQueryAACubeDirty();
@ -3234,7 +3244,16 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object,
entity->markDirtyFlags(Simulation::DIRTY_POSITION);
entityChanged(entity);
}
} else {
// if we're called on a non-entity, we might still have entity descendants
object->forEachChild([&](SpatiallyNestablePointer descendant) {
AACube entityAACube = updateEntityQueryAACubeWorker(descendant, packetSender, moveOperator, force, tellServer);
min = glm::min(min, entityAACube.getMinimumPoint());
max = glm::max(max, entityAACube.getMaximumPoint());
});
}
return AACube(Extents(min, max));
}
void EntityTree::updateEntityQueryAACube(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,

View file

@ -400,8 +400,9 @@ private:
std::map<QString, QString> _namedPaths;
void updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,
MovingEntitiesOperator& moveOperator, bool force, bool tellServer);
// Return an AACube containing object and all its entity descendants
AACube updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,
MovingEntitiesOperator& moveOperator, bool force, bool tellServer);
};
void convertGrabUserDataToProperties(EntityItemProperties& properties);

View file

@ -1144,7 +1144,7 @@ AACube SpatiallyNestable::calculateInitialQueryAACube(bool& success) {
}
}
bool SpatiallyNestable::updateQueryAACube() {
bool SpatiallyNestable::updateQueryAACube(bool updateParent) {
if (!queryAACubeNeedsUpdate()) {
return false;
}
@ -1171,9 +1171,39 @@ bool SpatiallyNestable::updateQueryAACube() {
_queryAACubeSet = true;
auto parent = getParentPointer(success);
if (success && parent) {
parent->updateQueryAACube();
if (updateParent) {
auto parent = getParentPointer(success);
if (success && parent) {
parent->updateQueryAACube();
}
}
return true;
}
bool SpatiallyNestable::updateQueryAACubeWithDescendantAACube(const AACube& descendantAACube, bool updateParent) {
if (!queryAACubeNeedsUpdateWithDescendantAACube(descendantAACube)) {
return false;
}
bool success;
AACube initialQueryAACube = calculateInitialQueryAACube(success);
if (!success) {
return false;
}
_queryAACube = initialQueryAACube;
_queryAACubeIsPuffed = shouldPuffQueryAACube();
_queryAACube += descendantAACube.getMinimumPoint();
_queryAACube += descendantAACube.getMaximumPoint();
_queryAACubeSet = true;
if (updateParent) {
auto parent = getParentPointer(success);
if (success && parent) {
parent->updateQueryAACube();
}
}
return true;
@ -1216,6 +1246,24 @@ bool SpatiallyNestable::queryAACubeNeedsUpdate() const {
return childNeedsUpdate;
}
bool SpatiallyNestable::queryAACubeNeedsUpdateWithDescendantAACube(const AACube& descendantAACube) const {
if (!_queryAACubeSet) {
return true;
}
bool success;
AACube maxAACube = getMaximumAACube(success);
if (success && !_queryAACube.contains(maxAACube)) {
return true;
}
if (shouldPuffQueryAACube() != _queryAACubeIsPuffed) {
return true;
}
return !_queryAACube.contains(descendantAACube);
}
AACube SpatiallyNestable::getQueryAACube(bool& success) const {
if (_queryAACubeSet) {
success = true;

View file

@ -117,8 +117,10 @@ public:
virtual void setQueryAACube(const AACube& queryAACube);
virtual bool queryAACubeNeedsUpdate() const;
virtual bool queryAACubeNeedsUpdateWithDescendantAACube(const AACube& descendantAACube) const;
virtual bool shouldPuffQueryAACube() const { return false; }
bool updateQueryAACube();
bool updateQueryAACube(bool updateParent = true);
bool updateQueryAACubeWithDescendantAACube(const AACube& descendentAACube, bool updateParent = true);
void forceQueryAACubeUpdate() { _queryAACubeSet = false; }
virtual AACube getQueryAACube(bool& success) const;
virtual AACube getQueryAACube() const;