CommonRigidBodyMTBase.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957
  1. /*
  2. Bullet Continuous Collision Detection and Physics Library
  3. Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
  4. This software is provided 'as-is', without any express or implied warranty.
  5. In no event will the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it freely,
  8. subject to the following restrictions:
  9. 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.
  10. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. 3. This notice may not be removed or altered from any source distribution.
  12. */
  13. #include "btBulletDynamicsCommon.h"
  14. #include "LinearMath/btIDebugDraw.h"
  15. #include <stdio.h>
  16. #include <algorithm>
  17. class btCollisionShape;
  18. #include "CommonRigidBodyMTBase.h"
  19. #include "../CommonInterfaces/CommonParameterInterface.h"
  20. #include "LinearMath/btAlignedObjectArray.h"
  21. #include "LinearMath/btPoolAllocator.h"
  22. #include "btBulletCollisionCommon.h"
  23. #include "BulletCollision/CollisionDispatch/btCollisionDispatcherMt.h"
  24. #include "BulletDynamics/Dynamics/btSimulationIslandManagerMt.h" // for setSplitIslands()
  25. #include "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h"
  26. #include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.h"
  27. #include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"
  28. #include "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h"
  29. #include "BulletDynamics/MLCPSolvers/btMLCPSolver.h"
  30. #include "BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h"
  31. #include "BulletDynamics/MLCPSolvers/btDantzigSolver.h"
  32. #include "BulletDynamics/MLCPSolvers/btLemkeSolver.h"
  33. static int gNumIslands = 0;
  34. bool gAllowNestedParallelForLoops = false;
  35. class Profiler
  36. {
  37. public:
  38. enum RecordType
  39. {
  40. kRecordInternalTimeStep,
  41. kRecordDispatchAllCollisionPairs,
  42. kRecordDispatchIslands,
  43. kRecordPredictUnconstrainedMotion,
  44. kRecordCreatePredictiveContacts,
  45. kRecordIntegrateTransforms,
  46. kRecordSolverTotal,
  47. kRecordSolverSetup,
  48. kRecordSolverIterations,
  49. kRecordSolverFinish,
  50. kRecordCount
  51. };
  52. private:
  53. btClock mClock;
  54. struct Record
  55. {
  56. int mCallCount;
  57. unsigned long long mAccum;
  58. unsigned int mStartTime;
  59. unsigned int mHistory[8];
  60. void begin(unsigned int curTime)
  61. {
  62. mStartTime = curTime;
  63. }
  64. void end(unsigned int curTime)
  65. {
  66. unsigned int endTime = curTime;
  67. unsigned int elapsed = endTime - mStartTime;
  68. mAccum += elapsed;
  69. mHistory[mCallCount & 7] = elapsed;
  70. ++mCallCount;
  71. }
  72. float getAverageTime() const
  73. {
  74. int count = btMin(8, mCallCount);
  75. if (count > 0)
  76. {
  77. unsigned int sum = 0;
  78. for (int i = 0; i < count; ++i)
  79. {
  80. sum += mHistory[i];
  81. }
  82. float avg = float(sum) / float(count);
  83. return avg;
  84. }
  85. return 0.0;
  86. }
  87. };
  88. Record mRecords[kRecordCount];
  89. public:
  90. void begin(RecordType rt)
  91. {
  92. mRecords[rt].begin(mClock.getTimeMicroseconds());
  93. }
  94. void end(RecordType rt)
  95. {
  96. mRecords[rt].end(mClock.getTimeMicroseconds());
  97. }
  98. float getAverageTime(RecordType rt) const
  99. {
  100. return mRecords[rt].getAverageTime();
  101. }
  102. };
  103. static Profiler gProfiler;
  104. class ProfileHelper
  105. {
  106. Profiler::RecordType mRecType;
  107. public:
  108. ProfileHelper(Profiler::RecordType rt)
  109. {
  110. mRecType = rt;
  111. gProfiler.begin(mRecType);
  112. }
  113. ~ProfileHelper()
  114. {
  115. gProfiler.end(mRecType);
  116. }
  117. };
  118. static void profileBeginCallback(btDynamicsWorld* world, btScalar timeStep)
  119. {
  120. gProfiler.begin(Profiler::kRecordInternalTimeStep);
  121. }
  122. static void profileEndCallback(btDynamicsWorld* world, btScalar timeStep)
  123. {
  124. gProfiler.end(Profiler::kRecordInternalTimeStep);
  125. }
  126. class MySequentialImpulseConstraintSolverMt : public btSequentialImpulseConstraintSolverMt
  127. {
  128. typedef btSequentialImpulseConstraintSolverMt ParentClass;
  129. public:
  130. BT_DECLARE_ALIGNED_ALLOCATOR();
  131. MySequentialImpulseConstraintSolverMt() {}
  132. // for profiling
  133. virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer) BT_OVERRIDE
  134. {
  135. ProfileHelper prof(Profiler::kRecordSolverSetup);
  136. btScalar ret = ParentClass::solveGroupCacheFriendlySetup(bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
  137. return ret;
  138. }
  139. virtual btScalar solveGroupCacheFriendlyIterations(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer) BT_OVERRIDE
  140. {
  141. ProfileHelper prof(Profiler::kRecordSolverIterations);
  142. btScalar ret = ParentClass::solveGroupCacheFriendlyIterations(bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
  143. return ret;
  144. }
  145. virtual btScalar solveGroupCacheFriendlyFinish(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal) BT_OVERRIDE
  146. {
  147. ProfileHelper prof(Profiler::kRecordSolverFinish);
  148. btScalar ret = ParentClass::solveGroupCacheFriendlyFinish(bodies, numBodies, infoGlobal);
  149. return ret;
  150. }
  151. virtual btScalar solveGroup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifold, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btDispatcher* dispatcher) BT_OVERRIDE
  152. {
  153. ProfileHelper prof(Profiler::kRecordSolverTotal);
  154. btScalar ret = ParentClass::solveGroup(bodies, numBodies, manifold, numManifolds, constraints, numConstraints, info, debugDrawer, dispatcher);
  155. return ret;
  156. }
  157. };
  158. ///
  159. /// MyCollisionDispatcher -- subclassed for profiling purposes
  160. ///
  161. class MyCollisionDispatcher : public btCollisionDispatcherMt
  162. {
  163. typedef btCollisionDispatcherMt ParentClass;
  164. public:
  165. MyCollisionDispatcher(btCollisionConfiguration* config, int grainSize) : btCollisionDispatcherMt(config, grainSize)
  166. {
  167. }
  168. virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache, const btDispatcherInfo& info, btDispatcher* dispatcher) BT_OVERRIDE
  169. {
  170. ProfileHelper prof(Profiler::kRecordDispatchAllCollisionPairs);
  171. ParentClass::dispatchAllCollisionPairs(pairCache, info, dispatcher);
  172. }
  173. };
  174. ///
  175. /// myParallelIslandDispatch -- wrap default parallel dispatch for profiling and to get the number of simulation islands
  176. //
  177. void myParallelIslandDispatch(btAlignedObjectArray<btSimulationIslandManagerMt::Island*>* islandsPtr, const btSimulationIslandManagerMt::SolverParams& solverParams)
  178. {
  179. ProfileHelper prof(Profiler::kRecordDispatchIslands);
  180. gNumIslands = islandsPtr->size();
  181. btSimulationIslandManagerMt::parallelIslandDispatch(islandsPtr, solverParams);
  182. }
  183. ///
  184. /// MyDiscreteDynamicsWorld -- subclassed for profiling purposes
  185. ///
  186. ATTRIBUTE_ALIGNED16(class)
  187. MyDiscreteDynamicsWorld : public btDiscreteDynamicsWorldMt
  188. {
  189. typedef btDiscreteDynamicsWorldMt ParentClass;
  190. protected:
  191. virtual void predictUnconstraintMotion(btScalar timeStep) BT_OVERRIDE
  192. {
  193. ProfileHelper prof(Profiler::kRecordPredictUnconstrainedMotion);
  194. ParentClass::predictUnconstraintMotion(timeStep);
  195. }
  196. virtual void createPredictiveContacts(btScalar timeStep) BT_OVERRIDE
  197. {
  198. ProfileHelper prof(Profiler::kRecordCreatePredictiveContacts);
  199. ParentClass::createPredictiveContacts(timeStep);
  200. }
  201. virtual void integrateTransforms(btScalar timeStep) BT_OVERRIDE
  202. {
  203. ProfileHelper prof(Profiler::kRecordIntegrateTransforms);
  204. ParentClass::integrateTransforms(timeStep);
  205. }
  206. public:
  207. BT_DECLARE_ALIGNED_ALLOCATOR();
  208. MyDiscreteDynamicsWorld(btDispatcher * dispatcher,
  209. btBroadphaseInterface * pairCache,
  210. btConstraintSolverPoolMt * constraintSolver,
  211. btSequentialImpulseConstraintSolverMt * constraintSolverMt,
  212. btCollisionConfiguration * collisionConfiguration) : btDiscreteDynamicsWorldMt(dispatcher, pairCache, constraintSolver, constraintSolverMt, collisionConfiguration)
  213. {
  214. btSimulationIslandManagerMt* islandMgr = static_cast<btSimulationIslandManagerMt*>(m_islandManager);
  215. islandMgr->setIslandDispatchFunction(myParallelIslandDispatch);
  216. }
  217. };
  218. btConstraintSolver* createSolverByType(SolverType t)
  219. {
  220. btMLCPSolverInterface* mlcpSolver = NULL;
  221. switch (t)
  222. {
  223. case SOLVER_TYPE_SEQUENTIAL_IMPULSE:
  224. return new btSequentialImpulseConstraintSolver();
  225. case SOLVER_TYPE_SEQUENTIAL_IMPULSE_MT:
  226. return new MySequentialImpulseConstraintSolverMt();
  227. case SOLVER_TYPE_NNCG:
  228. return new btNNCGConstraintSolver();
  229. case SOLVER_TYPE_MLCP_PGS:
  230. mlcpSolver = new btSolveProjectedGaussSeidel();
  231. break;
  232. case SOLVER_TYPE_MLCP_DANTZIG:
  233. mlcpSolver = new btDantzigSolver();
  234. break;
  235. case SOLVER_TYPE_MLCP_LEMKE:
  236. mlcpSolver = new btLemkeSolver();
  237. break;
  238. default:
  239. {
  240. }
  241. }
  242. if (mlcpSolver)
  243. {
  244. return new btMLCPSolver(mlcpSolver);
  245. }
  246. return NULL;
  247. }
  248. ///
  249. /// btTaskSchedulerManager -- manage a number of task schedulers so we can switch between them
  250. ///
  251. class btTaskSchedulerManager
  252. {
  253. btAlignedObjectArray<btITaskScheduler*> m_taskSchedulers;
  254. btAlignedObjectArray<btITaskScheduler*> m_allocatedTaskSchedulers;
  255. public:
  256. btTaskSchedulerManager() {}
  257. void init()
  258. {
  259. addTaskScheduler(btGetSequentialTaskScheduler());
  260. #if BT_THREADSAFE
  261. if (btITaskScheduler* ts = btCreateDefaultTaskScheduler())
  262. {
  263. m_allocatedTaskSchedulers.push_back(ts);
  264. addTaskScheduler(ts);
  265. }
  266. addTaskScheduler(btGetOpenMPTaskScheduler());
  267. addTaskScheduler(btGetTBBTaskScheduler());
  268. addTaskScheduler(btGetPPLTaskScheduler());
  269. if (getNumTaskSchedulers() > 1)
  270. {
  271. // prefer a non-sequential scheduler if available
  272. btSetTaskScheduler(m_taskSchedulers[1]);
  273. }
  274. else
  275. {
  276. btSetTaskScheduler(m_taskSchedulers[0]);
  277. }
  278. #endif // #if BT_THREADSAFE
  279. }
  280. void shutdown()
  281. {
  282. for (int i = 0; i < m_allocatedTaskSchedulers.size(); ++i)
  283. {
  284. delete m_allocatedTaskSchedulers[i];
  285. }
  286. m_allocatedTaskSchedulers.clear();
  287. }
  288. void addTaskScheduler(btITaskScheduler* ts)
  289. {
  290. if (ts)
  291. {
  292. #if BT_THREADSAFE
  293. // if initial number of threads is 0 or 1,
  294. if (ts->getNumThreads() <= 1)
  295. {
  296. // for OpenMP, TBB, PPL set num threads to number of logical cores
  297. ts->setNumThreads(ts->getMaxNumThreads());
  298. }
  299. #endif // #if BT_THREADSAFE
  300. m_taskSchedulers.push_back(ts);
  301. }
  302. }
  303. int getNumTaskSchedulers() const { return m_taskSchedulers.size(); }
  304. btITaskScheduler* getTaskScheduler(int i) { return m_taskSchedulers[i]; }
  305. };
  306. static btTaskSchedulerManager gTaskSchedulerMgr;
  307. #if BT_THREADSAFE
  308. static bool gMultithreadedWorld = true;
  309. static bool gDisplayProfileInfo = true;
  310. static SolverType gSolverType = SOLVER_TYPE_SEQUENTIAL_IMPULSE_MT;
  311. #else
  312. static bool gMultithreadedWorld = false;
  313. static bool gDisplayProfileInfo = false;
  314. static SolverType gSolverType = SOLVER_TYPE_SEQUENTIAL_IMPULSE;
  315. #endif
  316. static int gSolverMode = SOLVER_SIMD |
  317. SOLVER_USE_WARMSTARTING |
  318. // SOLVER_RANDMIZE_ORDER |
  319. // SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS |
  320. // SOLVER_USE_2_FRICTION_DIRECTIONS |
  321. 0;
  322. static btScalar gSliderSolverIterations = 10.0f; // should be int
  323. static btScalar gSliderNumThreads = 1.0f; // should be int
  324. static btScalar gSliderIslandBatchingThreshold = 0.0f; // should be int
  325. static btScalar gSliderMinBatchSize = btScalar(btSequentialImpulseConstraintSolverMt::s_minBatchSize); // should be int
  326. static btScalar gSliderMaxBatchSize = btScalar(btSequentialImpulseConstraintSolverMt::s_maxBatchSize); // should be int
  327. static btScalar gSliderLeastSquaresResidualThreshold = 0.0f;
  328. ////////////////////////////////////
  329. CommonRigidBodyMTBase::CommonRigidBodyMTBase(struct GUIHelperInterface* helper)
  330. : m_broadphase(0),
  331. m_dispatcher(0),
  332. m_solver(0),
  333. m_collisionConfiguration(0),
  334. m_dynamicsWorld(0),
  335. m_pickedBody(0),
  336. m_pickedConstraint(0),
  337. m_guiHelper(helper)
  338. {
  339. m_multithreadedWorld = false;
  340. m_multithreadCapable = false;
  341. if (gTaskSchedulerMgr.getNumTaskSchedulers() == 0)
  342. {
  343. gTaskSchedulerMgr.init();
  344. }
  345. }
  346. CommonRigidBodyMTBase::~CommonRigidBodyMTBase()
  347. {
  348. }
  349. static void boolPtrButtonCallback(int buttonId, bool buttonState, void* userPointer)
  350. {
  351. if (bool* val = static_cast<bool*>(userPointer))
  352. {
  353. *val = !*val;
  354. }
  355. }
  356. static void toggleSolverModeCallback(int buttonId, bool buttonState, void* userPointer)
  357. {
  358. if (buttonState)
  359. {
  360. gSolverMode |= buttonId;
  361. }
  362. else
  363. {
  364. gSolverMode &= ~buttonId;
  365. }
  366. if (CommonRigidBodyMTBase* crb = reinterpret_cast<CommonRigidBodyMTBase*>(userPointer))
  367. {
  368. if (crb->m_dynamicsWorld)
  369. {
  370. crb->m_dynamicsWorld->getSolverInfo().m_solverMode = gSolverMode;
  371. }
  372. }
  373. }
  374. void setSolverTypeComboBoxCallback(int combobox, const char* item, void* userPointer)
  375. {
  376. const char** items = static_cast<const char**>(userPointer);
  377. for (int i = 0; i < SOLVER_TYPE_COUNT; ++i)
  378. {
  379. if (strcmp(item, items[i]) == 0)
  380. {
  381. gSolverType = static_cast<SolverType>(i);
  382. break;
  383. }
  384. }
  385. }
  386. static void setNumThreads(int numThreads)
  387. {
  388. #if BT_THREADSAFE
  389. int newNumThreads = (std::min)(numThreads, int(BT_MAX_THREAD_COUNT));
  390. int oldNumThreads = btGetTaskScheduler()->getNumThreads();
  391. // only call when the thread count is different
  392. if (newNumThreads != oldNumThreads)
  393. {
  394. btGetTaskScheduler()->setNumThreads(newNumThreads);
  395. }
  396. #endif // #if BT_THREADSAFE
  397. }
  398. void setTaskSchedulerComboBoxCallback(int combobox, const char* item, void* userPointer)
  399. {
  400. #if BT_THREADSAFE
  401. const char** items = static_cast<const char**>(userPointer);
  402. for (int i = 0; i < 20; ++i)
  403. {
  404. if (strcmp(item, items[i]) == 0)
  405. {
  406. // change the task scheduler
  407. btITaskScheduler* ts = gTaskSchedulerMgr.getTaskScheduler(i);
  408. btSetTaskScheduler(ts);
  409. gSliderNumThreads = float(ts->getNumThreads());
  410. break;
  411. }
  412. }
  413. #endif // #if BT_THREADSAFE
  414. }
  415. void setBatchingMethodComboBoxCallback(int combobox, const char* item, void* userPointer)
  416. {
  417. #if BT_THREADSAFE
  418. const char** items = static_cast<const char**>(userPointer);
  419. for (int i = 0; i < btBatchedConstraints::BATCHING_METHOD_COUNT; ++i)
  420. {
  421. if (strcmp(item, items[i]) == 0)
  422. {
  423. // change the task scheduler
  424. btSequentialImpulseConstraintSolverMt::s_contactBatchingMethod = static_cast<btBatchedConstraints::BatchingMethod>(i);
  425. break;
  426. }
  427. }
  428. #endif // #if BT_THREADSAFE
  429. }
  430. static void setThreadCountCallback(float val, void* userPtr)
  431. {
  432. #if BT_THREADSAFE
  433. setNumThreads(int(gSliderNumThreads));
  434. gSliderNumThreads = float(btGetTaskScheduler()->getNumThreads());
  435. #endif // #if BT_THREADSAFE
  436. }
  437. static void setSolverIterationCountCallback(float val, void* userPtr)
  438. {
  439. if (btDiscreteDynamicsWorld* world = reinterpret_cast<btDiscreteDynamicsWorld*>(userPtr))
  440. {
  441. world->getSolverInfo().m_numIterations = btMax(1, int(gSliderSolverIterations));
  442. }
  443. }
  444. static void setLargeIslandManifoldCountCallback(float val, void* userPtr)
  445. {
  446. btSequentialImpulseConstraintSolverMt::s_minimumContactManifoldsForBatching = int(gSliderIslandBatchingThreshold);
  447. }
  448. static void setMinBatchSizeCallback(float val, void* userPtr)
  449. {
  450. gSliderMaxBatchSize = (std::max)(gSliderMinBatchSize, gSliderMaxBatchSize);
  451. btSequentialImpulseConstraintSolverMt::s_minBatchSize = int(gSliderMinBatchSize);
  452. btSequentialImpulseConstraintSolverMt::s_maxBatchSize = int(gSliderMaxBatchSize);
  453. }
  454. static void setMaxBatchSizeCallback(float val, void* userPtr)
  455. {
  456. gSliderMinBatchSize = (std::min)(gSliderMinBatchSize, gSliderMaxBatchSize);
  457. btSequentialImpulseConstraintSolverMt::s_minBatchSize = int(gSliderMinBatchSize);
  458. btSequentialImpulseConstraintSolverMt::s_maxBatchSize = int(gSliderMaxBatchSize);
  459. }
  460. static void setLeastSquaresResidualThresholdCallback(float val, void* userPtr)
  461. {
  462. if (btDiscreteDynamicsWorld* world = reinterpret_cast<btDiscreteDynamicsWorld*>(userPtr))
  463. {
  464. world->getSolverInfo().m_leastSquaresResidualThreshold = gSliderLeastSquaresResidualThreshold;
  465. }
  466. }
  467. void CommonRigidBodyMTBase::createEmptyDynamicsWorld()
  468. {
  469. gNumIslands = 0;
  470. m_solverType = gSolverType;
  471. #if BT_THREADSAFE
  472. btAssert(btGetTaskScheduler() != NULL);
  473. if (NULL != btGetTaskScheduler() && gTaskSchedulerMgr.getNumTaskSchedulers() > 1)
  474. {
  475. m_multithreadCapable = true;
  476. }
  477. #endif
  478. if (gMultithreadedWorld)
  479. {
  480. #if BT_THREADSAFE
  481. m_dispatcher = NULL;
  482. btDefaultCollisionConstructionInfo cci;
  483. cci.m_defaultMaxPersistentManifoldPoolSize = 80000;
  484. cci.m_defaultMaxCollisionAlgorithmPoolSize = 80000;
  485. m_collisionConfiguration = new btDefaultCollisionConfiguration(cci);
  486. m_dispatcher = new MyCollisionDispatcher(m_collisionConfiguration, 40);
  487. m_broadphase = new btDbvtBroadphase();
  488. btConstraintSolverPoolMt* solverPool;
  489. {
  490. SolverType poolSolverType = m_solverType;
  491. if (poolSolverType == SOLVER_TYPE_SEQUENTIAL_IMPULSE_MT)
  492. {
  493. // pool solvers shouldn't be parallel solvers, we don't allow that kind of
  494. // nested parallelism because of performance issues
  495. poolSolverType = SOLVER_TYPE_SEQUENTIAL_IMPULSE;
  496. }
  497. btConstraintSolver* solvers[BT_MAX_THREAD_COUNT];
  498. int maxThreadCount = BT_MAX_THREAD_COUNT;
  499. for (int i = 0; i < maxThreadCount; ++i)
  500. {
  501. solvers[i] = createSolverByType(poolSolverType);
  502. }
  503. solverPool = new btConstraintSolverPoolMt(solvers, maxThreadCount);
  504. m_solver = solverPool;
  505. }
  506. btSequentialImpulseConstraintSolverMt* solverMt = NULL;
  507. if (m_solverType == SOLVER_TYPE_SEQUENTIAL_IMPULSE_MT)
  508. {
  509. solverMt = new MySequentialImpulseConstraintSolverMt();
  510. }
  511. btDiscreteDynamicsWorld* world = new MyDiscreteDynamicsWorld(m_dispatcher, m_broadphase, solverPool, solverMt, m_collisionConfiguration);
  512. m_dynamicsWorld = world;
  513. m_multithreadedWorld = true;
  514. btAssert(btGetTaskScheduler() != NULL);
  515. #endif // #if BT_THREADSAFE
  516. }
  517. else
  518. {
  519. // single threaded world
  520. m_multithreadedWorld = false;
  521. ///collision configuration contains default setup for memory, collision setup
  522. m_collisionConfiguration = new btDefaultCollisionConfiguration();
  523. //m_collisionConfiguration->setConvexConvexMultipointIterations();
  524. ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
  525. m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
  526. m_broadphase = new btDbvtBroadphase();
  527. SolverType solverType = m_solverType;
  528. if (solverType == SOLVER_TYPE_SEQUENTIAL_IMPULSE_MT)
  529. {
  530. // using the parallel solver with the single-threaded world works, but is
  531. // disabled here to avoid confusion
  532. solverType = SOLVER_TYPE_SEQUENTIAL_IMPULSE;
  533. }
  534. m_solver = createSolverByType(solverType);
  535. m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);
  536. }
  537. m_dynamicsWorld->setInternalTickCallback(profileBeginCallback, NULL, true);
  538. m_dynamicsWorld->setInternalTickCallback(profileEndCallback, NULL, false);
  539. m_dynamicsWorld->setGravity(btVector3(0, -10, 0));
  540. m_dynamicsWorld->getSolverInfo().m_solverMode = gSolverMode;
  541. m_dynamicsWorld->getSolverInfo().m_numIterations = btMax(1, int(gSliderSolverIterations));
  542. createDefaultParameters();
  543. }
  544. void CommonRigidBodyMTBase::createDefaultParameters()
  545. {
  546. if (m_multithreadCapable)
  547. {
  548. // create a button to toggle multithreaded world
  549. ButtonParams button("Multithreaded world enable", 0, true);
  550. bool* ptr = &gMultithreadedWorld;
  551. button.m_initialState = *ptr;
  552. button.m_userPointer = ptr;
  553. button.m_callback = boolPtrButtonCallback;
  554. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  555. }
  556. {
  557. // create a button to toggle profile printing
  558. ButtonParams button("Display solver info", 0, true);
  559. bool* ptr = &gDisplayProfileInfo;
  560. button.m_initialState = *ptr;
  561. button.m_userPointer = ptr;
  562. button.m_callback = boolPtrButtonCallback;
  563. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  564. }
  565. {
  566. // create a combo box for selecting the solver type
  567. static const char* sSolverTypeComboBoxItems[SOLVER_TYPE_COUNT];
  568. for (int i = 0; i < SOLVER_TYPE_COUNT; ++i)
  569. {
  570. SolverType solverType = static_cast<SolverType>(i);
  571. sSolverTypeComboBoxItems[i] = getSolverTypeName(solverType);
  572. }
  573. ComboBoxParams comboParams;
  574. comboParams.m_userPointer = sSolverTypeComboBoxItems;
  575. comboParams.m_numItems = SOLVER_TYPE_COUNT;
  576. comboParams.m_startItem = gSolverType;
  577. comboParams.m_items = sSolverTypeComboBoxItems;
  578. comboParams.m_callback = setSolverTypeComboBoxCallback;
  579. m_guiHelper->getParameterInterface()->registerComboBox(comboParams);
  580. }
  581. {
  582. // a slider for the number of solver iterations
  583. SliderParams slider("Solver iterations", &gSliderSolverIterations);
  584. slider.m_minVal = 1.0f;
  585. slider.m_maxVal = 30.0f;
  586. slider.m_callback = setSolverIterationCountCallback;
  587. slider.m_userPointer = m_dynamicsWorld;
  588. slider.m_clampToIntegers = true;
  589. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
  590. }
  591. {
  592. // a slider for the solver leastSquaresResidualThreshold (used to run fewer solver iterations when convergence is good)
  593. SliderParams slider("Solver residual thresh", &gSliderLeastSquaresResidualThreshold);
  594. slider.m_minVal = 0.0f;
  595. slider.m_maxVal = 0.25f;
  596. slider.m_callback = setLeastSquaresResidualThresholdCallback;
  597. slider.m_userPointer = m_dynamicsWorld;
  598. slider.m_clampToIntegers = false;
  599. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
  600. }
  601. {
  602. ButtonParams button("Solver use SIMD", 0, true);
  603. button.m_buttonId = SOLVER_SIMD;
  604. button.m_initialState = !!(gSolverMode & button.m_buttonId);
  605. button.m_callback = toggleSolverModeCallback;
  606. button.m_userPointer = this;
  607. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  608. }
  609. {
  610. ButtonParams button("Solver randomize order", 0, true);
  611. button.m_buttonId = SOLVER_RANDMIZE_ORDER;
  612. button.m_initialState = !!(gSolverMode & button.m_buttonId);
  613. button.m_callback = toggleSolverModeCallback;
  614. button.m_userPointer = this;
  615. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  616. }
  617. {
  618. ButtonParams button("Solver interleave contact/friction", 0, true);
  619. button.m_buttonId = SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS;
  620. button.m_initialState = !!(gSolverMode & button.m_buttonId);
  621. button.m_callback = toggleSolverModeCallback;
  622. button.m_userPointer = this;
  623. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  624. }
  625. {
  626. ButtonParams button("Solver 2 friction directions", 0, true);
  627. button.m_buttonId = SOLVER_USE_2_FRICTION_DIRECTIONS;
  628. button.m_initialState = !!(gSolverMode & button.m_buttonId);
  629. button.m_callback = toggleSolverModeCallback;
  630. button.m_userPointer = this;
  631. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  632. }
  633. {
  634. ButtonParams button("Solver friction dir caching", 0, true);
  635. button.m_buttonId = SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
  636. button.m_initialState = !!(gSolverMode & button.m_buttonId);
  637. button.m_callback = toggleSolverModeCallback;
  638. button.m_userPointer = this;
  639. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  640. }
  641. {
  642. ButtonParams button("Solver warmstarting", 0, true);
  643. button.m_buttonId = SOLVER_USE_WARMSTARTING;
  644. button.m_initialState = !!(gSolverMode & button.m_buttonId);
  645. button.m_callback = toggleSolverModeCallback;
  646. button.m_userPointer = this;
  647. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  648. }
  649. if (m_multithreadedWorld)
  650. {
  651. #if BT_THREADSAFE
  652. if (gTaskSchedulerMgr.getNumTaskSchedulers() >= 1)
  653. {
  654. // create a combo box for selecting the task scheduler
  655. const int maxNumTaskSchedulers = 20;
  656. static const char* sTaskSchedulerComboBoxItems[maxNumTaskSchedulers];
  657. int startingItem = 0;
  658. for (int i = 0; i < gTaskSchedulerMgr.getNumTaskSchedulers(); ++i)
  659. {
  660. sTaskSchedulerComboBoxItems[i] = gTaskSchedulerMgr.getTaskScheduler(i)->getName();
  661. if (gTaskSchedulerMgr.getTaskScheduler(i) == btGetTaskScheduler())
  662. {
  663. startingItem = i;
  664. }
  665. }
  666. ComboBoxParams comboParams;
  667. comboParams.m_userPointer = sTaskSchedulerComboBoxItems;
  668. comboParams.m_numItems = gTaskSchedulerMgr.getNumTaskSchedulers();
  669. comboParams.m_startItem = startingItem;
  670. comboParams.m_items = sTaskSchedulerComboBoxItems;
  671. comboParams.m_callback = setTaskSchedulerComboBoxCallback;
  672. m_guiHelper->getParameterInterface()->registerComboBox(comboParams);
  673. }
  674. {
  675. // if slider has not been set yet (by another demo),
  676. if (gSliderNumThreads <= 1.0f)
  677. {
  678. // create a slider to set the number of threads to use
  679. int numThreads = btGetTaskScheduler()->getNumThreads();
  680. gSliderNumThreads = float(numThreads);
  681. }
  682. int maxNumThreads = btGetTaskScheduler()->getMaxNumThreads();
  683. SliderParams slider("Thread count", &gSliderNumThreads);
  684. slider.m_minVal = 1.0f;
  685. slider.m_maxVal = float(maxNumThreads);
  686. slider.m_callback = setThreadCountCallback;
  687. slider.m_clampToIntegers = true;
  688. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
  689. }
  690. {
  691. // a slider for the number of manifolds an island needs to be too large for parallel dispatch
  692. if (gSliderIslandBatchingThreshold < 1.0)
  693. {
  694. gSliderIslandBatchingThreshold = float(btSequentialImpulseConstraintSolverMt::s_minimumContactManifoldsForBatching);
  695. }
  696. SliderParams slider("IslandBatchThresh", &gSliderIslandBatchingThreshold);
  697. slider.m_minVal = 1.0f;
  698. slider.m_maxVal = 2000.0f;
  699. slider.m_callback = setLargeIslandManifoldCountCallback;
  700. slider.m_userPointer = NULL;
  701. slider.m_clampToIntegers = true;
  702. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
  703. }
  704. {
  705. // create a combo box for selecting the batching method
  706. static const char* sBatchingMethodComboBoxItems[btBatchedConstraints::BATCHING_METHOD_COUNT];
  707. {
  708. sBatchingMethodComboBoxItems[btBatchedConstraints::BATCHING_METHOD_SPATIAL_GRID_2D] = "Batching: 2D Grid";
  709. sBatchingMethodComboBoxItems[btBatchedConstraints::BATCHING_METHOD_SPATIAL_GRID_3D] = "Batching: 3D Grid";
  710. };
  711. ComboBoxParams comboParams;
  712. comboParams.m_userPointer = sBatchingMethodComboBoxItems;
  713. comboParams.m_numItems = btBatchedConstraints::BATCHING_METHOD_COUNT;
  714. comboParams.m_startItem = static_cast<int>(btSequentialImpulseConstraintSolverMt::s_contactBatchingMethod);
  715. comboParams.m_items = sBatchingMethodComboBoxItems;
  716. comboParams.m_callback = setBatchingMethodComboBoxCallback;
  717. m_guiHelper->getParameterInterface()->registerComboBox(comboParams);
  718. }
  719. {
  720. // a slider for the sequentialImpulseConstraintSolverMt min batch size (when batching)
  721. SliderParams slider("Min batch size", &gSliderMinBatchSize);
  722. slider.m_minVal = 1.0f;
  723. slider.m_maxVal = 1000.0f;
  724. slider.m_callback = setMinBatchSizeCallback;
  725. slider.m_userPointer = NULL;
  726. slider.m_clampToIntegers = true;
  727. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
  728. }
  729. {
  730. // a slider for the sequentialImpulseConstraintSolverMt max batch size (when batching)
  731. SliderParams slider("Max batch size", &gSliderMaxBatchSize);
  732. slider.m_minVal = 1.0f;
  733. slider.m_maxVal = 1000.0f;
  734. slider.m_callback = setMaxBatchSizeCallback;
  735. slider.m_userPointer = NULL;
  736. slider.m_clampToIntegers = true;
  737. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
  738. }
  739. {
  740. // create a button to toggle debug drawing of batching visualization
  741. ButtonParams button("Visualize batching", 0, true);
  742. bool* ptr = &btBatchedConstraints::s_debugDrawBatches;
  743. button.m_initialState = *ptr;
  744. button.m_userPointer = ptr;
  745. button.m_callback = boolPtrButtonCallback;
  746. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  747. }
  748. {
  749. ButtonParams button("Allow Nested ParallelFor", 0, true);
  750. button.m_initialState = btSequentialImpulseConstraintSolverMt::s_allowNestedParallelForLoops;
  751. button.m_userPointer = &btSequentialImpulseConstraintSolverMt::s_allowNestedParallelForLoops;
  752. button.m_callback = boolPtrButtonCallback;
  753. m_guiHelper->getParameterInterface()->registerButtonParameter(button);
  754. }
  755. #endif // #if BT_THREADSAFE
  756. }
  757. }
  758. void CommonRigidBodyMTBase::drawScreenText()
  759. {
  760. char msg[1024];
  761. int xCoord = 400;
  762. int yCoord = 30;
  763. int yStep = 30;
  764. int indent = 30;
  765. if (m_solverType != gSolverType)
  766. {
  767. sprintf(msg, "restart example to change solver type");
  768. m_guiHelper->getAppInterface()->drawText(msg, 300, yCoord, 0.4f);
  769. yCoord += yStep;
  770. }
  771. if (m_multithreadCapable)
  772. {
  773. if (m_multithreadedWorld != gMultithreadedWorld)
  774. {
  775. sprintf(msg, "restart example to begin in %s mode",
  776. gMultithreadedWorld ? "multithreaded" : "single threaded");
  777. m_guiHelper->getAppInterface()->drawText(msg, 300, yCoord, 0.4f);
  778. yCoord += yStep;
  779. }
  780. }
  781. if (gDisplayProfileInfo)
  782. {
  783. if (m_multithreadedWorld)
  784. {
  785. #if BT_THREADSAFE
  786. int numManifolds = m_dispatcher->getNumManifolds();
  787. int numContacts = 0;
  788. for (int i = 0; i < numManifolds; ++i)
  789. {
  790. const btPersistentManifold* man = m_dispatcher->getManifoldByIndexInternal(i);
  791. numContacts += man->getNumContacts();
  792. }
  793. const char* mtApi = btGetTaskScheduler()->getName();
  794. sprintf(msg, "islands=%d bodies=%d manifolds=%d contacts=%d [%s] threads=%d",
  795. gNumIslands,
  796. m_dynamicsWorld->getNumCollisionObjects(),
  797. numManifolds,
  798. numContacts,
  799. mtApi,
  800. btGetTaskScheduler()->getNumThreads());
  801. m_guiHelper->getAppInterface()->drawText(msg, 100, yCoord, 0.4f);
  802. yCoord += yStep;
  803. #endif // #if BT_THREADSAFE
  804. }
  805. {
  806. int sm = gSolverMode;
  807. sprintf(msg, "solver %s mode [%s%s%s%s%s%s]",
  808. getSolverTypeName(m_solverType),
  809. sm & SOLVER_SIMD ? "SIMD" : "",
  810. sm & SOLVER_RANDMIZE_ORDER ? " randomize" : "",
  811. sm & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS ? " interleave" : "",
  812. sm & SOLVER_USE_2_FRICTION_DIRECTIONS ? " friction2x" : "",
  813. sm & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING ? " frictionDirCaching" : "",
  814. sm & SOLVER_USE_WARMSTARTING ? " warm" : "");
  815. m_guiHelper->getAppInterface()->drawText(msg, xCoord, yCoord, 0.4f);
  816. yCoord += yStep;
  817. }
  818. sprintf(msg, "internalSimStep %5.3f ms",
  819. gProfiler.getAverageTime(Profiler::kRecordInternalTimeStep) * 0.001f);
  820. m_guiHelper->getAppInterface()->drawText(msg, xCoord, yCoord, 0.4f);
  821. yCoord += yStep;
  822. if (m_multithreadedWorld)
  823. {
  824. sprintf(msg,
  825. "DispatchCollisionPairs %5.3f ms",
  826. gProfiler.getAverageTime(Profiler::kRecordDispatchAllCollisionPairs) * 0.001f);
  827. m_guiHelper->getAppInterface()->drawText(msg, xCoord, yCoord, 0.4f);
  828. yCoord += yStep;
  829. sprintf(msg,
  830. "SolveAllIslands %5.3f ms",
  831. gProfiler.getAverageTime(Profiler::kRecordDispatchIslands) * 0.001f);
  832. m_guiHelper->getAppInterface()->drawText(msg, xCoord, yCoord, 0.4f);
  833. yCoord += yStep;
  834. sprintf(msg,
  835. "SolverTotal %5.3f ms",
  836. gProfiler.getAverageTime(Profiler::kRecordSolverTotal) * 0.001f);
  837. m_guiHelper->getAppInterface()->drawText(msg, xCoord, yCoord, 0.4f);
  838. yCoord += yStep;
  839. sprintf(msg,
  840. "SolverSetup %5.3f ms",
  841. gProfiler.getAverageTime(Profiler::kRecordSolverSetup) * 0.001f);
  842. m_guiHelper->getAppInterface()->drawText(msg, xCoord + indent, yCoord, 0.4f);
  843. yCoord += yStep;
  844. sprintf(msg,
  845. "SolverIterations %5.3f ms",
  846. gProfiler.getAverageTime(Profiler::kRecordSolverIterations) * 0.001f);
  847. m_guiHelper->getAppInterface()->drawText(msg, xCoord + indent, yCoord, 0.4f);
  848. yCoord += yStep;
  849. sprintf(msg,
  850. "SolverFinish %5.3f ms",
  851. gProfiler.getAverageTime(Profiler::kRecordSolverFinish) * 0.001f);
  852. m_guiHelper->getAppInterface()->drawText(msg, xCoord + indent, yCoord, 0.4f);
  853. yCoord += yStep;
  854. sprintf(msg,
  855. "PredictUnconstrainedMotion %5.3f ms",
  856. gProfiler.getAverageTime(Profiler::kRecordPredictUnconstrainedMotion) * 0.001f);
  857. m_guiHelper->getAppInterface()->drawText(msg, xCoord, yCoord, 0.4f);
  858. yCoord += yStep;
  859. sprintf(msg,
  860. "CreatePredictiveContacts %5.3f ms",
  861. gProfiler.getAverageTime(Profiler::kRecordCreatePredictiveContacts) * 0.001f);
  862. m_guiHelper->getAppInterface()->drawText(msg, xCoord, yCoord, 0.4f);
  863. yCoord += yStep;
  864. sprintf(msg,
  865. "IntegrateTransforms %5.3f ms",
  866. gProfiler.getAverageTime(Profiler::kRecordIntegrateTransforms) * 0.001f);
  867. m_guiHelper->getAppInterface()->drawText(msg, xCoord, yCoord, 0.4f);
  868. yCoord += yStep;
  869. }
  870. }
  871. }
  872. void CommonRigidBodyMTBase::physicsDebugDraw(int debugFlags)
  873. {
  874. if (m_dynamicsWorld && m_dynamicsWorld->getDebugDrawer())
  875. {
  876. m_dynamicsWorld->getDebugDrawer()->setDebugMode(debugFlags);
  877. m_dynamicsWorld->debugDrawWorld();
  878. }
  879. drawScreenText();
  880. }
  881. void CommonRigidBodyMTBase::renderScene()
  882. {
  883. m_guiHelper->syncPhysicsToGraphics(m_dynamicsWorld);
  884. m_guiHelper->render(m_dynamicsWorld);
  885. drawScreenText();
  886. }