Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -267,7 +267,6 @@ struct btDbvt
|
||||
|
||||
|
||||
btAlignedObjectArray<sStkNN> m_stkStack;
|
||||
mutable btAlignedObjectArray<const btDbvtNode*> m_rayTestStack;
|
||||
|
||||
|
||||
// Methods
|
||||
@@ -357,6 +356,7 @@ struct btDbvt
|
||||
btScalar lambda_max,
|
||||
const btVector3& aabbMin,
|
||||
const btVector3& aabbMax,
|
||||
btAlignedObjectArray<const btDbvtNode*>& stack,
|
||||
DBVT_IPOLICY) const;
|
||||
|
||||
DBVT_PREFIX
|
||||
@@ -1006,7 +1006,8 @@ inline void btDbvt::rayTestInternal( const btDbvtNode* root,
|
||||
btScalar lambda_max,
|
||||
const btVector3& aabbMin,
|
||||
const btVector3& aabbMax,
|
||||
DBVT_IPOLICY) const
|
||||
btAlignedObjectArray<const btDbvtNode*>& stack,
|
||||
DBVT_IPOLICY ) const
|
||||
{
|
||||
(void) rayTo;
|
||||
DBVT_CHECKTYPE
|
||||
@@ -1016,7 +1017,6 @@ inline void btDbvt::rayTestInternal( const btDbvtNode* root,
|
||||
|
||||
int depth=1;
|
||||
int treshold=DOUBLE_STACKSIZE-2;
|
||||
btAlignedObjectArray<const btDbvtNode*>& stack = m_rayTestStack;
|
||||
stack.resize(DOUBLE_STACKSIZE);
|
||||
stack[0]=root;
|
||||
btVector3 bounds[2];
|
||||
|
||||
@@ -16,6 +16,7 @@ subject to the following restrictions:
|
||||
///btDbvtBroadphase implementation by Nathanael Presson
|
||||
|
||||
#include "btDbvtBroadphase.h"
|
||||
#include "LinearMath/btThreads.h"
|
||||
|
||||
//
|
||||
// Profiling
|
||||
@@ -142,6 +143,11 @@ btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache)
|
||||
{
|
||||
m_stageRoots[i]=0;
|
||||
}
|
||||
#if BT_THREADSAFE
|
||||
m_rayTestStacks.resize(BT_MAX_THREAD_COUNT);
|
||||
#else
|
||||
m_rayTestStacks.resize(1);
|
||||
#endif
|
||||
#if DBVT_BP_PROFILE
|
||||
clear(m_profiling);
|
||||
#endif
|
||||
@@ -227,6 +233,23 @@ struct BroadphaseRayTester : btDbvt::ICollide
|
||||
void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax)
|
||||
{
|
||||
BroadphaseRayTester callback(rayCallback);
|
||||
btAlignedObjectArray<const btDbvtNode*>* stack = &m_rayTestStacks[0];
|
||||
#if BT_THREADSAFE
|
||||
// for this function to be threadsafe, each thread must have a separate copy
|
||||
// of this stack. This could be thread-local static to avoid dynamic allocations,
|
||||
// instead of just a local.
|
||||
int threadIndex = btGetCurrentThreadIndex();
|
||||
btAlignedObjectArray<const btDbvtNode*> localStack;
|
||||
if (threadIndex < m_rayTestStacks.size())
|
||||
{
|
||||
// use per-thread preallocated stack if possible to avoid dynamic allocations
|
||||
stack = &m_rayTestStacks[threadIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
stack = &localStack;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_sets[0].rayTestInternal( m_sets[0].m_root,
|
||||
rayFrom,
|
||||
@@ -236,6 +259,7 @@ void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo,
|
||||
rayCallback.m_lambda_max,
|
||||
aabbMin,
|
||||
aabbMax,
|
||||
*stack,
|
||||
callback);
|
||||
|
||||
m_sets[1].rayTestInternal( m_sets[1].m_root,
|
||||
@@ -246,6 +270,7 @@ void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo,
|
||||
rayCallback.m_lambda_max,
|
||||
aabbMin,
|
||||
aabbMax,
|
||||
*stack,
|
||||
callback);
|
||||
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ struct btDbvtBroadphase : btBroadphaseInterface
|
||||
bool m_releasepaircache; // Release pair cache on delete
|
||||
bool m_deferedcollide; // Defere dynamic/static collision to collide call
|
||||
bool m_needcleanup; // Need to run cleanup?
|
||||
btAlignedObjectArray< btAlignedObjectArray<const btDbvtNode*> > m_rayTestStacks;
|
||||
#if DBVT_BP_PROFILE
|
||||
btClock m_clock;
|
||||
struct {
|
||||
|
||||
@@ -33,6 +33,7 @@ SET(BulletCollision_SRCS
|
||||
CollisionDispatch/btInternalEdgeUtility.h
|
||||
CollisionDispatch/btManifoldResult.cpp
|
||||
CollisionDispatch/btSimulationIslandManager.cpp
|
||||
CollisionDispatch/btSimulationIslandManagerMt.cpp
|
||||
CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp
|
||||
CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp
|
||||
CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp
|
||||
@@ -140,6 +141,7 @@ SET(CollisionDispatch_HDRS
|
||||
CollisionDispatch/btHashedSimplePairCache.h
|
||||
CollisionDispatch/btManifoldResult.h
|
||||
CollisionDispatch/btSimulationIslandManager.h
|
||||
CollisionDispatch/btSimulationIslandManagerMt.h
|
||||
CollisionDispatch/btSphereBoxCollisionAlgorithm.h
|
||||
CollisionDispatch/btSphereSphereCollisionAlgorithm.h
|
||||
CollisionDispatch/btSphereTriangleCollisionAlgorithm.h
|
||||
|
||||
@@ -84,14 +84,10 @@ btPersistentManifold* btCollisionDispatcher::getNewManifold(const btCollisionObj
|
||||
|
||||
btScalar contactProcessingThreshold = btMin(body0->getContactProcessingThreshold(),body1->getContactProcessingThreshold());
|
||||
|
||||
void* mem = 0;
|
||||
|
||||
if (m_persistentManifoldPoolAllocator->getFreeCount())
|
||||
void* mem = m_persistentManifoldPoolAllocator->allocate( sizeof( btPersistentManifold ) );
|
||||
if (NULL == mem)
|
||||
{
|
||||
mem = m_persistentManifoldPoolAllocator->allocate(sizeof(btPersistentManifold));
|
||||
} else
|
||||
{
|
||||
//we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert.
|
||||
//we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert.
|
||||
if ((m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION)==0)
|
||||
{
|
||||
mem = btAlignedAlloc(sizeof(btPersistentManifold),16);
|
||||
@@ -294,13 +290,13 @@ void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair,
|
||||
|
||||
void* btCollisionDispatcher::allocateCollisionAlgorithm(int size)
|
||||
{
|
||||
if (m_collisionAlgorithmPoolAllocator->getFreeCount())
|
||||
{
|
||||
return m_collisionAlgorithmPoolAllocator->allocate(size);
|
||||
}
|
||||
|
||||
//warn user for overflow?
|
||||
return btAlignedAlloc(static_cast<size_t>(size), 16);
|
||||
void* mem = m_collisionAlgorithmPoolAllocator->allocate( size );
|
||||
if (NULL == mem)
|
||||
{
|
||||
//warn user for overflow?
|
||||
return btAlignedAlloc(static_cast<size_t>(size), 16);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr)
|
||||
|
||||
@@ -79,6 +79,7 @@ protected:
|
||||
|
||||
int m_islandTag1;
|
||||
int m_companionId;
|
||||
int m_uniqueId;
|
||||
|
||||
mutable int m_activationState1;
|
||||
mutable btScalar m_deactivationTime;
|
||||
@@ -455,7 +456,17 @@ public:
|
||||
m_companionId = id;
|
||||
}
|
||||
|
||||
SIMD_FORCE_INLINE btScalar getHitFraction() const
|
||||
SIMD_FORCE_INLINE int getUniqueId() const
|
||||
{
|
||||
return m_uniqueId;
|
||||
}
|
||||
|
||||
void setUniqueId( int id )
|
||||
{
|
||||
m_uniqueId = id;
|
||||
}
|
||||
|
||||
SIMD_FORCE_INLINE btScalar getHitFraction() const
|
||||
{
|
||||
return m_hitFraction;
|
||||
}
|
||||
|
||||
@@ -179,11 +179,10 @@ static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance(
|
||||
|
||||
|
||||
|
||||
btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver)
|
||||
btConvexConvexAlgorithm::CreateFunc::CreateFunc(btConvexPenetrationDepthSolver* pdSolver)
|
||||
{
|
||||
m_numPerturbationIterations = 0;
|
||||
m_minimumPointsPerturbationThreshold = 3;
|
||||
m_simplexSolver = simplexSolver;
|
||||
m_pdSolver = pdSolver;
|
||||
}
|
||||
|
||||
@@ -191,9 +190,8 @@ btConvexConvexAlgorithm::CreateFunc::~CreateFunc()
|
||||
{
|
||||
}
|
||||
|
||||
btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold)
|
||||
btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold)
|
||||
: btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap),
|
||||
m_simplexSolver(simplexSolver),
|
||||
m_pdSolver(pdSolver),
|
||||
m_ownManifold (false),
|
||||
m_manifoldPtr(mf),
|
||||
@@ -349,8 +347,8 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
|
||||
|
||||
|
||||
btGjkPairDetector::ClosestPointInput input;
|
||||
|
||||
btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver);
|
||||
btVoronoiSimplexSolver simplexSolver;
|
||||
btGjkPairDetector gjkPairDetector( min0, min1, &simplexSolver, m_pdSolver );
|
||||
//TODO: if (dispatchInfo.m_useContinuous)
|
||||
gjkPairDetector.setMinkowskiA(min0);
|
||||
gjkPairDetector.setMinkowskiB(min1);
|
||||
|
||||
@@ -43,7 +43,6 @@ class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm
|
||||
#ifdef USE_SEPDISTANCE_UTIL2
|
||||
btConvexSeparatingDistanceUtil m_sepDistance;
|
||||
#endif
|
||||
btSimplexSolverInterface* m_simplexSolver;
|
||||
btConvexPenetrationDepthSolver* m_pdSolver;
|
||||
|
||||
btVertexArray worldVertsB1;
|
||||
@@ -62,7 +61,7 @@ class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm
|
||||
|
||||
public:
|
||||
|
||||
btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold);
|
||||
btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold);
|
||||
|
||||
virtual ~btConvexConvexAlgorithm();
|
||||
|
||||
@@ -90,18 +89,17 @@ public:
|
||||
{
|
||||
|
||||
btConvexPenetrationDepthSolver* m_pdSolver;
|
||||
btSimplexSolverInterface* m_simplexSolver;
|
||||
int m_numPerturbationIterations;
|
||||
int m_minimumPointsPerturbationThreshold;
|
||||
|
||||
CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver);
|
||||
CreateFunc(btConvexPenetrationDepthSolver* pdSolver);
|
||||
|
||||
virtual ~CreateFunc();
|
||||
|
||||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap)
|
||||
{
|
||||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConvexAlgorithm));
|
||||
return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0Wrap,body1Wrap,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold);
|
||||
return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0Wrap,body1Wrap,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -44,9 +44,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault
|
||||
//btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btStackAlloc* stackAlloc,btPoolAllocator* persistentManifoldPool,btPoolAllocator* collisionAlgorithmPool)
|
||||
{
|
||||
|
||||
void* mem = btAlignedAlloc(sizeof(btVoronoiSimplexSolver),16);
|
||||
m_simplexSolver = new (mem)btVoronoiSimplexSolver();
|
||||
|
||||
void* mem = NULL;
|
||||
if (constructionInfo.m_useEpaPenetrationAlgorithm)
|
||||
{
|
||||
mem = btAlignedAlloc(sizeof(btGjkEpaPenetrationDepthSolver),16);
|
||||
@@ -59,7 +57,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault
|
||||
|
||||
//default CreationFunctions, filling the m_doubleDispatch table
|
||||
mem = btAlignedAlloc(sizeof(btConvexConvexAlgorithm::CreateFunc),16);
|
||||
m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_simplexSolver,m_pdSolver);
|
||||
m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_pdSolver);
|
||||
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16);
|
||||
m_convexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::CreateFunc;
|
||||
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16);
|
||||
@@ -193,9 +191,6 @@ btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration()
|
||||
m_planeConvexCF->~btCollisionAlgorithmCreateFunc();
|
||||
btAlignedFree( m_planeConvexCF);
|
||||
|
||||
m_simplexSolver->~btVoronoiSimplexSolver();
|
||||
btAlignedFree(m_simplexSolver);
|
||||
|
||||
m_pdSolver->~btConvexPenetrationDepthSolver();
|
||||
|
||||
btAlignedFree(m_pdSolver);
|
||||
|
||||
@@ -60,8 +60,7 @@ protected:
|
||||
btPoolAllocator* m_collisionAlgorithmPool;
|
||||
bool m_ownsCollisionAlgorithmPool;
|
||||
|
||||
//default simplex/penetration depth solvers
|
||||
btVoronoiSimplexSolver* m_simplexSolver;
|
||||
//default penetration depth solver
|
||||
btConvexPenetrationDepthSolver* m_pdSolver;
|
||||
|
||||
//default CreationFunctions, filling the m_doubleDispatch table
|
||||
@@ -102,12 +101,6 @@ public:
|
||||
}
|
||||
|
||||
|
||||
virtual btVoronoiSimplexSolver* getSimplexSolver()
|
||||
{
|
||||
return m_simplexSolver;
|
||||
}
|
||||
|
||||
|
||||
virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1);
|
||||
|
||||
///Use this method to allow to generate multiple contact points between at once, between two objects using the generic convex-convex algorithm.
|
||||
|
||||
@@ -0,0 +1,641 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include "LinearMath/btScalar.h"
|
||||
#include "btSimulationIslandManagerMt.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btDispatcher.h"
|
||||
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
|
||||
|
||||
//#include <stdio.h>
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
|
||||
|
||||
SIMD_FORCE_INLINE int calcBatchCost( int bodies, int manifolds, int constraints )
|
||||
{
|
||||
// rough estimate of the cost of a batch, used for merging
|
||||
int batchCost = bodies + 8 * manifolds + 4 * constraints;
|
||||
return batchCost;
|
||||
}
|
||||
|
||||
|
||||
SIMD_FORCE_INLINE int calcBatchCost( const btSimulationIslandManagerMt::Island* island )
|
||||
{
|
||||
return calcBatchCost( island->bodyArray.size(), island->manifoldArray.size(), island->constraintArray.size() );
|
||||
}
|
||||
|
||||
|
||||
btSimulationIslandManagerMt::btSimulationIslandManagerMt()
|
||||
{
|
||||
m_minimumSolverBatchSize = calcBatchCost(0, 128, 0);
|
||||
m_batchIslandMinBodyCount = 32;
|
||||
m_islandDispatch = defaultIslandDispatch;
|
||||
m_batchIsland = NULL;
|
||||
}
|
||||
|
||||
|
||||
btSimulationIslandManagerMt::~btSimulationIslandManagerMt()
|
||||
{
|
||||
for ( int i = 0; i < m_allocatedIslands.size(); ++i )
|
||||
{
|
||||
delete m_allocatedIslands[ i ];
|
||||
}
|
||||
m_allocatedIslands.resize( 0 );
|
||||
m_activeIslands.resize( 0 );
|
||||
m_freeIslands.resize( 0 );
|
||||
}
|
||||
|
||||
|
||||
inline int getIslandId(const btPersistentManifold* lhs)
|
||||
{
|
||||
const btCollisionObject* rcolObj0 = static_cast<const btCollisionObject*>(lhs->getBody0());
|
||||
const btCollisionObject* rcolObj1 = static_cast<const btCollisionObject*>(lhs->getBody1());
|
||||
int islandId = rcolObj0->getIslandTag() >= 0 ? rcolObj0->getIslandTag() : rcolObj1->getIslandTag();
|
||||
return islandId;
|
||||
}
|
||||
|
||||
|
||||
SIMD_FORCE_INLINE int btGetConstraintIslandId( const btTypedConstraint* lhs )
|
||||
{
|
||||
const btCollisionObject& rcolObj0 = lhs->getRigidBodyA();
|
||||
const btCollisionObject& rcolObj1 = lhs->getRigidBodyB();
|
||||
int islandId = rcolObj0.getIslandTag() >= 0 ? rcolObj0.getIslandTag() : rcolObj1.getIslandTag();
|
||||
return islandId;
|
||||
}
|
||||
|
||||
/// function object that routes calls to operator<
|
||||
class IslandBatchSizeSortPredicate
|
||||
{
|
||||
public:
|
||||
bool operator() ( const btSimulationIslandManagerMt::Island* lhs, const btSimulationIslandManagerMt::Island* rhs ) const
|
||||
{
|
||||
int lCost = calcBatchCost( lhs );
|
||||
int rCost = calcBatchCost( rhs );
|
||||
return lCost > rCost;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class IslandBodyCapacitySortPredicate
|
||||
{
|
||||
public:
|
||||
bool operator() ( const btSimulationIslandManagerMt::Island* lhs, const btSimulationIslandManagerMt::Island* rhs ) const
|
||||
{
|
||||
return lhs->bodyArray.capacity() > rhs->bodyArray.capacity();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void btSimulationIslandManagerMt::Island::append( const Island& other )
|
||||
{
|
||||
// append bodies
|
||||
for ( int i = 0; i < other.bodyArray.size(); ++i )
|
||||
{
|
||||
bodyArray.push_back( other.bodyArray[ i ] );
|
||||
}
|
||||
// append manifolds
|
||||
for ( int i = 0; i < other.manifoldArray.size(); ++i )
|
||||
{
|
||||
manifoldArray.push_back( other.manifoldArray[ i ] );
|
||||
}
|
||||
// append constraints
|
||||
for ( int i = 0; i < other.constraintArray.size(); ++i )
|
||||
{
|
||||
constraintArray.push_back( other.constraintArray[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool btIsBodyInIsland( const btSimulationIslandManagerMt::Island& island, const btCollisionObject* obj )
|
||||
{
|
||||
for ( int i = 0; i < island.bodyArray.size(); ++i )
|
||||
{
|
||||
if ( island.bodyArray[ i ] == obj )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void btSimulationIslandManagerMt::initIslandPools()
|
||||
{
|
||||
// reset island pools
|
||||
int numElem = getUnionFind().getNumElements();
|
||||
m_lookupIslandFromId.resize( numElem );
|
||||
for ( int i = 0; i < m_lookupIslandFromId.size(); ++i )
|
||||
{
|
||||
m_lookupIslandFromId[ i ] = NULL;
|
||||
}
|
||||
m_activeIslands.resize( 0 );
|
||||
m_freeIslands.resize( 0 );
|
||||
// check whether allocated islands are sorted by body capacity (largest to smallest)
|
||||
int lastCapacity = 0;
|
||||
bool isSorted = true;
|
||||
for ( int i = 0; i < m_allocatedIslands.size(); ++i )
|
||||
{
|
||||
Island* island = m_allocatedIslands[ i ];
|
||||
int cap = island->bodyArray.capacity();
|
||||
if ( cap > lastCapacity )
|
||||
{
|
||||
isSorted = false;
|
||||
break;
|
||||
}
|
||||
lastCapacity = cap;
|
||||
}
|
||||
if ( !isSorted )
|
||||
{
|
||||
m_allocatedIslands.quickSort( IslandBodyCapacitySortPredicate() );
|
||||
}
|
||||
|
||||
m_batchIsland = NULL;
|
||||
// mark all islands free (but avoid deallocation)
|
||||
for ( int i = 0; i < m_allocatedIslands.size(); ++i )
|
||||
{
|
||||
Island* island = m_allocatedIslands[ i ];
|
||||
island->bodyArray.resize( 0 );
|
||||
island->manifoldArray.resize( 0 );
|
||||
island->constraintArray.resize( 0 );
|
||||
island->id = -1;
|
||||
island->isSleeping = true;
|
||||
m_freeIslands.push_back( island );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::getIsland( int id )
|
||||
{
|
||||
Island* island = m_lookupIslandFromId[ id ];
|
||||
if ( island == NULL )
|
||||
{
|
||||
// search for existing island
|
||||
for ( int i = 0; i < m_activeIslands.size(); ++i )
|
||||
{
|
||||
if ( m_activeIslands[ i ]->id == id )
|
||||
{
|
||||
island = m_activeIslands[ i ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_lookupIslandFromId[ id ] = island;
|
||||
}
|
||||
return island;
|
||||
}
|
||||
|
||||
|
||||
btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::allocateIsland( int id, int numBodies )
|
||||
{
|
||||
Island* island = NULL;
|
||||
int allocSize = numBodies;
|
||||
if ( numBodies < m_batchIslandMinBodyCount )
|
||||
{
|
||||
if ( m_batchIsland )
|
||||
{
|
||||
island = m_batchIsland;
|
||||
m_lookupIslandFromId[ id ] = island;
|
||||
// if we've made a large enough batch,
|
||||
if ( island->bodyArray.size() + numBodies >= m_batchIslandMinBodyCount )
|
||||
{
|
||||
// next time start a new batch
|
||||
m_batchIsland = NULL;
|
||||
}
|
||||
return island;
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to allocate a batch island
|
||||
allocSize = m_batchIslandMinBodyCount * 2;
|
||||
}
|
||||
}
|
||||
btAlignedObjectArray<Island*>& freeIslands = m_freeIslands;
|
||||
|
||||
// search for free island
|
||||
if ( freeIslands.size() > 0 )
|
||||
{
|
||||
// try to reuse a previously allocated island
|
||||
int iFound = freeIslands.size();
|
||||
// linear search for smallest island that can hold our bodies
|
||||
for ( int i = freeIslands.size() - 1; i >= 0; --i )
|
||||
{
|
||||
if ( freeIslands[ i ]->bodyArray.capacity() >= allocSize )
|
||||
{
|
||||
iFound = i;
|
||||
island = freeIslands[ i ];
|
||||
island->id = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if found, shrink array while maintaining ordering
|
||||
if ( island )
|
||||
{
|
||||
int iDest = iFound;
|
||||
int iSrc = iDest + 1;
|
||||
while ( iSrc < freeIslands.size() )
|
||||
{
|
||||
freeIslands[ iDest++ ] = freeIslands[ iSrc++ ];
|
||||
}
|
||||
freeIslands.pop_back();
|
||||
}
|
||||
}
|
||||
if ( island == NULL )
|
||||
{
|
||||
// no free island found, allocate
|
||||
island = new Island(); // TODO: change this to use the pool allocator
|
||||
island->id = id;
|
||||
island->bodyArray.reserve( allocSize );
|
||||
m_allocatedIslands.push_back( island );
|
||||
}
|
||||
m_lookupIslandFromId[ id ] = island;
|
||||
if ( numBodies < m_batchIslandMinBodyCount )
|
||||
{
|
||||
m_batchIsland = island;
|
||||
}
|
||||
m_activeIslands.push_back( island );
|
||||
return island;
|
||||
}
|
||||
|
||||
|
||||
void btSimulationIslandManagerMt::buildIslands( btDispatcher* dispatcher, btCollisionWorld* collisionWorld )
|
||||
{
|
||||
|
||||
BT_PROFILE("islandUnionFindAndQuickSort");
|
||||
|
||||
btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
|
||||
|
||||
//we are going to sort the unionfind array, and store the element id in the size
|
||||
//afterwards, we clean unionfind, to make sure no-one uses it anymore
|
||||
|
||||
getUnionFind().sortIslands();
|
||||
int numElem = getUnionFind().getNumElements();
|
||||
|
||||
int endIslandIndex=1;
|
||||
int startIslandIndex;
|
||||
|
||||
//update the sleeping state for bodies, if all are sleeping
|
||||
for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
|
||||
{
|
||||
int islandId = getUnionFind().getElement(startIslandIndex).m_id;
|
||||
for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
|
||||
{
|
||||
}
|
||||
|
||||
//int numSleeping = 0;
|
||||
|
||||
bool allSleeping = true;
|
||||
|
||||
int idx;
|
||||
for (idx=startIslandIndex;idx<endIslandIndex;idx++)
|
||||
{
|
||||
int i = getUnionFind().getElement(idx).m_sz;
|
||||
|
||||
btCollisionObject* colObj0 = collisionObjects[i];
|
||||
if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
|
||||
{
|
||||
// printf("error in island management\n");
|
||||
}
|
||||
|
||||
btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
|
||||
if (colObj0->getIslandTag() == islandId)
|
||||
{
|
||||
if (colObj0->getActivationState()== ACTIVE_TAG)
|
||||
{
|
||||
allSleeping = false;
|
||||
}
|
||||
if (colObj0->getActivationState()== DISABLE_DEACTIVATION)
|
||||
{
|
||||
allSleeping = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allSleeping)
|
||||
{
|
||||
int idx;
|
||||
for (idx=startIslandIndex;idx<endIslandIndex;idx++)
|
||||
{
|
||||
int i = getUnionFind().getElement(idx).m_sz;
|
||||
btCollisionObject* colObj0 = collisionObjects[i];
|
||||
if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
|
||||
{
|
||||
// printf("error in island management\n");
|
||||
}
|
||||
|
||||
btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
|
||||
|
||||
if (colObj0->getIslandTag() == islandId)
|
||||
{
|
||||
colObj0->setActivationState( ISLAND_SLEEPING );
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
|
||||
int idx;
|
||||
for (idx=startIslandIndex;idx<endIslandIndex;idx++)
|
||||
{
|
||||
int i = getUnionFind().getElement(idx).m_sz;
|
||||
|
||||
btCollisionObject* colObj0 = collisionObjects[i];
|
||||
if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
|
||||
{
|
||||
// printf("error in island management\n");
|
||||
}
|
||||
|
||||
btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
|
||||
|
||||
if (colObj0->getIslandTag() == islandId)
|
||||
{
|
||||
if ( colObj0->getActivationState() == ISLAND_SLEEPING)
|
||||
{
|
||||
colObj0->setActivationState( WANTS_DEACTIVATION);
|
||||
colObj0->setDeactivationTime(0.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void btSimulationIslandManagerMt::addBodiesToIslands( btCollisionWorld* collisionWorld )
|
||||
{
|
||||
btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
|
||||
int endIslandIndex = 1;
|
||||
int startIslandIndex;
|
||||
int numElem = getUnionFind().getNumElements();
|
||||
|
||||
// create explicit islands and add bodies to each
|
||||
for ( startIslandIndex = 0; startIslandIndex < numElem; startIslandIndex = endIslandIndex )
|
||||
{
|
||||
int islandId = getUnionFind().getElement( startIslandIndex ).m_id;
|
||||
|
||||
// find end index
|
||||
for ( endIslandIndex = startIslandIndex; ( endIslandIndex < numElem ) && ( getUnionFind().getElement( endIslandIndex ).m_id == islandId ); endIslandIndex++ )
|
||||
{
|
||||
}
|
||||
// check if island is sleeping
|
||||
bool islandSleeping = true;
|
||||
for ( int iElem = startIslandIndex; iElem < endIslandIndex; iElem++ )
|
||||
{
|
||||
int i = getUnionFind().getElement( iElem ).m_sz;
|
||||
btCollisionObject* colObj = collisionObjects[ i ];
|
||||
if ( colObj->isActive() )
|
||||
{
|
||||
islandSleeping = false;
|
||||
}
|
||||
}
|
||||
if ( !islandSleeping )
|
||||
{
|
||||
// want to count the number of bodies before allocating the island to optimize memory usage of the Island structures
|
||||
int numBodies = endIslandIndex - startIslandIndex;
|
||||
Island* island = allocateIsland( islandId, numBodies );
|
||||
island->isSleeping = false;
|
||||
|
||||
// add bodies to island
|
||||
for ( int iElem = startIslandIndex; iElem < endIslandIndex; iElem++ )
|
||||
{
|
||||
int i = getUnionFind().getElement( iElem ).m_sz;
|
||||
btCollisionObject* colObj = collisionObjects[ i ];
|
||||
island->bodyArray.push_back( colObj );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void btSimulationIslandManagerMt::addManifoldsToIslands( btDispatcher* dispatcher )
|
||||
{
|
||||
// walk all the manifolds, activating bodies touched by kinematic objects, and add each manifold to its Island
|
||||
int maxNumManifolds = dispatcher->getNumManifolds();
|
||||
for ( int i = 0; i < maxNumManifolds; i++ )
|
||||
{
|
||||
btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal( i );
|
||||
|
||||
const btCollisionObject* colObj0 = static_cast<const btCollisionObject*>( manifold->getBody0() );
|
||||
const btCollisionObject* colObj1 = static_cast<const btCollisionObject*>( manifold->getBody1() );
|
||||
|
||||
///@todo: check sleeping conditions!
|
||||
if ( ( ( colObj0 ) && colObj0->getActivationState() != ISLAND_SLEEPING ) ||
|
||||
( ( colObj1 ) && colObj1->getActivationState() != ISLAND_SLEEPING ) )
|
||||
{
|
||||
|
||||
//kinematic objects don't merge islands, but wake up all connected objects
|
||||
if ( colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING )
|
||||
{
|
||||
if ( colObj0->hasContactResponse() )
|
||||
colObj1->activate();
|
||||
}
|
||||
if ( colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING )
|
||||
{
|
||||
if ( colObj1->hasContactResponse() )
|
||||
colObj0->activate();
|
||||
}
|
||||
//filtering for response
|
||||
if ( dispatcher->needsResponse( colObj0, colObj1 ) )
|
||||
{
|
||||
// scatter manifolds into various islands
|
||||
int islandId = getIslandId( manifold );
|
||||
// if island not sleeping,
|
||||
if ( Island* island = getIsland( islandId ) )
|
||||
{
|
||||
island->manifoldArray.push_back( manifold );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void btSimulationIslandManagerMt::addConstraintsToIslands( btAlignedObjectArray<btTypedConstraint*>& constraints )
|
||||
{
|
||||
// walk constraints
|
||||
for ( int i = 0; i < constraints.size(); i++ )
|
||||
{
|
||||
// scatter constraints into various islands
|
||||
btTypedConstraint* constraint = constraints[ i ];
|
||||
if ( constraint->isEnabled() )
|
||||
{
|
||||
int islandId = btGetConstraintIslandId( constraint );
|
||||
// if island is not sleeping,
|
||||
if ( Island* island = getIsland( islandId ) )
|
||||
{
|
||||
island->constraintArray.push_back( constraint );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void btSimulationIslandManagerMt::mergeIslands()
|
||||
{
|
||||
// sort islands in order of decreasing batch size
|
||||
m_activeIslands.quickSort( IslandBatchSizeSortPredicate() );
|
||||
|
||||
// merge small islands to satisfy minimum batch size
|
||||
// find first small batch island
|
||||
int destIslandIndex = m_activeIslands.size();
|
||||
for ( int i = 0; i < m_activeIslands.size(); ++i )
|
||||
{
|
||||
Island* island = m_activeIslands[ i ];
|
||||
int batchSize = calcBatchCost( island );
|
||||
if ( batchSize < m_minimumSolverBatchSize )
|
||||
{
|
||||
destIslandIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int lastIndex = m_activeIslands.size() - 1;
|
||||
while ( destIslandIndex < lastIndex )
|
||||
{
|
||||
// merge islands from the back of the list
|
||||
Island* island = m_activeIslands[ destIslandIndex ];
|
||||
int numBodies = island->bodyArray.size();
|
||||
int numManifolds = island->manifoldArray.size();
|
||||
int numConstraints = island->constraintArray.size();
|
||||
int firstIndex = lastIndex;
|
||||
// figure out how many islands we want to merge and find out how many bodies, manifolds and constraints we will have
|
||||
while ( true )
|
||||
{
|
||||
Island* src = m_activeIslands[ firstIndex ];
|
||||
numBodies += src->bodyArray.size();
|
||||
numManifolds += src->manifoldArray.size();
|
||||
numConstraints += src->constraintArray.size();
|
||||
int batchCost = calcBatchCost( numBodies, numManifolds, numConstraints );
|
||||
if ( batchCost >= m_minimumSolverBatchSize )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ( firstIndex - 1 == destIslandIndex )
|
||||
{
|
||||
break;
|
||||
}
|
||||
firstIndex--;
|
||||
}
|
||||
// reserve space for these pointers to minimize reallocation
|
||||
island->bodyArray.reserve( numBodies );
|
||||
island->manifoldArray.reserve( numManifolds );
|
||||
island->constraintArray.reserve( numConstraints );
|
||||
// merge islands
|
||||
for ( int i = firstIndex; i <= lastIndex; ++i )
|
||||
{
|
||||
island->append( *m_activeIslands[ i ] );
|
||||
}
|
||||
// shrink array to exclude the islands that were merged from
|
||||
m_activeIslands.resize( firstIndex );
|
||||
lastIndex = firstIndex - 1;
|
||||
destIslandIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void btSimulationIslandManagerMt::defaultIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, IslandCallback* callback )
|
||||
{
|
||||
// serial dispatch
|
||||
btAlignedObjectArray<Island*>& islands = *islandsPtr;
|
||||
for ( int i = 0; i < islands.size(); ++i )
|
||||
{
|
||||
Island* island = islands[ i ];
|
||||
btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL;
|
||||
btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL;
|
||||
callback->processIsland( &island->bodyArray[ 0 ],
|
||||
island->bodyArray.size(),
|
||||
manifolds,
|
||||
island->manifoldArray.size(),
|
||||
constraintsPtr,
|
||||
island->constraintArray.size(),
|
||||
island->id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
///@todo: this is random access, it can be walked 'cache friendly'!
|
||||
void btSimulationIslandManagerMt::buildAndProcessIslands( btDispatcher* dispatcher,
|
||||
btCollisionWorld* collisionWorld,
|
||||
btAlignedObjectArray<btTypedConstraint*>& constraints,
|
||||
IslandCallback* callback
|
||||
)
|
||||
{
|
||||
btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
|
||||
|
||||
buildIslands(dispatcher,collisionWorld);
|
||||
|
||||
BT_PROFILE("processIslands");
|
||||
|
||||
if(!getSplitIslands())
|
||||
{
|
||||
btPersistentManifold** manifolds = dispatcher->getInternalManifoldPointer();
|
||||
int maxNumManifolds = dispatcher->getNumManifolds();
|
||||
|
||||
for ( int i = 0; i < maxNumManifolds; i++ )
|
||||
{
|
||||
btPersistentManifold* manifold = manifolds[ i ];
|
||||
|
||||
const btCollisionObject* colObj0 = static_cast<const btCollisionObject*>( manifold->getBody0() );
|
||||
const btCollisionObject* colObj1 = static_cast<const btCollisionObject*>( manifold->getBody1() );
|
||||
|
||||
///@todo: check sleeping conditions!
|
||||
if ( ( ( colObj0 ) && colObj0->getActivationState() != ISLAND_SLEEPING ) ||
|
||||
( ( colObj1 ) && colObj1->getActivationState() != ISLAND_SLEEPING ) )
|
||||
{
|
||||
|
||||
//kinematic objects don't merge islands, but wake up all connected objects
|
||||
if ( colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING )
|
||||
{
|
||||
if ( colObj0->hasContactResponse() )
|
||||
colObj1->activate();
|
||||
}
|
||||
if ( colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING )
|
||||
{
|
||||
if ( colObj1->hasContactResponse() )
|
||||
colObj0->activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
btTypedConstraint** constraintsPtr = constraints.size() ? &constraints[ 0 ] : NULL;
|
||||
callback->processIsland(&collisionObjects[0],
|
||||
collisionObjects.size(),
|
||||
manifolds,
|
||||
maxNumManifolds,
|
||||
constraintsPtr,
|
||||
constraints.size(),
|
||||
-1
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
initIslandPools();
|
||||
|
||||
//traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated
|
||||
addBodiesToIslands( collisionWorld );
|
||||
addManifoldsToIslands( dispatcher );
|
||||
addConstraintsToIslands( constraints );
|
||||
|
||||
// m_activeIslands array should now contain all non-sleeping Islands, and each Island should
|
||||
// have all the necessary bodies, manifolds and constraints.
|
||||
|
||||
// if we want to merge islands with small batch counts,
|
||||
if ( m_minimumSolverBatchSize > 1 )
|
||||
{
|
||||
mergeIslands();
|
||||
}
|
||||
// dispatch islands to solver
|
||||
m_islandDispatch( &m_activeIslands, callback );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef BT_SIMULATION_ISLAND_MANAGER_MT_H
|
||||
#define BT_SIMULATION_ISLAND_MANAGER_MT_H
|
||||
|
||||
#include "btSimulationIslandManager.h"
|
||||
|
||||
class btTypedConstraint;
|
||||
|
||||
|
||||
///
|
||||
/// SimulationIslandManagerMt -- Multithread capable version of SimulationIslandManager
|
||||
/// Splits the world up into islands which can be solved in parallel.
|
||||
/// In order to solve islands in parallel, an IslandDispatch function
|
||||
/// must be provided which will dispatch calls to multiple threads.
|
||||
/// The amount of parallelism that can be achieved depends on the number
|
||||
/// of islands. If only a single island exists, then no parallelism is
|
||||
/// possible.
|
||||
///
|
||||
class btSimulationIslandManagerMt : public btSimulationIslandManager
|
||||
{
|
||||
public:
|
||||
struct Island
|
||||
{
|
||||
// a simulation island consisting of bodies, manifolds and constraints,
|
||||
// to be passed into a constraint solver.
|
||||
btAlignedObjectArray<btCollisionObject*> bodyArray;
|
||||
btAlignedObjectArray<btPersistentManifold*> manifoldArray;
|
||||
btAlignedObjectArray<btTypedConstraint*> constraintArray;
|
||||
int id; // island id
|
||||
bool isSleeping;
|
||||
|
||||
void append( const Island& other ); // add bodies, manifolds, constraints to my own
|
||||
};
|
||||
struct IslandCallback
|
||||
{
|
||||
virtual ~IslandCallback() {};
|
||||
|
||||
virtual void processIsland( btCollisionObject** bodies,
|
||||
int numBodies,
|
||||
btPersistentManifold** manifolds,
|
||||
int numManifolds,
|
||||
btTypedConstraint** constraints,
|
||||
int numConstraints,
|
||||
int islandId
|
||||
) = 0;
|
||||
};
|
||||
typedef void( *IslandDispatchFunc ) ( btAlignedObjectArray<Island*>* islands, IslandCallback* callback );
|
||||
static void defaultIslandDispatch( btAlignedObjectArray<Island*>* islands, IslandCallback* callback );
|
||||
protected:
|
||||
btAlignedObjectArray<Island*> m_allocatedIslands; // owner of all Islands
|
||||
btAlignedObjectArray<Island*> m_activeIslands; // islands actively in use
|
||||
btAlignedObjectArray<Island*> m_freeIslands; // islands ready to be reused
|
||||
btAlignedObjectArray<Island*> m_lookupIslandFromId; // big lookup table to map islandId to Island pointer
|
||||
Island* m_batchIsland;
|
||||
int m_minimumSolverBatchSize;
|
||||
int m_batchIslandMinBodyCount;
|
||||
IslandDispatchFunc m_islandDispatch;
|
||||
|
||||
Island* getIsland( int id );
|
||||
virtual Island* allocateIsland( int id, int numBodies );
|
||||
virtual void initIslandPools();
|
||||
virtual void addBodiesToIslands( btCollisionWorld* collisionWorld );
|
||||
virtual void addManifoldsToIslands( btDispatcher* dispatcher );
|
||||
virtual void addConstraintsToIslands( btAlignedObjectArray<btTypedConstraint*>& constraints );
|
||||
virtual void mergeIslands();
|
||||
|
||||
public:
|
||||
btSimulationIslandManagerMt();
|
||||
virtual ~btSimulationIslandManagerMt();
|
||||
|
||||
virtual void buildAndProcessIslands( btDispatcher* dispatcher, btCollisionWorld* collisionWorld, btAlignedObjectArray<btTypedConstraint*>& constraints, IslandCallback* callback );
|
||||
|
||||
virtual void buildIslands(btDispatcher* dispatcher,btCollisionWorld* colWorld);
|
||||
|
||||
int getMinimumSolverBatchSize() const
|
||||
{
|
||||
return m_minimumSolverBatchSize;
|
||||
}
|
||||
void setMinimumSolverBatchSize( int sz )
|
||||
{
|
||||
m_minimumSolverBatchSize = sz;
|
||||
}
|
||||
IslandDispatchFunc getIslandDispatchFunction() const
|
||||
{
|
||||
return m_islandDispatch;
|
||||
}
|
||||
// allow users to set their own dispatch function for multithreaded dispatch
|
||||
void setIslandDispatchFunction( IslandDispatchFunc func )
|
||||
{
|
||||
m_islandDispatch = func;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //BT_SIMULATION_ISLAND_MANAGER_H
|
||||
|
||||
@@ -23,6 +23,59 @@ subject to the following restrictions:
|
||||
#include "btGImpactMassUtil.h"
|
||||
|
||||
|
||||
btGImpactMeshShapePart::btGImpactMeshShapePart( btStridingMeshInterface * meshInterface, int part )
|
||||
{
|
||||
// moved from .h to .cpp because of conditional compilation
|
||||
// (The setting of BT_THREADSAFE may differ between various cpp files, so it is best to
|
||||
// avoid using it in h files)
|
||||
m_primitive_manager.m_meshInterface = meshInterface;
|
||||
m_primitive_manager.m_part = part;
|
||||
m_box_set.setPrimitiveManager( &m_primitive_manager );
|
||||
#if BT_THREADSAFE
|
||||
// If threadsafe is requested, this object uses a different lock/unlock
|
||||
// model with the btStridingMeshInterface -- lock once when the object is constructed
|
||||
// and unlock once in the destructor.
|
||||
// The other way of locking and unlocking for each collision check in the narrowphase
|
||||
// is not threadsafe. Note these are not thread-locks, they are calls to the meshInterface's
|
||||
// getLockedReadOnlyVertexIndexBase virtual function, which by default just returns a couple of
|
||||
// pointers. In theory a client could override the lock function to do all sorts of
|
||||
// things like reading data from GPU memory, or decompressing data on the fly, but such things
|
||||
// do not seem all that likely or useful, given the performance cost.
|
||||
m_primitive_manager.lock();
|
||||
#endif
|
||||
}
|
||||
|
||||
btGImpactMeshShapePart::~btGImpactMeshShapePart()
|
||||
{
|
||||
// moved from .h to .cpp because of conditional compilation
|
||||
#if BT_THREADSAFE
|
||||
m_primitive_manager.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void btGImpactMeshShapePart::lockChildShapes() const
|
||||
{
|
||||
// moved from .h to .cpp because of conditional compilation
|
||||
#if ! BT_THREADSAFE
|
||||
// called in the narrowphase -- not threadsafe!
|
||||
void * dummy = (void*) ( m_box_set.getPrimitiveManager() );
|
||||
TrimeshPrimitiveManager * dummymanager = static_cast<TrimeshPrimitiveManager *>( dummy );
|
||||
dummymanager->lock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void btGImpactMeshShapePart::unlockChildShapes() const
|
||||
{
|
||||
// moved from .h to .cpp because of conditional compilation
|
||||
#if ! BT_THREADSAFE
|
||||
// called in the narrowphase -- not threadsafe!
|
||||
void * dummy = (void*) ( m_box_set.getPrimitiveManager() );
|
||||
TrimeshPrimitiveManager * dummymanager = static_cast<TrimeshPrimitiveManager *>( dummy );
|
||||
dummymanager->unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define CALC_EXACT_INERTIA 1
|
||||
|
||||
|
||||
|
||||
@@ -722,17 +722,8 @@ public:
|
||||
m_box_set.setPrimitiveManager(&m_primitive_manager);
|
||||
}
|
||||
|
||||
|
||||
btGImpactMeshShapePart(btStridingMeshInterface * meshInterface, int part)
|
||||
{
|
||||
m_primitive_manager.m_meshInterface = meshInterface;
|
||||
m_primitive_manager.m_part = part;
|
||||
m_box_set.setPrimitiveManager(&m_primitive_manager);
|
||||
}
|
||||
|
||||
virtual ~btGImpactMeshShapePart()
|
||||
{
|
||||
}
|
||||
btGImpactMeshShapePart( btStridingMeshInterface * meshInterface, int part );
|
||||
virtual ~btGImpactMeshShapePart();
|
||||
|
||||
//! if true, then its children must get transforms.
|
||||
virtual bool childrenHasTransform() const
|
||||
@@ -742,19 +733,8 @@ public:
|
||||
|
||||
|
||||
//! call when reading child shapes
|
||||
virtual void lockChildShapes() const
|
||||
{
|
||||
void * dummy = (void*)(m_box_set.getPrimitiveManager());
|
||||
TrimeshPrimitiveManager * dummymanager = static_cast<TrimeshPrimitiveManager *>(dummy);
|
||||
dummymanager->lock();
|
||||
}
|
||||
|
||||
virtual void unlockChildShapes() const
|
||||
{
|
||||
void * dummy = (void*)(m_box_set.getPrimitiveManager());
|
||||
TrimeshPrimitiveManager * dummymanager = static_cast<TrimeshPrimitiveManager *>(dummy);
|
||||
dummymanager->unlock();
|
||||
}
|
||||
virtual void lockChildShapes() const;
|
||||
virtual void unlockChildShapes() const;
|
||||
|
||||
//! Gets the number of children
|
||||
virtual int getNumChildShapes() const
|
||||
|
||||
@@ -21,6 +21,7 @@ SET(BulletDynamics_SRCS
|
||||
ConstraintSolver/btTypedConstraint.cpp
|
||||
ConstraintSolver/btUniversalConstraint.cpp
|
||||
Dynamics/btDiscreteDynamicsWorld.cpp
|
||||
Dynamics/btDiscreteDynamicsWorldMt.cpp
|
||||
Dynamics/btRigidBody.cpp
|
||||
Dynamics/btSimpleDynamicsWorld.cpp
|
||||
# Dynamics/Bullet-C-API.cpp
|
||||
@@ -70,6 +71,7 @@ SET(ConstraintSolver_HDRS
|
||||
SET(Dynamics_HDRS
|
||||
Dynamics/btActionInterface.h
|
||||
Dynamics/btDiscreteDynamicsWorld.h
|
||||
Dynamics/btDiscreteDynamicsWorldMt.h
|
||||
Dynamics/btDynamicsWorld.h
|
||||
Dynamics/btSimpleDynamicsWorld.h
|
||||
Dynamics/btRigidBody.h
|
||||
|
||||
@@ -716,8 +716,64 @@ btSolverConstraint& btSequentialImpulseConstraintSolver::addTorsionalFrictionCon
|
||||
|
||||
int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject& body,btScalar timeStep)
|
||||
{
|
||||
#if BT_THREADSAFE
|
||||
int solverBodyId = -1;
|
||||
if ( !body.isStaticOrKinematicObject() )
|
||||
{
|
||||
// dynamic body
|
||||
// Dynamic bodies can only be in one island, so it's safe to write to the companionId
|
||||
solverBodyId = body.getCompanionId();
|
||||
if ( solverBodyId < 0 )
|
||||
{
|
||||
if ( btRigidBody* rb = btRigidBody::upcast( &body ) )
|
||||
{
|
||||
solverBodyId = m_tmpSolverBodyPool.size();
|
||||
btSolverBody& solverBody = m_tmpSolverBodyPool.expand();
|
||||
initSolverBody( &solverBody, &body, timeStep );
|
||||
body.setCompanionId( solverBodyId );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( body.isStaticObject() )
|
||||
{
|
||||
// all fixed bodies (inf mass) get mapped to a single solver id
|
||||
if ( m_fixedBodyId < 0 )
|
||||
{
|
||||
m_fixedBodyId = m_tmpSolverBodyPool.size();
|
||||
btSolverBody& fixedBody = m_tmpSolverBodyPool.expand();
|
||||
initSolverBody( &fixedBody, 0, timeStep );
|
||||
}
|
||||
solverBodyId = m_fixedBodyId;
|
||||
}
|
||||
else
|
||||
{
|
||||
// kinematic
|
||||
// Kinematic bodies can be in multiple islands at once, so it is a
|
||||
// race condition to write to them, so we use an alternate method
|
||||
// to record the solverBodyId
|
||||
int uniqueId = body.getUniqueId();
|
||||
const int INVALID_SOLVER_BODY_ID = -1;
|
||||
if (uniqueId >= m_kinematicBodyUniqueIdToSolverBodyTable.size())
|
||||
{
|
||||
m_kinematicBodyUniqueIdToSolverBodyTable.resize(uniqueId + 1, INVALID_SOLVER_BODY_ID);
|
||||
}
|
||||
solverBodyId = m_kinematicBodyUniqueIdToSolverBodyTable[ uniqueId ];
|
||||
// if no table entry yet,
|
||||
if ( solverBodyId == INVALID_SOLVER_BODY_ID )
|
||||
{
|
||||
// create a table entry for this body
|
||||
btRigidBody* rb = btRigidBody::upcast( &body );
|
||||
solverBodyId = m_tmpSolverBodyPool.size();
|
||||
btSolverBody& solverBody = m_tmpSolverBodyPool.expand();
|
||||
initSolverBody( &solverBody, &body, timeStep );
|
||||
m_kinematicBodyUniqueIdToSolverBodyTable[ uniqueId ] = solverBodyId;
|
||||
}
|
||||
}
|
||||
btAssert( solverBodyId < m_tmpSolverBodyPool.size() );
|
||||
return solverBodyId;
|
||||
#else // BT_THREADSAFE
|
||||
|
||||
int solverBodyIdA = -1;
|
||||
int solverBodyIdA = -1;
|
||||
|
||||
if (body.getCompanionId() >= 0)
|
||||
{
|
||||
@@ -749,6 +805,7 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject&
|
||||
}
|
||||
|
||||
return solverBodyIdA;
|
||||
#endif // BT_THREADSAFE
|
||||
|
||||
}
|
||||
#include <stdio.h>
|
||||
@@ -1263,7 +1320,9 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
|
||||
{
|
||||
bodies[i]->setCompanionId(-1);
|
||||
}
|
||||
|
||||
#if BT_THREADSAFE
|
||||
m_kinematicBodyUniqueIdToSolverBodyTable.resize( 0 );
|
||||
#endif // BT_THREADSAFE
|
||||
|
||||
m_tmpSolverBodyPool.reserve(numBodies+1);
|
||||
m_tmpSolverBodyPool.resize(0);
|
||||
|
||||
@@ -45,6 +45,14 @@ protected:
|
||||
btAlignedObjectArray<btTypedConstraint::btConstraintInfo1> m_tmpConstraintSizesPool;
|
||||
int m_maxOverrideNumSolverIterations;
|
||||
int m_fixedBodyId;
|
||||
// When running solvers on multiple threads, a race condition exists for Kinematic objects that
|
||||
// participate in more than one solver.
|
||||
// The getOrInitSolverBody() function writes the companionId of each body (storing the index of the solver body
|
||||
// for the current solver). For normal dynamic bodies it isn't an issue because they can only be in one island
|
||||
// (and therefore one thread) at a time. But kinematic bodies can be in multiple islands at once.
|
||||
// To avoid this race condition, this solver does not write the companionId, instead it stores the solver body
|
||||
// index in this solver-local table, indexed by the uniqueId of the body.
|
||||
btAlignedObjectArray<int> m_kinematicBodyUniqueIdToSolverBodyTable; // only used for multithreading
|
||||
|
||||
btSingleConstraintRowSolver m_resolveSingleConstraintRowGeneric;
|
||||
btSingleConstraintRowSolver m_resolveSingleConstraintRowLowerLimit;
|
||||
|
||||
@@ -878,25 +878,12 @@ public:
|
||||
int gNumClampedCcdMotions=0;
|
||||
|
||||
|
||||
void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep)
|
||||
void btDiscreteDynamicsWorld::createPredictiveContactsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep)
|
||||
{
|
||||
BT_PROFILE("createPredictiveContacts");
|
||||
|
||||
{
|
||||
BT_PROFILE("release predictive contact manifolds");
|
||||
|
||||
for (int i=0;i<m_predictiveManifolds.size();i++)
|
||||
{
|
||||
btPersistentManifold* manifold = m_predictiveManifolds[i];
|
||||
this->m_dispatcher1->releaseManifold(manifold);
|
||||
}
|
||||
m_predictiveManifolds.clear();
|
||||
}
|
||||
|
||||
btTransform predictedTrans;
|
||||
for ( int i=0;i<m_nonStaticRigidBodies.size();i++)
|
||||
for ( int i=0;i<numBodies;i++)
|
||||
{
|
||||
btRigidBody* body = m_nonStaticRigidBodies[i];
|
||||
btRigidBody* body = bodies[i];
|
||||
body->setHitFraction(1.f);
|
||||
|
||||
if (body->isActive() && (!body->isStaticOrKinematicObject()))
|
||||
@@ -953,7 +940,9 @@ void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep)
|
||||
|
||||
|
||||
btPersistentManifold* manifold = m_dispatcher1->getNewManifold(body,sweepResults.m_hitCollisionObject);
|
||||
btMutexLock( &m_predictiveManifoldsMutex );
|
||||
m_predictiveManifolds.push_back(manifold);
|
||||
btMutexUnlock( &m_predictiveManifoldsMutex );
|
||||
|
||||
btVector3 worldPointB = body->getWorldTransform().getOrigin()+distVec;
|
||||
btVector3 localPointB = sweepResults.m_hitCollisionObject->getWorldTransform().inverse()*worldPointB;
|
||||
@@ -974,13 +963,35 @@ void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep)
|
||||
}
|
||||
}
|
||||
}
|
||||
void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
|
||||
|
||||
void btDiscreteDynamicsWorld::releasePredictiveContacts()
|
||||
{
|
||||
BT_PROFILE( "release predictive contact manifolds" );
|
||||
|
||||
for ( int i = 0; i < m_predictiveManifolds.size(); i++ )
|
||||
{
|
||||
btPersistentManifold* manifold = m_predictiveManifolds[ i ];
|
||||
this->m_dispatcher1->releaseManifold( manifold );
|
||||
}
|
||||
m_predictiveManifolds.clear();
|
||||
}
|
||||
|
||||
void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep)
|
||||
{
|
||||
BT_PROFILE("createPredictiveContacts");
|
||||
releasePredictiveContacts();
|
||||
if (m_nonStaticRigidBodies.size() > 0)
|
||||
{
|
||||
createPredictiveContactsInternal( &m_nonStaticRigidBodies[ 0 ], m_nonStaticRigidBodies.size(), timeStep );
|
||||
}
|
||||
}
|
||||
|
||||
void btDiscreteDynamicsWorld::integrateTransformsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep )
|
||||
{
|
||||
BT_PROFILE("integrateTransforms");
|
||||
btTransform predictedTrans;
|
||||
for ( int i=0;i<m_nonStaticRigidBodies.size();i++)
|
||||
for (int i=0;i<numBodies;i++)
|
||||
{
|
||||
btRigidBody* body = m_nonStaticRigidBodies[i];
|
||||
btRigidBody* body = bodies[i];
|
||||
body->setHitFraction(1.f);
|
||||
|
||||
if (body->isActive() && (!body->isStaticOrKinematicObject()))
|
||||
@@ -1080,7 +1091,17 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
|
||||
|
||||
}
|
||||
|
||||
///this should probably be switched on by default, but it is not well tested yet
|
||||
}
|
||||
|
||||
void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
|
||||
{
|
||||
BT_PROFILE("integrateTransforms");
|
||||
if (m_nonStaticRigidBodies.size() > 0)
|
||||
{
|
||||
integrateTransformsInternal(&m_nonStaticRigidBodies[0], m_nonStaticRigidBodies.size(), timeStep);
|
||||
}
|
||||
|
||||
///this should probably be switched on by default, but it is not well tested yet
|
||||
if (m_applySpeculativeContactRestitution)
|
||||
{
|
||||
BT_PROFILE("apply speculative contact restitution");
|
||||
@@ -1114,14 +1135,12 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void btDiscreteDynamicsWorld::predictUnconstraintMotion(btScalar timeStep)
|
||||
{
|
||||
BT_PROFILE("predictUnconstraintMotion");
|
||||
|
||||
@@ -30,6 +30,7 @@ class btIDebugDraw;
|
||||
struct InplaceSolverIslandCallback;
|
||||
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "LinearMath/btThreads.h"
|
||||
|
||||
|
||||
///btDiscreteDynamicsWorld provides discrete rigid body simulation
|
||||
@@ -68,9 +69,11 @@ protected:
|
||||
bool m_latencyMotionStateInterpolation;
|
||||
|
||||
btAlignedObjectArray<btPersistentManifold*> m_predictiveManifolds;
|
||||
btSpinMutex m_predictiveManifoldsMutex; // used to synchronize threads creating predictive contacts
|
||||
|
||||
virtual void predictUnconstraintMotion(btScalar timeStep);
|
||||
|
||||
void integrateTransformsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep ); // can be called in parallel
|
||||
virtual void integrateTransforms(btScalar timeStep);
|
||||
|
||||
virtual void calculateSimulationIslands();
|
||||
@@ -85,7 +88,9 @@ protected:
|
||||
|
||||
virtual void internalSingleStepSimulation( btScalar timeStep);
|
||||
|
||||
void createPredictiveContacts(btScalar timeStep);
|
||||
void releasePredictiveContacts();
|
||||
void createPredictiveContactsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep ); // can be called in parallel
|
||||
virtual void createPredictiveContacts(btScalar timeStep);
|
||||
|
||||
virtual void saveKinematicState(btScalar timeStep);
|
||||
|
||||
|
||||
168
src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp
Normal file
168
src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include "btDiscreteDynamicsWorldMt.h"
|
||||
|
||||
//collision detection
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
||||
#include "BulletCollision/CollisionShapes/btCollisionShape.h"
|
||||
#include "BulletCollision/CollisionDispatch/btSimulationIslandManagerMt.h"
|
||||
#include "LinearMath/btTransformUtil.h"
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
|
||||
//rigidbody & constraints
|
||||
#include "BulletDynamics/Dynamics/btRigidBody.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btHingeConstraint.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btSliderConstraint.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btContactConstraint.h"
|
||||
|
||||
|
||||
#include "LinearMath/btIDebugDraw.h"
|
||||
#include "BulletCollision/CollisionShapes/btSphereShape.h"
|
||||
|
||||
|
||||
#include "BulletDynamics/Dynamics/btActionInterface.h"
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
#include "LinearMath/btMotionState.h"
|
||||
|
||||
#include "LinearMath/btSerializer.h"
|
||||
|
||||
|
||||
struct InplaceSolverIslandCallbackMt : public btSimulationIslandManagerMt::IslandCallback
|
||||
{
|
||||
btContactSolverInfo* m_solverInfo;
|
||||
btConstraintSolver* m_solver;
|
||||
btIDebugDraw* m_debugDrawer;
|
||||
btDispatcher* m_dispatcher;
|
||||
|
||||
InplaceSolverIslandCallbackMt(
|
||||
btConstraintSolver* solver,
|
||||
btStackAlloc* stackAlloc,
|
||||
btDispatcher* dispatcher)
|
||||
:m_solverInfo(NULL),
|
||||
m_solver(solver),
|
||||
m_debugDrawer(NULL),
|
||||
m_dispatcher(dispatcher)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
InplaceSolverIslandCallbackMt& operator=(InplaceSolverIslandCallbackMt& other)
|
||||
{
|
||||
btAssert(0);
|
||||
(void)other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SIMD_FORCE_INLINE void setup ( btContactSolverInfo* solverInfo, btIDebugDraw* debugDrawer)
|
||||
{
|
||||
btAssert(solverInfo);
|
||||
m_solverInfo = solverInfo;
|
||||
m_debugDrawer = debugDrawer;
|
||||
}
|
||||
|
||||
|
||||
virtual void processIsland( btCollisionObject** bodies,
|
||||
int numBodies,
|
||||
btPersistentManifold** manifolds,
|
||||
int numManifolds,
|
||||
btTypedConstraint** constraints,
|
||||
int numConstraints,
|
||||
int islandId
|
||||
)
|
||||
{
|
||||
m_solver->solveGroup( bodies,
|
||||
numBodies,
|
||||
manifolds,
|
||||
numManifolds,
|
||||
constraints,
|
||||
numConstraints,
|
||||
*m_solverInfo,
|
||||
m_debugDrawer,
|
||||
m_dispatcher
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
btDiscreteDynamicsWorldMt::btDiscreteDynamicsWorldMt(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver, btCollisionConfiguration* collisionConfiguration)
|
||||
: btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration)
|
||||
{
|
||||
if (m_ownsIslandManager)
|
||||
{
|
||||
m_islandManager->~btSimulationIslandManager();
|
||||
btAlignedFree( m_islandManager);
|
||||
}
|
||||
{
|
||||
void* mem = btAlignedAlloc(sizeof(InplaceSolverIslandCallbackMt),16);
|
||||
m_solverIslandCallbackMt = new (mem) InplaceSolverIslandCallbackMt (m_constraintSolver, 0, dispatcher);
|
||||
}
|
||||
{
|
||||
void* mem = btAlignedAlloc(sizeof(btSimulationIslandManagerMt),16);
|
||||
btSimulationIslandManagerMt* im = new (mem) btSimulationIslandManagerMt();
|
||||
m_islandManager = im;
|
||||
im->setMinimumSolverBatchSize( m_solverInfo.m_minimumSolverBatchSize );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
btDiscreteDynamicsWorldMt::~btDiscreteDynamicsWorldMt()
|
||||
{
|
||||
if (m_solverIslandCallbackMt)
|
||||
{
|
||||
m_solverIslandCallbackMt->~InplaceSolverIslandCallbackMt();
|
||||
btAlignedFree(m_solverIslandCallbackMt);
|
||||
}
|
||||
if (m_ownsConstraintSolver)
|
||||
{
|
||||
m_constraintSolver->~btConstraintSolver();
|
||||
btAlignedFree(m_constraintSolver);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void btDiscreteDynamicsWorldMt::solveConstraints(btContactSolverInfo& solverInfo)
|
||||
{
|
||||
BT_PROFILE("solveConstraints");
|
||||
|
||||
|
||||
m_solverIslandCallbackMt->setup(&solverInfo, getDebugDrawer());
|
||||
m_constraintSolver->prepareSolve(getCollisionWorld()->getNumCollisionObjects(), getCollisionWorld()->getDispatcher()->getNumManifolds());
|
||||
|
||||
/// solve all the constraints for this island
|
||||
btSimulationIslandManagerMt* im = static_cast<btSimulationIslandManagerMt*>(m_islandManager);
|
||||
im->buildAndProcessIslands( getCollisionWorld()->getDispatcher(), getCollisionWorld(), m_constraints, m_solverIslandCallbackMt );
|
||||
|
||||
m_constraintSolver->allSolved(solverInfo, m_debugDrawer);
|
||||
}
|
||||
|
||||
|
||||
void btDiscreteDynamicsWorldMt::addCollisionObject(btCollisionObject* collisionObject, short int collisionFilterGroup, short int collisionFilterMask)
|
||||
{
|
||||
collisionObject->setUniqueId(m_collisionObjects.size());
|
||||
btDiscreteDynamicsWorld::addCollisionObject(collisionObject, collisionFilterGroup, collisionFilterMask);
|
||||
}
|
||||
44
src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h
Normal file
44
src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BT_DISCRETE_DYNAMICS_WORLD_MT_H
|
||||
#define BT_DISCRETE_DYNAMICS_WORLD_MT_H
|
||||
|
||||
#include "btDiscreteDynamicsWorld.h"
|
||||
|
||||
struct InplaceSolverIslandCallbackMt;
|
||||
|
||||
///
|
||||
/// btDiscreteDynamicsWorldMt -- a version of DiscreteDynamicsWorld with some minor changes to support
|
||||
/// solving simulation islands on multiple threads.
|
||||
///
|
||||
ATTRIBUTE_ALIGNED16(class) btDiscreteDynamicsWorldMt : public btDiscreteDynamicsWorld
|
||||
{
|
||||
protected:
|
||||
InplaceSolverIslandCallbackMt* m_solverIslandCallbackMt;
|
||||
|
||||
virtual void solveConstraints(btContactSolverInfo& solverInfo);
|
||||
|
||||
public:
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
virtual void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=btBroadphaseProxy::StaticFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter);
|
||||
|
||||
btDiscreteDynamicsWorldMt(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration);
|
||||
virtual ~btDiscreteDynamicsWorldMt();
|
||||
};
|
||||
|
||||
#endif //BT_DISCRETE_DYNAMICS_WORLD_H
|
||||
@@ -215,12 +215,12 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
|
||||
jointNodeArray.reserve(2*m_allConstraintPtrArray.size());
|
||||
}
|
||||
|
||||
static btMatrixXu J3;
|
||||
btMatrixXu& J3 = m_scratchJ3;
|
||||
{
|
||||
BT_PROFILE("J3.resize");
|
||||
J3.resize(2*m,8);
|
||||
}
|
||||
static btMatrixXu JinvM3;
|
||||
btMatrixXu& JinvM3 = m_scratchJInvM3;
|
||||
{
|
||||
BT_PROFILE("JinvM3.resize/setZero");
|
||||
|
||||
@@ -230,7 +230,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
|
||||
}
|
||||
int cur=0;
|
||||
int rowOffset = 0;
|
||||
static btAlignedObjectArray<int> ofs;
|
||||
btAlignedObjectArray<int>& ofs = m_scratchOfs;
|
||||
{
|
||||
BT_PROFILE("ofs resize");
|
||||
ofs.resize(0);
|
||||
@@ -489,7 +489,7 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal)
|
||||
}
|
||||
}
|
||||
|
||||
static btMatrixXu Minv;
|
||||
btMatrixXu& Minv = m_scratchMInv;
|
||||
Minv.resize(6*numBodies,6*numBodies);
|
||||
Minv.setZero();
|
||||
for (int i=0;i<numBodies;i++)
|
||||
@@ -506,7 +506,7 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal)
|
||||
setElem(Minv,i*6+3+r,i*6+3+c,orgBody? orgBody->getInvInertiaTensorWorld()[r][c] : 0);
|
||||
}
|
||||
|
||||
static btMatrixXu J;
|
||||
btMatrixXu& J = m_scratchJ;
|
||||
J.resize(numConstraintRows,6*numBodies);
|
||||
J.setZero();
|
||||
|
||||
@@ -541,10 +541,10 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal)
|
||||
}
|
||||
}
|
||||
|
||||
static btMatrixXu J_transpose;
|
||||
btMatrixXu& J_transpose = m_scratchJTranspose;
|
||||
J_transpose= J.transpose();
|
||||
|
||||
static btMatrixXu tmp;
|
||||
btMatrixXu& tmp = m_scratchTmp;
|
||||
|
||||
{
|
||||
{
|
||||
|
||||
@@ -43,6 +43,17 @@ protected:
|
||||
btMLCPSolverInterface* m_solver;
|
||||
int m_fallback;
|
||||
|
||||
/// The following scratch variables are not stateful -- contents are cleared prior to each use.
|
||||
/// They are only cached here to avoid extra memory allocations and deallocations and to ensure
|
||||
/// that multiple instances of the solver can be run in parallel.
|
||||
btMatrixXu m_scratchJ3;
|
||||
btMatrixXu m_scratchJInvM3;
|
||||
btAlignedObjectArray<int> m_scratchOfs;
|
||||
btMatrixXu m_scratchMInv;
|
||||
btMatrixXu m_scratchJ;
|
||||
btMatrixXu m_scratchJTranspose;
|
||||
btMatrixXu m_scratchTmp;
|
||||
|
||||
virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
|
||||
virtual btScalar solveGroupCacheFriendlyIterations(btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ SET(LinearMath_SRCS
|
||||
btPolarDecomposition.cpp
|
||||
btQuickprof.cpp
|
||||
btSerializer.cpp
|
||||
btThreads.cpp
|
||||
btVector3.cpp
|
||||
)
|
||||
|
||||
@@ -38,6 +39,7 @@ SET(LinearMath_HDRS
|
||||
btScalar.h
|
||||
btSerializer.h
|
||||
btStackAlloc.h
|
||||
btThreads.h
|
||||
btTransform.h
|
||||
btTransformUtil.h
|
||||
btVector3.h
|
||||
|
||||
@@ -322,7 +322,7 @@ protected:
|
||||
{
|
||||
public:
|
||||
|
||||
bool operator() ( const T& a, const T& b )
|
||||
bool operator() ( const T& a, const T& b ) const
|
||||
{
|
||||
return ( a < b );
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ btVector3 NormalOf(const btVector3 *vert, const int n);
|
||||
btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1)
|
||||
{
|
||||
// returns the point where the line p0-p1 intersects the plane n&d
|
||||
static btVector3 dif;
|
||||
btVector3 dif;
|
||||
dif = p1-p0;
|
||||
btScalar dn= btDot(plane.normal,dif);
|
||||
btScalar t = -(plane.dist+btDot(plane.normal,p0) )/dn;
|
||||
@@ -112,7 +112,7 @@ btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v
|
||||
|
||||
btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint, btVector3 *vpoint)
|
||||
{
|
||||
static btVector3 cp;
|
||||
btVector3 cp;
|
||||
cp = btCross(udir,vdir).normalized();
|
||||
|
||||
btScalar distu = -btDot(cp,ustart);
|
||||
|
||||
@@ -18,6 +18,7 @@ subject to the following restrictions:
|
||||
|
||||
#include "btScalar.h"
|
||||
#include "btAlignedAllocator.h"
|
||||
#include "btThreads.h"
|
||||
|
||||
///The btPoolAllocator class allows to efficiently allocate a large pool of objects, instead of dynamically allocating them separately.
|
||||
class btPoolAllocator
|
||||
@@ -27,6 +28,7 @@ class btPoolAllocator
|
||||
int m_freeCount;
|
||||
void* m_firstFree;
|
||||
unsigned char* m_pool;
|
||||
btSpinMutex m_mutex; // only used if BT_THREADSAFE
|
||||
|
||||
public:
|
||||
|
||||
@@ -71,11 +73,16 @@ public:
|
||||
{
|
||||
// release mode fix
|
||||
(void)size;
|
||||
btMutexLock(&m_mutex);
|
||||
btAssert(!size || size<=m_elemSize);
|
||||
btAssert(m_freeCount>0);
|
||||
//btAssert(m_freeCount>0); // should return null if all full
|
||||
void* result = m_firstFree;
|
||||
m_firstFree = *(void**)m_firstFree;
|
||||
--m_freeCount;
|
||||
if (NULL != m_firstFree)
|
||||
{
|
||||
m_firstFree = *(void**)m_firstFree;
|
||||
--m_freeCount;
|
||||
}
|
||||
btMutexUnlock(&m_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -95,9 +102,11 @@ public:
|
||||
if (ptr) {
|
||||
btAssert((unsigned char*)ptr >= m_pool && (unsigned char*)ptr < m_pool + m_maxElements * m_elemSize);
|
||||
|
||||
btMutexLock(&m_mutex);
|
||||
*(void**)ptr = m_firstFree;
|
||||
m_firstFree = ptr;
|
||||
++m_freeCount;
|
||||
btMutexUnlock(&m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "btQuickprof.h"
|
||||
|
||||
|
||||
#if BT_THREADSAFE
|
||||
#include "btThreads.h"
|
||||
#endif //#if BT_THREADSAFE
|
||||
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
@@ -455,6 +458,14 @@ unsigned long int CProfileManager::ResetTime = 0;
|
||||
*=============================================================================================*/
|
||||
void CProfileManager::Start_Profile( const char * name )
|
||||
{
|
||||
#if BT_THREADSAFE
|
||||
// profile system is not designed for profiling multiple threads
|
||||
// disable collection on all but the main thread
|
||||
if ( !btIsMainThread() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif //#if BT_THREADSAFE
|
||||
if (name != CurrentNode->Get_Name()) {
|
||||
CurrentNode = CurrentNode->Get_Sub_Node( name );
|
||||
}
|
||||
@@ -468,6 +479,14 @@ void CProfileManager::Start_Profile( const char * name )
|
||||
*=============================================================================================*/
|
||||
void CProfileManager::Stop_Profile( void )
|
||||
{
|
||||
#if BT_THREADSAFE
|
||||
// profile system is not designed for profiling multiple threads
|
||||
// disable collection on all but the main thread
|
||||
if ( !btIsMainThread() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif //#if BT_THREADSAFE
|
||||
// Return will indicate whether we should back up to our parent (we may
|
||||
// be profiling a recursive function)
|
||||
if (CurrentNode->Return()) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
230
src/LinearMath/btThreads.cpp
Normal file
230
src/LinearMath/btThreads.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
Copyright (c) 2003-2014 Erwin Coumans http://bullet.googlecode.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include "btThreads.h"
|
||||
|
||||
//
|
||||
// Lightweight spin-mutex based on atomics
|
||||
// Using ordinary system-provided mutexes like Windows critical sections was noticeably slower
|
||||
// presumably because when it fails to lock at first it would sleep the thread and trigger costly
|
||||
// context switching.
|
||||
//
|
||||
|
||||
#if BT_THREADSAFE
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
|
||||
// for anything claiming full C++11 compliance, use C++11 atomics
|
||||
// on GCC or Clang you need to compile with -std=c++11
|
||||
#define USE_CPP11_ATOMICS 1
|
||||
|
||||
#elif defined( _MSC_VER )
|
||||
|
||||
// on MSVC, use intrinsics instead
|
||||
#define USE_MSVC_INTRINSICS 1
|
||||
|
||||
#elif defined( __GNUC__ ) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
|
||||
|
||||
// available since GCC 4.7 and some versions of clang
|
||||
// todo: check for clang
|
||||
#define USE_GCC_BUILTIN_ATOMICS 1
|
||||
|
||||
#elif defined( __GNUC__ ) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
|
||||
|
||||
// available since GCC 4.1
|
||||
#define USE_GCC_BUILTIN_ATOMICS_OLD 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if USE_CPP11_ATOMICS
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
#define THREAD_LOCAL_STATIC thread_local static
|
||||
|
||||
bool btSpinMutex::tryLock()
|
||||
{
|
||||
std::atomic<int>* aDest = reinterpret_cast<std::atomic<int>*>(&mLock);
|
||||
int expected = 0;
|
||||
return std::atomic_compare_exchange_weak_explicit( aDest, &expected, int(1), std::memory_order_acq_rel, std::memory_order_acquire );
|
||||
}
|
||||
|
||||
void btSpinMutex::lock()
|
||||
{
|
||||
// note: this lock does not sleep the thread.
|
||||
while (! tryLock())
|
||||
{
|
||||
// spin
|
||||
}
|
||||
}
|
||||
|
||||
void btSpinMutex::unlock()
|
||||
{
|
||||
std::atomic<int>* aDest = reinterpret_cast<std::atomic<int>*>(&mLock);
|
||||
std::atomic_store_explicit( aDest, int(0), std::memory_order_release );
|
||||
}
|
||||
|
||||
|
||||
#elif USE_MSVC_INTRINSICS
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
|
||||
#define THREAD_LOCAL_STATIC __declspec( thread ) static
|
||||
|
||||
|
||||
bool btSpinMutex::tryLock()
|
||||
{
|
||||
volatile long* aDest = reinterpret_cast<long*>(&mLock);
|
||||
return ( 0 == _InterlockedCompareExchange( aDest, 1, 0) );
|
||||
}
|
||||
|
||||
void btSpinMutex::lock()
|
||||
{
|
||||
// note: this lock does not sleep the thread
|
||||
while (! tryLock())
|
||||
{
|
||||
// spin
|
||||
}
|
||||
}
|
||||
|
||||
void btSpinMutex::unlock()
|
||||
{
|
||||
volatile long* aDest = reinterpret_cast<long*>( &mLock );
|
||||
_InterlockedExchange( aDest, 0 );
|
||||
}
|
||||
|
||||
#elif USE_GCC_BUILTIN_ATOMICS
|
||||
|
||||
#define THREAD_LOCAL_STATIC static __thread
|
||||
|
||||
|
||||
bool btSpinMutex::tryLock()
|
||||
{
|
||||
int expected = 0;
|
||||
bool weak = false;
|
||||
const int memOrderSuccess = __ATOMIC_ACQ_REL;
|
||||
const int memOrderFail = __ATOMIC_ACQUIRE;
|
||||
return __atomic_compare_exchange_n(&mLock, &expected, int(1), weak, memOrderSuccess, memOrderFail);
|
||||
}
|
||||
|
||||
void btSpinMutex::lock()
|
||||
{
|
||||
// note: this lock does not sleep the thread
|
||||
while (! tryLock())
|
||||
{
|
||||
// spin
|
||||
}
|
||||
}
|
||||
|
||||
void btSpinMutex::unlock()
|
||||
{
|
||||
__atomic_store_n(&mLock, int(0), __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
#elif USE_GCC_BUILTIN_ATOMICS_OLD
|
||||
|
||||
|
||||
#define THREAD_LOCAL_STATIC static __thread
|
||||
|
||||
bool btSpinMutex::tryLock()
|
||||
{
|
||||
return __sync_bool_compare_and_swap(&mLock, int(0), int(1));
|
||||
}
|
||||
|
||||
void btSpinMutex::lock()
|
||||
{
|
||||
// note: this lock does not sleep the thread
|
||||
while (! tryLock())
|
||||
{
|
||||
// spin
|
||||
}
|
||||
}
|
||||
|
||||
void btSpinMutex::unlock()
|
||||
{
|
||||
// write 0
|
||||
__sync_fetch_and_and(&mLock, int(0));
|
||||
}
|
||||
|
||||
#else //#elif USE_MSVC_INTRINSICS
|
||||
|
||||
#error "no threading primitives defined -- unknown platform"
|
||||
|
||||
#endif //#else //#elif USE_MSVC_INTRINSICS
|
||||
|
||||
|
||||
struct ThreadsafeCounter
|
||||
{
|
||||
unsigned int mCounter;
|
||||
btSpinMutex mMutex;
|
||||
|
||||
ThreadsafeCounter() {mCounter=0;}
|
||||
|
||||
unsigned int getNext()
|
||||
{
|
||||
// no need to optimize this with atomics, it is only called ONCE per thread!
|
||||
mMutex.lock();
|
||||
unsigned int val = mCounter++;
|
||||
mMutex.unlock();
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
static ThreadsafeCounter gThreadCounter;
|
||||
|
||||
|
||||
// return a unique index per thread, starting with 0 and counting up
|
||||
unsigned int btGetCurrentThreadIndex()
|
||||
{
|
||||
const unsigned int kNullIndex = ~0U;
|
||||
THREAD_LOCAL_STATIC unsigned int sThreadIndex = kNullIndex;
|
||||
if ( sThreadIndex == kNullIndex )
|
||||
{
|
||||
sThreadIndex = gThreadCounter.getNext();
|
||||
}
|
||||
return sThreadIndex;
|
||||
}
|
||||
|
||||
bool btIsMainThread()
|
||||
{
|
||||
return btGetCurrentThreadIndex() == 0;
|
||||
}
|
||||
|
||||
#else // #if BT_THREADSAFE
|
||||
|
||||
// These should not be called ever
|
||||
void btSpinMutex::lock()
|
||||
{
|
||||
btAssert(!"unimplemented btSpinMutex::lock() called");
|
||||
}
|
||||
|
||||
void btSpinMutex::unlock()
|
||||
{
|
||||
btAssert(!"unimplemented btSpinMutex::unlock() called");
|
||||
}
|
||||
|
||||
bool btSpinMutex::tryLock()
|
||||
{
|
||||
btAssert(!"unimplemented btSpinMutex::tryLock() called");
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // #else // #if BT_THREADSAFE
|
||||
|
||||
76
src/LinearMath/btThreads.h
Normal file
76
src/LinearMath/btThreads.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (c) 2003-2014 Erwin Coumans http://bullet.googlecode.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef BT_THREADS_H
|
||||
#define BT_THREADS_H
|
||||
|
||||
#include "btScalar.h" // has definitions like SIMD_FORCE_INLINE
|
||||
|
||||
///
|
||||
/// btSpinMutex -- lightweight spin-mutex implemented with atomic ops, never puts
|
||||
/// a thread to sleep because it is designed to be used with a task scheduler
|
||||
/// which has one thread per core and the threads don't sleep until they
|
||||
/// run out of tasks. Not good for general purpose use.
|
||||
///
|
||||
class btSpinMutex
|
||||
{
|
||||
int mLock;
|
||||
|
||||
public:
|
||||
btSpinMutex()
|
||||
{
|
||||
mLock = 0;
|
||||
}
|
||||
void lock();
|
||||
void unlock();
|
||||
bool tryLock();
|
||||
};
|
||||
|
||||
#if BT_THREADSAFE
|
||||
|
||||
// for internal Bullet use only
|
||||
SIMD_FORCE_INLINE void btMutexLock( btSpinMutex* mutex )
|
||||
{
|
||||
mutex->lock();
|
||||
}
|
||||
|
||||
SIMD_FORCE_INLINE void btMutexUnlock( btSpinMutex* mutex )
|
||||
{
|
||||
mutex->unlock();
|
||||
}
|
||||
|
||||
SIMD_FORCE_INLINE bool btMutexTryLock( btSpinMutex* mutex )
|
||||
{
|
||||
return mutex->tryLock();
|
||||
}
|
||||
|
||||
// for internal use only
|
||||
bool btIsMainThread();
|
||||
unsigned int btGetCurrentThreadIndex();
|
||||
const unsigned int BT_MAX_THREAD_COUNT = 64;
|
||||
|
||||
#else
|
||||
|
||||
// for internal Bullet use only
|
||||
// if BT_THREADSAFE is undefined or 0, should optimize away to nothing
|
||||
SIMD_FORCE_INLINE void btMutexLock( btSpinMutex* ) {}
|
||||
SIMD_FORCE_INLINE void btMutexUnlock( btSpinMutex* ) {}
|
||||
SIMD_FORCE_INLINE bool btMutexTryLock( btSpinMutex* ) {return true;}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif //BT_THREADS_H
|
||||
Reference in New Issue
Block a user