Skip to content

Commit

Permalink
Use common function for sync and async case. Now both cases follow the
Browse files Browse the repository at this point in the history
same flow, synchronous simulation is just a special case.
  • Loading branch information
fr3dz10 committed Oct 5, 2021
1 parent 499b161 commit 21dbe31
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 53 deletions.
80 changes: 35 additions & 45 deletions apps/openmw/mwphysics/mtphysics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,31 @@

namespace
{
/// @brief A scoped lock that is either shared or exclusive depending on configuration
/// @brief A scoped lock that is either shared, exclusive or inexistent depending on configuration
template<class Mutex>
class MaybeSharedLock
{
public:
/// @param mutex a shared mutex
/// @param canBeSharedLock decide wether the lock will be shared or exclusive
MaybeSharedLock(Mutex& mutex, bool canBeSharedLock) : mMutex(mutex), mCanBeSharedLock(canBeSharedLock)
/// @param threadCount decide wether the lock will be shared, exclusive or inexistent
MaybeSharedLock(Mutex& mutex, int threadCount) : mMutex(mutex), mThreadCount(threadCount)
{
if (mCanBeSharedLock)
if (mThreadCount > 1)
mMutex.lock_shared();
else
else if(mThreadCount == 1)
mMutex.lock();
}

~MaybeSharedLock()
{
if (mCanBeSharedLock)
if (mThreadCount > 1)
mMutex.unlock_shared();
else
else if(mThreadCount == 1)
mMutex.unlock();
}
private:
Mutex& mMutex;
bool mCanBeSharedLock;
int mThreadCount;
};

bool isUnderWater(const MWPhysics::ActorFrameData& actorData)
Expand All @@ -62,14 +62,14 @@ namespace

namespace Config
{
/// @return either the number of thread as configured by the user, or 1 if Bullet doesn't support multithreading
int computeNumThreads(bool& threadSafeBullet)
/// @return either the number of thread as configured by the user, or 1 if Bullet doesn't support multithreading and user requested more than 1 background threads
int computeNumThreads()
{
int wantedThread = Settings::Manager::getInt("async num threads", "Physics");

auto broad = std::make_unique<btDbvtBroadphase>();
auto maxSupportedThreads = broad->m_rayTestStacks.size();
threadSafeBullet = (maxSupportedThreads > 1);
auto threadSafeBullet = (maxSupportedThreads > 1);
if (!threadSafeBullet && wantedThread > 1)
{
Log(Debug::Warning) << "Bullet was not compiled with multithreading support, 1 async thread will be used";
Expand All @@ -88,6 +88,7 @@ namespace MWPhysics
, mTimeAccum(0.f)
, mCollisionWorld(collisionWorld)
, mDebugDrawer(debugDrawer)
, mNumThreads(Config::computeNumThreads())
, mNumJobs(0)
, mRemainingSteps(0)
, mLOSCacheExpiry(Settings::Manager::getInt("lineofsight keep inactive cache", "Physics"))
Expand All @@ -107,8 +108,6 @@ namespace MWPhysics
, mTimeEnd(0)
, mFrameStart(0)
{
mNumThreads = Config::computeNumThreads(mThreadSafeBullet);

if (mNumThreads >= 1)
{
for (int i = 0; i < mNumThreads; ++i)
Expand Down Expand Up @@ -197,8 +196,7 @@ namespace MWPhysics
// start by finishing previous background computation
if (mNumThreads != 0)
{
for (size_t i = 0; i < mActors.size(); ++i)
updateActor(*mActors[i], mActorsFrameData[i], mAdvanceSimulation, mTimeAccum, mPhysicsDt);
syncWithMainThread();

if(mAdvanceSimulation)
mAsyncBudget.update(mTimer->delta_s(mAsyncStartTime, mTimeEnd), mPrevStepCount, mBudgetCursor);
Expand Down Expand Up @@ -233,7 +231,8 @@ namespace MWPhysics

if (mNumThreads == 0)
{
syncComputation();
doSimulation();
syncWithMainThread();
if(mAdvanceSimulation)
mBudget.update(mTimer->delta_s(timeStart, mTimer->tick()), numSteps, mBudgetCursor);
return;
Expand Down Expand Up @@ -262,13 +261,13 @@ namespace MWPhysics

void PhysicsTaskScheduler::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const
{
MaybeSharedLock lock(mCollisionWorldMutex, mThreadSafeBullet);
MaybeSharedLock lock(mCollisionWorldMutex, mNumThreads);
mCollisionWorld->rayTest(rayFromWorld, rayToWorld, resultCallback);
}

void PhysicsTaskScheduler::convexSweepTest(const btConvexShape* castShape, const btTransform& from, const btTransform& to, btCollisionWorld::ConvexResultCallback& resultCallback) const
{
MaybeSharedLock lock(mCollisionWorldMutex, mThreadSafeBullet);
MaybeSharedLock lock(mCollisionWorldMutex, mNumThreads);
mCollisionWorld->convexSweepTest(castShape, from, to, resultCallback);
}

Expand All @@ -280,7 +279,7 @@ namespace MWPhysics

std::optional<btVector3> PhysicsTaskScheduler::getHitPoint(const btTransform& from, btCollisionObject* target)
{
MaybeSharedLock lock(mCollisionWorldMutex, mThreadSafeBullet);
MaybeSharedLock lock(mCollisionWorldMutex, mNumThreads);
// target the collision object's world origin, this should be the center of the collision object
btTransform rayTo;
rayTo.setIdentity();
Expand Down Expand Up @@ -411,22 +410,7 @@ namespace MWPhysics
if (!mNewFrame)
mHasJob.wait(lock, [&]() { return mQuit || mNewFrame; });

mPreStepBarrier->wait([this] { afterPreStep(); });

int job = 0;
while (mRemainingSteps && (job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
{
MaybeSharedLock lockColWorld(mCollisionWorldMutex, mThreadSafeBullet);
MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld, *mWorldFrameData);
}

mPostStepBarrier->wait([this] { afterPostStep(); });

if (!mRemainingSteps)
{
refreshLOSCache();
mPostSimBarrier->wait([this] { afterPostSim(); });
}
doSimulation();
}
}

Expand Down Expand Up @@ -485,29 +469,29 @@ namespace MWPhysics
resultCallback.m_collisionFilterGroup = 0xFF;
resultCallback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap|CollisionType_Door;

MaybeSharedLock lockColWorld(mCollisionWorldMutex, mThreadSafeBullet);
MaybeSharedLock lockColWorld(mCollisionWorldMutex, mNumThreads);
mCollisionWorld->rayTest(pos1, pos2, resultCallback);

return !resultCallback.hasHit();
}

void PhysicsTaskScheduler::syncComputation()
void PhysicsTaskScheduler::doSimulation()
{
while (mRemainingSteps--)
while (mRemainingSteps)
{
for (auto& actorData : mActorsFrameData)
mPreStepBarrier->wait([this] { afterPreStep(); });
int job = 0;
while ((job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
{
MovementSolver::unstuck(actorData, mCollisionWorld);
MovementSolver::move(actorData, mPhysicsDt, mCollisionWorld, *mWorldFrameData);
MaybeSharedLock lockColWorld(mCollisionWorldMutex, mNumThreads);
MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld, *mWorldFrameData);
}

updateActorsPositions();
mPostStepBarrier->wait([this] { afterPostStep(); });
}

for (size_t i = 0; i < mActors.size(); ++i)
updateActor(*mActors[i], mActorsFrameData[i], mAdvanceSimulation, mTimeAccum, mPhysicsDt);

refreshLOSCache();
mPostSimBarrier->wait([this] { afterPostSim(); });
}

void PhysicsTaskScheduler::updateStats(osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
Expand Down Expand Up @@ -580,4 +564,10 @@ namespace MWPhysics
}
mTimeEnd = mTimer->tick();
}

void PhysicsTaskScheduler::syncWithMainThread()
{
for (size_t i = 0; i < mActors.size(); ++i)
updateActor(*mActors[i], mActorsFrameData[i], mAdvanceSimulation, mTimeAccum, mPhysicsDt);
}
}
4 changes: 2 additions & 2 deletions apps/openmw/mwphysics/mtphysics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ namespace MWPhysics
void releaseSharedStates(); // destroy all objects whose destructor can't be safely called from ~PhysicsTaskScheduler()

private:
void syncComputation();
void doSimulation();
void worker();
void updateActorsPositions();
void updateActor(Actor& actor, ActorFrameData& actorData, bool simulationPerformed, float timeAccum, float dt) const;
Expand All @@ -74,6 +74,7 @@ namespace MWPhysics
void afterPreStep();
void afterPostStep();
void afterPostSim();
void syncWithMainThread();

std::unique_ptr<WorldFrameData> mWorldFrameData;
std::vector<std::shared_ptr<Actor>> mActors;
Expand All @@ -98,7 +99,6 @@ namespace MWPhysics
int mLOSCacheExpiry;
bool mNewFrame;
bool mAdvanceSimulation;
bool mThreadSafeBullet;
bool mQuit;
std::atomic<int> mNextJob;
std::atomic<int> mNextLOS;
Expand Down
15 changes: 9 additions & 6 deletions components/misc/barrier.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef OPENMW_BARRIER_H
#define OPENMW_BARRIER_H

#include <cassert>
#include <condition_variable>
#include <mutex>

Expand All @@ -12,7 +13,9 @@ namespace Misc
public:
/// @param count number of threads to wait on
explicit Barrier(int count) : mThreadCount(count), mRendezvousCount(0), mGeneration(0)
{}
{
assert(count >= 0);
}

/// @brief stop execution of threads until count distinct threads reach this point
/// @param func callable to be executed once after all threads have met
Expand All @@ -22,8 +25,8 @@ namespace Misc
std::unique_lock lock(mMutex);

++mRendezvousCount;
const int currentGeneration = mGeneration;
if (mRendezvousCount == mThreadCount)
const unsigned int currentGeneration = mGeneration;
if (mRendezvousCount == mThreadCount || mThreadCount == 0)
{
++mGeneration;
mRendezvousCount = 0;
Expand All @@ -37,9 +40,9 @@ namespace Misc
}

private:
int mThreadCount;
int mRendezvousCount;
int mGeneration;
unsigned int mThreadCount;
unsigned int mRendezvousCount;
unsigned int mGeneration;
mutable std::mutex mMutex;
std::condition_variable mRendezvous;
};
Expand Down

0 comments on commit 21dbe31

Please sign in to comment.