mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-03 08:11:32 +00:00
Use shared_ptr instead of weak_ptr for actors handle inside the
simulation The purpose of weak_ptr is to avoid performing the simulation on deleted Actor by promoting it to a shared_ptr via a lock() call. This clutter the code with a lot of branches, whereas the overwhelmingly common case is for the call to succeed. Since the simulation is decoupled from the engine state, we can use a shared_ptr instead of a weak_ptr. This allow us to ignore (ie not handle) the rarer case where the actor is delete from the scene. This means that the simulation will run for one frame more than before for each actor, whereas the rest of the engine will be ignorant of this.
This commit is contained in:
parent
640998aca0
commit
ec871e6bf7
4 changed files with 61 additions and 79 deletions
|
@ -207,12 +207,13 @@ namespace MWPhysics
|
||||||
return std::make_tuple(numSteps, actualDelta);
|
return std::make_tuple(numSteps, actualDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsTaskScheduler::applyQueuedMovements(float & timeAccum, std::vector<std::weak_ptr<Actor>>&& actors, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
void PhysicsTaskScheduler::applyQueuedMovements(float & timeAccum, std::vector<std::shared_ptr<Actor>>&& actors, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
||||||
{
|
{
|
||||||
// This function run in the main thread.
|
// This function run in the main thread.
|
||||||
// While the mSimulationMutex is held, background physics threads can't run.
|
// While the mSimulationMutex is held, background physics threads can't run.
|
||||||
|
|
||||||
std::unique_lock lock(mSimulationMutex);
|
std::unique_lock lock(mSimulationMutex);
|
||||||
|
assert(actors.size() == actorsData.size());
|
||||||
|
|
||||||
double timeStart = mTimer->tick();
|
double timeStart = mTimer->tick();
|
||||||
|
|
||||||
|
@ -221,11 +222,8 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < mActors.size(); ++i)
|
for (size_t i = 0; i < mActors.size(); ++i)
|
||||||
{
|
{
|
||||||
if (auto actor = mActors[i].lock())
|
updateMechanics(*mActors[i], mActorsFrameData[i]);
|
||||||
{
|
updateActor(*mActors[i], mActorsFrameData[i], mAdvanceSimulation, mTimeAccum, mPhysicsDt);
|
||||||
updateMechanics(*actor, mActorsFrameData[i]);
|
|
||||||
updateActor(*actor, mActorsFrameData[i], mAdvanceSimulation, mTimeAccum, mPhysicsDt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(mAdvanceSimulation)
|
if(mAdvanceSimulation)
|
||||||
mAsyncBudget.update(mTimer->delta_s(mAsyncStartTime, mTimeEnd), mPrevStepCount, mBudgetCursor);
|
mAsyncBudget.update(mTimer->delta_s(mAsyncStartTime, mTimeEnd), mPrevStepCount, mBudgetCursor);
|
||||||
|
@ -238,8 +236,7 @@ namespace MWPhysics
|
||||||
// init
|
// init
|
||||||
for (size_t i = 0; i < actors.size(); ++i)
|
for (size_t i = 0; i < actors.size(); ++i)
|
||||||
{
|
{
|
||||||
assert(actors[i].lock());
|
actorsData[i].updatePosition(*actors[i], mCollisionWorld);
|
||||||
actorsData[i].updatePosition(*actors[i].lock(), mCollisionWorld);
|
|
||||||
}
|
}
|
||||||
mPrevStepCount = numSteps;
|
mPrevStepCount = numSteps;
|
||||||
mRemainingSteps = numSteps;
|
mRemainingSteps = numSteps;
|
||||||
|
@ -355,7 +352,7 @@ namespace MWPhysics
|
||||||
mCollisionWorld->removeCollisionObject(collisionObject);
|
mCollisionWorld->removeCollisionObject(collisionObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsTaskScheduler::updateSingleAabb(std::weak_ptr<PtrHolder> ptr, bool immediate)
|
void PhysicsTaskScheduler::updateSingleAabb(std::shared_ptr<PtrHolder> ptr, bool immediate)
|
||||||
{
|
{
|
||||||
if (immediate || mNumThreads == 0)
|
if (immediate || mNumThreads == 0)
|
||||||
{
|
{
|
||||||
|
@ -368,20 +365,15 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsTaskScheduler::getLineOfSight(const std::weak_ptr<Actor>& actor1, const std::weak_ptr<Actor>& actor2)
|
bool PhysicsTaskScheduler::getLineOfSight(const std::shared_ptr<Actor>& actor1, const std::shared_ptr<Actor>& actor2)
|
||||||
{
|
{
|
||||||
std::unique_lock lock(mLOSCacheMutex);
|
std::unique_lock lock(mLOSCacheMutex);
|
||||||
|
|
||||||
auto actorPtr1 = actor1.lock();
|
|
||||||
auto actorPtr2 = actor2.lock();
|
|
||||||
if (!actorPtr1 || !actorPtr2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto req = LOSRequest(actor1, actor2);
|
auto req = LOSRequest(actor1, actor2);
|
||||||
auto result = std::find(mLOSCache.begin(), mLOSCache.end(), req);
|
auto result = std::find(mLOSCache.begin(), mLOSCache.end(), req);
|
||||||
if (result == mLOSCache.end())
|
if (result == mLOSCache.end())
|
||||||
{
|
{
|
||||||
req.mResult = hasLineOfSight(actorPtr1.get(), actorPtr2.get());
|
req.mResult = hasLineOfSight(actor1.get(), actor2.get());
|
||||||
mLOSCache.push_back(req);
|
mLOSCache.push_back(req);
|
||||||
return req.mResult;
|
return req.mResult;
|
||||||
}
|
}
|
||||||
|
@ -412,31 +404,28 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(mUpdateAabbMutex);
|
std::scoped_lock lock(mUpdateAabbMutex);
|
||||||
std::for_each(mUpdateAabb.begin(), mUpdateAabb.end(),
|
std::for_each(mUpdateAabb.begin(), mUpdateAabb.end(),
|
||||||
[this](const std::weak_ptr<PtrHolder>& ptr) { updatePtrAabb(ptr); });
|
[this](const std::shared_ptr<PtrHolder>& ptr) { updatePtrAabb(ptr); });
|
||||||
mUpdateAabb.clear();
|
mUpdateAabb.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsTaskScheduler::updatePtrAabb(const std::weak_ptr<PtrHolder>& ptr)
|
void PhysicsTaskScheduler::updatePtrAabb(const std::shared_ptr<PtrHolder>& ptr)
|
||||||
{
|
{
|
||||||
if (const auto p = ptr.lock())
|
std::scoped_lock lock(mCollisionWorldMutex);
|
||||||
|
if (const auto actor = std::dynamic_pointer_cast<Actor>(ptr))
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(mCollisionWorldMutex);
|
actor->updateCollisionObjectPosition();
|
||||||
if (const auto actor = std::dynamic_pointer_cast<Actor>(p))
|
mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
|
||||||
{
|
}
|
||||||
actor->updateCollisionObjectPosition();
|
else if (const auto object = std::dynamic_pointer_cast<Object>(ptr))
|
||||||
mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
|
{
|
||||||
}
|
object->commitPositionChange();
|
||||||
else if (const auto object = std::dynamic_pointer_cast<Object>(p))
|
mCollisionWorld->updateSingleAabb(object->getCollisionObject());
|
||||||
{
|
}
|
||||||
object->commitPositionChange();
|
else if (const auto projectile = std::dynamic_pointer_cast<Projectile>(ptr))
|
||||||
mCollisionWorld->updateSingleAabb(object->getCollisionObject());
|
{
|
||||||
}
|
projectile->commitPositionChange();
|
||||||
else if (const auto projectile = std::dynamic_pointer_cast<Projectile>(p))
|
mCollisionWorld->updateSingleAabb(projectile->getCollisionObject());
|
||||||
{
|
}
|
||||||
projectile->commitPositionChange();
|
|
||||||
mCollisionWorld->updateSingleAabb(projectile->getCollisionObject());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsTaskScheduler::worker()
|
void PhysicsTaskScheduler::worker()
|
||||||
|
@ -452,11 +441,8 @@ namespace MWPhysics
|
||||||
int job = 0;
|
int job = 0;
|
||||||
while (mRemainingSteps && (job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
|
while (mRemainingSteps && (job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
|
||||||
{
|
{
|
||||||
if(const auto actor = mActors[job].lock())
|
MaybeSharedLock lockColWorld(mCollisionWorldMutex, mThreadSafeBullet);
|
||||||
{
|
MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld, *mWorldFrameData);
|
||||||
MaybeSharedLock lockColWorld(mCollisionWorldMutex, mThreadSafeBullet);
|
|
||||||
MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld, *mWorldFrameData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mPostStepBarrier->wait([this] { afterPostStep(); });
|
mPostStepBarrier->wait([this] { afterPostStep(); });
|
||||||
|
@ -465,10 +451,7 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
while ((job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
|
while ((job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
|
||||||
{
|
{
|
||||||
if(const auto actor = mActors[job].lock())
|
handleFall(mActorsFrameData[job], mAdvanceSimulation);
|
||||||
{
|
|
||||||
handleFall(mActorsFrameData[job], mAdvanceSimulation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshLOSCache();
|
refreshLOSCache();
|
||||||
|
@ -481,15 +464,12 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < mActors.size(); ++i)
|
for (size_t i = 0; i < mActors.size(); ++i)
|
||||||
{
|
{
|
||||||
if(const auto actor = mActors[i].lock())
|
if (mActors[i]->setPosition(mActorsFrameData[i].mPosition))
|
||||||
{
|
{
|
||||||
if (actor->setPosition(mActorsFrameData[i].mPosition))
|
std::scoped_lock lock(mCollisionWorldMutex);
|
||||||
{
|
mActorsFrameData[i].mPosition = mActors[i]->getPosition(); // account for potential position change made by script
|
||||||
std::scoped_lock lock(mCollisionWorldMutex);
|
mActors[i]->updateCollisionObjectPosition();
|
||||||
mActorsFrameData[i].mPosition = actor->getPosition(); // account for potential position change made by script
|
mCollisionWorld->updateSingleAabb(mActors[i]->getCollisionObject());
|
||||||
actor->updateCollisionObjectPosition();
|
|
||||||
mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -545,11 +525,9 @@ namespace MWPhysics
|
||||||
|
|
||||||
for (size_t i = 0; i < mActors.size(); ++i)
|
for (size_t i = 0; i < mActors.size(); ++i)
|
||||||
{
|
{
|
||||||
auto actor = mActors[i].lock();
|
|
||||||
assert(actor);
|
|
||||||
handleFall(mActorsFrameData[i], mAdvanceSimulation);
|
handleFall(mActorsFrameData[i], mAdvanceSimulation);
|
||||||
updateMechanics(*actor, mActorsFrameData[i]);
|
updateMechanics(*mActors[i], mActorsFrameData[i]);
|
||||||
updateActor(*actor, mActorsFrameData[i], mAdvanceSimulation, mTimeAccum, mPhysicsDt);
|
updateActor(*mActors[i], mActorsFrameData[i], mAdvanceSimulation, mTimeAccum, mPhysicsDt);
|
||||||
}
|
}
|
||||||
refreshLOSCache();
|
refreshLOSCache();
|
||||||
}
|
}
|
||||||
|
@ -583,6 +561,13 @@ namespace MWPhysics
|
||||||
return (*it)->getUserPointer();
|
return (*it)->getUserPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhysicsTaskScheduler::releaseSharedStates()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(mSimulationMutex, mUpdateAabbMutex);
|
||||||
|
mActors.clear();
|
||||||
|
mUpdateAabb.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void PhysicsTaskScheduler::afterPreStep()
|
void PhysicsTaskScheduler::afterPreStep()
|
||||||
{
|
{
|
||||||
updateAabbs();
|
updateAabbs();
|
||||||
|
@ -590,11 +575,8 @@ namespace MWPhysics
|
||||||
return;
|
return;
|
||||||
for (size_t i = 0; i < mActors.size(); ++i)
|
for (size_t i = 0; i < mActors.size(); ++i)
|
||||||
{
|
{
|
||||||
if (auto actor = mActors[i].lock())
|
std::unique_lock lock(mCollisionWorldMutex);
|
||||||
{
|
MovementSolver::unstuck(mActorsFrameData[i], mCollisionWorld);
|
||||||
std::unique_lock lock(mCollisionWorldMutex);
|
|
||||||
MovementSolver::unstuck(mActorsFrameData[i], mCollisionWorld);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace MWPhysics
|
||||||
/// @param timeAccum accumulated time from previous run to interpolate movements
|
/// @param timeAccum accumulated time from previous run to interpolate movements
|
||||||
/// @param actorsData per actor data needed to compute new positions
|
/// @param actorsData per actor data needed to compute new positions
|
||||||
/// @return new position of each actor
|
/// @return new position of each actor
|
||||||
void applyQueuedMovements(float & timeAccum, std::vector<std::weak_ptr<Actor>>&& actors, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
|
void applyQueuedMovements(float & timeAccum, std::vector<std::shared_ptr<Actor>>&& actors, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
|
||||||
|
|
||||||
void resetSimulation(const ActorMap& actors);
|
void resetSimulation(const ActorMap& actors);
|
||||||
|
|
||||||
|
@ -53,11 +53,13 @@ namespace MWPhysics
|
||||||
void setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask);
|
void setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask);
|
||||||
void addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask);
|
void addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask);
|
||||||
void removeCollisionObject(btCollisionObject* collisionObject);
|
void removeCollisionObject(btCollisionObject* collisionObject);
|
||||||
void updateSingleAabb(std::weak_ptr<PtrHolder> ptr, bool immediate=false);
|
void updateSingleAabb(std::shared_ptr<PtrHolder> ptr, bool immediate=false);
|
||||||
bool getLineOfSight(const std::weak_ptr<Actor>& actor1, const std::weak_ptr<Actor>& actor2);
|
bool getLineOfSight(const std::shared_ptr<Actor>& actor1, const std::shared_ptr<Actor>& actor2);
|
||||||
void debugDraw();
|
void debugDraw();
|
||||||
void* getUserPointer(const btCollisionObject* object) const;
|
void* getUserPointer(const btCollisionObject* object) const;
|
||||||
|
|
||||||
|
void releaseSharedStates(); // destroy all objects whose destructor can't be safely called from ~PhysicsTaskScheduler()
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void syncComputation();
|
void syncComputation();
|
||||||
void worker();
|
void worker();
|
||||||
|
@ -66,7 +68,7 @@ namespace MWPhysics
|
||||||
bool hasLineOfSight(const Actor* actor1, const Actor* actor2);
|
bool hasLineOfSight(const Actor* actor1, const Actor* actor2);
|
||||||
void refreshLOSCache();
|
void refreshLOSCache();
|
||||||
void updateAabbs();
|
void updateAabbs();
|
||||||
void updatePtrAabb(const std::weak_ptr<PtrHolder>& ptr);
|
void updatePtrAabb(const std::shared_ptr<PtrHolder>& ptr);
|
||||||
void updateStats(osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
|
void updateStats(osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
|
||||||
std::tuple<int, float> calculateStepConfig(float timeAccum) const;
|
std::tuple<int, float> calculateStepConfig(float timeAccum) const;
|
||||||
void afterPreStep();
|
void afterPreStep();
|
||||||
|
@ -74,7 +76,7 @@ namespace MWPhysics
|
||||||
void afterPostSim();
|
void afterPostSim();
|
||||||
|
|
||||||
std::unique_ptr<WorldFrameData> mWorldFrameData;
|
std::unique_ptr<WorldFrameData> mWorldFrameData;
|
||||||
std::vector<std::weak_ptr<Actor>> mActors;
|
std::vector<std::shared_ptr<Actor>> mActors;
|
||||||
std::vector<ActorFrameData> mActorsFrameData;
|
std::vector<ActorFrameData> mActorsFrameData;
|
||||||
std::unordered_set<const btCollisionObject*> mCollisionObjects;
|
std::unordered_set<const btCollisionObject*> mCollisionObjects;
|
||||||
float mDefaultPhysicsDt;
|
float mDefaultPhysicsDt;
|
||||||
|
@ -83,7 +85,7 @@ namespace MWPhysics
|
||||||
btCollisionWorld* mCollisionWorld;
|
btCollisionWorld* mCollisionWorld;
|
||||||
MWRender::DebugDrawer* mDebugDrawer;
|
MWRender::DebugDrawer* mDebugDrawer;
|
||||||
std::vector<LOSRequest> mLOSCache;
|
std::vector<LOSRequest> mLOSCache;
|
||||||
std::set<std::weak_ptr<PtrHolder>, std::owner_less<std::weak_ptr<PtrHolder>>> mUpdateAabb;
|
std::set<std::shared_ptr<PtrHolder>> mUpdateAabb;
|
||||||
|
|
||||||
// TODO: use std::experimental::flex_barrier or std::barrier once it becomes a thing
|
// TODO: use std::experimental::flex_barrier or std::barrier once it becomes a thing
|
||||||
std::unique_ptr<Misc::Barrier> mPreStepBarrier;
|
std::unique_ptr<Misc::Barrier> mPreStepBarrier;
|
||||||
|
|
|
@ -153,6 +153,7 @@ namespace MWPhysics
|
||||||
if (mWaterCollisionObject)
|
if (mWaterCollisionObject)
|
||||||
mTaskScheduler->removeCollisionObject(mWaterCollisionObject.get());
|
mTaskScheduler->removeCollisionObject(mWaterCollisionObject.get());
|
||||||
|
|
||||||
|
mTaskScheduler->releaseSharedStates();
|
||||||
mHeightFields.clear();
|
mHeightFields.clear();
|
||||||
mObjects.clear();
|
mObjects.clear();
|
||||||
mActors.clear();
|
mActors.clear();
|
||||||
|
@ -373,15 +374,12 @@ namespace MWPhysics
|
||||||
|
|
||||||
bool PhysicsSystem::getLineOfSight(const MWWorld::ConstPtr &actor1, const MWWorld::ConstPtr &actor2) const
|
bool PhysicsSystem::getLineOfSight(const MWWorld::ConstPtr &actor1, const MWWorld::ConstPtr &actor2) const
|
||||||
{
|
{
|
||||||
const auto getWeakPtr = [&](const MWWorld::ConstPtr &ptr) -> std::weak_ptr<Actor>
|
const auto it1 = mActors.find(actor1);
|
||||||
{
|
const auto it2 = mActors.find(actor2);
|
||||||
const auto found = mActors.find(ptr);
|
if (it1 == mActors.end() || it2 == mActors.end())
|
||||||
if (found != mActors.end())
|
return false;
|
||||||
return { found->second };
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
return mTaskScheduler->getLineOfSight(getWeakPtr(actor1), getWeakPtr(actor2));
|
return mTaskScheduler->getLineOfSight(it1->second, it2->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsSystem::isOnGround(const MWWorld::Ptr &actor)
|
bool PhysicsSystem::isOnGround(const MWWorld::Ptr &actor)
|
||||||
|
@ -769,9 +767,9 @@ namespace MWPhysics
|
||||||
actor->setVelocity(osg::Vec3f());
|
actor->setVelocity(osg::Vec3f());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::vector<std::weak_ptr<Actor>>, std::vector<ActorFrameData>> PhysicsSystem::prepareFrameData(bool willSimulate)
|
std::pair<std::vector<std::shared_ptr<Actor>>, std::vector<ActorFrameData>> PhysicsSystem::prepareFrameData(bool willSimulate)
|
||||||
{
|
{
|
||||||
std::pair<std::vector<std::weak_ptr<Actor>>, std::vector<ActorFrameData>> framedata;
|
std::pair<std::vector<std::shared_ptr<Actor>>, std::vector<ActorFrameData>> framedata;
|
||||||
framedata.first.reserve(mActors.size());
|
framedata.first.reserve(mActors.size());
|
||||||
framedata.second.reserve(mActors.size());
|
framedata.second.reserve(mActors.size());
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
|
|
@ -259,7 +259,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
void updateWater();
|
void updateWater();
|
||||||
|
|
||||||
std::pair<std::vector<std::weak_ptr<Actor>>, std::vector<ActorFrameData>> prepareFrameData(bool willSimulate);
|
std::pair<std::vector<std::shared_ptr<Actor>>, std::vector<ActorFrameData>> prepareFrameData(bool willSimulate);
|
||||||
|
|
||||||
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
|
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue