mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 00:26:39 +00:00 
			
		
		
		
	Introduce 3 scoped mutex wrappers to allow to conditionally skip taking
mutexes in synchronous case.
This commit is contained in:
		
							parent
							
								
									21dbe314bf
								
							
						
					
					
						commit
						3b174d72d8
					
				
					 1 changed files with 83 additions and 32 deletions
				
			
		| 
						 | 
				
			
			@ -22,22 +22,73 @@
 | 
			
		|||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
    /// @brief A scoped lock that is either shared, exclusive or inexistent depending on configuration
 | 
			
		||||
    /// @brief A scoped lock that is either exclusive or inexistent depending on configuration
 | 
			
		||||
    template<class Mutex>
 | 
			
		||||
    class MaybeExclusiveLock
 | 
			
		||||
    {
 | 
			
		||||
        public:
 | 
			
		||||
            /// @param mutex a mutex
 | 
			
		||||
            /// @param threadCount decide wether the excluse lock will be taken
 | 
			
		||||
            MaybeExclusiveLock(Mutex& mutex, int threadCount) : mMutex(mutex), mThreadCount(threadCount)
 | 
			
		||||
            {
 | 
			
		||||
                assert(threadCount >= 0);
 | 
			
		||||
                if (mThreadCount > 0)
 | 
			
		||||
                    mMutex.lock();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ~MaybeExclusiveLock()
 | 
			
		||||
            {
 | 
			
		||||
                if (mThreadCount > 0)
 | 
			
		||||
                    mMutex.unlock();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            Mutex& mMutex;
 | 
			
		||||
            unsigned int mThreadCount;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /// @brief A scoped lock that is either shared or inexistent depending on configuration
 | 
			
		||||
    template<class Mutex>
 | 
			
		||||
    class MaybeSharedLock
 | 
			
		||||
    {
 | 
			
		||||
        public:
 | 
			
		||||
            /// @param mutex a shared mutex
 | 
			
		||||
            /// @param threadCount decide wether the lock will be shared, exclusive or inexistent
 | 
			
		||||
            /// @param threadCount decide wether the shared lock will be taken
 | 
			
		||||
            MaybeSharedLock(Mutex& mutex, int threadCount) : mMutex(mutex), mThreadCount(threadCount)
 | 
			
		||||
            {
 | 
			
		||||
                assert(threadCount >= 0);
 | 
			
		||||
                if (mThreadCount > 0)
 | 
			
		||||
                    mMutex.lock_shared();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ~MaybeSharedLock()
 | 
			
		||||
            {
 | 
			
		||||
                if (mThreadCount > 0)
 | 
			
		||||
                    mMutex.unlock_shared();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            Mutex& mMutex;
 | 
			
		||||
            unsigned int mThreadCount;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /// @brief A scoped lock that is either shared, exclusive or inexistent depending on configuration
 | 
			
		||||
    template<class Mutex>
 | 
			
		||||
    class MaybeLock
 | 
			
		||||
    {
 | 
			
		||||
        public:
 | 
			
		||||
            /// @param mutex a shared mutex
 | 
			
		||||
            /// @param threadCount decide wether the lock will be shared, exclusive or inexistent
 | 
			
		||||
            MaybeLock(Mutex& mutex, int threadCount) : mMutex(mutex), mThreadCount(threadCount)
 | 
			
		||||
            {
 | 
			
		||||
                assert(threadCount >= 0);
 | 
			
		||||
                if (mThreadCount > 1)
 | 
			
		||||
                    mMutex.lock_shared();
 | 
			
		||||
                else if(mThreadCount == 1)
 | 
			
		||||
                    mMutex.lock();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ~MaybeSharedLock()
 | 
			
		||||
            ~MaybeLock()
 | 
			
		||||
            {
 | 
			
		||||
                if (mThreadCount > 1)
 | 
			
		||||
                    mMutex.unlock_shared();
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +97,7 @@ namespace
 | 
			
		|||
            }
 | 
			
		||||
        private:
 | 
			
		||||
            Mutex& mMutex;
 | 
			
		||||
            int mThreadCount;
 | 
			
		||||
            unsigned int mThreadCount;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool isUnderWater(const MWPhysics::ActorFrameData& actorData)
 | 
			
		||||
| 
						 | 
				
			
			@ -127,11 +178,12 @@ namespace MWPhysics
 | 
			
		|||
 | 
			
		||||
    PhysicsTaskScheduler::~PhysicsTaskScheduler()
 | 
			
		||||
    {
 | 
			
		||||
        std::unique_lock lock(mSimulationMutex);
 | 
			
		||||
        mQuit = true;
 | 
			
		||||
        mNumJobs = 0;
 | 
			
		||||
        mRemainingSteps = 0;
 | 
			
		||||
        lock.unlock();
 | 
			
		||||
        {
 | 
			
		||||
            MaybeExclusiveLock lock(mSimulationMutex, mNumThreads);
 | 
			
		||||
            mQuit = true;
 | 
			
		||||
            mNumJobs = 0;
 | 
			
		||||
            mRemainingSteps = 0;
 | 
			
		||||
        }
 | 
			
		||||
        mHasJob.notify_all();
 | 
			
		||||
        for (auto& thread : mThreads)
 | 
			
		||||
            thread.join();
 | 
			
		||||
| 
						 | 
				
			
			@ -188,7 +240,7 @@ namespace MWPhysics
 | 
			
		|||
        // This function run in the main thread.
 | 
			
		||||
        // While the mSimulationMutex is held, background physics threads can't run.
 | 
			
		||||
 | 
			
		||||
        std::unique_lock lock(mSimulationMutex);
 | 
			
		||||
        MaybeExclusiveLock lock(mSimulationMutex, mNumThreads);
 | 
			
		||||
        assert(actors.size() == actorsData.size());
 | 
			
		||||
 | 
			
		||||
        double timeStart = mTimer->tick();
 | 
			
		||||
| 
						 | 
				
			
			@ -239,7 +291,6 @@ namespace MWPhysics
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        mAsyncStartTime = mTimer->tick();
 | 
			
		||||
        lock.unlock();
 | 
			
		||||
        mHasJob.notify_all();
 | 
			
		||||
        if (mAdvanceSimulation)
 | 
			
		||||
            mBudget.update(mTimer->delta_s(timeStart, mTimer->tick()), 1, mBudgetCursor);
 | 
			
		||||
| 
						 | 
				
			
			@ -247,7 +298,7 @@ namespace MWPhysics
 | 
			
		|||
 | 
			
		||||
    void PhysicsTaskScheduler::resetSimulation(const ActorMap& actors)
 | 
			
		||||
    {
 | 
			
		||||
        std::unique_lock lock(mSimulationMutex);
 | 
			
		||||
        MaybeExclusiveLock lock(mSimulationMutex, mNumThreads);
 | 
			
		||||
        mBudget.reset(mDefaultPhysicsDt);
 | 
			
		||||
        mAsyncBudget.reset(0.0f);
 | 
			
		||||
        mActors.clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -261,25 +312,25 @@ namespace MWPhysics
 | 
			
		|||
 | 
			
		||||
    void PhysicsTaskScheduler::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const
 | 
			
		||||
    {
 | 
			
		||||
        MaybeSharedLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        MaybeLock 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, mNumThreads);
 | 
			
		||||
        MaybeLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        mCollisionWorld->convexSweepTest(castShape, from, to, resultCallback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PhysicsTaskScheduler::contactTest(btCollisionObject* colObj, btCollisionWorld::ContactResultCallback& resultCallback)
 | 
			
		||||
    {
 | 
			
		||||
        std::shared_lock lock(mCollisionWorldMutex);
 | 
			
		||||
        MaybeSharedLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        ContactTestWrapper::contactTest(mCollisionWorld, colObj, resultCallback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::optional<btVector3> PhysicsTaskScheduler::getHitPoint(const btTransform& from, btCollisionObject* target)
 | 
			
		||||
    {
 | 
			
		||||
        MaybeSharedLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        MaybeLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        // target the collision object's world origin, this should be the center of the collision object
 | 
			
		||||
        btTransform rayTo;
 | 
			
		||||
        rayTo.setIdentity();
 | 
			
		||||
| 
						 | 
				
			
			@ -296,33 +347,33 @@ namespace MWPhysics
 | 
			
		|||
 | 
			
		||||
    void PhysicsTaskScheduler::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback)
 | 
			
		||||
    {
 | 
			
		||||
        std::shared_lock lock(mCollisionWorldMutex);
 | 
			
		||||
        MaybeSharedLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        mCollisionWorld->getBroadphase()->aabbTest(aabbMin, aabbMax, callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PhysicsTaskScheduler::getAabb(const btCollisionObject* obj, btVector3& min, btVector3& max)
 | 
			
		||||
    {
 | 
			
		||||
        std::shared_lock lock(mCollisionWorldMutex);
 | 
			
		||||
        MaybeSharedLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        obj->getCollisionShape()->getAabb(obj->getWorldTransform(), min, max);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PhysicsTaskScheduler::setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask)
 | 
			
		||||
    {
 | 
			
		||||
        std::unique_lock lock(mCollisionWorldMutex);
 | 
			
		||||
        MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        collisionObject->getBroadphaseHandle()->m_collisionFilterMask = collisionFilterMask;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PhysicsTaskScheduler::addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask)
 | 
			
		||||
    {
 | 
			
		||||
        mCollisionObjects.insert(collisionObject);
 | 
			
		||||
        std::unique_lock lock(mCollisionWorldMutex);
 | 
			
		||||
        MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        mCollisionWorld->addCollisionObject(collisionObject, collisionFilterGroup, collisionFilterMask);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PhysicsTaskScheduler::removeCollisionObject(btCollisionObject* collisionObject)
 | 
			
		||||
    {
 | 
			
		||||
        mCollisionObjects.erase(collisionObject);
 | 
			
		||||
        std::unique_lock lock(mCollisionWorldMutex);
 | 
			
		||||
        MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        mCollisionWorld->removeCollisionObject(collisionObject);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -334,14 +385,14 @@ namespace MWPhysics
 | 
			
		|||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            std::unique_lock lock(mUpdateAabbMutex);
 | 
			
		||||
            MaybeExclusiveLock lock(mUpdateAabbMutex, mNumThreads);
 | 
			
		||||
            mUpdateAabb.insert(std::move(ptr));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool PhysicsTaskScheduler::getLineOfSight(const std::shared_ptr<Actor>& actor1, const std::shared_ptr<Actor>& actor2)
 | 
			
		||||
    {
 | 
			
		||||
        std::unique_lock lock(mLOSCacheMutex);
 | 
			
		||||
        MaybeExclusiveLock lock(mLOSCacheMutex, mNumThreads);
 | 
			
		||||
 | 
			
		||||
        auto req = LOSRequest(actor1, actor2);
 | 
			
		||||
        auto result = std::find(mLOSCache.begin(), mLOSCache.end(), req);
 | 
			
		||||
| 
						 | 
				
			
			@ -357,7 +408,7 @@ namespace MWPhysics
 | 
			
		|||
 | 
			
		||||
    void PhysicsTaskScheduler::refreshLOSCache()
 | 
			
		||||
    {
 | 
			
		||||
        std::shared_lock lock(mLOSCacheMutex);
 | 
			
		||||
        MaybeSharedLock lock(mLOSCacheMutex, mNumThreads);
 | 
			
		||||
        int job = 0;
 | 
			
		||||
        int numLOS = mLOSCache.size();
 | 
			
		||||
        while ((job = mNextLOS.fetch_add(1, std::memory_order_relaxed)) < numLOS)
 | 
			
		||||
| 
						 | 
				
			
			@ -376,7 +427,7 @@ namespace MWPhysics
 | 
			
		|||
 | 
			
		||||
    void PhysicsTaskScheduler::updateAabbs()
 | 
			
		||||
    {
 | 
			
		||||
        std::scoped_lock lock(mUpdateAabbMutex);
 | 
			
		||||
        MaybeExclusiveLock lock(mUpdateAabbMutex, mNumThreads);
 | 
			
		||||
        std::for_each(mUpdateAabb.begin(), mUpdateAabb.end(),
 | 
			
		||||
            [this](const std::shared_ptr<PtrHolder>& ptr) { updatePtrAabb(ptr); });
 | 
			
		||||
        mUpdateAabb.clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -384,7 +435,7 @@ namespace MWPhysics
 | 
			
		|||
 | 
			
		||||
    void PhysicsTaskScheduler::updatePtrAabb(const std::shared_ptr<PtrHolder>& ptr)
 | 
			
		||||
    {
 | 
			
		||||
        std::scoped_lock lock(mCollisionWorldMutex);
 | 
			
		||||
        MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        if (const auto actor = std::dynamic_pointer_cast<Actor>(ptr))
 | 
			
		||||
        {
 | 
			
		||||
            actor->updateCollisionObjectPosition();
 | 
			
		||||
| 
						 | 
				
			
			@ -420,7 +471,7 @@ namespace MWPhysics
 | 
			
		|||
        {
 | 
			
		||||
            if (mActors[i]->setPosition(mActorsFrameData[i].mPosition))
 | 
			
		||||
            {
 | 
			
		||||
                std::scoped_lock lock(mCollisionWorldMutex);
 | 
			
		||||
                MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
                mActorsFrameData[i].mPosition = mActors[i]->getPosition(); // account for potential position change made by script
 | 
			
		||||
                mActors[i]->updateCollisionObjectPosition();
 | 
			
		||||
                mCollisionWorld->updateSingleAabb(mActors[i]->getCollisionObject());
 | 
			
		||||
| 
						 | 
				
			
			@ -469,7 +520,7 @@ namespace MWPhysics
 | 
			
		|||
        resultCallback.m_collisionFilterGroup = 0xFF;
 | 
			
		||||
        resultCallback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap|CollisionType_Door;
 | 
			
		||||
 | 
			
		||||
        MaybeSharedLock lockColWorld(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        MaybeLock lockColWorld(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        mCollisionWorld->rayTest(pos1, pos2, resultCallback);
 | 
			
		||||
 | 
			
		||||
        return !resultCallback.hasHit();
 | 
			
		||||
| 
						 | 
				
			
			@ -483,7 +534,7 @@ namespace MWPhysics
 | 
			
		|||
            int job = 0;
 | 
			
		||||
            while ((job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
 | 
			
		||||
            {
 | 
			
		||||
                MaybeSharedLock lockColWorld(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
                MaybeLock lockColWorld(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
                MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld, *mWorldFrameData);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -511,7 +562,7 @@ namespace MWPhysics
 | 
			
		|||
 | 
			
		||||
    void PhysicsTaskScheduler::debugDraw()
 | 
			
		||||
    {
 | 
			
		||||
        std::shared_lock lock(mCollisionWorldMutex);
 | 
			
		||||
        MaybeSharedLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
        mDebugDrawer->step();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -537,7 +588,7 @@ namespace MWPhysics
 | 
			
		|||
            return;
 | 
			
		||||
        for (size_t i = 0; i < mActors.size(); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            std::unique_lock lock(mCollisionWorldMutex);
 | 
			
		||||
            MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
 | 
			
		||||
            MovementSolver::unstuck(mActorsFrameData[i], mCollisionWorld);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -556,7 +607,7 @@ namespace MWPhysics
 | 
			
		|||
    {
 | 
			
		||||
        mNewFrame = false;
 | 
			
		||||
        {
 | 
			
		||||
            std::unique_lock lock(mLOSCacheMutex);
 | 
			
		||||
            MaybeExclusiveLock lock(mLOSCacheMutex, mNumThreads);
 | 
			
		||||
            mLOSCache.erase(
 | 
			
		||||
                    std::remove_if(mLOSCache.begin(), mLOSCache.end(),
 | 
			
		||||
                        [](const LOSRequest& req) { return req.mStale; }),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue