MultiThreaded Demo:

- fixing various race conditions throughout (usage of static vars, etc)
 - addition of a few lightweight mutexes (which are compiled out by default)
 - slight code rearrangement in discreteDynamicsWorld to facilitate multithreading
 - PoolAllocator::allocate() can now be called when pool is full without
     crashing (null pointer returned)
 - PoolAllocator allocate and freeMemory, are OPTIONALLY threadsafe
     (default is un-threadsafe)
 - CollisionDispatcher no longer checks if the pool allocator is full
     before calling allocate(), instead it just calls allocate() and
     checks if the return is null -- this avoids a race condition
 - SequentialImpulseConstraintSolver OPTIONALLY uses different logic in
     getOrInitSolverBody() to avoid a race condition with kinematic bodies
 - addition of 2 classes which together allow simulation islands to be run
   in parallel:
    - btSimulationIslandManagerMt
    - btDiscreteDynamicsWorldMt
 - MultiThreadedDemo example in the example browser demonstrating use of
   OpenMP, Microsoft PPL, and Intel TBB
 - use multithreading for other demos
 - benchmark demo: add parallel raycasting
This commit is contained in:
Lunkhound
2016-09-27 00:01:45 -07:00
parent f01389ded2
commit 1c3686ca51
48 changed files with 3168 additions and 197 deletions

View File

@@ -32,10 +32,12 @@ subject to the following restrictions:
#include "LinearMath/btAlignedObjectArray.h"
#include "LinearMath/btTransform.h"
#include "../CommonInterfaces/ParallelFor.h"
class btDynamicsWorld;
#define NUMRAYS 500
#define USE_PARALLEL_RAYCASTS 1
class btRigidBody;
class btBroadphaseInterface;
@@ -204,7 +206,39 @@ public:
sign = -1.0;
}
void cast (btCollisionWorld* cw)
void castRays( btCollisionWorld* cw, int iBegin, int iEnd )
{
for ( int i = iBegin; i < iEnd; ++i )
{
btCollisionWorld::ClosestRayResultCallback cb(source[i], dest[i]);
cw->rayTest (source[i], dest[i], cb);
if (cb.hasHit ())
{
hit[i] = cb.m_hitPointWorld;
normal[i] = cb.m_hitNormalWorld;
normal[i].normalize ();
} else {
hit[i] = dest[i];
normal[i] = btVector3(1.0, 0.0, 0.0);
}
}
}
struct CastRaysLoopBody
{
btRaycastBar2* mRaycasts;
btCollisionWorld* mWorld;
CastRaysLoopBody(btCollisionWorld* cw, btRaycastBar2* rb) : mWorld(cw), mRaycasts(rb) {}
void forLoop( int iBegin, int iEnd ) const
{
mRaycasts->castRays(mWorld, iBegin, iEnd);
}
};
void cast (btCollisionWorld* cw, bool multiThreading = false)
{
#ifdef USE_BT_CLOCK
frame_timer.reset ();
@@ -228,22 +262,19 @@ public:
normal[i].normalize ();
}
#else
for (int i = 0; i < NUMRAYS; i++)
{
btCollisionWorld::ClosestRayResultCallback cb(source[i], dest[i]);
cw->rayTest (source[i], dest[i], cb);
if (cb.hasHit ())
{
hit[i] = cb.m_hitPointWorld;
normal[i] = cb.m_hitNormalWorld;
normal[i].normalize ();
} else {
hit[i] = dest[i];
normal[i] = btVector3(1.0, 0.0, 0.0);
}
}
#if USE_PARALLEL_RAYCASTS
if ( multiThreading )
{
CastRaysLoopBody rayLooper(cw, this);
int grainSize = 20; // number of raycasts per task
parallelFor( 0, NUMRAYS, grainSize, rayLooper );
}
else
#endif // USE_PARALLEL_RAYCASTS
{
// single threaded
castRays(cw, 0, NUMRAYS);
}
#ifdef USE_BT_CLOCK
ms += frame_timer.getTimeMilliseconds ();
#endif //USE_BT_CLOCK
@@ -354,42 +385,43 @@ void BenchmarkDemo::initPhysics()
setCameraDistance(btScalar(100.));
///collision configuration contains default setup for memory, collision setup
btDefaultCollisionConstructionInfo cci;
cci.m_defaultMaxPersistentManifoldPoolSize = 32768;
m_collisionConfiguration = new btDefaultCollisionConfiguration(cci);
createEmptyDynamicsWorld();
/////collision configuration contains default setup for memory, collision setup
//btDefaultCollisionConstructionInfo cci;
//cci.m_defaultMaxPersistentManifoldPoolSize = 32768;
//m_collisionConfiguration = new btDefaultCollisionConfiguration(cci);
///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
m_dispatcher->setDispatcherFlags(btCollisionDispatcher::CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
/////use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
//m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
//
//m_dispatcher->setDispatcherFlags(btCollisionDispatcher::CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
///the maximum size of the collision world. Make sure objects stay within these boundaries
///Don't make the world AABB size too large, it will harm simulation quality and performance
btVector3 worldAabbMin(-1000,-1000,-1000);
btVector3 worldAabbMax(1000,1000,1000);
btHashedOverlappingPairCache* pairCache = new btHashedOverlappingPairCache();
m_broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,3500,pairCache);
/////the maximum size of the collision world. Make sure objects stay within these boundaries
/////Don't make the world AABB size too large, it will harm simulation quality and performance
//btVector3 worldAabbMin(-1000,-1000,-1000);
//btVector3 worldAabbMax(1000,1000,1000);
//
//btHashedOverlappingPairCache* pairCache = new btHashedOverlappingPairCache();
//m_broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,3500,pairCache);
// m_broadphase = new btSimpleBroadphase();
// m_broadphase = new btDbvtBroadphase();
///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
//btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
m_solver = sol;
//m_solver = sol;
btDiscreteDynamicsWorld* dynamicsWorld;
m_dynamicsWorld = dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
//btDiscreteDynamicsWorld* dynamicsWorld;
//m_dynamicsWorld = dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
///the following 3 lines increase the performance dramatically, with a little bit of loss of quality
m_dynamicsWorld->getSolverInfo().m_solverMode |=SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; //don't recalculate friction values each frame
dynamicsWorld->getSolverInfo().m_numIterations = 5; //few solver iterations
m_dynamicsWorld->getSolverInfo().m_numIterations = 5; //few solver iterations
//m_defaultContactProcessingThreshold = 0.f;//used when creating bodies: body->setContactProcessingThreshold(...);
m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
@@ -1242,7 +1274,7 @@ void BenchmarkDemo::initRays()
void BenchmarkDemo::castRays()
{
raycastBar.cast (m_dynamicsWorld);
raycastBar.cast (m_dynamicsWorld, m_multithreadedWorld);
}
void BenchmarkDemo::createTest7()