btBatchedConstraints.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128
  1. /*
  2. Bullet Continuous Collision Detection and Physics Library
  3. Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
  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 "btBatchedConstraints.h"
  14. #include "LinearMath/btIDebugDraw.h"
  15. #include "LinearMath/btMinMax.h"
  16. #include "LinearMath/btStackAlloc.h"
  17. #include "LinearMath/btQuickprof.h"
  18. #include <string.h> //for memset
  19. const int kNoMerge = -1;
  20. bool btBatchedConstraints::s_debugDrawBatches = false;
  21. struct btBatchedConstraintInfo
  22. {
  23. int constraintIndex;
  24. int numConstraintRows;
  25. int bodyIds[2];
  26. };
  27. struct btBatchInfo
  28. {
  29. int numConstraints;
  30. int mergeIndex;
  31. btBatchInfo() : numConstraints(0), mergeIndex(kNoMerge) {}
  32. };
  33. bool btBatchedConstraints::validate(btConstraintArray* constraints, const btAlignedObjectArray<btSolverBody>& bodies) const
  34. {
  35. //
  36. // validate: for debugging only. Verify coloring of bodies, that no body is touched by more than one batch in any given phase
  37. //
  38. int errors = 0;
  39. const int kUnassignedBatch = -1;
  40. btAlignedObjectArray<int> bodyBatchId;
  41. for (int iPhase = 0; iPhase < m_phases.size(); ++iPhase)
  42. {
  43. bodyBatchId.resizeNoInitialize(0);
  44. bodyBatchId.resize( bodies.size(), kUnassignedBatch );
  45. const Range& phase = m_phases[iPhase];
  46. for (int iBatch = phase.begin; iBatch < phase.end; ++iBatch)
  47. {
  48. const Range& batch = m_batches[iBatch];
  49. for (int iiCons = batch.begin; iiCons < batch.end; ++iiCons)
  50. {
  51. int iCons = m_constraintIndices[iiCons];
  52. const btSolverConstraint& cons = constraints->at(iCons);
  53. const btSolverBody& bodyA = bodies[cons.m_solverBodyIdA];
  54. const btSolverBody& bodyB = bodies[cons.m_solverBodyIdB];
  55. if (! bodyA.internalGetInvMass().isZero())
  56. {
  57. int thisBodyBatchId = bodyBatchId[cons.m_solverBodyIdA];
  58. if (thisBodyBatchId == kUnassignedBatch)
  59. {
  60. bodyBatchId[cons.m_solverBodyIdA] = iBatch;
  61. }
  62. else if (thisBodyBatchId != iBatch)
  63. {
  64. btAssert( !"dynamic body is used in 2 different batches in the same phase" );
  65. errors++;
  66. }
  67. }
  68. if (! bodyB.internalGetInvMass().isZero())
  69. {
  70. int thisBodyBatchId = bodyBatchId[cons.m_solverBodyIdB];
  71. if (thisBodyBatchId == kUnassignedBatch)
  72. {
  73. bodyBatchId[cons.m_solverBodyIdB] = iBatch;
  74. }
  75. else if (thisBodyBatchId != iBatch)
  76. {
  77. btAssert( !"dynamic body is used in 2 different batches in the same phase" );
  78. errors++;
  79. }
  80. }
  81. }
  82. }
  83. }
  84. return errors == 0;
  85. }
  86. static void debugDrawSingleBatch( const btBatchedConstraints* bc,
  87. btConstraintArray* constraints,
  88. const btAlignedObjectArray<btSolverBody>& bodies,
  89. int iBatch,
  90. const btVector3& color,
  91. const btVector3& offset
  92. )
  93. {
  94. if (bc && bc->m_debugDrawer && iBatch < bc->m_batches.size())
  95. {
  96. const btBatchedConstraints::Range& b = bc->m_batches[iBatch];
  97. for (int iiCon = b.begin; iiCon < b.end; ++iiCon)
  98. {
  99. int iCon = bc->m_constraintIndices[iiCon];
  100. const btSolverConstraint& con = constraints->at(iCon);
  101. int iBody0 = con.m_solverBodyIdA;
  102. int iBody1 = con.m_solverBodyIdB;
  103. btVector3 pos0 = bodies[iBody0].getWorldTransform().getOrigin() + offset;
  104. btVector3 pos1 = bodies[iBody1].getWorldTransform().getOrigin() + offset;
  105. bc->m_debugDrawer->drawLine(pos0, pos1, color);
  106. }
  107. }
  108. }
  109. static void debugDrawPhase( const btBatchedConstraints* bc,
  110. btConstraintArray* constraints,
  111. const btAlignedObjectArray<btSolverBody>& bodies,
  112. int iPhase,
  113. const btVector3& color0,
  114. const btVector3& color1,
  115. const btVector3& offset
  116. )
  117. {
  118. BT_PROFILE( "debugDrawPhase" );
  119. if ( bc && bc->m_debugDrawer && iPhase < bc->m_phases.size() )
  120. {
  121. const btBatchedConstraints::Range& phase = bc->m_phases[iPhase];
  122. for (int iBatch = phase.begin; iBatch < phase.end; ++iBatch)
  123. {
  124. float tt = float(iBatch - phase.begin) / float(btMax(1, phase.end - phase.begin - 1));
  125. btVector3 col = lerp(color0, color1, tt);
  126. debugDrawSingleBatch(bc, constraints, bodies, iBatch, col, offset);
  127. }
  128. }
  129. }
  130. static void debugDrawAllBatches( const btBatchedConstraints* bc,
  131. btConstraintArray* constraints,
  132. const btAlignedObjectArray<btSolverBody>& bodies
  133. )
  134. {
  135. BT_PROFILE( "debugDrawAllBatches" );
  136. if ( bc && bc->m_debugDrawer && bc->m_phases.size() > 0 )
  137. {
  138. btVector3 bboxMin(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT);
  139. btVector3 bboxMax = -bboxMin;
  140. for (int iBody = 0; iBody < bodies.size(); ++iBody)
  141. {
  142. const btVector3& pos = bodies[iBody].getWorldTransform().getOrigin();
  143. bboxMin.setMin(pos);
  144. bboxMax.setMax(pos);
  145. }
  146. btVector3 bboxExtent = bboxMax - bboxMin;
  147. btVector3 offsetBase = btVector3( 0, bboxExtent.y()*1.1f, 0 );
  148. btVector3 offsetStep = btVector3( 0, 0, bboxExtent.z()*1.1f );
  149. int numPhases = bc->m_phases.size();
  150. for (int iPhase = 0; iPhase < numPhases; ++iPhase)
  151. {
  152. float b = float(iPhase)/float(numPhases-1);
  153. btVector3 color0 = btVector3(1,0,b);
  154. btVector3 color1 = btVector3(0,1,b);
  155. btVector3 offset = offsetBase + offsetStep*(float(iPhase) - float(numPhases-1)*0.5);
  156. debugDrawPhase(bc, constraints, bodies, iPhase, color0, color1, offset);
  157. }
  158. }
  159. }
  160. static void initBatchedBodyDynamicFlags(btAlignedObjectArray<bool>* outBodyDynamicFlags, const btAlignedObjectArray<btSolverBody>& bodies)
  161. {
  162. BT_PROFILE("initBatchedBodyDynamicFlags");
  163. btAlignedObjectArray<bool>& bodyDynamicFlags = *outBodyDynamicFlags;
  164. bodyDynamicFlags.resizeNoInitialize(bodies.size());
  165. for (int i = 0; i < bodies.size(); ++i)
  166. {
  167. const btSolverBody& body = bodies[ i ];
  168. bodyDynamicFlags[i] = ( body.internalGetInvMass().x() > btScalar( 0 ) );
  169. }
  170. }
  171. static int runLengthEncodeConstraintInfo(btBatchedConstraintInfo* outConInfos, int numConstraints)
  172. {
  173. BT_PROFILE("runLengthEncodeConstraintInfo");
  174. // detect and run-length encode constraint rows that repeat the same bodies
  175. int iDest = 0;
  176. int iSrc = 0;
  177. while (iSrc < numConstraints)
  178. {
  179. const btBatchedConstraintInfo& srcConInfo = outConInfos[iSrc];
  180. btBatchedConstraintInfo& conInfo = outConInfos[iDest];
  181. conInfo.constraintIndex = iSrc;
  182. conInfo.bodyIds[0] = srcConInfo.bodyIds[0];
  183. conInfo.bodyIds[1] = srcConInfo.bodyIds[1];
  184. while (iSrc < numConstraints && outConInfos[iSrc].bodyIds[0] == srcConInfo.bodyIds[0] && outConInfos[iSrc].bodyIds[1] == srcConInfo.bodyIds[1])
  185. {
  186. ++iSrc;
  187. }
  188. conInfo.numConstraintRows = iSrc - conInfo.constraintIndex;
  189. ++iDest;
  190. }
  191. return iDest;
  192. }
  193. struct ReadSolverConstraintsLoop : public btIParallelForBody
  194. {
  195. btBatchedConstraintInfo* m_outConInfos;
  196. btConstraintArray* m_constraints;
  197. ReadSolverConstraintsLoop( btBatchedConstraintInfo* outConInfos, btConstraintArray* constraints )
  198. {
  199. m_outConInfos = outConInfos;
  200. m_constraints = constraints;
  201. }
  202. void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
  203. {
  204. for (int i = iBegin; i < iEnd; ++i)
  205. {
  206. btBatchedConstraintInfo& conInfo = m_outConInfos[i];
  207. const btSolverConstraint& con = m_constraints->at( i );
  208. conInfo.bodyIds[0] = con.m_solverBodyIdA;
  209. conInfo.bodyIds[1] = con.m_solverBodyIdB;
  210. conInfo.constraintIndex = i;
  211. conInfo.numConstraintRows = 1;
  212. }
  213. }
  214. };
  215. static int initBatchedConstraintInfo(btBatchedConstraintInfo* outConInfos, btConstraintArray* constraints)
  216. {
  217. BT_PROFILE("initBatchedConstraintInfo");
  218. int numConstraints = constraints->size();
  219. bool inParallel = true;
  220. if (inParallel)
  221. {
  222. ReadSolverConstraintsLoop loop(outConInfos, constraints);
  223. int grainSize = 1200;
  224. btParallelFor(0, numConstraints, grainSize, loop);
  225. }
  226. else
  227. {
  228. for (int i = 0; i < numConstraints; ++i)
  229. {
  230. btBatchedConstraintInfo& conInfo = outConInfos[i];
  231. const btSolverConstraint& con = constraints->at( i );
  232. conInfo.bodyIds[0] = con.m_solverBodyIdA;
  233. conInfo.bodyIds[1] = con.m_solverBodyIdB;
  234. conInfo.constraintIndex = i;
  235. conInfo.numConstraintRows = 1;
  236. }
  237. }
  238. bool useRunLengthEncoding = true;
  239. if (useRunLengthEncoding)
  240. {
  241. numConstraints = runLengthEncodeConstraintInfo(outConInfos, numConstraints);
  242. }
  243. return numConstraints;
  244. }
  245. static void expandConstraintRowsInPlace(int* constraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraints, int numConstraintRows)
  246. {
  247. BT_PROFILE("expandConstraintRowsInPlace");
  248. if (numConstraintRows > numConstraints)
  249. {
  250. // we walk the array in reverse to avoid overwriteing
  251. for (int iCon = numConstraints - 1; iCon >= 0; --iCon)
  252. {
  253. const btBatchedConstraintInfo& conInfo = conInfos[iCon];
  254. int iBatch = constraintBatchIds[iCon];
  255. for (int i = conInfo.numConstraintRows - 1; i >= 0; --i)
  256. {
  257. int iDest = conInfo.constraintIndex + i;
  258. btAssert(iDest >= iCon);
  259. btAssert(iDest >= 0 && iDest < numConstraintRows);
  260. constraintBatchIds[iDest] = iBatch;
  261. }
  262. }
  263. }
  264. }
  265. static void expandConstraintRows(int* destConstraintBatchIds, const int* srcConstraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraints, int numConstraintRows)
  266. {
  267. BT_PROFILE("expandConstraintRows");
  268. for ( int iCon = 0; iCon < numConstraints; ++iCon )
  269. {
  270. const btBatchedConstraintInfo& conInfo = conInfos[ iCon ];
  271. int iBatch = srcConstraintBatchIds[ iCon ];
  272. for ( int i = 0; i < conInfo.numConstraintRows; ++i )
  273. {
  274. int iDest = conInfo.constraintIndex + i;
  275. btAssert( iDest >= iCon );
  276. btAssert( iDest >= 0 && iDest < numConstraintRows );
  277. destConstraintBatchIds[ iDest ] = iBatch;
  278. }
  279. }
  280. }
  281. struct ExpandConstraintRowsLoop : public btIParallelForBody
  282. {
  283. int* m_destConstraintBatchIds;
  284. const int* m_srcConstraintBatchIds;
  285. const btBatchedConstraintInfo* m_conInfos;
  286. int m_numConstraintRows;
  287. ExpandConstraintRowsLoop( int* destConstraintBatchIds, const int* srcConstraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraintRows)
  288. {
  289. m_destConstraintBatchIds = destConstraintBatchIds;
  290. m_srcConstraintBatchIds = srcConstraintBatchIds;
  291. m_conInfos = conInfos;
  292. m_numConstraintRows = numConstraintRows;
  293. }
  294. void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
  295. {
  296. expandConstraintRows(m_destConstraintBatchIds, m_srcConstraintBatchIds + iBegin, m_conInfos + iBegin, iEnd - iBegin, m_numConstraintRows);
  297. }
  298. };
  299. static void expandConstraintRowsMt(int* destConstraintBatchIds, const int* srcConstraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraints, int numConstraintRows)
  300. {
  301. BT_PROFILE("expandConstraintRowsMt");
  302. ExpandConstraintRowsLoop loop(destConstraintBatchIds, srcConstraintBatchIds, conInfos, numConstraintRows);
  303. int grainSize = 600;
  304. btParallelFor(0, numConstraints, grainSize, loop);
  305. }
  306. static void initBatchedConstraintInfoArray(btAlignedObjectArray<btBatchedConstraintInfo>* outConInfos, btConstraintArray* constraints)
  307. {
  308. BT_PROFILE("initBatchedConstraintInfoArray");
  309. btAlignedObjectArray<btBatchedConstraintInfo>& conInfos = *outConInfos;
  310. int numConstraints = constraints->size();
  311. conInfos.resizeNoInitialize(numConstraints);
  312. int newSize = initBatchedConstraintInfo(&outConInfos->at(0), constraints);
  313. conInfos.resizeNoInitialize(newSize);
  314. }
  315. static void mergeSmallBatches(btBatchInfo* batches, int iBeginBatch, int iEndBatch, int minBatchSize, int maxBatchSize)
  316. {
  317. BT_PROFILE("mergeSmallBatches");
  318. for ( int iBatch = iEndBatch - 1; iBatch >= iBeginBatch; --iBatch )
  319. {
  320. btBatchInfo& batch = batches[ iBatch ];
  321. if ( batch.mergeIndex == kNoMerge && batch.numConstraints > 0 && batch.numConstraints < minBatchSize )
  322. {
  323. for ( int iDestBatch = iBatch - 1; iDestBatch >= iBeginBatch; --iDestBatch )
  324. {
  325. btBatchInfo& destBatch = batches[ iDestBatch ];
  326. if ( destBatch.mergeIndex == kNoMerge && ( destBatch.numConstraints + batch.numConstraints ) < maxBatchSize )
  327. {
  328. destBatch.numConstraints += batch.numConstraints;
  329. batch.numConstraints = 0;
  330. batch.mergeIndex = iDestBatch;
  331. break;
  332. }
  333. }
  334. }
  335. }
  336. // flatten mergeIndexes
  337. // e.g. in case where A was merged into B and then B was merged into C, we need A to point to C instead of B
  338. // Note: loop goes forward through batches because batches always merge from higher indexes to lower,
  339. // so by going from low to high it reduces the amount of trail-following
  340. for ( int iBatch = iBeginBatch; iBatch < iEndBatch; ++iBatch )
  341. {
  342. btBatchInfo& batch = batches[ iBatch ];
  343. if ( batch.mergeIndex != kNoMerge )
  344. {
  345. int iMergeDest = batches[ batch.mergeIndex ].mergeIndex;
  346. // follow trail of merges to the end
  347. while ( iMergeDest != kNoMerge )
  348. {
  349. int iNext = batches[ iMergeDest ].mergeIndex;
  350. if ( iNext == kNoMerge )
  351. {
  352. batch.mergeIndex = iMergeDest;
  353. break;
  354. }
  355. iMergeDest = iNext;
  356. }
  357. }
  358. }
  359. }
  360. static void updateConstraintBatchIdsForMerges(int* constraintBatchIds, int numConstraints, const btBatchInfo* batches, int numBatches)
  361. {
  362. BT_PROFILE("updateConstraintBatchIdsForMerges");
  363. // update batchIds to account for merges
  364. for (int i = 0; i < numConstraints; ++i)
  365. {
  366. int iBatch = constraintBatchIds[i];
  367. btAssert(iBatch < numBatches);
  368. // if this constraint references a batch that was merged into another batch
  369. if (batches[iBatch].mergeIndex != kNoMerge)
  370. {
  371. // update batchId
  372. constraintBatchIds[i] = batches[iBatch].mergeIndex;
  373. }
  374. }
  375. }
  376. struct UpdateConstraintBatchIdsForMergesLoop : public btIParallelForBody
  377. {
  378. int* m_constraintBatchIds;
  379. const btBatchInfo* m_batches;
  380. int m_numBatches;
  381. UpdateConstraintBatchIdsForMergesLoop( int* constraintBatchIds, const btBatchInfo* batches, int numBatches )
  382. {
  383. m_constraintBatchIds = constraintBatchIds;
  384. m_batches = batches;
  385. m_numBatches = numBatches;
  386. }
  387. void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
  388. {
  389. BT_PROFILE( "UpdateConstraintBatchIdsForMergesLoop" );
  390. updateConstraintBatchIdsForMerges( m_constraintBatchIds + iBegin, iEnd - iBegin, m_batches, m_numBatches );
  391. }
  392. };
  393. static void updateConstraintBatchIdsForMergesMt(int* constraintBatchIds, int numConstraints, const btBatchInfo* batches, int numBatches)
  394. {
  395. BT_PROFILE( "updateConstraintBatchIdsForMergesMt" );
  396. UpdateConstraintBatchIdsForMergesLoop loop(constraintBatchIds, batches, numBatches);
  397. int grainSize = 800;
  398. btParallelFor(0, numConstraints, grainSize, loop);
  399. }
  400. inline bool BatchCompare(const btBatchedConstraints::Range& a, const btBatchedConstraints::Range& b)
  401. {
  402. int lenA = a.end - a.begin;
  403. int lenB = b.end - b.begin;
  404. return lenA > lenB;
  405. }
  406. static void writeOutConstraintIndicesForRangeOfBatches(btBatchedConstraints* bc,
  407. const int* constraintBatchIds,
  408. int numConstraints,
  409. int* constraintIdPerBatch,
  410. int batchBegin,
  411. int batchEnd
  412. )
  413. {
  414. BT_PROFILE("writeOutConstraintIndicesForRangeOfBatches");
  415. for ( int iCon = 0; iCon < numConstraints; ++iCon )
  416. {
  417. int iBatch = constraintBatchIds[ iCon ];
  418. if (iBatch >= batchBegin && iBatch < batchEnd)
  419. {
  420. int iDestCon = constraintIdPerBatch[ iBatch ];
  421. constraintIdPerBatch[ iBatch ] = iDestCon + 1;
  422. bc->m_constraintIndices[ iDestCon ] = iCon;
  423. }
  424. }
  425. }
  426. struct WriteOutConstraintIndicesLoop : public btIParallelForBody
  427. {
  428. btBatchedConstraints* m_batchedConstraints;
  429. const int* m_constraintBatchIds;
  430. int m_numConstraints;
  431. int* m_constraintIdPerBatch;
  432. int m_maxNumBatchesPerPhase;
  433. WriteOutConstraintIndicesLoop( btBatchedConstraints* bc, const int* constraintBatchIds, int numConstraints, int* constraintIdPerBatch, int maxNumBatchesPerPhase )
  434. {
  435. m_batchedConstraints = bc;
  436. m_constraintBatchIds = constraintBatchIds;
  437. m_numConstraints = numConstraints;
  438. m_constraintIdPerBatch = constraintIdPerBatch;
  439. m_maxNumBatchesPerPhase = maxNumBatchesPerPhase;
  440. }
  441. void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
  442. {
  443. BT_PROFILE( "WriteOutConstraintIndicesLoop" );
  444. int batchBegin = iBegin * m_maxNumBatchesPerPhase;
  445. int batchEnd = iEnd * m_maxNumBatchesPerPhase;
  446. writeOutConstraintIndicesForRangeOfBatches(m_batchedConstraints,
  447. m_constraintBatchIds,
  448. m_numConstraints,
  449. m_constraintIdPerBatch,
  450. batchBegin,
  451. batchEnd
  452. );
  453. }
  454. };
  455. static void writeOutConstraintIndicesMt(btBatchedConstraints* bc,
  456. const int* constraintBatchIds,
  457. int numConstraints,
  458. int* constraintIdPerBatch,
  459. int maxNumBatchesPerPhase,
  460. int numPhases
  461. )
  462. {
  463. BT_PROFILE("writeOutConstraintIndicesMt");
  464. bool inParallel = true;
  465. if (inParallel)
  466. {
  467. WriteOutConstraintIndicesLoop loop( bc, constraintBatchIds, numConstraints, constraintIdPerBatch, maxNumBatchesPerPhase );
  468. btParallelFor( 0, numPhases, 1, loop );
  469. }
  470. else
  471. {
  472. for ( int iCon = 0; iCon < numConstraints; ++iCon )
  473. {
  474. int iBatch = constraintBatchIds[ iCon ];
  475. int iDestCon = constraintIdPerBatch[ iBatch ];
  476. constraintIdPerBatch[ iBatch ] = iDestCon + 1;
  477. bc->m_constraintIndices[ iDestCon ] = iCon;
  478. }
  479. }
  480. }
  481. static void writeGrainSizes(btBatchedConstraints* bc)
  482. {
  483. typedef btBatchedConstraints::Range Range;
  484. int numPhases = bc->m_phases.size();
  485. bc->m_phaseGrainSize.resizeNoInitialize(numPhases);
  486. int numThreads = btGetTaskScheduler()->getNumThreads();
  487. for (int iPhase = 0; iPhase < numPhases; ++iPhase)
  488. {
  489. const Range& phase = bc->m_phases[ iPhase ];
  490. int numBatches = phase.end - phase.begin;
  491. float grainSize = floor((0.25f*numBatches / float(numThreads)) + 0.0f);
  492. bc->m_phaseGrainSize[ iPhase ] = btMax(1, int(grainSize));
  493. }
  494. }
  495. static void writeOutBatches(btBatchedConstraints* bc,
  496. const int* constraintBatchIds,
  497. int numConstraints,
  498. const btBatchInfo* batches,
  499. int* batchWork,
  500. int maxNumBatchesPerPhase,
  501. int numPhases
  502. )
  503. {
  504. BT_PROFILE("writeOutBatches");
  505. typedef btBatchedConstraints::Range Range;
  506. bc->m_constraintIndices.reserve( numConstraints );
  507. bc->m_batches.resizeNoInitialize( 0 );
  508. bc->m_phases.resizeNoInitialize( 0 );
  509. //int maxNumBatches = numPhases * maxNumBatchesPerPhase;
  510. {
  511. int* constraintIdPerBatch = batchWork; // for each batch, keep an index into the next available slot in the m_constraintIndices array
  512. int iConstraint = 0;
  513. for (int iPhase = 0; iPhase < numPhases; ++iPhase)
  514. {
  515. int curPhaseBegin = bc->m_batches.size();
  516. int iBegin = iPhase * maxNumBatchesPerPhase;
  517. int iEnd = iBegin + maxNumBatchesPerPhase;
  518. for ( int i = iBegin; i < iEnd; ++i )
  519. {
  520. const btBatchInfo& batch = batches[ i ];
  521. int curBatchBegin = iConstraint;
  522. constraintIdPerBatch[ i ] = curBatchBegin; // record the start of each batch in m_constraintIndices array
  523. int numConstraints = batch.numConstraints;
  524. iConstraint += numConstraints;
  525. if ( numConstraints > 0 )
  526. {
  527. bc->m_batches.push_back( Range( curBatchBegin, iConstraint ) );
  528. }
  529. }
  530. // if any batches were emitted this phase,
  531. if ( bc->m_batches.size() > curPhaseBegin )
  532. {
  533. // output phase
  534. bc->m_phases.push_back( Range( curPhaseBegin, bc->m_batches.size() ) );
  535. }
  536. }
  537. btAssert(iConstraint == numConstraints);
  538. bc->m_constraintIndices.resizeNoInitialize( numConstraints );
  539. writeOutConstraintIndicesMt( bc, constraintBatchIds, numConstraints, constraintIdPerBatch, maxNumBatchesPerPhase, numPhases );
  540. }
  541. // for each phase
  542. for (int iPhase = 0; iPhase < bc->m_phases.size(); ++iPhase)
  543. {
  544. // sort the batches from largest to smallest (can be helpful to some task schedulers)
  545. const Range& curBatches = bc->m_phases[iPhase];
  546. bc->m_batches.quickSortInternal(BatchCompare, curBatches.begin, curBatches.end-1);
  547. }
  548. bc->m_phaseOrder.resize(bc->m_phases.size());
  549. for (int i = 0; i < bc->m_phases.size(); ++i)
  550. {
  551. bc->m_phaseOrder[i] = i;
  552. }
  553. writeGrainSizes(bc);
  554. }
  555. //
  556. // PreallocatedMemoryHelper -- helper object for allocating a number of chunks of memory in a single contiguous block.
  557. // It is generally more efficient to do a single larger allocation than many smaller allocations.
  558. //
  559. // Example Usage:
  560. //
  561. // btVector3* bodyPositions = NULL;
  562. // btBatchedConstraintInfo* conInfos = NULL;
  563. // {
  564. // PreallocatedMemoryHelper<8> memHelper;
  565. // memHelper.addChunk( (void**) &bodyPositions, sizeof( btVector3 ) * bodies.size() );
  566. // memHelper.addChunk( (void**) &conInfos, sizeof( btBatchedConstraintInfo ) * numConstraints );
  567. // void* memPtr = malloc( memHelper.getSizeToAllocate() ); // allocate the memory
  568. // memHelper.setChunkPointers( memPtr ); // update pointers to chunks
  569. // }
  570. template <int N>
  571. class PreallocatedMemoryHelper
  572. {
  573. struct Chunk
  574. {
  575. void** ptr;
  576. size_t size;
  577. };
  578. Chunk m_chunks[N];
  579. int m_numChunks;
  580. public:
  581. PreallocatedMemoryHelper() {m_numChunks=0;}
  582. void addChunk( void** ptr, size_t sz )
  583. {
  584. btAssert( m_numChunks < N );
  585. if ( m_numChunks < N )
  586. {
  587. Chunk& chunk = m_chunks[ m_numChunks ];
  588. chunk.ptr = ptr;
  589. chunk.size = sz;
  590. m_numChunks++;
  591. }
  592. }
  593. size_t getSizeToAllocate() const
  594. {
  595. size_t totalSize = 0;
  596. for (int i = 0; i < m_numChunks; ++i)
  597. {
  598. totalSize += m_chunks[i].size;
  599. }
  600. return totalSize;
  601. }
  602. void setChunkPointers(void* mem) const
  603. {
  604. size_t totalSize = 0;
  605. for (int i = 0; i < m_numChunks; ++i)
  606. {
  607. const Chunk& chunk = m_chunks[ i ];
  608. char* chunkPtr = static_cast<char*>(mem) + totalSize;
  609. *chunk.ptr = chunkPtr;
  610. totalSize += chunk.size;
  611. }
  612. }
  613. };
  614. static btVector3 findMaxDynamicConstraintExtent(
  615. btVector3* bodyPositions,
  616. bool* bodyDynamicFlags,
  617. btBatchedConstraintInfo* conInfos,
  618. int numConstraints,
  619. int numBodies
  620. )
  621. {
  622. BT_PROFILE("findMaxDynamicConstraintExtent");
  623. btVector3 consExtent = btVector3(1,1,1) * 0.001;
  624. for (int iCon = 0; iCon < numConstraints; ++iCon)
  625. {
  626. const btBatchedConstraintInfo& con = conInfos[ iCon ];
  627. int iBody0 = con.bodyIds[0];
  628. int iBody1 = con.bodyIds[1];
  629. btAssert(iBody0 >= 0 && iBody0 < numBodies);
  630. btAssert(iBody1 >= 0 && iBody1 < numBodies);
  631. // is it a dynamic constraint?
  632. if (bodyDynamicFlags[iBody0] && bodyDynamicFlags[iBody1])
  633. {
  634. btVector3 delta = bodyPositions[iBody1] - bodyPositions[iBody0];
  635. consExtent.setMax(delta.absolute());
  636. }
  637. }
  638. return consExtent;
  639. }
  640. struct btIntVec3
  641. {
  642. int m_ints[ 3 ];
  643. SIMD_FORCE_INLINE const int& operator[](int i) const {return m_ints[i];}
  644. SIMD_FORCE_INLINE int& operator[](int i) {return m_ints[i];}
  645. };
  646. struct AssignConstraintsToGridBatchesParams
  647. {
  648. bool* bodyDynamicFlags;
  649. btIntVec3* bodyGridCoords;
  650. int numBodies;
  651. btBatchedConstraintInfo* conInfos;
  652. int* constraintBatchIds;
  653. btIntVec3 gridChunkDim;
  654. int maxNumBatchesPerPhase;
  655. int numPhases;
  656. int phaseMask;
  657. AssignConstraintsToGridBatchesParams()
  658. {
  659. memset(this, 0, sizeof(*this));
  660. }
  661. };
  662. static void assignConstraintsToGridBatches(const AssignConstraintsToGridBatchesParams& params, int iConBegin, int iConEnd)
  663. {
  664. BT_PROFILE("assignConstraintsToGridBatches");
  665. // (can be done in parallel)
  666. for ( int iCon = iConBegin; iCon < iConEnd; ++iCon )
  667. {
  668. const btBatchedConstraintInfo& con = params.conInfos[ iCon ];
  669. int iBody0 = con.bodyIds[ 0 ];
  670. int iBody1 = con.bodyIds[ 1 ];
  671. int iPhase = iCon; //iBody0; // pseudorandom choice to distribute evenly amongst phases
  672. iPhase &= params.phaseMask;
  673. int gridCoord[ 3 ];
  674. // is it a dynamic constraint?
  675. if ( params.bodyDynamicFlags[ iBody0 ] && params.bodyDynamicFlags[ iBody1 ] )
  676. {
  677. const btIntVec3& body0Coords = params.bodyGridCoords[iBody0];
  678. const btIntVec3& body1Coords = params.bodyGridCoords[iBody1];
  679. // for each dimension x,y,z,
  680. for (int i = 0; i < 3; ++i)
  681. {
  682. int coordMin = btMin(body0Coords.m_ints[i], body1Coords.m_ints[i]);
  683. int coordMax = btMax(body0Coords.m_ints[i], body1Coords.m_ints[i]);
  684. if (coordMin != coordMax)
  685. {
  686. btAssert( coordMax == coordMin + 1 );
  687. if ((coordMin&1) == 0)
  688. {
  689. iPhase &= ~(1 << i); // force bit off
  690. }
  691. else
  692. {
  693. iPhase |= (1 << i); // force bit on
  694. iPhase &= params.phaseMask;
  695. }
  696. }
  697. gridCoord[ i ] = coordMin;
  698. }
  699. }
  700. else
  701. {
  702. if ( !params.bodyDynamicFlags[ iBody0 ] )
  703. {
  704. iBody0 = con.bodyIds[ 1 ];
  705. }
  706. btAssert(params.bodyDynamicFlags[ iBody0 ]);
  707. const btIntVec3& body0Coords = params.bodyGridCoords[iBody0];
  708. // for each dimension x,y,z,
  709. for ( int i = 0; i < 3; ++i )
  710. {
  711. gridCoord[ i ] = body0Coords.m_ints[ i ];
  712. }
  713. }
  714. // calculate chunk coordinates
  715. int chunkCoord[ 3 ];
  716. btIntVec3 gridChunkDim = params.gridChunkDim;
  717. // for each dimension x,y,z,
  718. for ( int i = 0; i < 3; ++i )
  719. {
  720. int coordOffset = ( iPhase >> i ) & 1;
  721. chunkCoord[ i ] = (gridCoord[ i ] - coordOffset)/2;
  722. btClamp( chunkCoord[ i ], 0, gridChunkDim[ i ] - 1);
  723. btAssert( chunkCoord[ i ] < gridChunkDim[ i ] );
  724. }
  725. int iBatch = iPhase * params.maxNumBatchesPerPhase + chunkCoord[ 0 ] + chunkCoord[ 1 ] * gridChunkDim[ 0 ] + chunkCoord[ 2 ] * gridChunkDim[ 0 ] * gridChunkDim[ 1 ];
  726. btAssert(iBatch >= 0 && iBatch < params.maxNumBatchesPerPhase*params.numPhases);
  727. params.constraintBatchIds[ iCon ] = iBatch;
  728. }
  729. }
  730. struct AssignConstraintsToGridBatchesLoop : public btIParallelForBody
  731. {
  732. const AssignConstraintsToGridBatchesParams* m_params;
  733. AssignConstraintsToGridBatchesLoop( const AssignConstraintsToGridBatchesParams& params )
  734. {
  735. m_params = &params;
  736. }
  737. void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
  738. {
  739. assignConstraintsToGridBatches(*m_params, iBegin, iEnd);
  740. }
  741. };
  742. //
  743. // setupSpatialGridBatchesMt -- generate batches using a uniform 3D grid
  744. //
  745. /*
  746. Bodies are treated as 3D points at their center of mass. We only consider dynamic bodies at this stage,
  747. because only dynamic bodies are mutated when a constraint is solved, thus subject to race conditions.
  748. 1. Compute a bounding box around all dynamic bodies
  749. 2. Compute the maximum extent of all dynamic constraints. Each dynamic constraint is treated as a line segment, and we need the size of
  750. box that will fully enclose any single dynamic constraint
  751. 3. Establish the cell size of our grid, the cell size in each dimension must be at least as large as the dynamic constraints max-extent,
  752. so that no dynamic constraint can span more than 2 cells of our grid on any axis of the grid. The cell size should be adjusted
  753. larger in order to keep the total number of cells from being excessively high
  754. Key idea: Given that each constraint spans 1 or 2 grid cells in each dimension, we can handle all constraints by processing
  755. in chunks of 2x2x2 cells with 8 different 1-cell offsets ((0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0)...).
  756. For each of the 8 offsets, we create a phase, and for each 2x2x2 chunk with dynamic constraints becomes a batch in that phase.
  757. 4. Once the grid is established, we can calculate for each constraint which phase and batch it belongs in.
  758. 5. Do a merge small batches on the batches of each phase separately, to try to even out the sizes of batches
  759. Optionally, we can "collapse" one dimension of our 3D grid to turn it into a 2D grid, which reduces the number of phases
  760. to 4. With fewer phases, there are more constraints per phase and this makes it easier to create batches of a useful size.
  761. */
  762. //
  763. static void setupSpatialGridBatchesMt(
  764. btBatchedConstraints* batchedConstraints,
  765. btAlignedObjectArray<char>* scratchMemory,
  766. btConstraintArray* constraints,
  767. const btAlignedObjectArray<btSolverBody>& bodies,
  768. int minBatchSize,
  769. int maxBatchSize,
  770. bool use2DGrid
  771. )
  772. {
  773. BT_PROFILE("setupSpatialGridBatchesMt");
  774. const int numPhases = 8;
  775. int numConstraints = constraints->size();
  776. int numConstraintRows = constraints->size();
  777. const int maxGridChunkCount = 128;
  778. int allocNumBatchesPerPhase = maxGridChunkCount;
  779. int minNumBatchesPerPhase = 16;
  780. int allocNumBatches = allocNumBatchesPerPhase * numPhases;
  781. btVector3* bodyPositions = NULL;
  782. bool* bodyDynamicFlags = NULL;
  783. btIntVec3* bodyGridCoords = NULL;
  784. btBatchInfo* batches = NULL;
  785. int* batchWork = NULL;
  786. btBatchedConstraintInfo* conInfos = NULL;
  787. int* constraintBatchIds = NULL;
  788. int* constraintRowBatchIds = NULL;
  789. {
  790. PreallocatedMemoryHelper<10> memHelper;
  791. memHelper.addChunk( (void**) &bodyPositions, sizeof( btVector3 ) * bodies.size() );
  792. memHelper.addChunk( (void**) &bodyDynamicFlags, sizeof( bool ) * bodies.size() );
  793. memHelper.addChunk( (void**) &bodyGridCoords, sizeof( btIntVec3 ) * bodies.size() );
  794. memHelper.addChunk( (void**) &batches, sizeof( btBatchInfo )* allocNumBatches );
  795. memHelper.addChunk( (void**) &batchWork, sizeof( int )* allocNumBatches );
  796. memHelper.addChunk( (void**) &conInfos, sizeof( btBatchedConstraintInfo ) * numConstraints );
  797. memHelper.addChunk( (void**) &constraintBatchIds, sizeof( int ) * numConstraints );
  798. memHelper.addChunk( (void**) &constraintRowBatchIds, sizeof( int ) * numConstraintRows );
  799. size_t scratchSize = memHelper.getSizeToAllocate();
  800. // if we need to reallocate
  801. if (scratchMemory->capacity() < scratchSize)
  802. {
  803. // allocate 6.25% extra to avoid repeated reallocs
  804. scratchMemory->reserve( scratchSize + scratchSize/16 );
  805. }
  806. scratchMemory->resizeNoInitialize( scratchSize );
  807. char* memPtr = &scratchMemory->at(0);
  808. memHelper.setChunkPointers( memPtr );
  809. }
  810. numConstraints = initBatchedConstraintInfo(conInfos, constraints);
  811. // compute bounding box around all dynamic bodies
  812. // (could be done in parallel)
  813. btVector3 bboxMin(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT);
  814. btVector3 bboxMax = -bboxMin;
  815. //int dynamicBodyCount = 0;
  816. for (int i = 0; i < bodies.size(); ++i)
  817. {
  818. const btSolverBody& body = bodies[i];
  819. btVector3 bodyPos = body.getWorldTransform().getOrigin();
  820. bool isDynamic = ( body.internalGetInvMass().x() > btScalar( 0 ) );
  821. bodyPositions[i] = bodyPos;
  822. bodyDynamicFlags[i] = isDynamic;
  823. if (isDynamic)
  824. {
  825. //dynamicBodyCount++;
  826. bboxMin.setMin(bodyPos);
  827. bboxMax.setMax(bodyPos);
  828. }
  829. }
  830. // find max extent of all dynamic constraints
  831. // (could be done in parallel)
  832. btVector3 consExtent = findMaxDynamicConstraintExtent(bodyPositions, bodyDynamicFlags, conInfos, numConstraints, bodies.size());
  833. btVector3 gridExtent = bboxMax - bboxMin;
  834. btVector3 gridCellSize = consExtent;
  835. int gridDim[3];
  836. gridDim[ 0 ] = int( 1.0 + gridExtent.x() / gridCellSize.x() );
  837. gridDim[ 1 ] = int( 1.0 + gridExtent.y() / gridCellSize.y() );
  838. gridDim[ 2 ] = int( 1.0 + gridExtent.z() / gridCellSize.z() );
  839. // if we can collapse an axis, it will cut our number of phases in half which could be more efficient
  840. int phaseMask = 7;
  841. bool collapseAxis = use2DGrid;
  842. if ( collapseAxis )
  843. {
  844. // pick the smallest axis to collapse, leaving us with the greatest number of cells in our grid
  845. int iAxisToCollapse = 0;
  846. int axisDim = gridDim[iAxisToCollapse];
  847. //for each dimension
  848. for ( int i = 0; i < 3; ++i )
  849. {
  850. if (gridDim[i] < axisDim)
  851. {
  852. iAxisToCollapse = i;
  853. axisDim = gridDim[i];
  854. }
  855. }
  856. // collapse it
  857. gridCellSize[iAxisToCollapse] = gridExtent[iAxisToCollapse] * 2.0f;
  858. phaseMask &= ~(1 << iAxisToCollapse);
  859. }
  860. int numGridChunks = 0;
  861. btIntVec3 gridChunkDim; // each chunk is 2x2x2 group of cells
  862. while (true)
  863. {
  864. gridDim[0] = int( 1.0 + gridExtent.x() / gridCellSize.x() );
  865. gridDim[1] = int( 1.0 + gridExtent.y() / gridCellSize.y() );
  866. gridDim[2] = int( 1.0 + gridExtent.z() / gridCellSize.z() );
  867. gridChunkDim[ 0 ] = btMax( 1, ( gridDim[ 0 ] + 0 ) / 2 );
  868. gridChunkDim[ 1 ] = btMax( 1, ( gridDim[ 1 ] + 0 ) / 2 );
  869. gridChunkDim[ 2 ] = btMax( 1, ( gridDim[ 2 ] + 0 ) / 2 );
  870. numGridChunks = gridChunkDim[ 0 ] * gridChunkDim[ 1 ] * gridChunkDim[ 2 ];
  871. float nChunks = float(gridChunkDim[0]) * float(gridChunkDim[1]) * float(gridChunkDim[2]); // suceptible to integer overflow
  872. if ( numGridChunks <= maxGridChunkCount && nChunks <= maxGridChunkCount )
  873. {
  874. break;
  875. }
  876. gridCellSize *= 1.25; // should roughly cut numCells in half
  877. }
  878. btAssert(numGridChunks <= maxGridChunkCount );
  879. int maxNumBatchesPerPhase = numGridChunks;
  880. // for each dynamic body, compute grid coords
  881. btVector3 invGridCellSize = btVector3(1,1,1)/gridCellSize;
  882. // (can be done in parallel)
  883. for (int iBody = 0; iBody < bodies.size(); ++iBody)
  884. {
  885. btIntVec3& coords = bodyGridCoords[iBody];
  886. if (bodyDynamicFlags[iBody])
  887. {
  888. btVector3 v = ( bodyPositions[ iBody ] - bboxMin )*invGridCellSize;
  889. coords.m_ints[0] = int(v.x());
  890. coords.m_ints[1] = int(v.y());
  891. coords.m_ints[2] = int(v.z());
  892. btAssert(coords.m_ints[0] >= 0 && coords.m_ints[0] < gridDim[0]);
  893. btAssert(coords.m_ints[1] >= 0 && coords.m_ints[1] < gridDim[1]);
  894. btAssert(coords.m_ints[2] >= 0 && coords.m_ints[2] < gridDim[2]);
  895. }
  896. else
  897. {
  898. coords.m_ints[0] = -1;
  899. coords.m_ints[1] = -1;
  900. coords.m_ints[2] = -1;
  901. }
  902. }
  903. for (int iPhase = 0; iPhase < numPhases; ++iPhase)
  904. {
  905. int batchBegin = iPhase * maxNumBatchesPerPhase;
  906. int batchEnd = batchBegin + maxNumBatchesPerPhase;
  907. for ( int iBatch = batchBegin; iBatch < batchEnd; ++iBatch )
  908. {
  909. btBatchInfo& batch = batches[ iBatch ];
  910. batch = btBatchInfo();
  911. }
  912. }
  913. {
  914. AssignConstraintsToGridBatchesParams params;
  915. params.bodyDynamicFlags = bodyDynamicFlags;
  916. params.bodyGridCoords = bodyGridCoords;
  917. params.numBodies = bodies.size();
  918. params.conInfos = conInfos;
  919. params.constraintBatchIds = constraintBatchIds;
  920. params.gridChunkDim = gridChunkDim;
  921. params.maxNumBatchesPerPhase = maxNumBatchesPerPhase;
  922. params.numPhases = numPhases;
  923. params.phaseMask = phaseMask;
  924. bool inParallel = true;
  925. if (inParallel)
  926. {
  927. AssignConstraintsToGridBatchesLoop loop(params);
  928. int grainSize = 250;
  929. btParallelFor(0, numConstraints, grainSize, loop);
  930. }
  931. else
  932. {
  933. assignConstraintsToGridBatches( params, 0, numConstraints );
  934. }
  935. }
  936. for ( int iCon = 0; iCon < numConstraints; ++iCon )
  937. {
  938. const btBatchedConstraintInfo& con = conInfos[ iCon ];
  939. int iBatch = constraintBatchIds[ iCon ];
  940. btBatchInfo& batch = batches[iBatch];
  941. batch.numConstraints += con.numConstraintRows;
  942. }
  943. for (int iPhase = 0; iPhase < numPhases; ++iPhase)
  944. {
  945. // if phase is legit,
  946. if (iPhase == (iPhase&phaseMask))
  947. {
  948. int iBeginBatch = iPhase * maxNumBatchesPerPhase;
  949. int iEndBatch = iBeginBatch + maxNumBatchesPerPhase;
  950. mergeSmallBatches( batches, iBeginBatch, iEndBatch, minBatchSize, maxBatchSize );
  951. }
  952. }
  953. // all constraints have been assigned a batchId
  954. updateConstraintBatchIdsForMergesMt(constraintBatchIds, numConstraints, batches, maxNumBatchesPerPhase*numPhases);
  955. if (numConstraintRows > numConstraints)
  956. {
  957. expandConstraintRowsMt(&constraintRowBatchIds[0], &constraintBatchIds[0], &conInfos[0], numConstraints, numConstraintRows);
  958. }
  959. else
  960. {
  961. constraintRowBatchIds = constraintBatchIds;
  962. }
  963. writeOutBatches(batchedConstraints, constraintRowBatchIds, numConstraintRows, batches, batchWork, maxNumBatchesPerPhase, numPhases);
  964. btAssert(batchedConstraints->validate(constraints, bodies));
  965. }
  966. static void setupSingleBatch(
  967. btBatchedConstraints* bc,
  968. int numConstraints
  969. )
  970. {
  971. BT_PROFILE("setupSingleBatch");
  972. typedef btBatchedConstraints::Range Range;
  973. bc->m_constraintIndices.resize( numConstraints );
  974. for ( int i = 0; i < numConstraints; ++i )
  975. {
  976. bc->m_constraintIndices[ i ] = i;
  977. }
  978. bc->m_batches.resizeNoInitialize( 0 );
  979. bc->m_phases.resizeNoInitialize( 0 );
  980. bc->m_phaseOrder.resizeNoInitialize( 0 );
  981. bc->m_phaseGrainSize.resizeNoInitialize( 0 );
  982. if (numConstraints > 0)
  983. {
  984. bc->m_batches.push_back( Range( 0, numConstraints ) );
  985. bc->m_phases.push_back( Range( 0, 1 ) );
  986. bc->m_phaseOrder.push_back(0);
  987. bc->m_phaseGrainSize.push_back(1);
  988. }
  989. }
  990. void btBatchedConstraints::setup(
  991. btConstraintArray* constraints,
  992. const btAlignedObjectArray<btSolverBody>& bodies,
  993. BatchingMethod batchingMethod,
  994. int minBatchSize,
  995. int maxBatchSize,
  996. btAlignedObjectArray<char>* scratchMemory
  997. )
  998. {
  999. if (constraints->size() >= minBatchSize*4)
  1000. {
  1001. bool use2DGrid = batchingMethod == BATCHING_METHOD_SPATIAL_GRID_2D;
  1002. setupSpatialGridBatchesMt( this, scratchMemory, constraints, bodies, minBatchSize, maxBatchSize, use2DGrid );
  1003. if (s_debugDrawBatches)
  1004. {
  1005. debugDrawAllBatches( this, constraints, bodies );
  1006. }
  1007. }
  1008. else
  1009. {
  1010. setupSingleBatch( this, constraints->size() );
  1011. }
  1012. }