2
0

btBatchedConstraints.cpp 35 KB

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