split work out of EntityTree::update(), call it preUpdate()

This commit is contained in:
Andrew Meadows 2019-04-26 11:55:50 -07:00
parent 3eed8218ca
commit 915cbb69df
14 changed files with 76 additions and 35 deletions

View file

@ -37,6 +37,7 @@ void EntityTreeHeadlessViewer::update() {
if (_tree) { if (_tree) {
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree); EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
tree->withTryWriteLock([&] { tree->withTryWriteLock([&] {
tree->preUpdate();
tree->update(); tree->update();
}); });
} }

View file

@ -6399,6 +6399,8 @@ void Application::update(float deltaTime) {
PROFILE_RANGE(simulation_physics, "Simulation"); PROFILE_RANGE(simulation_physics, "Simulation");
PerformanceTimer perfTimer("simulation"); PerformanceTimer perfTimer("simulation");
getEntities()->preUpdate();
if (_physicsEnabled) { if (_physicsEnabled) {
auto t0 = std::chrono::high_resolution_clock::now(); auto t0 = std::chrono::high_resolution_clock::now();
auto t1 = t0; auto t1 = t0;

View file

@ -474,6 +474,12 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
} }
} }
void EntityTreeRenderer::preUpdate() {
if (_tree && !_shuttingDown) {
_tree->preUpdate();
}
}
void EntityTreeRenderer::update(bool simulate) { void EntityTreeRenderer::update(bool simulate) {
PROFILE_RANGE(simulation_physics, "ETR::update"); PROFILE_RANGE(simulation_physics, "ETR::update");
PerformanceTimer perfTimer("ETRupdate"); PerformanceTimer perfTimer("ETRupdate");

View file

@ -78,6 +78,7 @@ public:
void setSetPrecisionPickingOperator(std::function<void(unsigned int, bool)> setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; } void setSetPrecisionPickingOperator(std::function<void(unsigned int, bool)> setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; }
void shutdown(); void shutdown();
void preUpdate();
void update(bool simulate); void update(bool simulate);
EntityTreePointer getTree() { return std::static_pointer_cast<EntityTree>(_tree); } EntityTreePointer getTree() { return std::static_pointer_cast<EntityTree>(_tree); }

View file

@ -176,17 +176,26 @@ void EntitySimulation::addEntity(EntityItemPointer entity) {
void EntitySimulation::changeEntity(EntityItemPointer entity) { void EntitySimulation::changeEntity(EntityItemPointer entity) {
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);
assert(entity); assert(entity);
if (!entity->isSimulated()) { _changedEntities.insert(entity);
// This entity was either never added to the simulation or has been removed }
// (probably for pending delete), so we don't want to keep a pointer to it
// on any internal lists.
return;
}
void EntitySimulation::processChangedEntities() {
QMutexLocker lock(&_mutex);
PROFILE_RANGE_EX(simulation_physics, "processChangedEntities", 0xffff00ff, (uint64_t)_changedEntities.size());
for (auto& entity : _changedEntities) {
if (entity->isSimulated()) {
processChangedEntity(entity);
}
}
_changedEntities.clear();
}
void EntitySimulation::processChangedEntity(const EntityItemPointer& entity) {
uint32_t dirtyFlags = entity->getDirtyFlags();
/* TODO? maybe add to _entitiesToSort when DIRTY_POSITION is set?
// Although it is not the responsibility of the EntitySimulation to sort the tree for EXTERNAL changes // Although it is not the responsibility of the EntitySimulation to sort the tree for EXTERNAL changes
// it IS responsibile for triggering deletes for entities that leave the bounds of the domain, hence // it IS responsibile for triggering deletes for entities that leave the bounds of the domain, hence
// we must check for that case here, however we rely on the change event to have set DIRTY_POSITION flag. // we must check for that case here, however we rely on the change event to have set DIRTY_POSITION flag.
uint32_t dirtyFlags = entity->getDirtyFlags();
if (dirtyFlags & Simulation::DIRTY_POSITION) { if (dirtyFlags & Simulation::DIRTY_POSITION) {
AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE), (float)TREE_SCALE); AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE), (float)TREE_SCALE);
bool success; bool success;
@ -198,25 +207,29 @@ void EntitySimulation::changeEntity(EntityItemPointer entity) {
return; return;
} }
} }
*/
if (dirtyFlags & Simulation::DIRTY_LIFETIME) { if (dirtyFlags & (Simulation::DIRTY_LIFETIME | Simulation::DIRTY_UPDATEABLE)) {
if (entity->isMortal()) { if (dirtyFlags & Simulation::DIRTY_LIFETIME) {
_mortalEntities.insert(entity); if (entity->isMortal()) {
uint64_t expiry = entity->getExpiry(); _mortalEntities.insert(entity);
if (expiry < _nextExpiry) { uint64_t expiry = entity->getExpiry();
_nextExpiry = expiry; if (expiry < _nextExpiry) {
_nextExpiry = expiry;
}
} else {
_mortalEntities.remove(entity);
} }
} else {
_mortalEntities.remove(entity);
} }
entity->clearDirtyFlags(Simulation::DIRTY_LIFETIME); if (dirtyFlags & Simulation::DIRTY_UPDATEABLE) {
if (entity->needsToCallUpdate()) {
_entitiesToUpdate.insert(entity);
} else {
_entitiesToUpdate.remove(entity);
}
}
entity->clearDirtyFlags(Simulation::DIRTY_LIFETIME | Simulation::DIRTY_UPDATEABLE);
} }
if (entity->needsToCallUpdate()) {
_entitiesToUpdate.insert(entity);
} else {
_entitiesToUpdate.remove(entity);
}
changeEntityInternal(entity);
} }
void EntitySimulation::clearEntities() { void EntitySimulation::clearEntities() {

View file

@ -13,6 +13,7 @@
#define hifi_EntitySimulation_h #define hifi_EntitySimulation_h
#include <limits> #include <limits>
#include <unordered_set>
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QSet> #include <QSet>
@ -82,13 +83,15 @@ public:
/// \param entity pointer to EntityItem that needs to be put on the entitiesToDelete list and removed from others. /// \param entity pointer to EntityItem that needs to be put on the entitiesToDelete list and removed from others.
virtual void prepareEntityForDelete(EntityItemPointer entity); virtual void prepareEntityForDelete(EntityItemPointer entity);
void processChangedEntities();
protected: protected:
// These pure virtual methods are protected because they are not to be called will-nilly. The base class // These pure virtual methods are protected because they are not to be called will-nilly. The base class
// calls them in the right places. // calls them in the right places.
virtual void updateEntitiesInternal(uint64_t now) = 0; virtual void updateEntitiesInternal(uint64_t now) = 0;
virtual void addEntityInternal(EntityItemPointer entity) = 0; virtual void addEntityInternal(EntityItemPointer entity) = 0;
virtual void removeEntityInternal(EntityItemPointer entity); virtual void removeEntityInternal(EntityItemPointer entity);
virtual void changeEntityInternal(EntityItemPointer entity) = 0; virtual void processChangedEntity(const EntityItemPointer& entity);
virtual void clearEntitiesInternal() = 0; virtual void clearEntitiesInternal() = 0;
void expireMortalEntities(uint64_t now); void expireMortalEntities(uint64_t now);
@ -114,11 +117,11 @@ private:
// We maintain multiple lists, each for its distinct purpose. // We maintain multiple lists, each for its distinct purpose.
// An entity may be in more than one list. // An entity may be in more than one list.
std::unordered_set<EntityItemPointer> _changedEntities; // all changes this frame
SetOfEntities _allEntities; // tracks all entities added the simulation SetOfEntities _allEntities; // tracks all entities added the simulation
SetOfEntities _mortalEntities; // entities that have an expiry SetOfEntities _mortalEntities; // entities that have an expiry
uint64_t _nextExpiry; uint64_t _nextExpiry;
SetOfEntities _entitiesToUpdate; // entities that need to call EntityItem::update() SetOfEntities _entitiesToUpdate; // entities that need to call EntityItem::update()
}; };

View file

@ -2188,11 +2188,19 @@ void EntityTree::addToNeedsParentFixupList(EntityItemPointer entity) {
_needsParentFixup.append(entity); _needsParentFixup.append(entity);
} }
void EntityTree::preUpdate() {
withWriteLock([&] {
fixupNeedsParentFixups();
if (_simulation) {
_simulation->processChangedEntities();
}
});
}
void EntityTree::update(bool simulate) { void EntityTree::update(bool simulate) {
PROFILE_RANGE(simulation_physics, "UpdateTree"); PROFILE_RANGE(simulation_physics, "UpdateTree");
PerformanceTimer perfTimer("updateTree"); PerformanceTimer perfTimer("updateTree");
withWriteLock([&] { withWriteLock([&] {
fixupNeedsParentFixups();
if (simulate && _simulation) { if (simulate && _simulation) {
_simulation->updateEntities(); _simulation->updateEntities();
{ {

View file

@ -109,9 +109,10 @@ public:
virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const override; virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const override;
virtual void update() override { update(true); } // Why preUpdate() and update()?
// Because sometimes we need to do stuff between the two.
void update(bool simulate); void preUpdate() override;
void update(bool simulate = true) override;
// The newer API... // The newer API...
void postAddEntity(EntityItemPointer entityItem); void postAddEntity(EntityItemPointer entityItem);

View file

@ -85,7 +85,9 @@ void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) {
_entitiesThatNeedSimulationOwner.remove(entity); _entitiesThatNeedSimulationOwner.remove(entity);
} }
void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) { void SimpleEntitySimulation::processChangedEntity(const EntityItemPointer& entity) {
EntitySimulation::processChangedEntity(entity);
uint32_t flags = entity->getDirtyFlags(); uint32_t flags = entity->getDirtyFlags();
if ((flags & Simulation::DIRTY_SIMULATOR_ID) || (flags & Simulation::DIRTY_VELOCITIES)) { if ((flags & Simulation::DIRTY_SIMULATOR_ID) || (flags & Simulation::DIRTY_VELOCITIES)) {
if (entity->getSimulatorID().isNull()) { if (entity->getSimulatorID().isNull()) {

View file

@ -31,7 +31,7 @@ protected:
void updateEntitiesInternal(uint64_t now) override; void updateEntitiesInternal(uint64_t now) override;
void addEntityInternal(EntityItemPointer entity) override; void addEntityInternal(EntityItemPointer entity) override;
void removeEntityInternal(EntityItemPointer entity) override; void removeEntityInternal(EntityItemPointer entity) override;
void changeEntityInternal(EntityItemPointer entity) override; void processChangedEntity(const EntityItemPointer& entity) override;
void clearEntitiesInternal() override; void clearEntitiesInternal() override;
void sortEntitiesThatMoved() override; void sortEntitiesThatMoved() override;

View file

@ -145,7 +145,10 @@ public:
virtual bool rootElementHasData() const { return false; } virtual bool rootElementHasData() const { return false; }
virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { } virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { }
virtual void update() { } // nothing to do by default // Why preUpdate() and update()?
// Because EntityTree needs them.
virtual void preUpdate() { }
virtual void update(bool simulate = true) { }
OctreeElementPointer getRoot() { return _rootElement; } OctreeElementPointer getRoot() { return _rootElement; }

View file

@ -242,6 +242,7 @@ bool OctreePersistThread::backupCurrentFile() {
} }
void OctreePersistThread::process() { void OctreePersistThread::process() {
_tree->preUpdate();
_tree->update(); _tree->update();
auto now = std::chrono::steady_clock::now(); auto now = std::chrono::steady_clock::now();

View file

@ -131,10 +131,10 @@ void PhysicalEntitySimulation::takeDeadAvatarEntities(SetOfEntities& deadEntitie
_deadAvatarEntities.clear(); _deadAvatarEntities.clear();
} }
void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) { void PhysicalEntitySimulation::processChangedEntity(const EntityItemPointer& entity) {
EntitySimulation::processChangedEntity(entity);
// queue incoming changes: from external sources (script, EntityServer, etc) to physics engine // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine
QMutexLocker lock(&_mutex);
assert(entity);
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo()); EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
uint8_t region = _space->getRegion(entity->getSpaceIndex()); uint8_t region = _space->getRegion(entity->getSpaceIndex());
bool shouldBePhysical = region < workload::Region::R3 && entity->shouldBePhysical(); bool shouldBePhysical = region < workload::Region::R3 && entity->shouldBePhysical();

View file

@ -72,7 +72,7 @@ protected: // only called by EntitySimulation
virtual void updateEntitiesInternal(uint64_t now) override; virtual void updateEntitiesInternal(uint64_t now) override;
virtual void addEntityInternal(EntityItemPointer entity) override; virtual void addEntityInternal(EntityItemPointer entity) override;
virtual void removeEntityInternal(EntityItemPointer entity) override; virtual void removeEntityInternal(EntityItemPointer entity) override;
virtual void changeEntityInternal(EntityItemPointer entity) override; void processChangedEntity(const EntityItemPointer& entity) override;
virtual void clearEntitiesInternal() override; virtual void clearEntitiesInternal() override;
void removeOwnershipData(EntityMotionState* motionState); void removeOwnershipData(EntityMotionState* motionState);