1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 06:23:53 +00:00

Merge branch 'noweak' into 'master'

use shared_ptr inside the physics simulation to simplify the code

See merge request OpenMW/openmw!1141
This commit is contained in:
elsid 2021-08-15 21:59:47 +00:00
commit f966fdb65e
4 changed files with 61 additions and 79 deletions

View file

@ -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);
}
} }
} }

View file

@ -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;

View file

@ -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();

View file

@ -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;