summaryrefslogtreecommitdiff
path: root/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp')
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp1084
1 files changed, 0 insertions, 1084 deletions
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp
deleted file mode 100644
index 0f5ed1c2ce..0000000000
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp
+++ /dev/null
@@ -1,1084 +0,0 @@
-/*
-Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
-
-This software is provided 'as-is', without any express or implied warranty.
-In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
-subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
-2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
-3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include "btBatchedConstraints.h"
-
-#include "LinearMath/btIDebugDraw.h"
-#include "LinearMath/btMinMax.h"
-#include "LinearMath/btStackAlloc.h"
-#include "LinearMath/btQuickprof.h"
-
-#include <string.h> //for memset
-
-#include <cmath>
-
-const int kNoMerge = -1;
-
-bool btBatchedConstraints::s_debugDrawBatches = false;
-
-struct btBatchedConstraintInfo
-{
- int constraintIndex;
- int numConstraintRows;
- int bodyIds[2];
-};
-
-struct btBatchInfo
-{
- int numConstraints;
- int mergeIndex;
-
- btBatchInfo() : numConstraints(0), mergeIndex(kNoMerge) {}
-};
-
-bool btBatchedConstraints::validate(btConstraintArray* constraints, const btAlignedObjectArray<btSolverBody>& bodies) const
-{
- //
- // validate: for debugging only. Verify coloring of bodies, that no body is touched by more than one batch in any given phase
- //
- int errors = 0;
- const int kUnassignedBatch = -1;
-
- btAlignedObjectArray<int> bodyBatchId;
- for (int iPhase = 0; iPhase < m_phases.size(); ++iPhase)
- {
- bodyBatchId.resizeNoInitialize(0);
- bodyBatchId.resize(bodies.size(), kUnassignedBatch);
- const Range& phase = m_phases[iPhase];
- for (int iBatch = phase.begin; iBatch < phase.end; ++iBatch)
- {
- const Range& batch = m_batches[iBatch];
- for (int iiCons = batch.begin; iiCons < batch.end; ++iiCons)
- {
- int iCons = m_constraintIndices[iiCons];
- const btSolverConstraint& cons = constraints->at(iCons);
- const btSolverBody& bodyA = bodies[cons.m_solverBodyIdA];
- const btSolverBody& bodyB = bodies[cons.m_solverBodyIdB];
- if (!bodyA.internalGetInvMass().isZero())
- {
- int thisBodyBatchId = bodyBatchId[cons.m_solverBodyIdA];
- if (thisBodyBatchId == kUnassignedBatch)
- {
- bodyBatchId[cons.m_solverBodyIdA] = iBatch;
- }
- else if (thisBodyBatchId != iBatch)
- {
- btAssert(!"dynamic body is used in 2 different batches in the same phase");
- errors++;
- }
- }
- if (!bodyB.internalGetInvMass().isZero())
- {
- int thisBodyBatchId = bodyBatchId[cons.m_solverBodyIdB];
- if (thisBodyBatchId == kUnassignedBatch)
- {
- bodyBatchId[cons.m_solverBodyIdB] = iBatch;
- }
- else if (thisBodyBatchId != iBatch)
- {
- btAssert(!"dynamic body is used in 2 different batches in the same phase");
- errors++;
- }
- }
- }
- }
- }
- return errors == 0;
-}
-
-static void debugDrawSingleBatch(const btBatchedConstraints* bc,
- btConstraintArray* constraints,
- const btAlignedObjectArray<btSolverBody>& bodies,
- int iBatch,
- const btVector3& color,
- const btVector3& offset)
-{
- if (bc && bc->m_debugDrawer && iBatch < bc->m_batches.size())
- {
- const btBatchedConstraints::Range& b = bc->m_batches[iBatch];
- for (int iiCon = b.begin; iiCon < b.end; ++iiCon)
- {
- int iCon = bc->m_constraintIndices[iiCon];
- const btSolverConstraint& con = constraints->at(iCon);
- int iBody0 = con.m_solverBodyIdA;
- int iBody1 = con.m_solverBodyIdB;
- btVector3 pos0 = bodies[iBody0].getWorldTransform().getOrigin() + offset;
- btVector3 pos1 = bodies[iBody1].getWorldTransform().getOrigin() + offset;
- bc->m_debugDrawer->drawLine(pos0, pos1, color);
- }
- }
-}
-
-static void debugDrawPhase(const btBatchedConstraints* bc,
- btConstraintArray* constraints,
- const btAlignedObjectArray<btSolverBody>& bodies,
- int iPhase,
- const btVector3& color0,
- const btVector3& color1,
- const btVector3& offset)
-{
- BT_PROFILE("debugDrawPhase");
- if (bc && bc->m_debugDrawer && iPhase < bc->m_phases.size())
- {
- const btBatchedConstraints::Range& phase = bc->m_phases[iPhase];
- for (int iBatch = phase.begin; iBatch < phase.end; ++iBatch)
- {
- float tt = float(iBatch - phase.begin) / float(btMax(1, phase.end - phase.begin - 1));
- btVector3 col = lerp(color0, color1, tt);
- debugDrawSingleBatch(bc, constraints, bodies, iBatch, col, offset);
- }
- }
-}
-
-static void debugDrawAllBatches(const btBatchedConstraints* bc,
- btConstraintArray* constraints,
- const btAlignedObjectArray<btSolverBody>& bodies)
-{
- BT_PROFILE("debugDrawAllBatches");
- if (bc && bc->m_debugDrawer && bc->m_phases.size() > 0)
- {
- btVector3 bboxMin(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT);
- btVector3 bboxMax = -bboxMin;
- for (int iBody = 0; iBody < bodies.size(); ++iBody)
- {
- const btVector3& pos = bodies[iBody].getWorldTransform().getOrigin();
- bboxMin.setMin(pos);
- bboxMax.setMax(pos);
- }
- btVector3 bboxExtent = bboxMax - bboxMin;
- btVector3 offsetBase = btVector3(0, bboxExtent.y() * 1.1f, 0);
- btVector3 offsetStep = btVector3(0, 0, bboxExtent.z() * 1.1f);
- int numPhases = bc->m_phases.size();
- for (int iPhase = 0; iPhase < numPhases; ++iPhase)
- {
- float b = float(iPhase) / float(numPhases - 1);
- btVector3 color0 = btVector3(1, 0, b);
- btVector3 color1 = btVector3(0, 1, b);
- btVector3 offset = offsetBase + offsetStep * (float(iPhase) - float(numPhases - 1) * 0.5);
- debugDrawPhase(bc, constraints, bodies, iPhase, color0, color1, offset);
- }
- }
-}
-
-static void initBatchedBodyDynamicFlags(btAlignedObjectArray<bool>* outBodyDynamicFlags, const btAlignedObjectArray<btSolverBody>& bodies)
-{
- BT_PROFILE("initBatchedBodyDynamicFlags");
- btAlignedObjectArray<bool>& bodyDynamicFlags = *outBodyDynamicFlags;
- bodyDynamicFlags.resizeNoInitialize(bodies.size());
- for (int i = 0; i < bodies.size(); ++i)
- {
- const btSolverBody& body = bodies[i];
- bodyDynamicFlags[i] = (body.internalGetInvMass().x() > btScalar(0));
- }
-}
-
-static int runLengthEncodeConstraintInfo(btBatchedConstraintInfo* outConInfos, int numConstraints)
-{
- BT_PROFILE("runLengthEncodeConstraintInfo");
- // detect and run-length encode constraint rows that repeat the same bodies
- int iDest = 0;
- int iSrc = 0;
- while (iSrc < numConstraints)
- {
- const btBatchedConstraintInfo& srcConInfo = outConInfos[iSrc];
- btBatchedConstraintInfo& conInfo = outConInfos[iDest];
- conInfo.constraintIndex = iSrc;
- conInfo.bodyIds[0] = srcConInfo.bodyIds[0];
- conInfo.bodyIds[1] = srcConInfo.bodyIds[1];
- while (iSrc < numConstraints && outConInfos[iSrc].bodyIds[0] == srcConInfo.bodyIds[0] && outConInfos[iSrc].bodyIds[1] == srcConInfo.bodyIds[1])
- {
- ++iSrc;
- }
- conInfo.numConstraintRows = iSrc - conInfo.constraintIndex;
- ++iDest;
- }
- return iDest;
-}
-
-struct ReadSolverConstraintsLoop : public btIParallelForBody
-{
- btBatchedConstraintInfo* m_outConInfos;
- btConstraintArray* m_constraints;
-
- ReadSolverConstraintsLoop(btBatchedConstraintInfo* outConInfos, btConstraintArray* constraints)
- {
- m_outConInfos = outConInfos;
- m_constraints = constraints;
- }
- void forLoop(int iBegin, int iEnd) const BT_OVERRIDE
- {
- for (int i = iBegin; i < iEnd; ++i)
- {
- btBatchedConstraintInfo& conInfo = m_outConInfos[i];
- const btSolverConstraint& con = m_constraints->at(i);
- conInfo.bodyIds[0] = con.m_solverBodyIdA;
- conInfo.bodyIds[1] = con.m_solverBodyIdB;
- conInfo.constraintIndex = i;
- conInfo.numConstraintRows = 1;
- }
- }
-};
-
-static int initBatchedConstraintInfo(btBatchedConstraintInfo* outConInfos, btConstraintArray* constraints)
-{
- BT_PROFILE("initBatchedConstraintInfo");
- int numConstraints = constraints->size();
- bool inParallel = true;
- if (inParallel)
- {
- ReadSolverConstraintsLoop loop(outConInfos, constraints);
- int grainSize = 1200;
- btParallelFor(0, numConstraints, grainSize, loop);
- }
- else
- {
- for (int i = 0; i < numConstraints; ++i)
- {
- btBatchedConstraintInfo& conInfo = outConInfos[i];
- const btSolverConstraint& con = constraints->at(i);
- conInfo.bodyIds[0] = con.m_solverBodyIdA;
- conInfo.bodyIds[1] = con.m_solverBodyIdB;
- conInfo.constraintIndex = i;
- conInfo.numConstraintRows = 1;
- }
- }
- bool useRunLengthEncoding = true;
- if (useRunLengthEncoding)
- {
- numConstraints = runLengthEncodeConstraintInfo(outConInfos, numConstraints);
- }
- return numConstraints;
-}
-
-static void expandConstraintRowsInPlace(int* constraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraints, int numConstraintRows)
-{
- BT_PROFILE("expandConstraintRowsInPlace");
- if (numConstraintRows > numConstraints)
- {
- // we walk the array in reverse to avoid overwriteing
- for (int iCon = numConstraints - 1; iCon >= 0; --iCon)
- {
- const btBatchedConstraintInfo& conInfo = conInfos[iCon];
- int iBatch = constraintBatchIds[iCon];
- for (int i = conInfo.numConstraintRows - 1; i >= 0; --i)
- {
- int iDest = conInfo.constraintIndex + i;
- btAssert(iDest >= iCon);
- btAssert(iDest >= 0 && iDest < numConstraintRows);
- constraintBatchIds[iDest] = iBatch;
- }
- }
- }
-}
-
-static void expandConstraintRows(int* destConstraintBatchIds, const int* srcConstraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraints, int numConstraintRows)
-{
- BT_PROFILE("expandConstraintRows");
- for (int iCon = 0; iCon < numConstraints; ++iCon)
- {
- const btBatchedConstraintInfo& conInfo = conInfos[iCon];
- int iBatch = srcConstraintBatchIds[iCon];
- for (int i = 0; i < conInfo.numConstraintRows; ++i)
- {
- int iDest = conInfo.constraintIndex + i;
- btAssert(iDest >= iCon);
- btAssert(iDest >= 0 && iDest < numConstraintRows);
- destConstraintBatchIds[iDest] = iBatch;
- }
- }
-}
-
-struct ExpandConstraintRowsLoop : public btIParallelForBody
-{
- int* m_destConstraintBatchIds;
- const int* m_srcConstraintBatchIds;
- const btBatchedConstraintInfo* m_conInfos;
- int m_numConstraintRows;
-
- ExpandConstraintRowsLoop(int* destConstraintBatchIds, const int* srcConstraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraintRows)
- {
- m_destConstraintBatchIds = destConstraintBatchIds;
- m_srcConstraintBatchIds = srcConstraintBatchIds;
- m_conInfos = conInfos;
- m_numConstraintRows = numConstraintRows;
- }
- void forLoop(int iBegin, int iEnd) const BT_OVERRIDE
- {
- expandConstraintRows(m_destConstraintBatchIds, m_srcConstraintBatchIds + iBegin, m_conInfos + iBegin, iEnd - iBegin, m_numConstraintRows);
- }
-};
-
-static void expandConstraintRowsMt(int* destConstraintBatchIds, const int* srcConstraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraints, int numConstraintRows)
-{
- BT_PROFILE("expandConstraintRowsMt");
- ExpandConstraintRowsLoop loop(destConstraintBatchIds, srcConstraintBatchIds, conInfos, numConstraintRows);
- int grainSize = 600;
- btParallelFor(0, numConstraints, grainSize, loop);
-}
-
-static void initBatchedConstraintInfoArray(btAlignedObjectArray<btBatchedConstraintInfo>* outConInfos, btConstraintArray* constraints)
-{
- BT_PROFILE("initBatchedConstraintInfoArray");
- btAlignedObjectArray<btBatchedConstraintInfo>& conInfos = *outConInfos;
- int numConstraints = constraints->size();
- conInfos.resizeNoInitialize(numConstraints);
-
- int newSize = initBatchedConstraintInfo(&outConInfos->at(0), constraints);
- conInfos.resizeNoInitialize(newSize);
-}
-
-static void mergeSmallBatches(btBatchInfo* batches, int iBeginBatch, int iEndBatch, int minBatchSize, int maxBatchSize)
-{
- BT_PROFILE("mergeSmallBatches");
- for (int iBatch = iEndBatch - 1; iBatch >= iBeginBatch; --iBatch)
- {
- btBatchInfo& batch = batches[iBatch];
- if (batch.mergeIndex == kNoMerge && batch.numConstraints > 0 && batch.numConstraints < minBatchSize)
- {
- for (int iDestBatch = iBatch - 1; iDestBatch >= iBeginBatch; --iDestBatch)
- {
- btBatchInfo& destBatch = batches[iDestBatch];
- if (destBatch.mergeIndex == kNoMerge && (destBatch.numConstraints + batch.numConstraints) < maxBatchSize)
- {
- destBatch.numConstraints += batch.numConstraints;
- batch.numConstraints = 0;
- batch.mergeIndex = iDestBatch;
- break;
- }
- }
- }
- }
- // flatten mergeIndexes
- // 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
- // Note: loop goes forward through batches because batches always merge from higher indexes to lower,
- // so by going from low to high it reduces the amount of trail-following
- for (int iBatch = iBeginBatch; iBatch < iEndBatch; ++iBatch)
- {
- btBatchInfo& batch = batches[iBatch];
- if (batch.mergeIndex != kNoMerge)
- {
- int iMergeDest = batches[batch.mergeIndex].mergeIndex;
- // follow trail of merges to the end
- while (iMergeDest != kNoMerge)
- {
- int iNext = batches[iMergeDest].mergeIndex;
- if (iNext == kNoMerge)
- {
- batch.mergeIndex = iMergeDest;
- break;
- }
- iMergeDest = iNext;
- }
- }
- }
-}
-
-static void updateConstraintBatchIdsForMerges(int* constraintBatchIds, int numConstraints, const btBatchInfo* batches, int numBatches)
-{
- BT_PROFILE("updateConstraintBatchIdsForMerges");
- // update batchIds to account for merges
- for (int i = 0; i < numConstraints; ++i)
- {
- int iBatch = constraintBatchIds[i];
- btAssert(iBatch < numBatches);
- // if this constraint references a batch that was merged into another batch
- if (batches[iBatch].mergeIndex != kNoMerge)
- {
- // update batchId
- constraintBatchIds[i] = batches[iBatch].mergeIndex;
- }
- }
-}
-
-struct UpdateConstraintBatchIdsForMergesLoop : public btIParallelForBody
-{
- int* m_constraintBatchIds;
- const btBatchInfo* m_batches;
- int m_numBatches;
-
- UpdateConstraintBatchIdsForMergesLoop(int* constraintBatchIds, const btBatchInfo* batches, int numBatches)
- {
- m_constraintBatchIds = constraintBatchIds;
- m_batches = batches;
- m_numBatches = numBatches;
- }
- void forLoop(int iBegin, int iEnd) const BT_OVERRIDE
- {
- BT_PROFILE("UpdateConstraintBatchIdsForMergesLoop");
- updateConstraintBatchIdsForMerges(m_constraintBatchIds + iBegin, iEnd - iBegin, m_batches, m_numBatches);
- }
-};
-
-static void updateConstraintBatchIdsForMergesMt(int* constraintBatchIds, int numConstraints, const btBatchInfo* batches, int numBatches)
-{
- BT_PROFILE("updateConstraintBatchIdsForMergesMt");
- UpdateConstraintBatchIdsForMergesLoop loop(constraintBatchIds, batches, numBatches);
- int grainSize = 800;
- btParallelFor(0, numConstraints, grainSize, loop);
-}
-
-inline bool BatchCompare(const btBatchedConstraints::Range& a, const btBatchedConstraints::Range& b)
-{
- int lenA = a.end - a.begin;
- int lenB = b.end - b.begin;
- return lenA > lenB;
-}
-
-static void writeOutConstraintIndicesForRangeOfBatches(btBatchedConstraints* bc,
- const int* constraintBatchIds,
- int numConstraints,
- int* constraintIdPerBatch,
- int batchBegin,
- int batchEnd)
-{
- BT_PROFILE("writeOutConstraintIndicesForRangeOfBatches");
- for (int iCon = 0; iCon < numConstraints; ++iCon)
- {
- int iBatch = constraintBatchIds[iCon];
- if (iBatch >= batchBegin && iBatch < batchEnd)
- {
- int iDestCon = constraintIdPerBatch[iBatch];
- constraintIdPerBatch[iBatch] = iDestCon + 1;
- bc->m_constraintIndices[iDestCon] = iCon;
- }
- }
-}
-
-struct WriteOutConstraintIndicesLoop : public btIParallelForBody
-{
- btBatchedConstraints* m_batchedConstraints;
- const int* m_constraintBatchIds;
- int m_numConstraints;
- int* m_constraintIdPerBatch;
- int m_maxNumBatchesPerPhase;
-
- WriteOutConstraintIndicesLoop(btBatchedConstraints* bc, const int* constraintBatchIds, int numConstraints, int* constraintIdPerBatch, int maxNumBatchesPerPhase)
- {
- m_batchedConstraints = bc;
- m_constraintBatchIds = constraintBatchIds;
- m_numConstraints = numConstraints;
- m_constraintIdPerBatch = constraintIdPerBatch;
- m_maxNumBatchesPerPhase = maxNumBatchesPerPhase;
- }
- void forLoop(int iBegin, int iEnd) const BT_OVERRIDE
- {
- BT_PROFILE("WriteOutConstraintIndicesLoop");
- int batchBegin = iBegin * m_maxNumBatchesPerPhase;
- int batchEnd = iEnd * m_maxNumBatchesPerPhase;
- writeOutConstraintIndicesForRangeOfBatches(m_batchedConstraints,
- m_constraintBatchIds,
- m_numConstraints,
- m_constraintIdPerBatch,
- batchBegin,
- batchEnd);
- }
-};
-
-static void writeOutConstraintIndicesMt(btBatchedConstraints* bc,
- const int* constraintBatchIds,
- int numConstraints,
- int* constraintIdPerBatch,
- int maxNumBatchesPerPhase,
- int numPhases)
-{
- BT_PROFILE("writeOutConstraintIndicesMt");
- bool inParallel = true;
- if (inParallel)
- {
- WriteOutConstraintIndicesLoop loop(bc, constraintBatchIds, numConstraints, constraintIdPerBatch, maxNumBatchesPerPhase);
- btParallelFor(0, numPhases, 1, loop);
- }
- else
- {
- for (int iCon = 0; iCon < numConstraints; ++iCon)
- {
- int iBatch = constraintBatchIds[iCon];
- int iDestCon = constraintIdPerBatch[iBatch];
- constraintIdPerBatch[iBatch] = iDestCon + 1;
- bc->m_constraintIndices[iDestCon] = iCon;
- }
- }
-}
-
-static void writeGrainSizes(btBatchedConstraints* bc)
-{
- typedef btBatchedConstraints::Range Range;
- int numPhases = bc->m_phases.size();
- bc->m_phaseGrainSize.resizeNoInitialize(numPhases);
- int numThreads = btGetTaskScheduler()->getNumThreads();
- for (int iPhase = 0; iPhase < numPhases; ++iPhase)
- {
- const Range& phase = bc->m_phases[iPhase];
- int numBatches = phase.end - phase.begin;
- float grainSize = std::floor((0.25f * numBatches / float(numThreads)) + 0.0f);
- bc->m_phaseGrainSize[iPhase] = btMax(1, int(grainSize));
- }
-}
-
-static void writeOutBatches(btBatchedConstraints* bc,
- const int* constraintBatchIds,
- int numConstraints,
- const btBatchInfo* batches,
- int* batchWork,
- int maxNumBatchesPerPhase,
- int numPhases)
-{
- BT_PROFILE("writeOutBatches");
- typedef btBatchedConstraints::Range Range;
- bc->m_constraintIndices.reserve(numConstraints);
- bc->m_batches.resizeNoInitialize(0);
- bc->m_phases.resizeNoInitialize(0);
-
- //int maxNumBatches = numPhases * maxNumBatchesPerPhase;
- {
- int* constraintIdPerBatch = batchWork; // for each batch, keep an index into the next available slot in the m_constraintIndices array
- int iConstraint = 0;
- for (int iPhase = 0; iPhase < numPhases; ++iPhase)
- {
- int curPhaseBegin = bc->m_batches.size();
- int iBegin = iPhase * maxNumBatchesPerPhase;
- int iEnd = iBegin + maxNumBatchesPerPhase;
- for (int i = iBegin; i < iEnd; ++i)
- {
- const btBatchInfo& batch = batches[i];
- int curBatchBegin = iConstraint;
- constraintIdPerBatch[i] = curBatchBegin; // record the start of each batch in m_constraintIndices array
- int numConstraints = batch.numConstraints;
- iConstraint += numConstraints;
- if (numConstraints > 0)
- {
- bc->m_batches.push_back(Range(curBatchBegin, iConstraint));
- }
- }
- // if any batches were emitted this phase,
- if (bc->m_batches.size() > curPhaseBegin)
- {
- // output phase
- bc->m_phases.push_back(Range(curPhaseBegin, bc->m_batches.size()));
- }
- }
-
- btAssert(iConstraint == numConstraints);
- bc->m_constraintIndices.resizeNoInitialize(numConstraints);
- writeOutConstraintIndicesMt(bc, constraintBatchIds, numConstraints, constraintIdPerBatch, maxNumBatchesPerPhase, numPhases);
- }
- // for each phase
- for (int iPhase = 0; iPhase < bc->m_phases.size(); ++iPhase)
- {
- // sort the batches from largest to smallest (can be helpful to some task schedulers)
- const Range& curBatches = bc->m_phases[iPhase];
- bc->m_batches.quickSortInternal(BatchCompare, curBatches.begin, curBatches.end - 1);
- }
- bc->m_phaseOrder.resize(bc->m_phases.size());
- for (int i = 0; i < bc->m_phases.size(); ++i)
- {
- bc->m_phaseOrder[i] = i;
- }
- writeGrainSizes(bc);
-}
-
-//
-// PreallocatedMemoryHelper -- helper object for allocating a number of chunks of memory in a single contiguous block.
-// It is generally more efficient to do a single larger allocation than many smaller allocations.
-//
-// Example Usage:
-//
-// btVector3* bodyPositions = NULL;
-// btBatchedConstraintInfo* conInfos = NULL;
-// {
-// PreallocatedMemoryHelper<8> memHelper;
-// memHelper.addChunk( (void**) &bodyPositions, sizeof( btVector3 ) * bodies.size() );
-// memHelper.addChunk( (void**) &conInfos, sizeof( btBatchedConstraintInfo ) * numConstraints );
-// void* memPtr = malloc( memHelper.getSizeToAllocate() ); // allocate the memory
-// memHelper.setChunkPointers( memPtr ); // update pointers to chunks
-// }
-template <int N>
-class PreallocatedMemoryHelper
-{
- struct Chunk
- {
- void** ptr;
- size_t size;
- };
- Chunk m_chunks[N];
- int m_numChunks;
-
-public:
- PreallocatedMemoryHelper() { m_numChunks = 0; }
- void addChunk(void** ptr, size_t sz)
- {
- btAssert(m_numChunks < N);
- if (m_numChunks < N)
- {
- Chunk& chunk = m_chunks[m_numChunks];
- chunk.ptr = ptr;
- chunk.size = sz;
- m_numChunks++;
- }
- }
- size_t getSizeToAllocate() const
- {
- size_t totalSize = 0;
- for (int i = 0; i < m_numChunks; ++i)
- {
- totalSize += m_chunks[i].size;
- }
- return totalSize;
- }
- void setChunkPointers(void* mem) const
- {
- size_t totalSize = 0;
- for (int i = 0; i < m_numChunks; ++i)
- {
- const Chunk& chunk = m_chunks[i];
- char* chunkPtr = static_cast<char*>(mem) + totalSize;
- *chunk.ptr = chunkPtr;
- totalSize += chunk.size;
- }
- }
-};
-
-static btVector3 findMaxDynamicConstraintExtent(
- btVector3* bodyPositions,
- bool* bodyDynamicFlags,
- btBatchedConstraintInfo* conInfos,
- int numConstraints,
- int numBodies)
-{
- BT_PROFILE("findMaxDynamicConstraintExtent");
- btVector3 consExtent = btVector3(1, 1, 1) * 0.001;
- for (int iCon = 0; iCon < numConstraints; ++iCon)
- {
- const btBatchedConstraintInfo& con = conInfos[iCon];
- int iBody0 = con.bodyIds[0];
- int iBody1 = con.bodyIds[1];
- btAssert(iBody0 >= 0 && iBody0 < numBodies);
- btAssert(iBody1 >= 0 && iBody1 < numBodies);
- // is it a dynamic constraint?
- if (bodyDynamicFlags[iBody0] && bodyDynamicFlags[iBody1])
- {
- btVector3 delta = bodyPositions[iBody1] - bodyPositions[iBody0];
- consExtent.setMax(delta.absolute());
- }
- }
- return consExtent;
-}
-
-struct btIntVec3
-{
- int m_ints[3];
-
- SIMD_FORCE_INLINE const int& operator[](int i) const { return m_ints[i]; }
- SIMD_FORCE_INLINE int& operator[](int i) { return m_ints[i]; }
-};
-
-struct AssignConstraintsToGridBatchesParams
-{
- bool* bodyDynamicFlags;
- btIntVec3* bodyGridCoords;
- int numBodies;
- btBatchedConstraintInfo* conInfos;
- int* constraintBatchIds;
- btIntVec3 gridChunkDim;
- int maxNumBatchesPerPhase;
- int numPhases;
- int phaseMask;
-
- AssignConstraintsToGridBatchesParams()
- {
- memset(this, 0, sizeof(*this));
- }
-};
-
-static void assignConstraintsToGridBatches(const AssignConstraintsToGridBatchesParams& params, int iConBegin, int iConEnd)
-{
- BT_PROFILE("assignConstraintsToGridBatches");
- // (can be done in parallel)
- for (int iCon = iConBegin; iCon < iConEnd; ++iCon)
- {
- const btBatchedConstraintInfo& con = params.conInfos[iCon];
- int iBody0 = con.bodyIds[0];
- int iBody1 = con.bodyIds[1];
- int iPhase = iCon; //iBody0; // pseudorandom choice to distribute evenly amongst phases
- iPhase &= params.phaseMask;
- int gridCoord[3];
- // is it a dynamic constraint?
- if (params.bodyDynamicFlags[iBody0] && params.bodyDynamicFlags[iBody1])
- {
- const btIntVec3& body0Coords = params.bodyGridCoords[iBody0];
- const btIntVec3& body1Coords = params.bodyGridCoords[iBody1];
- // for each dimension x,y,z,
- for (int i = 0; i < 3; ++i)
- {
- int coordMin = btMin(body0Coords.m_ints[i], body1Coords.m_ints[i]);
- int coordMax = btMax(body0Coords.m_ints[i], body1Coords.m_ints[i]);
- if (coordMin != coordMax)
- {
- btAssert(coordMax == coordMin + 1);
- if ((coordMin & 1) == 0)
- {
- iPhase &= ~(1 << i); // force bit off
- }
- else
- {
- iPhase |= (1 << i); // force bit on
- iPhase &= params.phaseMask;
- }
- }
- gridCoord[i] = coordMin;
- }
- }
- else
- {
- if (!params.bodyDynamicFlags[iBody0])
- {
- iBody0 = con.bodyIds[1];
- }
- btAssert(params.bodyDynamicFlags[iBody0]);
- const btIntVec3& body0Coords = params.bodyGridCoords[iBody0];
- // for each dimension x,y,z,
- for (int i = 0; i < 3; ++i)
- {
- gridCoord[i] = body0Coords.m_ints[i];
- }
- }
- // calculate chunk coordinates
- int chunkCoord[3];
- btIntVec3 gridChunkDim = params.gridChunkDim;
- // for each dimension x,y,z,
- for (int i = 0; i < 3; ++i)
- {
- int coordOffset = (iPhase >> i) & 1;
- chunkCoord[i] = (gridCoord[i] - coordOffset) / 2;
- btClamp(chunkCoord[i], 0, gridChunkDim[i] - 1);
- btAssert(chunkCoord[i] < gridChunkDim[i]);
- }
- int iBatch = iPhase * params.maxNumBatchesPerPhase + chunkCoord[0] + chunkCoord[1] * gridChunkDim[0] + chunkCoord[2] * gridChunkDim[0] * gridChunkDim[1];
- btAssert(iBatch >= 0 && iBatch < params.maxNumBatchesPerPhase * params.numPhases);
- params.constraintBatchIds[iCon] = iBatch;
- }
-}
-
-struct AssignConstraintsToGridBatchesLoop : public btIParallelForBody
-{
- const AssignConstraintsToGridBatchesParams* m_params;
-
- AssignConstraintsToGridBatchesLoop(const AssignConstraintsToGridBatchesParams& params)
- {
- m_params = &params;
- }
- void forLoop(int iBegin, int iEnd) const BT_OVERRIDE
- {
- assignConstraintsToGridBatches(*m_params, iBegin, iEnd);
- }
-};
-
-//
-// setupSpatialGridBatchesMt -- generate batches using a uniform 3D grid
-//
-/*
-
-Bodies are treated as 3D points at their center of mass. We only consider dynamic bodies at this stage,
-because only dynamic bodies are mutated when a constraint is solved, thus subject to race conditions.
-
-1. Compute a bounding box around all dynamic bodies
-2. Compute the maximum extent of all dynamic constraints. Each dynamic constraint is treated as a line segment, and we need the size of
- box that will fully enclose any single dynamic constraint
-
-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,
- 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
- larger in order to keep the total number of cells from being excessively high
-
-Key idea: Given that each constraint spans 1 or 2 grid cells in each dimension, we can handle all constraints by processing
- 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)...).
- For each of the 8 offsets, we create a phase, and for each 2x2x2 chunk with dynamic constraints becomes a batch in that phase.
-
-4. Once the grid is established, we can calculate for each constraint which phase and batch it belongs in.
-
-5. Do a merge small batches on the batches of each phase separately, to try to even out the sizes of batches
-
-Optionally, we can "collapse" one dimension of our 3D grid to turn it into a 2D grid, which reduces the number of phases
-to 4. With fewer phases, there are more constraints per phase and this makes it easier to create batches of a useful size.
-*/
-//
-static void setupSpatialGridBatchesMt(
- btBatchedConstraints* batchedConstraints,
- btAlignedObjectArray<char>* scratchMemory,
- btConstraintArray* constraints,
- const btAlignedObjectArray<btSolverBody>& bodies,
- int minBatchSize,
- int maxBatchSize,
- bool use2DGrid)
-{
- BT_PROFILE("setupSpatialGridBatchesMt");
- const int numPhases = 8;
- int numConstraints = constraints->size();
- int numConstraintRows = constraints->size();
-
- const int maxGridChunkCount = 128;
- int allocNumBatchesPerPhase = maxGridChunkCount;
- int minNumBatchesPerPhase = 16;
- int allocNumBatches = allocNumBatchesPerPhase * numPhases;
-
- btVector3* bodyPositions = NULL;
- bool* bodyDynamicFlags = NULL;
- btIntVec3* bodyGridCoords = NULL;
- btBatchInfo* batches = NULL;
- int* batchWork = NULL;
- btBatchedConstraintInfo* conInfos = NULL;
- int* constraintBatchIds = NULL;
- int* constraintRowBatchIds = NULL;
- {
- PreallocatedMemoryHelper<10> memHelper;
- memHelper.addChunk((void**)&bodyPositions, sizeof(btVector3) * bodies.size());
- memHelper.addChunk((void**)&bodyDynamicFlags, sizeof(bool) * bodies.size());
- memHelper.addChunk((void**)&bodyGridCoords, sizeof(btIntVec3) * bodies.size());
- memHelper.addChunk((void**)&batches, sizeof(btBatchInfo) * allocNumBatches);
- memHelper.addChunk((void**)&batchWork, sizeof(int) * allocNumBatches);
- memHelper.addChunk((void**)&conInfos, sizeof(btBatchedConstraintInfo) * numConstraints);
- memHelper.addChunk((void**)&constraintBatchIds, sizeof(int) * numConstraints);
- memHelper.addChunk((void**)&constraintRowBatchIds, sizeof(int) * numConstraintRows);
- size_t scratchSize = memHelper.getSizeToAllocate();
- // if we need to reallocate
- if (static_cast<size_t>(scratchMemory->capacity()) < scratchSize)
- {
- // allocate 6.25% extra to avoid repeated reallocs
- scratchMemory->reserve(scratchSize + scratchSize / 16);
- }
- scratchMemory->resizeNoInitialize(scratchSize);
- char* memPtr = &scratchMemory->at(0);
- memHelper.setChunkPointers(memPtr);
- }
-
- numConstraints = initBatchedConstraintInfo(conInfos, constraints);
-
- // compute bounding box around all dynamic bodies
- // (could be done in parallel)
- btVector3 bboxMin(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT);
- btVector3 bboxMax = -bboxMin;
- //int dynamicBodyCount = 0;
- for (int i = 0; i < bodies.size(); ++i)
- {
- const btSolverBody& body = bodies[i];
- btVector3 bodyPos = body.getWorldTransform().getOrigin();
- bool isDynamic = (body.internalGetInvMass().x() > btScalar(0));
- bodyPositions[i] = bodyPos;
- bodyDynamicFlags[i] = isDynamic;
- if (isDynamic)
- {
- //dynamicBodyCount++;
- bboxMin.setMin(bodyPos);
- bboxMax.setMax(bodyPos);
- }
- }
-
- // find max extent of all dynamic constraints
- // (could be done in parallel)
- btVector3 consExtent = findMaxDynamicConstraintExtent(bodyPositions, bodyDynamicFlags, conInfos, numConstraints, bodies.size());
-
- btVector3 gridExtent = bboxMax - bboxMin;
-
- gridExtent.setMax(btVector3(btScalar(1), btScalar(1), btScalar(1)));
-
- btVector3 gridCellSize = consExtent;
- int gridDim[3];
- gridDim[0] = int(1.0 + gridExtent.x() / gridCellSize.x());
- gridDim[1] = int(1.0 + gridExtent.y() / gridCellSize.y());
- gridDim[2] = int(1.0 + gridExtent.z() / gridCellSize.z());
-
- // if we can collapse an axis, it will cut our number of phases in half which could be more efficient
- int phaseMask = 7;
- bool collapseAxis = use2DGrid;
- if (collapseAxis)
- {
- // pick the smallest axis to collapse, leaving us with the greatest number of cells in our grid
- int iAxisToCollapse = 0;
- int axisDim = gridDim[iAxisToCollapse];
- //for each dimension
- for (int i = 0; i < 3; ++i)
- {
- if (gridDim[i] < axisDim)
- {
- iAxisToCollapse = i;
- axisDim = gridDim[i];
- }
- }
- // collapse it
- gridCellSize[iAxisToCollapse] = gridExtent[iAxisToCollapse] * 2.0f;
- phaseMask &= ~(1 << iAxisToCollapse);
- }
-
- int numGridChunks = 0;
- btIntVec3 gridChunkDim; // each chunk is 2x2x2 group of cells
- while (true)
- {
- gridDim[0] = int(1.0 + gridExtent.x() / gridCellSize.x());
- gridDim[1] = int(1.0 + gridExtent.y() / gridCellSize.y());
- gridDim[2] = int(1.0 + gridExtent.z() / gridCellSize.z());
- gridChunkDim[0] = btMax(1, (gridDim[0] + 0) / 2);
- gridChunkDim[1] = btMax(1, (gridDim[1] + 0) / 2);
- gridChunkDim[2] = btMax(1, (gridDim[2] + 0) / 2);
- numGridChunks = gridChunkDim[0] * gridChunkDim[1] * gridChunkDim[2];
- float nChunks = float(gridChunkDim[0]) * float(gridChunkDim[1]) * float(gridChunkDim[2]); // suceptible to integer overflow
- if (numGridChunks <= maxGridChunkCount && nChunks <= maxGridChunkCount)
- {
- break;
- }
- gridCellSize *= 1.25; // should roughly cut numCells in half
- }
- btAssert(numGridChunks <= maxGridChunkCount);
- int maxNumBatchesPerPhase = numGridChunks;
-
- // for each dynamic body, compute grid coords
- btVector3 invGridCellSize = btVector3(1, 1, 1) / gridCellSize;
- // (can be done in parallel)
- for (int iBody = 0; iBody < bodies.size(); ++iBody)
- {
- btIntVec3& coords = bodyGridCoords[iBody];
- if (bodyDynamicFlags[iBody])
- {
- btVector3 v = (bodyPositions[iBody] - bboxMin) * invGridCellSize;
- coords.m_ints[0] = int(v.x());
- coords.m_ints[1] = int(v.y());
- coords.m_ints[2] = int(v.z());
- btAssert(coords.m_ints[0] >= 0 && coords.m_ints[0] < gridDim[0]);
- btAssert(coords.m_ints[1] >= 0 && coords.m_ints[1] < gridDim[1]);
- btAssert(coords.m_ints[2] >= 0 && coords.m_ints[2] < gridDim[2]);
- }
- else
- {
- coords.m_ints[0] = -1;
- coords.m_ints[1] = -1;
- coords.m_ints[2] = -1;
- }
- }
-
- for (int iPhase = 0; iPhase < numPhases; ++iPhase)
- {
- int batchBegin = iPhase * maxNumBatchesPerPhase;
- int batchEnd = batchBegin + maxNumBatchesPerPhase;
- for (int iBatch = batchBegin; iBatch < batchEnd; ++iBatch)
- {
- btBatchInfo& batch = batches[iBatch];
- batch = btBatchInfo();
- }
- }
-
- {
- AssignConstraintsToGridBatchesParams params;
- params.bodyDynamicFlags = bodyDynamicFlags;
- params.bodyGridCoords = bodyGridCoords;
- params.numBodies = bodies.size();
- params.conInfos = conInfos;
- params.constraintBatchIds = constraintBatchIds;
- params.gridChunkDim = gridChunkDim;
- params.maxNumBatchesPerPhase = maxNumBatchesPerPhase;
- params.numPhases = numPhases;
- params.phaseMask = phaseMask;
- bool inParallel = true;
- if (inParallel)
- {
- AssignConstraintsToGridBatchesLoop loop(params);
- int grainSize = 250;
- btParallelFor(0, numConstraints, grainSize, loop);
- }
- else
- {
- assignConstraintsToGridBatches(params, 0, numConstraints);
- }
- }
- for (int iCon = 0; iCon < numConstraints; ++iCon)
- {
- const btBatchedConstraintInfo& con = conInfos[iCon];
- int iBatch = constraintBatchIds[iCon];
- btBatchInfo& batch = batches[iBatch];
- batch.numConstraints += con.numConstraintRows;
- }
-
- for (int iPhase = 0; iPhase < numPhases; ++iPhase)
- {
- // if phase is legit,
- if (iPhase == (iPhase & phaseMask))
- {
- int iBeginBatch = iPhase * maxNumBatchesPerPhase;
- int iEndBatch = iBeginBatch + maxNumBatchesPerPhase;
- mergeSmallBatches(batches, iBeginBatch, iEndBatch, minBatchSize, maxBatchSize);
- }
- }
- // all constraints have been assigned a batchId
- updateConstraintBatchIdsForMergesMt(constraintBatchIds, numConstraints, batches, maxNumBatchesPerPhase * numPhases);
-
- if (numConstraintRows > numConstraints)
- {
- expandConstraintRowsMt(&constraintRowBatchIds[0], &constraintBatchIds[0], &conInfos[0], numConstraints, numConstraintRows);
- }
- else
- {
- constraintRowBatchIds = constraintBatchIds;
- }
-
- writeOutBatches(batchedConstraints, constraintRowBatchIds, numConstraintRows, batches, batchWork, maxNumBatchesPerPhase, numPhases);
- btAssert(batchedConstraints->validate(constraints, bodies));
-}
-
-static void setupSingleBatch(
- btBatchedConstraints* bc,
- int numConstraints)
-{
- BT_PROFILE("setupSingleBatch");
- typedef btBatchedConstraints::Range Range;
-
- bc->m_constraintIndices.resize(numConstraints);
- for (int i = 0; i < numConstraints; ++i)
- {
- bc->m_constraintIndices[i] = i;
- }
-
- bc->m_batches.resizeNoInitialize(0);
- bc->m_phases.resizeNoInitialize(0);
- bc->m_phaseOrder.resizeNoInitialize(0);
- bc->m_phaseGrainSize.resizeNoInitialize(0);
-
- if (numConstraints > 0)
- {
- bc->m_batches.push_back(Range(0, numConstraints));
- bc->m_phases.push_back(Range(0, 1));
- bc->m_phaseOrder.push_back(0);
- bc->m_phaseGrainSize.push_back(1);
- }
-}
-
-void btBatchedConstraints::setup(
- btConstraintArray* constraints,
- const btAlignedObjectArray<btSolverBody>& bodies,
- BatchingMethod batchingMethod,
- int minBatchSize,
- int maxBatchSize,
- btAlignedObjectArray<char>* scratchMemory)
-{
- if (constraints->size() >= minBatchSize * 4)
- {
- bool use2DGrid = batchingMethod == BATCHING_METHOD_SPATIAL_GRID_2D;
- setupSpatialGridBatchesMt(this, scratchMemory, constraints, bodies, minBatchSize, maxBatchSize, use2DGrid);
- if (s_debugDrawBatches)
- {
- debugDrawAllBatches(this, constraints, bodies);
- }
- }
- else
- {
- setupSingleBatch(this, constraints->size());
- }
-}