aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/LowLevelDynamics/src/DyDynamics.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/LowLevelDynamics/src/DyDynamics.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/LowLevelDynamics/src/DyDynamics.cpp')
-rw-r--r--PhysX_3.4/Source/LowLevelDynamics/src/DyDynamics.cpp2950
1 files changed, 2950 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/LowLevelDynamics/src/DyDynamics.cpp b/PhysX_3.4/Source/LowLevelDynamics/src/DyDynamics.cpp
new file mode 100644
index 00000000..07f3b642
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevelDynamics/src/DyDynamics.cpp
@@ -0,0 +1,2950 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "PsTime.h"
+#include "PsAtomic.h"
+#include "PxvDynamics.h"
+
+#include "foundation/PxProfiler.h"
+#include "PxsRigidBody.h"
+#include "PxsContactManager.h"
+#include "DyDynamics.h"
+#include "DyBodyCoreIntegrator.h"
+#include "DySolverCore.h"
+#include "DySolverControl.h"
+#include "DySolverContact.h"
+#include "DySolverContactPF.h"
+#include "DyArticulationContactPrep.h"
+#include "DySolverBody.h"
+
+#include "DyConstraintPrep.h"
+#include "DyConstraintPartition.h"
+#include "DyArticulation.h"
+
+#include "CmFlushPool.h"
+#include "DyArticulationPImpl.h"
+#include "PxsMaterialManager.h"
+#include "DySolverContactPF4.h"
+#include "DyContactReduction.h"
+#include "PxcNpContactPrepShared.h"
+#include "DyContactPrep.h"
+#include "DySolverControlPF.h"
+#include "PxSceneDesc.h"
+#include "PxsSimpleIslandManager.h"
+#include "PxvNphaseImplementationContext.h"
+#include "PxsContactManagerState.h"
+#include "PxsDefaultMemoryManager.h"
+#include "DyContactPrepShared.h"
+
+//KS - used to turn on/off batched SIMD constraints.
+#define DY_BATCH_CONSTRAINTS 1
+//KS - used to specifically turn on/off batches 1D SIMD constraints.
+#define DY_BATCH_1D 1
+
+namespace physx
+{
+namespace Dy
+{
+
+struct SolverIslandObjects
+{
+ PxsRigidBody** bodies;
+ Articulation** articulations;
+ Dy::Articulation** articulationOwners;
+ PxsIndexedContactManager* contactManagers;
+ //PxsIndexedConstraint* constraints;
+
+ const IG::IslandId* islandIds;
+ PxU32 numIslands;
+ PxU32* bodyRemapTable;
+ PxU32* nodeIndexArray;
+
+ PxSolverConstraintDesc* constraintDescs;
+ PxSolverConstraintDesc* orderedConstraintDescs;
+ PxSolverConstraintDesc* tempConstraintDescs;
+ PxConstraintBatchHeader* constraintBatchHeaders;
+ Cm::SpatialVector* motionVelocities;
+ PxsBodyCore** bodyCoreArray;
+
+ SolverIslandObjects() : bodies(NULL), articulations(NULL), articulationOwners(NULL),
+ contactManagers(NULL), islandIds(NULL), numIslands(0), nodeIndexArray(NULL), constraintDescs(NULL), orderedConstraintDescs(NULL),
+ tempConstraintDescs(NULL), constraintBatchHeaders(NULL), motionVelocities(NULL), bodyCoreArray(NULL)
+ {
+ }
+};
+
+Context* createDynamicsContext( PxcNpMemBlockPool* memBlockPool,
+ PxcScratchAllocator& scratchAllocator, Cm::FlushPool& taskPool,
+ PxvSimStats& simStats, PxTaskManager* taskManager, Ps::VirtualAllocatorCallback* allocatorCallback, PxsMaterialManager* materialManager,
+ IG::IslandSim* accurateIslandSim, PxU64 contextID,
+ const bool enableStabilization, const bool useEnhancedDeterminism, const bool useAdaptiveForce
+ )
+{
+ return DynamicsContext::create( memBlockPool, scratchAllocator, taskPool, simStats, taskManager, allocatorCallback, materialManager, accurateIslandSim,
+ contextID, enableStabilization, useEnhancedDeterminism, useAdaptiveForce);
+}
+
+// PT: TODO: consider removing this function. We already have "createDynamicsContext".
+DynamicsContext* DynamicsContext::create( PxcNpMemBlockPool* memBlockPool,
+ PxcScratchAllocator& scratchAllocator,
+ Cm::FlushPool& taskPool,
+ PxvSimStats& simStats,
+ PxTaskManager* taskManager,
+ Ps::VirtualAllocatorCallback* allocatorCallback,
+ PxsMaterialManager* materialManager,
+ IG::IslandSim* accurateIslandSim,
+ PxU64 contextID,
+ const bool enableStabilization,
+ const bool useEnhancedDeterminism,
+ const bool useAdaptiveForce
+ )
+{
+ // PT: TODO: inherit from UserAllocated, remove placement new
+ DynamicsContext* dc = reinterpret_cast<DynamicsContext*>(PX_ALLOC(sizeof(DynamicsContext), "DynamicsContext"));
+ if(dc)
+ {
+ new(dc)DynamicsContext(memBlockPool, scratchAllocator, taskPool, simStats, taskManager, allocatorCallback, materialManager, accurateIslandSim, contextID, enableStabilization, useEnhancedDeterminism, useAdaptiveForce);
+ }
+ return dc;
+}
+
+
+void DynamicsContext::destroy()
+{
+ this->~DynamicsContext();
+ PX_FREE(this);
+}
+
+void DynamicsContext::resetThreadContexts()
+{
+ PxcThreadCoherentCacheIterator<ThreadContext, PxcNpMemBlockPool> threadContextIt(mThreadContextPool);
+ ThreadContext* threadContext = threadContextIt.getNext();
+
+ while(threadContext != NULL)
+ {
+ threadContext->reset();
+ threadContext = threadContextIt.getNext();
+ }
+}
+
+
+// =========================== Basic methods
+
+
+DynamicsContext::DynamicsContext( PxcNpMemBlockPool* memBlockPool,
+ PxcScratchAllocator& scratchAllocator,
+ Cm::FlushPool& taskPool,
+ PxvSimStats& simStats,
+ PxTaskManager* taskManager,
+ Ps::VirtualAllocatorCallback* allocatorCallback,
+ PxsMaterialManager* materialManager,
+ IG::IslandSim* accurateIslandSim,
+ PxU64 contextID,
+ const bool enableStabilization,
+ const bool useEnhancedDeterminism,
+ const bool useAdaptiveForce
+ ) :
+ Dy::Context (accurateIslandSim, allocatorCallback, simStats, enableStabilization, useEnhancedDeterminism, useAdaptiveForce),
+ mThreadContextPool (memBlockPool),
+ mMaterialManager (materialManager),
+ mScratchAllocator (scratchAllocator),
+ mTaskPool (taskPool),
+ mTaskManager (taskManager),
+ mContextID (contextID)
+{
+ createThresholdStream(*allocatorCallback);
+ createForceChangeThresholdStream(*allocatorCallback);
+ mExceededForceThresholdStream[0] = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(ThresholdStream), PX_DEBUG_EXP("ExceededForceThresholdStream[0]")), ThresholdStream(*allocatorCallback));
+ mExceededForceThresholdStream[1] = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(ThresholdStream), PX_DEBUG_EXP("ExceededForceThresholdStream[1]")), ThresholdStream(*allocatorCallback));
+ mThresholdStreamOut = 0;
+ mCurrentIndex = 0;
+ mWorldSolverBody.linearVelocity = PxVec3(0);
+ mWorldSolverBody.angularState = PxVec3(0);
+ mWorldSolverBodyData.invMass = 0;
+ mWorldSolverBodyData.sqrtInvInertia = PxMat33(PxZero);
+ mWorldSolverBodyData.nodeIndex = IG_INVALID_NODE;
+ mWorldSolverBodyData.reportThreshold = PX_MAX_REAL;
+ mWorldSolverBodyData.penBiasClamp = -PX_MAX_REAL;
+ mWorldSolverBodyData.maxContactImpulse = PX_MAX_REAL;
+ mWorldSolverBody.solverProgress=MAX_PERMITTED_SOLVER_PROGRESS;
+ mWorldSolverBody.maxSolverNormalProgress=MAX_PERMITTED_SOLVER_PROGRESS;
+ mWorldSolverBody.maxSolverFrictionProgress=MAX_PERMITTED_SOLVER_PROGRESS;
+ mWorldSolverBodyData.linearVelocity = mWorldSolverBodyData.angularVelocity = PxVec3(0.f);
+ mWorldSolverBodyData.body2World = PxTransform(PxIdentity);
+ mWorldSolverBodyData.lockFlags = 0;
+ mSolverCore[PxFrictionType::ePATCH] = SolverCoreGeneral::create();
+ mSolverCore[PxFrictionType::eONE_DIRECTIONAL] = SolverCoreGeneralPF::create();
+ mSolverCore[PxFrictionType::eTWO_DIRECTIONAL] = SolverCoreGeneralPF::create();
+}
+
+DynamicsContext::~DynamicsContext()
+{
+ for(PxU32 i = 0; i < PxFrictionType::eFRICTION_COUNT; ++i)
+ {
+ mSolverCore[i]->destroyV();
+ }
+
+ if(mExceededForceThresholdStream[0])
+ {
+ mExceededForceThresholdStream[0]->~ThresholdStream();
+ PX_FREE(mExceededForceThresholdStream[0]);
+ }
+ mExceededForceThresholdStream[0] = NULL;
+
+ if(mExceededForceThresholdStream[1])
+ {
+ mExceededForceThresholdStream[1]->~ThresholdStream();
+ PX_FREE(mExceededForceThresholdStream[1]);
+ }
+ mExceededForceThresholdStream[1] = NULL;
+
+}
+
+#if PX_ENABLE_SIM_STATS
+void DynamicsContext::addThreadStats(const ThreadContext::ThreadSimStats& stats)
+{
+ mSimStats.mNbActiveConstraints += stats.numActiveConstraints;
+ mSimStats.mNbActiveDynamicBodies += stats.numActiveDynamicBodies;
+ mSimStats.mNbActiveKinematicBodies += stats.numActiveKinematicBodies;
+ mSimStats.mNbAxisSolverConstraints += stats.numAxisSolverConstraints;
+}
+#endif
+
+// =========================== Solve methods!
+
+void DynamicsContext::setDescFromIndices(PxSolverConstraintDesc& desc, const PxsIndexedInteraction& constraint, const PxU32 solverBodyOffset)
+{
+ PX_COMPILE_TIME_ASSERT(PxsIndexedInteraction::eBODY == 0);
+ PX_COMPILE_TIME_ASSERT(PxsIndexedInteraction::eKINEMATIC == 1);
+ const PxU32 offsetMap[] = {solverBodyOffset, 0};
+ //const PxU32 offsetMap[] = {mKinematicCount, 0};
+
+ if(constraint.indexType0 == PxsIndexedInteraction::eARTICULATION)
+ {
+ Articulation* a = getArticulation(constraint.articulation0);
+ desc.articulationA = a->getFsDataPtr();
+ desc.articulationALength = Ps::to16(a->getSolverDataSize());
+ PX_ASSERT(0==(desc.articulationALength & 0x0f));
+ desc.linkIndexA = Ps::to16(a->getLinkIndex(constraint.articulation0));
+ }
+ else
+ {
+ desc.linkIndexA = PxSolverConstraintDesc::NO_LINK;
+ //desc.articulationALength = 0; //this is unioned with bodyADataIndex
+ /*desc.bodyA = constraint.indexType0 == PxsIndexedInteraction::eWORLD ? &mWorldSolverBody
+ : &mSolverBodyPool[(PxU32)constraint.solverBody0 + offsetMap[constraint.indexType0]];
+ desc.bodyADataIndex = PxU16(constraint.indexType0 == PxsIndexedInteraction::eWORLD ? 0
+ : (PxU16)constraint.solverBody0 + 1 + offsetMap[constraint.indexType0]);*/
+
+ desc.bodyA = constraint.indexType0 == PxsIndexedInteraction::eWORLD ? &mWorldSolverBody
+ : &mSolverBodyPool[PxU32(constraint.solverBody0) + offsetMap[constraint.indexType0]];
+ desc.bodyADataIndex = PxU16(constraint.indexType0 == PxsIndexedInteraction::eWORLD ? 0
+ : PxU16(constraint.solverBody0) + 1 + offsetMap[constraint.indexType0]);
+ }
+
+ if(constraint.indexType1 == PxsIndexedInteraction::eARTICULATION)
+ {
+ Articulation* a = getArticulation(constraint.articulation1);
+ desc.articulationB = a->getFsDataPtr();
+ desc.articulationBLength = Ps::to16(a->getSolverDataSize());
+ PX_ASSERT(0==(desc.articulationBLength & 0x0f));
+ desc.linkIndexB = Ps::to16(a->getLinkIndex(constraint.articulation1));
+ }
+ else
+ {
+ desc.linkIndexB = PxSolverConstraintDesc::NO_LINK;
+ //desc.articulationBLength = 0; //this is unioned with bodyBDataIndex
+ desc.bodyB = constraint.indexType1 == PxsIndexedInteraction::eWORLD ? &mWorldSolverBody
+ : &mSolverBodyPool[PxU32(constraint.solverBody1) + offsetMap[constraint.indexType1]];
+ desc.bodyBDataIndex = PxU16(constraint.indexType1 == PxsIndexedInteraction::eWORLD ? 0
+ : PxU16(constraint.solverBody1) + 1 + offsetMap[constraint.indexType1]);
+ }
+}
+
+void DynamicsContext::setDescFromIndices(PxSolverConstraintDesc& desc, IG::EdgeIndex edgeIndex, const IG::SimpleIslandManager& islandManager,
+ PxU32* bodyRemap, const PxU32 solverBodyOffset)
+{
+ PX_COMPILE_TIME_ASSERT(PxsIndexedInteraction::eBODY == 0);
+ PX_COMPILE_TIME_ASSERT(PxsIndexedInteraction::eKINEMATIC == 1);
+
+ const IG::IslandSim& islandSim = islandManager.getAccurateIslandSim();
+
+ IG::NodeIndex node1 = islandSim.getNodeIndex1(edgeIndex);
+ if (node1.isStaticBody())
+ {
+ desc.bodyA = &mWorldSolverBody;
+ desc.bodyADataIndex = 0;
+ desc.linkIndexA = PxSolverConstraintDesc::NO_LINK;
+ }
+ else
+ {
+ const IG::Node& node = islandSim.getNode(node1);
+ if (node.getNodeType() == IG::Node::eARTICULATION_TYPE)
+ {
+ Dy::Articulation* a = islandSim.getLLArticulation(node1);
+ desc.articulationA = a->getFsDataPtr();
+ desc.articulationALength = Ps::to16(a->getSolverDataSize());
+ PX_ASSERT(0 == (desc.articulationALength & 0x0f));
+ desc.linkIndexA = Ps::to16(node1.articulationLinkId());
+ }
+ else
+ {
+ PxU32 activeIndex = islandSim.getActiveNodeIndex(node1);
+ PxU32 index = node.isKinematic() ? activeIndex : bodyRemap[activeIndex] + solverBodyOffset;
+ desc.bodyA = &mSolverBodyPool[index];
+ desc.bodyADataIndex = Ps::to16(index + 1);
+ desc.linkIndexA = PxSolverConstraintDesc::NO_LINK;
+ }
+ }
+
+ IG::NodeIndex node2 = islandSim.getNodeIndex2(edgeIndex);
+ if (node2.isStaticBody())
+ {
+ desc.bodyB = &mWorldSolverBody;
+ desc.bodyBDataIndex = 0;
+ desc.linkIndexB = PxSolverConstraintDesc::NO_LINK;
+ }
+ else
+ {
+ const IG::Node& node = islandSim.getNode(node2);
+ if (node.getNodeType() == IG::Node::eARTICULATION_TYPE)
+ {
+ Dy::Articulation* a = islandSim.getLLArticulation(node2);
+ desc.articulationB = a->getFsDataPtr();
+ desc.articulationBLength = Ps::to16(a->getSolverDataSize());
+ PX_ASSERT(0 == (desc.articulationBLength & 0x0f));
+ desc.linkIndexB = Ps::to16(node2.articulationLinkId());
+ }
+ else
+ {
+ PxU32 activeIndex = islandSim.getActiveNodeIndex(node2);
+ PxU32 index = node.isKinematic() ? activeIndex : bodyRemap[activeIndex] + solverBodyOffset;
+ desc.bodyB = &mSolverBodyPool[index];
+ desc.bodyBDataIndex = Ps::to16(index + 1);
+ desc.linkIndexB = PxSolverConstraintDesc::NO_LINK;
+ }
+ }
+}
+
+
+class PxsPreIntegrateTask : public Cm::Task
+{
+ PxsPreIntegrateTask& operator=(const PxsPreIntegrateTask&);
+public:
+ PxsPreIntegrateTask( DynamicsContext& context,
+ PxsBodyCore*const* bodyArray,
+ PxsRigidBody*const* originalBodyArray,
+ PxU32 const* nodeIndexArray,
+ PxSolverBody* solverBodies,
+ PxSolverBodyData* solverBodyDataPool,
+ PxF32 dt,
+ PxU32 numBodies,
+ volatile PxU32* maxSolverPositionIterations,
+ volatile PxU32* maxSolverVelocityIterations,
+ const PxU32 startIndex,
+ const PxU32 numToIntegrate,
+ const PxVec3& gravity) :
+ mContext(context),
+ mBodyArray(bodyArray),
+ mOriginalBodyArray(originalBodyArray),
+ mNodeIndexArray(nodeIndexArray),
+ mSolverBodies(solverBodies),
+ mSolverBodyDataPool(solverBodyDataPool),
+ mDt(dt),
+ mNumBodies(numBodies),
+ mMaxSolverPositionIterations(maxSolverPositionIterations),
+ mMaxSolverVelocityIterations(maxSolverVelocityIterations),
+ mStartIndex(startIndex),
+ mNumToIntegrate(numToIntegrate),
+ mGravity(gravity)
+ {}
+
+ virtual void runInternal();
+
+ virtual const char* getName() const
+ {
+ return "PxsDynamics.preIntegrate";
+ }
+
+public:
+ DynamicsContext& mContext;
+ PxsBodyCore*const* mBodyArray;
+ PxsRigidBody*const* mOriginalBodyArray;
+ PxU32 const* mNodeIndexArray;
+ PxSolverBody* mSolverBodies;
+ PxSolverBodyData* mSolverBodyDataPool;
+ PxF32 mDt;
+ PxU32 mNumBodies;
+ volatile PxU32* mMaxSolverPositionIterations;
+ volatile PxU32* mMaxSolverVelocityIterations;
+ PxU32 mStartIndex;
+ PxU32 mNumToIntegrate;
+ PxVec3 mGravity;
+
+};
+
+
+
+class PxsParallelSolverTask : public Cm::Task
+{
+ PxsParallelSolverTask& operator=(PxsParallelSolverTask&);
+public:
+
+ PxsParallelSolverTask(SolverIslandParams& params, DynamicsContext& context, PxFrictionType::Enum frictionType, IG::IslandSim& islandSim)
+ : mParams(params), mContext(context), mFrictionType(frictionType), mIslandSim(islandSim)
+ {
+ }
+
+ virtual void runInternal()
+ {
+ solveParallel(mContext, mParams, mIslandSim);
+ }
+
+ virtual const char* getName() const
+ {
+ return "PxsDynamics.parallelSolver";
+ }
+
+ SolverIslandParams& mParams;
+ DynamicsContext& mContext;
+ PxFrictionType::Enum mFrictionType;
+ IG::IslandSim& mIslandSim;
+};
+
+
+#define PX_CONTACT_REDUCTION 1
+
+class PxsSolverConstraintPostProcessTask : public Cm::Task
+{
+ PxsSolverConstraintPostProcessTask& operator=(const PxsSolverConstraintPostProcessTask&);
+public:
+
+ PxsSolverConstraintPostProcessTask(DynamicsContext& context,
+ ThreadContext& threadContext,
+ const SolverIslandObjects& objects,
+ const PxU32 solverBodyOffset,
+ PxU32 startIndex,
+ PxU32 stride,
+ PxsMaterialManager* materialManager,
+ PxsContactManagerOutputIterator& iterator) :
+ mContext(context),
+ mThreadContext(threadContext),
+ mObjects(objects),
+ mSolverBodyOffset(solverBodyOffset),
+ mStartIndex(startIndex),
+ mStride(stride),
+ mMaterialManager(materialManager),
+ mOutputs(iterator)
+ {}
+
+ void mergeContacts(CompoundContactManager& header, ThreadContext& threadContext)
+ {
+ Gu::ContactBuffer& buffer = threadContext.mContactBuffer;
+ PxsMaterialInfo materialInfo[Gu::ContactBuffer::MAX_CONTACTS];
+ PxU32 size = 0;
+
+ for(PxU32 a = 0; a < header.mStride; ++a)
+ {
+ PxsContactManager* manager = mThreadContext.orderedContactList[a+header.mStartIndex]->contactManager;
+ PxcNpWorkUnit& unit = manager->getWorkUnit();
+ PxsContactManagerOutput& output = mOutputs.getContactManager(unit.mNpIndex);
+ PxContactStreamIterator iter(output.contactPatches, output.contactPoints, output.getInternalFaceIndice(), output.nbPatches, output.nbContacts);
+
+ PxU32 origSize = size;
+ PX_UNUSED(origSize);
+ if(!iter.forceNoResponse)
+ {
+ while(iter.hasNextPatch())
+ {
+ iter.nextPatch();
+ while(iter.hasNextContact())
+ {
+ PX_ASSERT(size < Gu::ContactBuffer::MAX_CONTACTS);
+ iter.nextContact();
+ PxsMaterialInfo& info = materialInfo[size];
+ Gu::ContactPoint& point = buffer.contacts[size++];
+ point.dynamicFriction = iter.getDynamicFriction();
+ point.staticFriction = iter.getStaticFriction();
+ point.restitution = iter.getRestitution();
+ point.internalFaceIndex1 = iter.getFaceIndex1();
+ point.materialFlags = PxU8(iter.getMaterialFlags());
+ point.maxImpulse = iter.getMaxImpulse();
+ point.targetVel = iter.getTargetVel();
+ point.normal = iter.getContactNormal();
+ point.point = iter.getContactPoint();
+ point.separation = iter.getSeparation();
+ info.mMaterialIndex0 = iter.getMaterialIndex0();
+ info.mMaterialIndex1 = iter.getMaterialIndex1();
+ }
+ }
+ PX_ASSERT(output.nbContacts == (size - origSize));
+ }
+ }
+
+ PxU32 origSize = size;
+#if PX_CONTACT_REDUCTION
+ ContactReduction<6> reduction(buffer.contacts, materialInfo, size);
+ reduction.reduceContacts();
+ //OK, now we write back the contacts...
+
+ PxU8 histo[Gu::ContactBuffer::MAX_CONTACTS];
+ PxMemZero(histo, sizeof(histo));
+
+ size = 0;
+ for(PxU32 a = 0; a < reduction.mNumPatches; ++a)
+ {
+ ReducedContactPatch& patch = reduction.mPatches[a];
+ for(PxU32 b = 0; b < patch.numContactPoints; ++b)
+ {
+ histo[patch.contactPoints[b]] = 1;
+ ++size;
+ }
+ }
+#endif
+
+ PxU16* PX_RESTRICT data = reinterpret_cast<PxU16*>(threadContext.mConstraintBlockStream.reserve(size * sizeof(PxU16), mThreadContext.mConstraintBlockManager));
+ header.forceBufferList = data;
+
+
+#if PX_CONTACT_REDUCTION
+ const PxU32 reservedSize = size;
+ PX_UNUSED(reservedSize);
+ size = 0;
+ for(PxU32 a = 0; a < origSize; ++a)
+ {
+ if(histo[a])
+ {
+ if(size != a)
+ {
+ buffer.contacts[size] = buffer.contacts[a];
+ materialInfo[size] = materialInfo[a];
+ }
+ data[size] = Ps::to16(a);
+ size++;
+ }
+ }
+ PX_ASSERT(reservedSize >= size);
+#else
+ for(PxU32 a = 0; a < size; ++a)
+ data[a] = a;
+#endif
+
+
+ PxU32 contactForceByteSize = size * sizeof(PxReal);
+
+
+ PxsContactManagerOutput& output = mOutputs.getContactManager(header.unit->mNpIndex);
+
+ PxU16 compressedContactSize;
+
+ physx::writeCompressedContact(buffer.contacts, size, NULL, output.nbContacts, output.contactPatches, output.contactPoints, compressedContactSize,
+ reinterpret_cast<PxReal*&>(output.contactForces), contactForceByteSize, mMaterialManager, false,
+ false, materialInfo, output.nbPatches, 0, &mThreadContext.mConstraintBlockManager, &threadContext.mConstraintBlockStream, false);
+ }
+
+ virtual void runInternal()
+ {
+ PxU32 endIndex = mStartIndex + mStride;
+
+ ThreadContext* threadContext = mContext.getThreadContext();
+ //TODO - we need to do this somewhere else
+ //threadContext->mContactBlockStream.reset();
+ threadContext->mConstraintBlockStream.reset();
+
+ for(PxU32 a = mStartIndex; a < endIndex; ++a)
+ {
+ mergeContacts(mThreadContext.compoundConstraints[a], *threadContext);
+ }
+ mContext.putThreadContext(threadContext);
+ }
+
+ virtual const char* getName() const { return "PxsDynamics.solverConstraintPostProcess"; }
+
+
+ DynamicsContext& mContext;
+ ThreadContext& mThreadContext;
+ const SolverIslandObjects mObjects;
+ PxU32 mSolverBodyOffset;
+ PxU32 mStartIndex;
+ PxU32 mStride;
+ PxsMaterialManager* mMaterialManager;
+ PxsContactManagerOutputIterator& mOutputs;
+};
+
+class PxsForceThresholdTask : public Cm::Task
+{
+ DynamicsContext& mDynamicsContext;
+
+ PxsForceThresholdTask& operator=(const PxsForceThresholdTask&);
+public:
+
+ PxsForceThresholdTask(DynamicsContext& context): mDynamicsContext(context)
+ {
+ }
+
+ void createForceChangeThresholdStream()
+ {
+ ThresholdStream& thresholdStream = mDynamicsContext.getThresholdStream();
+ //bool haveThresholding = thresholdStream.size()!=0;
+
+ ThresholdTable& thresholdTable = mDynamicsContext.getThresholdTable();
+ thresholdTable.build(thresholdStream);
+
+ //generate current force exceeded threshold stream
+ ThresholdStream& curExceededForceThresholdStream = *mDynamicsContext.mExceededForceThresholdStream[mDynamicsContext.mCurrentIndex];
+ ThresholdStream& preExceededForceThresholdStream = *mDynamicsContext.mExceededForceThresholdStream[1 - mDynamicsContext.mCurrentIndex];
+ curExceededForceThresholdStream.forceSize_Unsafe(0);
+
+ //fill in the currrent exceeded force threshold stream
+ for(PxU32 i=0; i<thresholdTable.mPairsSize; ++i)
+ {
+ ThresholdTable::Pair& pair = thresholdTable.mPairs[i];
+ ThresholdStreamElement& elem = thresholdStream[pair.thresholdStreamIndex];
+ if(pair.accumulatedForce > elem.threshold * mDynamicsContext.mDt)
+ {
+ elem.accumulatedForce = pair.accumulatedForce;
+ curExceededForceThresholdStream.pushBack(elem);
+ }
+ }
+
+ ThresholdStream& forceChangeThresholdStream = mDynamicsContext.getForceChangedThresholdStream();
+ forceChangeThresholdStream.forceSize_Unsafe(0);
+ Ps::Array<PxU32>& forceChangeMask = mDynamicsContext.mExceededForceThresholdStreamMask;
+
+ const PxU32 nbPreExceededForce = preExceededForceThresholdStream.size();
+ const PxU32 nbCurExceededForce = curExceededForceThresholdStream.size();
+
+ //generate force change thresholdStream
+ if(nbPreExceededForce)
+ {
+ thresholdTable.build(preExceededForceThresholdStream);
+
+ //set force change mask
+ const PxU32 nbTotalExceededForce = nbPreExceededForce + nbCurExceededForce;
+ forceChangeMask.reserve(nbTotalExceededForce);
+ forceChangeMask.forceSize_Unsafe(nbTotalExceededForce);
+
+ //initialize the forceChangeMask
+ for (PxU32 i = 0; i < nbTotalExceededForce; ++i)
+ forceChangeMask[i] = 1;
+
+ for(PxU32 i=0; i< nbCurExceededForce; ++i)
+ {
+ ThresholdStreamElement& curElem = curExceededForceThresholdStream[i];
+
+ PxU32 pos;
+ if(thresholdTable.check(preExceededForceThresholdStream, curElem, pos))
+ {
+ forceChangeMask[pos] = 0;
+ forceChangeMask[i + nbPreExceededForce] = 0;
+ }
+ }
+
+ //create force change threshold stream
+ for(PxU32 i=0; i<nbTotalExceededForce; ++i)
+ {
+ const PxU32 hasForceChange = forceChangeMask[i];
+ if(hasForceChange)
+ {
+ bool lostPair = (i < nbPreExceededForce);
+ ThresholdStreamElement& elem = lostPair ? preExceededForceThresholdStream[i] : curExceededForceThresholdStream[i - nbPreExceededForce];
+ ThresholdStreamElement elt;
+ elt = elem;
+ elt.accumulatedForce = lostPair ? 0.f : elem.accumulatedForce;
+ forceChangeThresholdStream.pushBack(elt);
+ }
+ else
+ {
+ //persistent pair
+ if (i < nbPreExceededForce)
+ {
+ ThresholdStreamElement& elem = preExceededForceThresholdStream[i];
+ ThresholdStreamElement elt;
+ elt = elem;
+ elt.accumulatedForce = elem.accumulatedForce;
+ forceChangeThresholdStream.pushBack(elt);
+ }
+ }
+ }
+ }
+ else
+ {
+ forceChangeThresholdStream.reserve(nbCurExceededForce);
+ forceChangeThresholdStream.forceSize_Unsafe(nbCurExceededForce);
+ PxMemCopy(forceChangeThresholdStream.begin(), curExceededForceThresholdStream.begin(), sizeof(ThresholdStreamElement) * nbCurExceededForce);
+ }
+ }
+
+ virtual void runInternal()
+ {
+ mDynamicsContext.getThresholdStream().forceSize_Unsafe(PxU32(mDynamicsContext.mThresholdStreamOut));
+ createForceChangeThresholdStream();
+ }
+
+ virtual const char* getName() const { return "PxsDynamics.createForceChangeThresholdStream"; }
+};
+
+
+struct ConstraintLess
+{
+ bool operator()(const PxSolverConstraintDesc& left, const PxSolverConstraintDesc& right) const
+ {
+ return reinterpret_cast<Constraint*>(left.constraint)->index > reinterpret_cast<Constraint*>(right.constraint)->index;
+ }
+};
+
+struct ArticulationSortPredicate
+{
+ bool operator()(const PxsIndexedContactManager*& left, const PxsIndexedContactManager*& right) const
+ {
+ return left->contactManager->getWorkUnit().index < right->contactManager->getWorkUnit().index;
+ }
+};
+
+class SolverArticulationUpdateTask : public Cm::Task
+{
+
+
+ ThreadContext& mIslandThreadContext;
+
+ Articulation** mArticulations;
+ ArticulationSolverDesc* mArticulationDescArray;
+ PxU32 mNbToProcess;
+
+ Dy::DynamicsContext& mContext;
+ PxU32 mStartIdx;
+
+public:
+
+ static const PxU32 NbArticulationsPerTask = 8;
+
+ SolverArticulationUpdateTask(ThreadContext& islandThreadContext, Articulation** articulations, ArticulationSolverDesc* articulationDescArray, PxU32 nbToProcess, Dy::DynamicsContext& context,
+ PxU32 startIdx):
+ mIslandThreadContext(islandThreadContext), mArticulations(articulations), mArticulationDescArray(articulationDescArray), mNbToProcess(nbToProcess), mContext(context), mStartIdx(startIdx)
+ {
+ }
+
+ virtual const char* getName() const { return "SolverArticulationUpdateTask"; }
+
+ virtual void runInternal()
+ {
+ ThreadContext& threadContext = *mContext.getThreadContext();
+
+ threadContext.mConstraintBlockStream.reset(); //Clear in case there's some left-over memory in this context, for which the block has already been freed
+ PxU32 maxVelIters = 0;
+ PxU32 maxPosIters = 0;
+ PxU32 maxArticulationLength = 0;
+ PxU32 maxSolverArticLength = 0;
+
+ PxU32 startIdx = mStartIdx;
+ for(PxU32 i=0;i<mNbToProcess; i++)
+ {
+ Articulation& a = *(mArticulations[i]);
+ a.getSolverDesc(mArticulationDescArray[i]);
+
+ PxU32 acCount, descCount;
+
+ descCount = ArticulationPImpl::computeUnconstrainedVelocities(mArticulationDescArray[i], mContext.mDt, threadContext.mConstraintBlockStream,
+ mIslandThreadContext.mContactDescPtr + startIdx, acCount, mContext.getScratchAllocator(),
+ mIslandThreadContext.mConstraintBlockManager, mContext.getGravity(), mContext.getContextId());
+
+ mArticulationDescArray[i].numInternalConstraints = Ps::to8(descCount);
+
+ maxArticulationLength = PxMax(maxArticulationLength, PxU32(mArticulationDescArray[i].totalDataSize));
+ maxSolverArticLength = PxMax(maxSolverArticLength, PxU32(mArticulationDescArray[i].solverDataSize));
+
+ const PxU16 iterWord = a.getIterationCounts();
+ maxVelIters = PxMax<PxU32>(PxU32(iterWord >> 8), maxVelIters);
+ maxPosIters = PxMax<PxU32>(PxU32(iterWord & 0xff), maxPosIters);
+ startIdx += DY_ARTICULATION_MAX_SIZE;
+ }
+ Ps::atomicMax(reinterpret_cast<PxI32*>(&mIslandThreadContext.mMaxSolverPositionIterations), PxI32(maxPosIters));
+ Ps::atomicMax(reinterpret_cast<PxI32*>(&mIslandThreadContext.mMaxSolverVelocityIterations), PxI32(maxVelIters));
+ Ps::atomicMax(reinterpret_cast<PxI32*>(&mIslandThreadContext.mMaxArticulationLength), PxI32(maxArticulationLength));
+ Ps::atomicMax(reinterpret_cast<PxI32*>(&mIslandThreadContext.mMaxArticulationSolverLength), PxI32(maxSolverArticLength));
+
+ mContext.putThreadContext(&threadContext);
+ }
+
+private:
+ PX_NOCOPY(SolverArticulationUpdateTask)
+};
+
+
+struct EnhancedSortPredicate
+{
+ bool operator()(const PxsIndexedContactManager& left, const PxsIndexedContactManager& right) const
+ {
+ PxcNpWorkUnit& unit0 = left.contactManager->getWorkUnit();
+ PxcNpWorkUnit& unit1 = right.contactManager->getWorkUnit();
+ return (unit0.mTransformCache0 < unit1.mTransformCache0) ||
+ ((unit0.mTransformCache0 == unit1.mTransformCache0) && (unit0.mTransformCache1 < unit1.mTransformCache1));
+ }
+};
+
+
+class PxsSolverStartTask : public Cm::Task
+{
+ PxsSolverStartTask& operator=(const PxsSolverStartTask&);
+public:
+
+ PxsSolverStartTask(DynamicsContext& context,
+ IslandContext& islandContext,
+ const SolverIslandObjects& objects,
+ const PxU32 solverBodyOffset,
+ const PxU32 kinematicCount,
+ IG::SimpleIslandManager& islandManager,
+ PxU32* bodyRemapTable,
+ PxsMaterialManager* materialManager,
+ PxsContactManagerOutputIterator& iterator,
+ bool enhancedDeterminism
+ ) :
+ mContext (context),
+ mIslandContext (islandContext),
+ mObjects (objects),
+ mSolverBodyOffset (solverBodyOffset),
+ mKinematicCount (kinematicCount),
+ mIslandManager (islandManager),
+ mBodyRemapTable (bodyRemapTable),
+ mMaterialManager (materialManager),
+ mOutputs (iterator),
+ mEnhancedDeterminism (enhancedDeterminism)
+ {}
+
+ void startTasks()
+ {
+ PX_PROFILE_ZONE("Dynamics.solveGroup", mContext.getContextId());
+ {
+ ThreadContext& mThreadContext = *mContext.getThreadContext();
+
+ mIslandContext.mThreadContext = &mThreadContext;
+
+ mThreadContext.mMaxSolverPositionIterations = 0;
+ mThreadContext.mMaxSolverVelocityIterations = 0;
+ mThreadContext.mAxisConstraintCount = 0;
+ mThreadContext.mContactDescPtr = mThreadContext.contactConstraintDescArray;
+ mThreadContext.mFrictionDescPtr = mThreadContext.frictionConstraintDescArray.begin();
+ mThreadContext.mNumDifferentBodyConstraints = 0;
+ mThreadContext.mNumSelfConstraintBlocks = 0;
+ mThreadContext.mNumSelfConstraints = 0;
+ mThreadContext.mNumDifferentBodyFrictionConstraints = 0;
+ mThreadContext.mNumSelfConstraintFrictionBlocks = 0;
+ mThreadContext.mNumSelfFrictionConstraints = 0;
+ mThreadContext.numContactConstraintBatches = 0;
+ mThreadContext.contactDescArraySize = 0;
+
+
+ mThreadContext.contactConstraintDescArray = mObjects.constraintDescs;
+ mThreadContext.orderedContactConstraints = mObjects.orderedConstraintDescs;
+ mThreadContext.mContactDescPtr = mObjects.constraintDescs;
+ mThreadContext.tempConstraintDescArray = mObjects.tempConstraintDescs;
+ mThreadContext.contactConstraintBatchHeaders = mObjects.constraintBatchHeaders;
+ mThreadContext.motionVelocityArray = mObjects.motionVelocities;
+ mThreadContext.mBodyCoreArray = mObjects.bodyCoreArray;
+ mThreadContext.mRigidBodyArray = mObjects.bodies;
+ mThreadContext.mArticulationArray = mObjects.articulations;
+ mThreadContext.bodyRemapTable = mObjects.bodyRemapTable;
+ mThreadContext.mNodeIndexArray = mObjects.nodeIndexArray;
+
+ const PxU32 frictionConstraintCount = mContext.getFrictionType() == PxFrictionType::ePATCH ? 0 : PxU32(mIslandContext.mCounts.contactManagers);
+ mThreadContext.resizeArrays(frictionConstraintCount, mIslandContext.mCounts.articulations);
+
+ PxsBodyCore** PX_RESTRICT bodyArrayPtr = mThreadContext.mBodyCoreArray;
+ PxsRigidBody** PX_RESTRICT rigidBodyPtr = mThreadContext.mRigidBodyArray;
+ Articulation** PX_RESTRICT articulationPtr = mThreadContext.mArticulationArray;
+ PxU32* PX_RESTRICT bodyRemapTable = mThreadContext.bodyRemapTable;
+ PxU32* PX_RESTRICT nodeIndexArray = mThreadContext.mNodeIndexArray;
+
+ PxU32 nbIslands = mObjects.numIslands;
+ const IG::IslandId* const islandIds = mObjects.islandIds;
+
+ const IG::IslandSim& islandSim = mIslandManager.getAccurateIslandSim();
+
+ PxU32 bodyIndex = 0, articIndex = 0;
+ for(PxU32 i = 0; i < nbIslands; ++i)
+ {
+ const IG::Island& island = islandSim.getIsland(islandIds[i]);
+
+ IG::NodeIndex currentIndex = island.mRootNode;
+
+ while(currentIndex.isValid())
+ {
+ const IG::Node& node = islandSim.getNode(currentIndex);
+
+ if(node.getNodeType() == IG::Node::eARTICULATION_TYPE)
+ {
+ articulationPtr[articIndex++] = node.getArticulation();
+ }
+ else
+ {
+ PxsRigidBody* rigid = node.getRigidBody();
+ PX_ASSERT(bodyIndex < (mIslandContext.mCounts.bodies + mContext.mKinematicCount + 1));
+ rigidBodyPtr[bodyIndex] = rigid;
+ bodyArrayPtr[bodyIndex] = &rigid->getCore();
+ nodeIndexArray[bodyIndex] = currentIndex.index();
+ bodyRemapTable[islandSim.getActiveNodeIndex(currentIndex)] = bodyIndex++;
+ }
+
+ currentIndex = node.mNextNode;
+ }
+ }
+
+
+ PxsIndexedContactManager* indexedManagers = mObjects.contactManagers;
+
+ PxU32 currentContactIndex = 0;
+ for(PxU32 i = 0; i < nbIslands; ++i)
+ {
+ const IG::Island& island = islandSim.getIsland(islandIds[i]);
+
+ IG::EdgeIndex contactEdgeIndex = island.mFirstEdge[IG::Edge::eCONTACT_MANAGER];
+
+ while(contactEdgeIndex != IG_INVALID_EDGE)
+ {
+ const IG::Edge& edge = islandSim.getEdge(contactEdgeIndex);
+
+ PxsContactManager* contactManager = mIslandManager.getContactManager(contactEdgeIndex);
+
+ if(contactManager)
+ {
+ const IG::NodeIndex nodeIndex1 = islandSim.getNodeIndex1(contactEdgeIndex);
+ const IG::NodeIndex nodeIndex2 = islandSim.getNodeIndex2(contactEdgeIndex);
+
+ PxsIndexedContactManager& indexedManager = indexedManagers[currentContactIndex++];
+ indexedManager.contactManager = contactManager;
+
+ PX_ASSERT(!nodeIndex1.isStaticBody());
+ {
+ const IG::Node& node1 = islandSim.getNode(nodeIndex1);
+
+ //Is it an articulation or not???
+ if(node1.getNodeType() == IG::Node::eARTICULATION_TYPE)
+ {
+ indexedManager.indexType0 = PxsIndexedInteraction::eARTICULATION;
+ indexedManager.solverBody0 = size_t(node1.getArticulation()) | nodeIndex1.articulationLinkId();
+ }
+ else
+ {
+ if(node1.isKinematic())
+ {
+ indexedManager.indexType0 = PxsIndexedInteraction::eKINEMATIC;
+ indexedManager.solverBody0 = islandSim.getActiveNodeIndex(nodeIndex1);
+ }
+ else
+ {
+ indexedManager.indexType0 = PxsIndexedInteraction::eBODY;
+ indexedManager.solverBody0 = bodyRemapTable[islandSim.getActiveNodeIndex(nodeIndex1)];
+ }
+ PX_ASSERT(indexedManager.solverBody0 < (mIslandContext.mCounts.bodies + mContext.mKinematicCount + 1));
+ }
+
+ }
+
+ if(nodeIndex2.isStaticBody())
+ {
+ indexedManager.indexType1 = PxsIndexedInteraction::eWORLD;
+ }
+ else
+ {
+ const IG::Node& node2 = islandSim.getNode(nodeIndex2);
+
+ //Is it an articulation or not???
+ if(node2.getNodeType() == IG::Node::eARTICULATION_TYPE)
+ {
+ indexedManager.indexType1 = PxsIndexedInteraction::eARTICULATION;
+ indexedManager.solverBody1 = size_t(node2.getArticulation()) | nodeIndex2.articulationLinkId();
+ }
+ else
+ {
+ if(node2.isKinematic())
+ {
+ indexedManager.indexType1 = PxsIndexedInteraction::eKINEMATIC;
+ indexedManager.solverBody1 = islandSim.getActiveNodeIndex(nodeIndex2);
+ }
+ else
+ {
+ indexedManager.indexType1 = PxsIndexedInteraction::eBODY;
+ indexedManager.solverBody1 = bodyRemapTable[islandSim.getActiveNodeIndex(nodeIndex2)];
+ }
+ PX_ASSERT(indexedManager.solverBody1 < (mIslandContext.mCounts.bodies + mContext.mKinematicCount + 1));
+ }
+ }
+
+ }
+ contactEdgeIndex = edge.mNextIslandEdge;
+ }
+ }
+
+ if (mEnhancedDeterminism)
+ {
+ Ps::sort(indexedManagers, currentContactIndex, EnhancedSortPredicate());
+ }
+
+ mIslandContext.mCounts.contactManagers = currentContactIndex;
+ }
+ }
+
+ void integrate()
+ {
+ ThreadContext& mThreadContext = *mIslandContext.mThreadContext;
+ PxSolverBody* solverBodies = mContext.mSolverBodyPool.begin() + mSolverBodyOffset;
+ PxSolverBodyData* solverBodyData = mContext.mSolverBodyDataPool.begin() + mSolverBodyOffset;
+
+ {
+ PX_PROFILE_ZONE("Dynamics.updateVelocities", mContext.getContextId());
+
+ mContext.preIntegrationParallel(
+ mContext.mDt,
+ mThreadContext.mBodyCoreArray,
+ mObjects.bodies,
+ mThreadContext.mNodeIndexArray,
+ mIslandContext.mCounts.bodies,
+ solverBodies,
+ solverBodyData,
+ mThreadContext.motionVelocityArray,
+ mThreadContext.mMaxSolverPositionIterations,
+ mThreadContext.mMaxSolverVelocityIterations,
+ *mCont
+ );
+ }
+ }
+
+ void articulationTask()
+ {
+ ThreadContext& mThreadContext = *mIslandContext.mThreadContext;
+ ArticulationSolverDesc* articulationDescArray = mThreadContext.getArticulations().begin();
+
+ for(PxU32 i=0;i<mIslandContext.mCounts.articulations; i+= SolverArticulationUpdateTask::NbArticulationsPerTask)
+ {
+
+ SolverArticulationUpdateTask* task = PX_PLACEMENT_NEW(mContext.getTaskPool().allocate(sizeof(SolverArticulationUpdateTask)), SolverArticulationUpdateTask)(mThreadContext,
+ &mObjects.articulations[i], &articulationDescArray[i], PxMin(SolverArticulationUpdateTask::NbArticulationsPerTask, mIslandContext.mCounts.articulations - i), mContext,
+ i*DY_ARTICULATION_MAX_SIZE);
+
+ task->setContinuation(mCont);
+ task->removeReference();
+
+ }
+ }
+
+ void setupDescTask()
+ {
+ ThreadContext& mThreadContext = *mIslandContext.mThreadContext;
+ PxSolverConstraintDesc* contactDescPtr = mThreadContext.mContactDescPtr;
+
+ //PxU32 constraintCount = mCounts.constraints + mCounts.contactManagers;
+
+ PxU32 nbIslands = mObjects.numIslands;
+ const IG::IslandId* const islandIds = mObjects.islandIds;
+
+ const IG::IslandSim& islandSim = mIslandManager.getAccurateIslandSim();
+
+ for(PxU32 i = 0; i < nbIslands; ++i)
+ {
+ const IG::Island& island = islandSim.getIsland(islandIds[i]);
+
+ IG::EdgeIndex edgeId = island.mFirstEdge[IG::Edge::eCONSTRAINT];
+
+ while(edgeId != IG_INVALID_EDGE)
+ {
+ PxSolverConstraintDesc& desc = *contactDescPtr;
+
+ const IG::Edge& edge = islandSim.getEdge(edgeId);
+ Dy::Constraint* constraint = mIslandManager.getConstraint(edgeId);
+ mContext.setDescFromIndices(desc, edgeId, mIslandManager, mBodyRemapTable, mSolverBodyOffset);
+ desc.constraint = reinterpret_cast<PxU8*>(constraint);
+ desc.constraintLengthOver16 = DY_SC_TYPE_RB_1D;
+ contactDescPtr++;
+ edgeId = edge.mNextIslandEdge;
+ }
+
+ }
+
+#if 1
+ Ps::sort(mThreadContext.mContactDescPtr, PxU32(contactDescPtr - mThreadContext.mContactDescPtr), ConstraintLess());
+#endif
+
+
+ mThreadContext.orderedContactList.forceSize_Unsafe(0);
+ mThreadContext.orderedContactList.reserve(mIslandContext.mCounts.contactManagers);
+ mThreadContext.orderedContactList.forceSize_Unsafe(mIslandContext.mCounts.contactManagers);
+ mThreadContext.tempContactList.forceSize_Unsafe(0);
+ mThreadContext.tempContactList.reserve(mIslandContext.mCounts.contactManagers);
+ mThreadContext.tempContactList.forceSize_Unsafe(mIslandContext.mCounts.contactManagers);
+
+ const PxsIndexedContactManager** constraints = mThreadContext.orderedContactList.begin();
+
+
+ //OK, we sort the orderedContactList
+
+ mThreadContext.compoundConstraints.forceSize_Unsafe(0);
+ if(mIslandContext.mCounts.contactManagers)
+ {
+ {
+ mThreadContext.sortIndexArray.forceSize_Unsafe(0);
+
+ PX_COMPILE_TIME_ASSERT(PxsIndexedInteraction::eBODY == 0);
+ PX_COMPILE_TIME_ASSERT(PxsIndexedInteraction::eKINEMATIC == 1);
+
+ const PxI32 offsetMap[] = {PxI32(mContext.mKinematicCount), 0};
+
+ const PxU32 totalBodies = mContext.mKinematicCount + mIslandContext.mCounts.bodies+1;
+
+ mThreadContext.sortIndexArray.reserve(totalBodies);
+ mThreadContext.sortIndexArray.forceSize_Unsafe(totalBodies);
+ PxMemZero(mThreadContext.sortIndexArray.begin(), totalBodies * 4);
+
+ //Iterate over the array based on solverBodyDatapool, creating a list of sorted constraints (in order of body pair)
+ //We only do this with contacts. It's important that this is done this way because we don't want to break our rules that all joints
+ //appear before all contacts in the constraint list otherwise we will lose all guarantees about sorting joints.
+
+ for(PxU32 a = 0; a < mIslandContext.mCounts.contactManagers; ++a)
+ {
+ PX_ASSERT(mObjects.contactManagers[a].indexType0 != PxsIndexedInteraction::eWORLD);
+ //Index first body...
+ PxU8 indexType = mObjects.contactManagers[a].indexType0;
+ if(indexType != PxsIndexedInteraction::eARTICULATION && mObjects.contactManagers[a].indexType1 != PxsIndexedInteraction::eARTICULATION)
+ {
+ PX_ASSERT((indexType == PxsIndexedInteraction::eBODY) || (indexType == PxsIndexedInteraction::eKINEMATIC));
+
+ PxI32 index = PxI32(mObjects.contactManagers[a].solverBody0 + offsetMap[indexType]);
+ PX_ASSERT(index >= 0);
+ mThreadContext.sortIndexArray[PxU32(index)]++;
+ }
+ }
+
+ PxU32 accumulatedCount = 0;
+
+ for(PxU32 a = mThreadContext.sortIndexArray.size(); a > 0; --a)
+ {
+ PxU32 ind = a - 1;
+ PxU32 val = mThreadContext.sortIndexArray[ind];
+ mThreadContext.sortIndexArray[ind] = accumulatedCount;
+ accumulatedCount += val;
+ }
+
+ //OK, now copy across data to orderedConstraintDescs, pushing articulations to the end...
+ for(PxU32 a = 0; a < mIslandContext.mCounts.contactManagers; ++a)
+ {
+ //Index first body...
+ PxU8 indexType = mObjects.contactManagers[a].indexType0;
+ if(indexType != PxsIndexedInteraction::eARTICULATION && mObjects.contactManagers[a].indexType1 != PxsIndexedInteraction::eARTICULATION)
+ {
+ PX_ASSERT((indexType == PxsIndexedInteraction::eBODY) || (indexType == PxsIndexedInteraction::eKINEMATIC));
+
+ PxI32 index = PxI32(mObjects.contactManagers[a].solverBody0 + offsetMap[indexType]);
+ PX_ASSERT(index >= 0);
+ mThreadContext.tempContactList[mThreadContext.sortIndexArray[PxU32(index)]++] = &mObjects.contactManagers[a];
+ }
+ else
+ {
+ mThreadContext.tempContactList[accumulatedCount++] = &mObjects.contactManagers[a];
+ }
+ }
+
+ //Now do the same again with bodyB, being careful not to overwrite the joints
+ PxMemZero(mThreadContext.sortIndexArray.begin(), totalBodies * 4);
+
+
+ for(PxU32 a = 0; a < mIslandContext.mCounts.contactManagers; ++a)
+ {
+ //Index first body...
+ PxU8 indexType = mThreadContext.tempContactList[a]->indexType1;
+ if(indexType != PxsIndexedInteraction::eARTICULATION && mObjects.contactManagers[a].indexType0 != PxsIndexedInteraction::eARTICULATION)
+ {
+ PX_ASSERT((indexType == PxsIndexedInteraction::eBODY) || (indexType == PxsIndexedInteraction::eKINEMATIC) || (indexType == PxsIndexedInteraction::eWORLD));
+
+ PxI32 index = (indexType == PxsIndexedInteraction::eWORLD) ? 0 : PxI32(mThreadContext.tempContactList[a]->solverBody1 + offsetMap[indexType]);
+ PX_ASSERT(index >= 0);
+ mThreadContext.sortIndexArray[PxU32(index)]++;
+ }
+ }
+
+ accumulatedCount = 0;
+ for(PxU32 a = mThreadContext.sortIndexArray.size(); a > 0; --a)
+ {
+ PxU32 ind = a - 1;
+ PxU32 val = mThreadContext.sortIndexArray[ind];
+ mThreadContext.sortIndexArray[ind] = accumulatedCount;
+ accumulatedCount += val;
+ }
+
+ PxU32 articulationStartIndex = accumulatedCount;
+
+ //OK, now copy across data to orderedConstraintDescs, pushing articulations to the end...
+ for(PxU32 a = 0; a < mIslandContext.mCounts.contactManagers; ++a)
+ {
+ //Index first body...
+ PxU8 indexType = mThreadContext.tempContactList[a]->indexType1;
+ if(indexType != PxsIndexedInteraction::eARTICULATION && mObjects.contactManagers[a].indexType0 != PxsIndexedInteraction::eARTICULATION)
+ {
+ PX_ASSERT((indexType == PxsIndexedInteraction::eBODY) || (indexType == PxsIndexedInteraction::eKINEMATIC) || (indexType == PxsIndexedInteraction::eWORLD));
+
+ PxI32 index = (indexType == PxsIndexedInteraction::eWORLD) ? 0 : PxI32(mThreadContext.tempContactList[a]->solverBody1 + offsetMap[indexType]);
+ PX_ASSERT(index >= 0);
+ constraints[mThreadContext.sortIndexArray[PxU32(index)]++] = mThreadContext.tempContactList[a];
+ }
+ else
+ {
+ constraints[accumulatedCount++] = mThreadContext.tempContactList[a];
+ }
+ }
+
+#if 1
+ Ps::sort(constraints + articulationStartIndex, accumulatedCount - articulationStartIndex, ArticulationSortPredicate());
+#endif
+ }
+
+ mThreadContext.mStartContactDescPtr = contactDescPtr;
+
+ mThreadContext.compoundConstraints.reserve(1024);
+ mThreadContext.compoundConstraints.forceSize_Unsafe(0);
+ //mThreadContext.compoundConstraints.forceSize_Unsafe(mCounts.contactManagers);
+
+ PxSolverConstraintDesc* startDesc = contactDescPtr;
+ mContext.setDescFromIndices(*startDesc, *constraints[0], mSolverBodyOffset);
+ startDesc->constraint = reinterpret_cast<PxU8*>(constraints[0]->contactManager);
+ startDesc->constraintLengthOver16 = DY_SC_TYPE_RB_CONTACT;
+
+ PxsContactManagerOutput* startManagerOutput = &mOutputs.getContactManager(constraints[0]->contactManager->getWorkUnit().mNpIndex);
+ PxU32 contactCount = startManagerOutput->nbContacts;
+ PxU32 startIndex = 0;
+ PxU32 numHeaders = 0;
+ for(PxU32 a = 1; a < mIslandContext.mCounts.contactManagers; ++a)
+ {
+ PxSolverConstraintDesc& desc = *(contactDescPtr+1);
+ mContext.setDescFromIndices(desc, *constraints[a], mSolverBodyOffset);
+
+ PxsContactManager* manager = constraints[a]->contactManager;
+ PxsContactManagerOutput& output = mOutputs.getContactManager(manager->getWorkUnit().mNpIndex);
+
+ desc.constraint = reinterpret_cast<PxU8*>(constraints[a]->contactManager);
+ desc.constraintLengthOver16 = DY_SC_TYPE_RB_CONTACT;
+
+ if (contactCount == 0)
+ {
+ //This is the first object in the pair
+ *startDesc = *(contactDescPtr + 1);
+ startIndex = a;
+ startManagerOutput = &output;
+ }
+
+ if(startDesc->bodyA != desc.bodyA || startDesc->bodyB != desc.bodyB
+ || startDesc->linkIndexA != PxSolverConstraintDesc::NO_LINK || startDesc->linkIndexB != PxSolverConstraintDesc::NO_LINK
+ || contactCount + output.nbContacts > Gu::ContactBuffer::MAX_CONTACTS
+ || manager->isChangeable()
+ ) //If this is the first thing and no contacts...then we skip
+ {
+ PxU32 stride = a - startIndex;
+ if(contactCount > 0)
+ {
+ if(stride > 1)
+ {
+ ++numHeaders;
+ CompoundContactManager& header = mThreadContext.compoundConstraints.insert();
+ header.mStartIndex = startIndex;
+ header.mStride = Ps::to16(stride);
+ header.mReducedContactCount = Ps::to16(contactCount);
+ PxsContactManager* manager1 = constraints[startIndex]->contactManager;
+ PxcNpWorkUnit& unit = manager1->getWorkUnit();
+
+ PX_ASSERT(startManagerOutput == &mOutputs.getContactManager(unit.mNpIndex));
+
+ header.unit = &unit;
+ header.cmOutput = startManagerOutput;
+ header.originalContactPatches = startManagerOutput->contactPatches;
+ header.originalContactPoints = startManagerOutput->contactPoints;
+ header.originalContactCount = startManagerOutput->nbContacts;
+ header.originalPatchCount = startManagerOutput->nbPatches;
+ header.originalForceBuffer = reinterpret_cast<PxReal*>(startManagerOutput->contactForces);
+ header.originalStatusFlags = startManagerOutput->statusFlag;
+ }
+ startDesc = ++contactDescPtr;
+ }
+ else
+ {
+ //Copy back next contactDescPtr
+ *startDesc = *(contactDescPtr+1);
+ }
+ contactCount = 0;
+ startIndex = a;
+ startManagerOutput = &output;
+ }
+ contactCount += output.nbContacts;
+
+ }
+ PxU32 stride = mIslandContext.mCounts.contactManagers - startIndex;
+ if(contactCount > 0)
+ {
+ if(stride > 1)
+ {
+ ++numHeaders;
+ CompoundContactManager& header = mThreadContext.compoundConstraints.insert();
+ header.mStartIndex = startIndex;
+ header.mStride = Ps::to16(stride);
+ header.mReducedContactCount = Ps::to16(contactCount);
+ PxsContactManager* manager = constraints[startIndex]->contactManager;
+ PxcNpWorkUnit& unit = manager->getWorkUnit();
+ header.unit = &unit;
+ header.cmOutput = startManagerOutput;
+ header.originalContactPatches = startManagerOutput->contactPatches;
+ header.originalContactPoints = startManagerOutput->contactPoints;
+ header.originalContactCount = startManagerOutput->nbContacts;
+ header.originalPatchCount = startManagerOutput->nbPatches;
+ header.originalForceBuffer = reinterpret_cast<PxReal*>(startManagerOutput->contactForces);
+ header.originalStatusFlags = startManagerOutput->statusFlag;
+ }
+ contactDescPtr++;
+ }
+
+ if(numHeaders)
+ {
+ const PxU32 unrollSize = 8;
+ for(PxU32 a = 0; a < numHeaders; a+= unrollSize)
+ {
+ PxsSolverConstraintPostProcessTask* postProcessTask = PX_PLACEMENT_NEW( mContext.getTaskPool().allocate(sizeof(PxsSolverConstraintPostProcessTask)),
+ PxsSolverConstraintPostProcessTask)(mContext, mThreadContext, mObjects, mSolverBodyOffset, a, PxMin(unrollSize, numHeaders - a), mMaterialManager,
+ mOutputs);
+ postProcessTask->setContinuation(mCont);
+ postProcessTask->removeReference();
+ }
+ }
+ }
+ mThreadContext.contactDescArraySize = PxU32(contactDescPtr - mThreadContext.contactConstraintDescArray);
+ mThreadContext.mContactDescPtr = contactDescPtr;
+ }
+
+ virtual void runInternal()
+ {
+ startTasks();
+ integrate();
+ setupDescTask();
+ articulationTask();
+ }
+
+ virtual const char* getName() const
+ {
+ return "PxsDynamics.solverStart";
+ }
+
+private:
+ DynamicsContext& mContext;
+ IslandContext& mIslandContext;
+ const SolverIslandObjects mObjects;
+ const PxU32 mSolverBodyOffset;
+ const PxU32 mKinematicCount;
+ IG::SimpleIslandManager& mIslandManager;
+ PxU32* mBodyRemapTable;
+ PxsMaterialManager* mMaterialManager;
+ PxsContactManagerOutputIterator& mOutputs;
+ bool mEnhancedDeterminism;
+};
+
+class PxsSolverConstraintPartitionTask : public Cm::Task
+{
+ PxsSolverConstraintPartitionTask& operator=(const PxsSolverConstraintPartitionTask&);
+public:
+
+ PxsSolverConstraintPartitionTask(DynamicsContext& context,
+ IslandContext& islandContext,
+ const SolverIslandObjects& objects,
+ const PxU32 solverBodyOffset, bool enhancedDeterminism) :
+ mContext(context),
+ mIslandContext(islandContext),
+ mObjects(objects),
+ mSolverBodyOffset(solverBodyOffset),
+ mEnhancedDeterminism(enhancedDeterminism)
+ {}
+
+ virtual void runInternal()
+ {
+
+ ThreadContext& mThreadContext = *mIslandContext.mThreadContext;
+
+ //Compact articulation pairs...
+ ArticulationSolverDesc* artics = mThreadContext.getArticulations().begin();
+
+ if(mIslandContext.mCounts.articulations)
+ {
+ PxU32 nbArticConstraints = artics[0].numInternalConstraints;
+
+ PxSolverConstraintDesc* currDesc = mThreadContext.mContactDescPtr;
+ for(PxU32 a = 1; a < mIslandContext.mCounts.articulations; ++a)
+ {
+ //Compact pairs...
+ const PxU32 nbInternalConstraints = artics[a].numInternalConstraints;
+ const PxU32 startIdx = a * DY_ARTICULATION_MAX_SIZE;
+ const PxU32 endIdx = startIdx + nbInternalConstraints;
+
+ for(PxU32 b = startIdx; b < endIdx; ++b)
+ {
+ currDesc[nbArticConstraints++] = currDesc[b];
+ }
+ }
+
+ mThreadContext.contactDescArraySize += nbArticConstraints;
+ }
+
+ PxSolverConstraintDesc* descBegin = mThreadContext.contactConstraintDescArray;
+ PxU32 descCount = mThreadContext.contactDescArraySize;
+
+ PxSolverBody* solverBodies = mContext.mSolverBodyPool.begin() + mSolverBodyOffset;
+
+ mThreadContext.mNumDifferentBodyConstraints = descCount;
+
+ {
+ mThreadContext.mNumDifferentBodyConstraints = 0;
+ mThreadContext.mNumSelfConstraints = 0;
+ mThreadContext.mNumSelfConstraintBlocks = 0;
+ mThreadContext.mNumDifferentBodyFrictionConstraints = 0;
+ mThreadContext.mNumSelfConstraintFrictionBlocks = 0;
+ mThreadContext.mNumSelfFrictionConstraints = 0;
+
+ if(descCount > 0)
+ {
+ ConstraintPartitionArgs args;
+ args.mBodies = solverBodies;
+ args.mArticulationPtrs = artics;
+ args.mContactConstraintDescriptors = descBegin;
+ args.mNumArticulationPtrs = mThreadContext.getArticulations().size();
+ args.mNumBodies = mIslandContext.mCounts.bodies;
+ args.mNumContactConstraintDescriptors = descCount;
+ args.mOrderedContactConstraintDescriptors = mThreadContext.orderedContactConstraints;
+ args.mTempContactConstraintDescriptors = mThreadContext.tempConstraintDescArray;
+ args.mNumDifferentBodyConstraints = args.mNumSelfConstraints = args.mNumSelfConstraintBlocks = 0;
+ args.mConstraintsPerPartition = &mThreadContext.mConstraintsPerPartition;
+ args.mBitField = &mThreadContext.mPartitionNormalizationBitmap;
+ args.enhancedDeterminism = mEnhancedDeterminism;
+
+ mThreadContext.mMaxPartitions = partitionContactConstraints(args);
+ mThreadContext.mNumDifferentBodyConstraints = args.mNumDifferentBodyConstraints;
+ mThreadContext.mNumSelfConstraints = args.mNumSelfConstraints;
+ mThreadContext.mNumSelfConstraintBlocks = args.mNumSelfConstraintBlocks;
+ }
+ else
+ {
+ PxMemZero(mThreadContext.mConstraintsPerPartition.begin(), sizeof(PxU32)*mThreadContext.mConstraintsPerPartition.capacity());
+ }
+
+ PX_ASSERT((mThreadContext.mNumDifferentBodyConstraints + mThreadContext.mNumSelfConstraints) == descCount);
+ }
+
+ }
+
+ virtual const char* getName() const { return "PxsDynamics.solverConstraintPartition"; }
+
+ DynamicsContext& mContext;
+ IslandContext& mIslandContext;
+ const SolverIslandObjects mObjects;
+ PxU32 mSolverBodyOffset;
+ bool mEnhancedDeterminism;
+};
+
+
+class PxsSolverSetupSolveTask : public Cm::Task
+{
+ PxsSolverSetupSolveTask& operator=(const PxsSolverSetupSolveTask&);
+public:
+
+ PxsSolverSetupSolveTask(
+ DynamicsContext& context,
+ IslandContext& islandContext,
+ const SolverIslandObjects& objects,
+ const PxU32 solverBodyOffset,
+ IG::IslandSim& islandSim) :
+ mContext(context),
+ mIslandContext(islandContext),
+ mObjects(objects),
+ mSolverBodyOffset(solverBodyOffset),
+ mIslandSim(islandSim)
+ {}
+
+
+ virtual void runInternal()
+ {
+ ThreadContext& mThreadContext = *mIslandContext.mThreadContext;
+
+ PxSolverConstraintDesc* contactDescBegin = mThreadContext.orderedContactConstraints;
+ PxSolverConstraintDesc* contactDescPtr = mThreadContext.orderedContactConstraints;
+
+ PxSolverBody* solverBodies = mContext.mSolverBodyPool.begin() + mSolverBodyOffset;
+ PxSolverBodyData* solverBodyDatas = mContext.mSolverBodyDataPool.begin();
+
+ PxU32 frictionDescCount = mThreadContext.mNumDifferentBodyFrictionConstraints;
+
+ PxU32 j = 0, i = 0;
+
+ //On PS3, self-constraints will be bumped to the end of the constraint list
+ //and processed separately. On PC/360, they will be mixed in the array and
+ //classed as "different body" constraints regardless of the fact that they're self-constraints.
+ //PxU32 numBatches = mThreadContext.numDifferentBodyBatchHeaders;
+ // TODO: maybe replace with non-null joints from end of the array
+
+ PxU32 numBatches = 0;
+
+ PxU32 currIndex = 0;
+ for(PxU32 a = 0; a < mThreadContext.mConstraintsPerPartition.size(); ++a)
+ {
+ PxU32 endIndex = currIndex + mThreadContext.mConstraintsPerPartition[a];
+
+ PxU32 numBatchesInPartition = 0;
+ for(PxU32 b = currIndex; b < endIndex; ++b)
+ {
+ PxConstraintBatchHeader& _header = mThreadContext.contactConstraintBatchHeaders[b];
+ PxU16 stride = _header.mStride, newStride = _header.mStride;
+ PxU32 startIndex = j;
+ for(PxU16 c = 0; c < stride; ++c)
+ {
+ if(getConstraintLength(contactDescBegin[i]) == 0)
+ {
+ newStride--;
+ i++;
+ }
+ else
+ {
+ if(i!=j)
+ contactDescBegin[j] = contactDescBegin[i];
+ i++;
+ j++;
+ contactDescPtr++;
+ }
+ }
+
+ if(newStride != 0)
+ {
+ mThreadContext.contactConstraintBatchHeaders[numBatches].mStartIndex = startIndex;
+ mThreadContext.contactConstraintBatchHeaders[numBatches].mStride = newStride;
+ PxU8 type = *contactDescBegin[startIndex].constraint;
+ if(type == DY_SC_TYPE_STATIC_CONTACT)
+ {
+ //Check if any block of constraints is classified as type static (single) contact constraint.
+ //If they are, iterate over all constraints grouped with it and switch to "dynamic" contact constraint
+ //type if there's a dynamic contact constraint in the group.
+ for(PxU32 c = 1; c < newStride; ++c)
+ {
+ if(*contactDescBegin[startIndex+c].constraint == DY_SC_TYPE_RB_CONTACT)
+ {
+ type = DY_SC_TYPE_RB_CONTACT;
+ }
+ }
+ }
+
+ mThreadContext.contactConstraintBatchHeaders[numBatches].mConstraintType = type;
+ numBatches++;
+ numBatchesInPartition++;
+ }
+ }
+ PxU32 numHeaders = numBatchesInPartition;
+ currIndex += mThreadContext.mConstraintsPerPartition[a];
+ mThreadContext.mConstraintsPerPartition[a] = numHeaders;
+ }
+
+ PxU32 contactDescCount = PxU32(contactDescPtr - contactDescBegin);
+
+ mThreadContext.mNumDifferentBodyConstraints = contactDescCount;
+
+ PxU32 numSelfConstraintBlocks = mThreadContext.mNumSelfConstraintBlocks;
+
+ //Remap self constraint array. Self-constraint blocks exists on PS3 as an optimization for SPU solver.
+ for(PxU32 a = 0; a < numSelfConstraintBlocks; ++a)
+ {
+ PX_ASSERT(mThreadContext.mSelfConstraintBlocks[a].startId == i);
+ PxU32 origNumSelfConstraints = mThreadContext.mSelfConstraintBlocks[a].numSelfConstraints;
+ PxU32 startId = j;
+
+ for(PxU32 b = 0; b < origNumSelfConstraints; ++b)
+ {
+ PxSolverConstraintDesc& desc = contactDescBegin[i];
+
+ if(getConstraintLength(desc))
+ {
+ PxConstraintBatchHeader& header = mThreadContext.contactConstraintBatchHeaders[numBatches++];
+ header.mStride = 1;
+ header.mStartIndex = j;
+ header.mConstraintType = *desc.constraint;
+ if(i != j)
+ contactDescBegin[j] = contactDescBegin[i];
+ j++;
+ }
+ i++;
+ }
+ mThreadContext.mSelfConstraintBlocks[a].startId = startId;
+ mThreadContext.mSelfConstraintBlocks[a].numSelfConstraints = j - startId;
+ }
+
+ mThreadContext.numContactConstraintBatches = numBatches;
+ mThreadContext.mNumSelfConstraints = j - contactDescCount; //self constraint count
+ contactDescCount = j;
+ mThreadContext.mOrderedContactDescCount = j;
+
+ //Now do the friction constraints if we're not using the sticky model
+ if(mContext.getFrictionType() != PxFrictionType::ePATCH)
+ {
+ PxSolverConstraintDesc* frictionDescBegin = mThreadContext.frictionConstraintDescArray.begin();
+ PxSolverConstraintDesc* frictionDescPtr = frictionDescBegin;
+
+ Ps::Array<PxConstraintBatchHeader>& frictionHeaderArray = mThreadContext.frictionConstraintBatchHeaders;
+ frictionHeaderArray.forceSize_Unsafe(0);
+ frictionHeaderArray.reserve(mThreadContext.numContactConstraintBatches);
+ PxConstraintBatchHeader* headers = frictionHeaderArray.begin();
+
+ Ps::Array<PxU32>& constraintsPerPartition = mThreadContext.mConstraintsPerPartition;
+ Ps::Array<PxU32>& frictionConstraintsPerPartition = mThreadContext.mFrictionConstraintsPerPartition;
+ frictionConstraintsPerPartition.forceSize_Unsafe(0);
+ frictionConstraintsPerPartition.reserve(constraintsPerPartition.capacity());
+
+
+ PxU32 fricI = 0;
+ PxU32 startIndex = 0;
+ PxU32 fricHeaders = 0;
+ for(PxU32 k = 0; k < constraintsPerPartition.size(); ++k)
+ {
+ PxU32 numBatchesInK = constraintsPerPartition[k];
+ PxU32 endIndex = startIndex + numBatchesInK;
+
+ PxU32 startFricH = fricHeaders;
+
+ for(PxU32 a = startIndex; a < endIndex; ++a)
+ {
+ PxConstraintBatchHeader& _header = mThreadContext.contactConstraintBatchHeaders[a];
+ PxU16 stride = _header.mStride;
+ if(_header.mConstraintType == DY_SC_TYPE_RB_CONTACT || _header.mConstraintType == DY_SC_TYPE_EXT_CONTACT ||
+ _header.mConstraintType == DY_SC_TYPE_STATIC_CONTACT)
+ {
+ PxU8 type = 0;
+ //Extract friction from this constraint
+ for(PxU16 b = 0; b < stride; ++b)
+ {
+ //create the headers...
+ PxSolverConstraintDesc& desc = contactDescBegin[_header.mStartIndex + b];
+ PX_ASSERT(desc.constraint);
+ SolverContactCoulombHeader* header = reinterpret_cast<SolverContactCoulombHeader*>(desc.constraint);
+ PxU32 frictionOffset = header->frictionOffset;
+ PxU8* PX_RESTRICT constraint = reinterpret_cast<PxU8*>(header) + frictionOffset;
+ const PxU32 origLength = getConstraintLength(desc);
+ const PxU32 length = (origLength - frictionOffset);
+
+ setConstraintLength(*frictionDescPtr, length);
+ frictionDescPtr->constraint = constraint;
+ frictionDescPtr->bodyA = desc.bodyA;
+ frictionDescPtr->bodyB = desc.bodyB;
+ frictionDescPtr->bodyADataIndex = desc.bodyADataIndex;
+ frictionDescPtr->bodyBDataIndex = desc.bodyBDataIndex;
+ frictionDescPtr->linkIndexA = desc.linkIndexA;
+ frictionDescPtr->linkIndexB = desc.linkIndexB;
+ frictionDescPtr->writeBack = NULL;
+ frictionDescPtr->writeBackLengthOver4 = 0;
+ type = *constraint;
+ frictionDescPtr++;
+ }
+ headers->mStartIndex = fricI;
+ headers->mStride = stride;
+ headers->mConstraintType = type;
+ headers++;
+ fricHeaders++;
+ fricI += stride;
+ }
+ else if(_header.mConstraintType == DY_SC_TYPE_BLOCK_RB_CONTACT || _header.mConstraintType == DY_SC_TYPE_BLOCK_STATIC_RB_CONTACT)
+ {
+ //KS - TODO - Extract block of 4 contacts from this constraint. This isn't implemented yet for coulomb friction model
+ PX_ASSERT(contactDescBegin[_header.mStartIndex].constraint);
+ SolverContactCoulombHeader4* head = reinterpret_cast<SolverContactCoulombHeader4*>(contactDescBegin[_header.mStartIndex].constraint);
+ PxU32 frictionOffset = head->frictionOffset;
+ PxU8* PX_RESTRICT constraint = reinterpret_cast<PxU8*>(head) + frictionOffset;
+ const PxU32 origLength = getConstraintLength(contactDescBegin[_header.mStartIndex]);
+ const PxU32 length = (origLength - frictionOffset);
+ PxU8 type = *constraint;
+ PX_ASSERT(type == DY_SC_TYPE_BLOCK_FRICTION || type == DY_SC_TYPE_BLOCK_STATIC_FRICTION);
+ for(PxU32 b = 0; b < 4; ++b)
+ {
+ PxSolverConstraintDesc& desc = contactDescBegin[_header.mStartIndex+b];
+ setConstraintLength(*frictionDescPtr, length);
+ frictionDescPtr->constraint = constraint;
+ frictionDescPtr->bodyA = desc.bodyA;
+ frictionDescPtr->bodyB = desc.bodyB;
+ frictionDescPtr->bodyADataIndex = desc.bodyADataIndex;
+ frictionDescPtr->bodyBDataIndex = desc.bodyBDataIndex;
+ frictionDescPtr->linkIndexA = desc.linkIndexA;
+ frictionDescPtr->linkIndexB = desc.linkIndexB;
+ frictionDescPtr->writeBack = NULL;
+ frictionDescPtr->writeBackLengthOver4 = 0;
+ frictionDescPtr++;
+ }
+ headers->mStartIndex = fricI;
+ headers->mStride = stride;
+ headers->mConstraintType = type;
+ headers++;
+ fricHeaders++;
+ fricI += stride;
+ }
+ }
+ startIndex += numBatchesInK;
+ if(startFricH < fricHeaders)
+ {
+ frictionConstraintsPerPartition.pushBack(fricHeaders - startFricH);
+ }
+ }
+
+
+ frictionDescCount = PxU32(frictionDescPtr - frictionDescBegin);
+
+ mThreadContext.mNumDifferentBodyFrictionConstraints = frictionDescCount;
+
+ frictionHeaderArray.forceSize_Unsafe(PxU32(headers - frictionHeaderArray.begin()));
+
+ mThreadContext.mNumSelfFrictionConstraints = fricI - frictionDescCount; //self constraint count
+ mThreadContext.mNumDifferentBodyFrictionConstraints = frictionDescCount;
+ frictionDescCount = fricI;
+ mThreadContext.mOrderedFrictionDescCount = frictionDescCount;
+
+
+ }
+
+ {
+ {
+ PX_PROFILE_ZONE("Dynamics.solver", mContext.getContextId());
+
+ PxSolverConstraintDesc* contactDescs = mThreadContext.orderedContactConstraints;
+ PxSolverConstraintDesc* frictionDescs = mThreadContext.frictionConstraintDescArray.begin();
+
+ PxI32* thresholdPairsOut = &mContext.mThresholdStreamOut;
+
+ SolverIslandParams& params = *reinterpret_cast<SolverIslandParams*>(mContext.getTaskPool().allocate(sizeof(SolverIslandParams)));
+ params.positionIterations = mThreadContext.mMaxSolverPositionIterations;
+ params.velocityIterations = mThreadContext.mMaxSolverVelocityIterations;
+ params.bodyListStart = solverBodies;
+ params.bodyDataList = solverBodyDatas;
+ params.solverBodyOffset = mSolverBodyOffset;
+ params.bodyListSize = mIslandContext.mCounts.bodies;
+ params.articulationListStart = mThreadContext.getArticulations().begin();
+ params.articulationListSize = mThreadContext.getArticulations().size();
+ params.constraintList = contactDescs;
+ params.constraintIndex = 0;
+ params.constraintIndex2 = 0;
+ params.bodyListIndex = 0;
+ params.bodyListIndex2 = 0;
+ params.bodyIntegrationListIndex = 0;
+ params.thresholdStream = mContext.getThresholdStream().begin();
+ params.thresholdStreamLength = mContext.getThresholdStream().size();
+ params.outThresholdPairs = thresholdPairsOut;
+ params.motionVelocityArray = mThreadContext.motionVelocityArray;
+ params.bodyArray = mThreadContext.mBodyCoreArray;
+ params.numObjectsIntegrated = 0;
+ params.constraintBatchHeaders = mThreadContext.contactConstraintBatchHeaders;
+ params.numConstraintHeaders = mThreadContext.numContactConstraintBatches;
+ params.headersPerPartition = mThreadContext.mConstraintsPerPartition.begin();
+ params.nbPartitions = mThreadContext.mConstraintsPerPartition.size();
+ params.rigidBodies = const_cast<PxsRigidBody**>(mObjects.bodies);
+ params.frictionHeadersPerPartition = mThreadContext.mFrictionConstraintsPerPartition.begin();
+ params.nbFrictionPartitions = mThreadContext.mFrictionConstraintsPerPartition.size();
+ params.frictionConstraintBatches = mThreadContext.frictionConstraintBatchHeaders.begin();
+ params.numFrictionConstraintHeaders = mThreadContext.frictionConstraintBatchHeaders.size();
+ params.frictionConstraintIndex = 0;
+ params.frictionConstraintList = frictionDescs;
+
+ const PxU32 unrollSize = 8;
+ const PxU32 denom = PxMax(1u, (mThreadContext.mMaxPartitions*unrollSize));
+ const PxU32 MaxTasks = getTaskManager()->getCpuDispatcher()->getWorkerCount();
+ const PxU32 idealThreads = mThreadContext.numContactConstraintBatches/denom;
+ const PxU32 numTasks = PxMax(1u, PxMin(idealThreads, MaxTasks));
+
+ if(numTasks > 1)
+ {
+ const PxU32 idealBatchSize = PxMax(unrollSize, idealThreads*unrollSize/(numTasks*2));
+
+ params.batchSize = idealBatchSize; //assigning ideal batch size for the solver to grab work at. Only needed by the multi-threaded island solver.
+
+ for(PxU32 a = 1; a < numTasks; ++a)
+ {
+ void* tsk = mContext.getTaskPool().allocate(sizeof(PxsParallelSolverTask));
+ PxsParallelSolverTask* pTask = PX_PLACEMENT_NEW(tsk, PxsParallelSolverTask)(
+ params, mContext, mContext.getFrictionType(), mIslandSim);
+
+ //Force to complete before merge task!
+ pTask->setContinuation(mCont);
+
+ pTask->removeReference();
+ }
+
+ //Avoid kicking off one parallel task when we can do the work inline in this function
+ {
+ PX_PROFILE_ZONE("Dynamics.parallelSolve", mContext.getContextId());
+
+ solveParallel(mContext, params, mIslandSim);
+ }
+ const PxI32 numBodiesPlusArtics = PxI32( mIslandContext.mCounts.bodies + mIslandContext.mCounts.articulations );
+
+ PxI32* numObjectsIntegrated = &params.numObjectsIntegrated;
+
+ WAIT_FOR_PROGRESS_NO_TIMER(numObjectsIntegrated, numBodiesPlusArtics);
+
+ }
+ else
+ {
+
+ //Only one task - a small island so do a sequential solve (avoid the atomic overheads)
+ solveVBlock(mContext.mSolverCore[mContext.getFrictionType()], params);
+
+ const PxU32 bodyCountMin1 = mIslandContext.mCounts.bodies - 1u;
+ PxSolverBodyData* solverBodyData2 = solverBodyDatas + mSolverBodyOffset + 1;
+ for(PxU32 k=0; k < mIslandContext.mCounts.bodies; k++)
+ {
+ const PxU32 prefetchAddress = PxMin(k+4, bodyCountMin1);
+ Ps::prefetchLine(mThreadContext.mBodyCoreArray[prefetchAddress]);
+ Ps::prefetchLine(&mThreadContext.motionVelocityArray[k], 128);
+ Ps::prefetchLine(&mThreadContext.mBodyCoreArray[prefetchAddress], 128);
+ Ps::prefetchLine(&mObjects.bodies[prefetchAddress]);
+
+ PxSolverBodyData& solverBodyData = solverBodyData2[k];
+
+ integrateCore(mThreadContext.motionVelocityArray[k].linear, mThreadContext.motionVelocityArray[k].angular,
+ solverBodies[k], solverBodyData, mContext.mDt);
+
+ PxsRigidBody& rBody = *mObjects.bodies[k];
+ PxsBodyCore& core = rBody.getCore();
+ rBody.mLastTransform = core.body2World;
+ core.body2World = solverBodyData.body2World;
+ core.linearVelocity = solverBodyData.linearVelocity;
+ core.angularVelocity = solverBodyData.angularVelocity;
+
+
+ bool hasStaticTouch = mIslandSim.getIslandStaticTouchCount(IG::NodeIndex(solverBodyData.nodeIndex)) != 0;
+ sleepCheck(const_cast<PxsRigidBody*>(mObjects.bodies[k]), mContext.mDt, mContext.mInvDt, mContext.mEnableStabilization, mContext.mUseAdaptiveForce, mThreadContext.motionVelocityArray[k],
+ hasStaticTouch);
+ }
+
+ for(PxU32 cnt=0;cnt<mIslandContext.mCounts.articulations;cnt++)
+ {
+ ArticulationSolverDesc &d = mThreadContext.getArticulations()[cnt];
+ PX_PROFILE_ZONE("Articulations.integrate", mContext.getContextId());
+
+ ArticulationPImpl::updateBodies(d, mContext.getDt());
+ }
+ }
+ }
+ }
+ }
+
+ virtual const char* getName() const { return "PxsDynamics.solverSetupSolve"; }
+
+ DynamicsContext& mContext;
+ IslandContext& mIslandContext;
+ const SolverIslandObjects mObjects;
+ PxU32 mSolverBodyOffset;
+ IG::IslandSim& mIslandSim;
+};
+
+class PxsSolverEndTask : public Cm::Task
+{
+ PxsSolverEndTask& operator=(const PxsSolverEndTask&);
+public:
+
+ PxsSolverEndTask(DynamicsContext& context,
+ IslandContext& islandContext,
+ const SolverIslandObjects& objects,
+ const PxU32 solverBodyOffset,
+ PxsContactManagerOutputIterator& cmOutputs) :
+ mContext (context),
+ mIslandContext (islandContext),
+ mObjects (objects),
+ mSolverBodyOffset (solverBodyOffset),
+ mOutputs (cmOutputs)
+ {}
+
+ virtual void runInternal()
+ {
+ ThreadContext& mThreadContext = *mIslandContext.mThreadContext;
+#if PX_ENABLE_SIM_STATS
+ mThreadContext.getSimStats().numAxisSolverConstraints += mThreadContext.mAxisConstraintCount;
+#endif
+ //Patch up the contact managers (TODO - fix up force writeback)
+ PxU32 numCompoundConstraints = mThreadContext.compoundConstraints.size();
+ for(PxU32 i = 0; i < numCompoundConstraints; ++i)
+ {
+ CompoundContactManager& manager = mThreadContext.compoundConstraints[i];
+ PxsContactManagerOutput* cmOutput = manager.cmOutput;
+
+ PxReal* contactForces = reinterpret_cast<PxReal*>(cmOutput->contactForces);
+ PxU32 contactCount = cmOutput->nbContacts;
+
+ cmOutput->contactPatches = manager.originalContactPatches;
+ cmOutput->contactPoints = manager.originalContactPoints;
+ cmOutput->nbContacts = manager.originalContactCount;
+ cmOutput->nbPatches = manager.originalPatchCount;
+ cmOutput->statusFlag = manager.originalStatusFlags;
+ cmOutput->contactForces = manager.originalForceBuffer;
+
+ for(PxU32 a = 1; a < manager.mStride; ++a)
+ {
+ PxsContactManager* pManager = mThreadContext.orderedContactList[manager.mStartIndex + a]->contactManager;
+ pManager->getWorkUnit().frictionDataPtr = manager.unit->frictionDataPtr;
+ pManager->getWorkUnit().frictionPatchCount = manager.unit->frictionPatchCount;
+ //pManager->getWorkUnit().prevFrictionPatchCount = manager.unit->prevFrictionPatchCount;
+ }
+
+ //This is a stride-based contact force writer. The assumption is that we may have skipped certain unimportant contacts reported by the
+ //discrete narrow phase
+ if(contactForces)
+ {
+ PxU32 currentContactIndex = 0;
+ PxU32 currentManagerIndex = manager.mStartIndex;
+ PxU32 currentManagerContactIndex = 0;
+
+ for(PxU32 a = 0; a < contactCount; ++a)
+ {
+ PxU32 index = manager.forceBufferList[a];
+ PxsContactManager* pManager = mThreadContext.orderedContactList[currentManagerIndex]->contactManager;
+ PxsContactManagerOutput* output = &mOutputs.getContactManager(pManager->getWorkUnit().mNpIndex);
+ while(currentContactIndex < index || output->nbContacts == 0)
+ {
+ //Step forwards...first in this manager...
+
+ PxU32 numToStep = PxMin(index - currentContactIndex, PxU32(output->nbContacts) - currentManagerContactIndex);
+ currentContactIndex += numToStep;
+ currentManagerContactIndex += numToStep;
+ if(currentManagerContactIndex == output->nbContacts)
+ {
+ currentManagerIndex++;
+ currentManagerContactIndex = 0;
+ pManager = mThreadContext.orderedContactList[currentManagerIndex]->contactManager;
+ output = &mOutputs.getContactManager(pManager->getWorkUnit().mNpIndex);
+ }
+ }
+ if(output->nbContacts > 0 && output->contactForces)
+ output->contactForces[currentManagerContactIndex] = contactForces[a];
+ }
+ }
+ }
+
+ mThreadContext.compoundConstraints.forceSize_Unsafe(0);
+
+ mThreadContext.mConstraintBlockManager.reset();
+
+ mContext.putThreadContext(&mThreadContext);
+ }
+
+
+ virtual const char* getName() const
+ {
+ return "PxsDynamics.solverEnd";
+ }
+
+ DynamicsContext& mContext;
+ IslandContext& mIslandContext;
+ const SolverIslandObjects mObjects;
+ const PxU32 mSolverBodyOffset;
+ PxsContactManagerOutputIterator& mOutputs;
+};
+
+class PxsSolverCreateFinalizeConstraintsTask : public Cm::Task
+{
+ PxsSolverCreateFinalizeConstraintsTask& operator=(const PxsSolverCreateFinalizeConstraintsTask&);
+public:
+
+ PxsSolverCreateFinalizeConstraintsTask(
+ DynamicsContext& context,
+ IslandContext& islandContext,
+ PxU32 solverDataOffset,
+ PxsContactManagerOutputIterator& outputs,
+ bool enhancedDeterminism) :
+ mContext (context),
+ mIslandContext (islandContext),
+ mSolverDataOffset (solverDataOffset),
+ mOutputs (outputs),
+ mEnhancedDeterminism (enhancedDeterminism)
+ {
+ }
+
+ virtual void runInternal();
+
+ virtual const char* getName() const { return "PxsDynamics.solverCreateFinalizeConstraints"; }
+
+ DynamicsContext& mContext;
+ IslandContext& mIslandContext;
+ PxU32 mSolverDataOffset;
+ PxsContactManagerOutputIterator& mOutputs;
+ bool mEnhancedDeterminism;
+};
+
+
+// helper function to join two tasks together and ensure ref counts are correct
+void chainTasks(PxLightCpuTask* first, PxLightCpuTask* next)
+{
+ first->setContinuation(next);
+ next->removeReference();
+}
+
+PxBaseTask* createSolverTaskChain(DynamicsContext& dynamicContext,
+ const SolverIslandObjects& objects,
+ const PxsIslandIndices& counts,
+ const PxU32 solverBodyOffset,
+ IG::SimpleIslandManager& islandManager,
+ PxU32* bodyRemapTable, PxsMaterialManager* materialManager, PxBaseTask* continuation,
+ PxsContactManagerOutputIterator& iterator, bool useEnhancedDeterminism)
+{
+ Cm::FlushPool& taskPool = dynamicContext.getTaskPool();
+
+ taskPool.lock();
+
+
+ IslandContext* islandContext = reinterpret_cast<IslandContext*>(taskPool.allocate(sizeof(IslandContext)));
+ islandContext->mThreadContext = NULL;
+ islandContext->mCounts = counts;
+
+
+ // create lead task
+ PxsSolverStartTask* startTask = PX_PLACEMENT_NEW(taskPool.allocateNotThreadSafe(sizeof(PxsSolverStartTask)), PxsSolverStartTask)(dynamicContext, *islandContext, objects, solverBodyOffset, dynamicContext.getKinematicCount(),
+ islandManager, bodyRemapTable, materialManager, iterator, useEnhancedDeterminism);
+ PxsSolverEndTask* endTask = PX_PLACEMENT_NEW(taskPool.allocateNotThreadSafe(sizeof(PxsSolverEndTask)), PxsSolverEndTask)(dynamicContext, *islandContext, objects, solverBodyOffset, iterator);
+
+
+ PxsSolverCreateFinalizeConstraintsTask* createFinalizeConstraintsTask = PX_PLACEMENT_NEW(taskPool.allocateNotThreadSafe(sizeof(PxsSolverCreateFinalizeConstraintsTask)), PxsSolverCreateFinalizeConstraintsTask)(dynamicContext, *islandContext, solverBodyOffset, iterator, useEnhancedDeterminism);
+ PxsSolverSetupSolveTask* setupSolveTask = PX_PLACEMENT_NEW(taskPool.allocateNotThreadSafe(sizeof(PxsSolverSetupSolveTask)), PxsSolverSetupSolveTask)(dynamicContext, *islandContext, objects, solverBodyOffset, islandManager.getAccurateIslandSim());
+
+ PxsSolverConstraintPartitionTask* partitionConstraintsTask = PX_PLACEMENT_NEW(taskPool.allocateNotThreadSafe(sizeof(PxsSolverConstraintPartitionTask)), PxsSolverConstraintPartitionTask)(dynamicContext, *islandContext, objects, solverBodyOffset, useEnhancedDeterminism);
+
+ endTask->setContinuation(continuation);
+
+ // set up task chain in reverse order
+ chainTasks(setupSolveTask, endTask);
+ chainTasks(createFinalizeConstraintsTask, setupSolveTask);
+ chainTasks(partitionConstraintsTask, createFinalizeConstraintsTask);
+ chainTasks(startTask, partitionConstraintsTask);
+
+ taskPool.unlock();
+
+ return startTask;
+}
+
+
+void DynamicsContext::update(IG::SimpleIslandManager& simpleIslandManager, PxBaseTask* /*continuation*/, PxBaseTask* lostTouchTask,
+ PxsContactManager** /*foundPatchManagers*/, PxU32 /*nbFoundPatchManagers*/,
+ PxsContactManager** /*lostPatchManagers*/, PxU32 /*nbLostPatchManagers*/,
+ PxU32 /*maxPatchesPerCM*/,
+ PxsContactManagerOutputIterator& iterator,
+ PxsContactManagerOutput*,
+ const PxReal dt, const PxVec3& gravity, const PxU32 /*bitMapWordCounts*/)
+{
+ PX_PROFILE_ZONE("Dynamics.solverQueueTasks", mContextID);
+
+ PX_UNUSED(simpleIslandManager);
+
+ mOutputIterator = iterator;
+
+ mDt = dt;
+ mInvDt = dt == 0.0f ? 0.0f : 1.0f/dt;
+ mGravity = gravity;
+
+ const IG::IslandSim& islandSim = simpleIslandManager.getAccurateIslandSim();
+
+ const PxU32 islandCount = islandSim.getNbActiveIslands();
+
+ const PxU32 activatedContactCount = islandSim.getNbActivatedEdges(IG::Edge::eCONTACT_MANAGER);
+ const IG::EdgeIndex* const activatingEdges = islandSim.getActivatedEdges(IG::Edge::eCONTACT_MANAGER);
+
+ for(PxU32 a = 0; a < activatedContactCount; ++a)
+ {
+ PxsContactManager* cm = simpleIslandManager.getContactManager(activatingEdges[a]);
+ if(cm)
+ {
+ cm->getWorkUnit().frictionPatchCount = 0; //KS - zero the friction patch count on any activating edges
+ }
+ }
+
+#if PX_ENABLE_SIM_STATS
+ if(islandCount > 0)
+ {
+ mSimStats.mNbActiveKinematicBodies = islandSim.getNbActiveKinematics();
+ mSimStats.mNbActiveDynamicBodies = islandSim.getNbActiveNodes(IG::Node::eRIGID_BODY_TYPE);
+ mSimStats.mNbActiveConstraints = islandSim.getNbActiveEdges(IG::Edge::eCONSTRAINT);
+ }
+ else
+ {
+ mSimStats.mNbActiveKinematicBodies = islandSim.getNbActiveKinematics();
+ mSimStats.mNbActiveDynamicBodies = 0;
+ mSimStats.mNbActiveConstraints = 0;
+ }
+#endif
+
+ mThresholdStreamOut = 0;
+
+ resetThreadContexts();
+
+ //If there is no work to do then we can do nothing at all.
+ if(0 == islandCount)
+ {
+ return;
+ }
+
+ //KS - test that world solver body's velocities are finite and 0, then set it to 0.
+ //Technically, the velocity should always be 0 but can be stomped if a NAN creeps into the simulation.
+ PX_ASSERT(mWorldSolverBody.linearVelocity == PxVec3(0.f));
+ PX_ASSERT(mWorldSolverBody.angularState == PxVec3(0.f));
+ PX_ASSERT(mWorldSolverBody.linearVelocity.isFinite());
+ PX_ASSERT(mWorldSolverBody.angularState.isFinite());
+
+ mWorldSolverBody.linearVelocity = mWorldSolverBody.angularState = PxVec3(0.f);
+
+ const PxU32 kinematicCount = islandSim.getNbActiveKinematics();
+ const IG::NodeIndex* const kinematicIndices = islandSim.getActiveKinematics();
+ mKinematicCount = kinematicCount;
+
+ const PxU32 bodyCount = islandSim.getNbActiveNodes(IG::Node::eRIGID_BODY_TYPE);
+
+ PxU32 numArtics = islandSim.getNbActiveNodes(IG::Node::eARTICULATION_TYPE);
+
+ {
+ if(kinematicCount + bodyCount > mSolverBodyPool.capacity())
+ {
+ mSolverBodyPool.reserve((kinematicCount + bodyCount + 31) & ~31); // pad out to 32 * 128 = 4k to prevent alloc churn
+ mSolverBodyDataPool.reserve((kinematicCount + bodyCount + 31 + 1) & ~31); // pad out to 32 * 128 = 4k to prevent alloc churn
+ mSolverBodyRemapTable.reserve((kinematicCount + bodyCount + 31 + 1) & ~31);
+ }
+
+ {
+ PxSolverBody emptySolverBody;
+ PxMemZero(&emptySolverBody, sizeof(PxSolverBody));
+ mSolverBodyPool.resize(kinematicCount + bodyCount, emptySolverBody);
+ PxSolverBodyData emptySolverBodyData;
+ PxMemZero(&emptySolverBodyData, sizeof(PxSolverBodyData));
+ mSolverBodyDataPool.resize(kinematicCount + bodyCount + 1, emptySolverBodyData);
+ mSolverBodyRemapTable.resize(bodyCount);
+ }
+
+ // integrate and copy all the kinematics - overkill, since not all kinematics
+ // need solver bodies
+
+ mSolverBodyDataPool[0] = mWorldSolverBodyData;
+
+
+ {
+ PX_PROFILE_ZONE("Dynamics.updateKinematics", mContextID);
+ PxMemZero(mSolverBodyPool.begin(), kinematicCount*sizeof(PxSolverBody));
+ for(PxU32 i=0;i<kinematicCount;i++)
+ {
+ PxsRigidBody* rigidBody = islandSim.getRigidBody(kinematicIndices[i]);
+ const PxsBodyCore& core = rigidBody->getCore();
+ copyToSolverBodyData(core.linearVelocity, core.angularVelocity, core.inverseMass, core.inverseInertia, core.body2World, core.maxPenBias,
+ core.maxContactImpulse, kinematicIndices[i].index(), core.contactReportThreshold, mSolverBodyDataPool[i + 1], core.lockFlags);
+ rigidBody->saveLastCCDTransform();
+ // Only really necessary for PS3 at the moment (for the cross island parallel constraint solver
+ // but we might switch to the same on other platforms)
+ mSolverBodyPool[i].solverProgress=MAX_PERMITTED_SOLVER_PROGRESS;
+ mSolverBodyPool[i].maxSolverNormalProgress=MAX_PERMITTED_SOLVER_PROGRESS;
+ mSolverBodyPool[i].maxSolverFrictionProgress=MAX_PERMITTED_SOLVER_PROGRESS;
+ }
+ }
+ }
+
+ PxU32 solverBatchMax = mSolverBatchSize;
+ PxU32 articulationBatchMax = 2;
+ PxU32 minimumConstraintCount = 1;
+
+
+ //Resize arrays of solver constraints...
+ PxU32 numArticulationConstraints=numArtics*Dy::DY_ARTICULATION_MAX_SIZE; //Just allocate enough memory to fit worst-case maximum size articulations...
+
+ const PxU32 nbActiveContactManagers = islandSim.getNbActiveEdges(IG::Edge::eCONTACT_MANAGER);
+ const PxU32 nbActiveConstraints = islandSim.getNbActiveEdges(IG::Edge::eCONSTRAINT);
+
+ PxU32 totalConstraintCount = nbActiveConstraints + nbActiveContactManagers + numArticulationConstraints;
+
+ mSolverConstraintDescPool.forceSize_Unsafe(0);
+ mSolverConstraintDescPool.reserve((totalConstraintCount + 63) & (~63));
+ mSolverConstraintDescPool.forceSize_Unsafe(totalConstraintCount);
+
+ mOrderedSolverConstraintDescPool.forceSize_Unsafe(0);
+ mOrderedSolverConstraintDescPool.reserve((totalConstraintCount + 63) & (~63));
+ mOrderedSolverConstraintDescPool.forceSize_Unsafe(totalConstraintCount);
+
+ mTempSolverConstraintDescPool.forceSize_Unsafe(0);
+ mTempSolverConstraintDescPool.reserve((totalConstraintCount + 63) & (~63));
+ mTempSolverConstraintDescPool.forceSize_Unsafe(totalConstraintCount);
+
+ mContactConstraintBatchHeaders.forceSize_Unsafe(0);
+ mContactConstraintBatchHeaders.reserve((totalConstraintCount + 63) & (~63));
+ mContactConstraintBatchHeaders.forceSize_Unsafe(totalConstraintCount);
+
+ mContactList.forceSize_Unsafe(0);
+ mContactList.reserve((nbActiveContactManagers +63u) & (~63u));
+ mContactList.forceSize_Unsafe(nbActiveContactManagers);
+
+ mMotionVelocityArray.forceSize_Unsafe(0);
+ mMotionVelocityArray.reserve((bodyCount + 63u) & (~63u));
+ mMotionVelocityArray.forceSize_Unsafe(bodyCount);
+
+ mBodyCoreArray.forceSize_Unsafe(0);
+ mBodyCoreArray.reserve((bodyCount + 63u) & (~63u));
+ mBodyCoreArray.forceSize_Unsafe(bodyCount);
+
+ mRigidBodyArray.forceSize_Unsafe(0);
+ mRigidBodyArray.reserve((bodyCount + 63u) & (~63u));
+ mRigidBodyArray.forceSize_Unsafe(bodyCount);
+
+ mArticulationArray.forceSize_Unsafe(0);
+ mArticulationArray.reserve((numArtics + 63u) & (~63u));
+ mArticulationArray.forceSize_Unsafe(numArtics);
+
+ mNodeIndexArray.forceSize_Unsafe(0);
+ mNodeIndexArray.reserve((bodyCount + 63u) & (~63u));
+ mNodeIndexArray.forceSize_Unsafe(bodyCount);
+
+
+ ThresholdStream& stream = getThresholdStream();
+ stream.forceSize_Unsafe(0);
+ stream.reserve(Ps::nextPowerOfTwo(nbActiveContactManagers != 0 ? nbActiveContactManagers-1 : nbActiveContactManagers));
+
+ PxU32 constraintIndex = 0;
+
+ //flip exceeded force threshold buffer
+ mCurrentIndex = 1 - mCurrentIndex;
+
+ //create force threshold tasks to produce force change events
+ PxsForceThresholdTask* forceThresholdTask = PX_PLACEMENT_NEW(getTaskPool().allocateNotThreadSafe(sizeof(PxsForceThresholdTask)), PxsForceThresholdTask)(*this);
+ forceThresholdTask->setContinuation(lostTouchTask);
+
+ const IG::IslandId*const islandIds = islandSim.getActiveIslands();
+
+ PxU32 currentIsland = 0;
+ PxU32 currentBodyIndex = 0;
+ PxU32 currentArticulation = 0;
+ PxU32 currentContact = 0;
+ //while(start<sentinel)
+ while(currentIsland < islandCount)
+ {
+ SolverIslandObjects objectStarts;
+ objectStarts.articulations = mArticulationArray.begin()+ currentArticulation;
+ objectStarts.bodies = mRigidBodyArray.begin() + currentBodyIndex;
+ objectStarts.contactManagers = mContactList.begin() + currentContact;
+ objectStarts.constraintDescs = mSolverConstraintDescPool.begin() + constraintIndex;
+ objectStarts.orderedConstraintDescs = mOrderedSolverConstraintDescPool.begin() + constraintIndex;
+ objectStarts.tempConstraintDescs = mTempSolverConstraintDescPool.begin() + constraintIndex;
+ objectStarts.constraintBatchHeaders = mContactConstraintBatchHeaders.begin() + constraintIndex;
+ objectStarts.motionVelocities = mMotionVelocityArray.begin() + currentBodyIndex;
+ objectStarts.bodyCoreArray = mBodyCoreArray.begin() + currentBodyIndex;
+ objectStarts.islandIds = islandIds + currentIsland;
+ objectStarts.bodyRemapTable = mSolverBodyRemapTable.begin();
+ objectStarts.nodeIndexArray = mNodeIndexArray.begin() + currentBodyIndex;
+
+ PxU32 startIsland = currentIsland;
+ PxU32 constraintCount = 0;
+
+ PxU32 nbArticulations = 0;
+ PxU32 nbBodies = 0;
+ PxU32 nbConstraints = 0;
+ PxU32 nbContactManagers =0;
+
+ //KS - logic is a bit funky here. We will keep rolling the island together provided currentIsland < islandCount AND either we haven't exceeded the max number of bodies or we have
+ //zero constraints AND we haven't exceeded articulation batch counts (it's still currently beneficial to keep articulations in separate islands but this is only temporary).
+ while((currentIsland < islandCount && (nbBodies < solverBatchMax || constraintCount < minimumConstraintCount)) && nbArticulations < articulationBatchMax)
+ {
+ const IG::Island& island = islandSim.getIsland(islandIds[currentIsland]);
+ nbBodies += island.mSize[IG::Node::eRIGID_BODY_TYPE];
+ nbArticulations += island.mSize[IG::Node::eARTICULATION_TYPE];
+ nbConstraints += island.mEdgeCount[IG::Edge::eCONSTRAINT];
+ nbContactManagers += island.mEdgeCount[IG::Edge::eCONTACT_MANAGER];
+ constraintCount = nbConstraints + nbContactManagers;
+ currentIsland++;
+ }
+
+
+ objectStarts.numIslands = currentIsland - startIsland;
+
+ constraintIndex += nbArticulations*Dy::DY_ARTICULATION_MAX_SIZE;
+
+ PxsIslandIndices counts;
+
+ counts.articulations = nbArticulations;
+ counts.bodies = nbBodies;
+
+ counts.constraints = nbConstraints;
+ counts.contactManagers = nbContactManagers;
+ if(counts.articulations + counts.bodies > 0)
+ {
+ PxBaseTask* task = createSolverTaskChain(*this, objectStarts, counts,
+ kinematicCount + currentBodyIndex, simpleIslandManager, mSolverBodyRemapTable.begin(), mMaterialManager, forceThresholdTask, mOutputIterator, mUseEnhancedDeterminism);
+ task->removeReference();
+ }
+
+ currentBodyIndex += nbBodies;
+ currentArticulation += nbArticulations;
+ currentContact += nbContactManagers;
+
+ constraintIndex += constraintCount;
+ }
+
+ //kick off forceThresholdTask
+ forceThresholdTask->removeReference();
+}
+
+void DynamicsContext::updateBodyCore(PxBaseTask* continuation)
+{
+ PX_UNUSED(continuation);
+}
+
+void DynamicsContext::mergeResults()
+{
+ PX_PROFILE_ZONE("Dynamics.solverMergeResults", mContextID);
+ //OK. Sum up sim stats here...
+
+#if PX_ENABLE_SIM_STATS
+ PxcThreadCoherentCacheIterator<ThreadContext, PxcNpMemBlockPool> threadContextIt(mThreadContextPool);
+ ThreadContext* threadContext = threadContextIt.getNext();
+
+ while(threadContext != NULL)
+ {
+ ThreadContext::ThreadSimStats& threadStats = threadContext->getSimStats();
+ addThreadStats(threadStats);
+ threadStats.clear();
+ threadContext = threadContextIt.getNext();
+ }
+#endif
+}
+
+
+static void preIntegrationParallel(
+ const PxF32 dt,
+ PxsBodyCore*const* bodyArray, // INOUT: core body attributes
+ PxsRigidBody*const* originalBodyArray, // IN: original bodies (LEGACY - DON'T deref the ptrs!!)
+ PxU32 const* nodeIndexArray, // IN: island node index
+ PxU32 bodyCount, // IN: body count
+ PxSolverBody* solverBodyPool, // IN: solver body pool (space preallocated)
+ PxSolverBodyData* solverBodyDataPool, // IN: solver body data pool (space preallocated)
+ volatile PxU32* maxSolverPositionIterations,
+ volatile PxU32* maxSolverVelocityIterations,
+ const PxVec3& gravity)
+{
+ PxU32 localMaxPosIter = 0;
+ PxU32 localMaxVelIter = 0;
+
+
+ for(PxU32 a = 1; a < bodyCount; ++a)
+ {
+ PxU32 i = a-1;
+ Ps::prefetchLine(bodyArray[a]);
+ Ps::prefetchLine(bodyArray[a],128);
+ Ps::prefetchLine(&solverBodyDataPool[a]);
+ Ps::prefetchLine(&solverBodyDataPool[a],128);
+
+ PxsBodyCore& core = *bodyArray[i];
+ const PxsRigidBody& rBody = *originalBodyArray[i];
+
+ PxU16 iterWord = core.solverIterationCounts;
+ localMaxPosIter = PxMax<PxU32>(PxU32(iterWord & 0xff), localMaxPosIter);
+ localMaxVelIter = PxMax<PxU32>(PxU32(iterWord >> 8), localMaxVelIter);
+
+ //const Cm::SpatialVector& accel = originalBodyArray[i]->getAccelerationV();
+ bodyCoreComputeUnconstrainedVelocity(gravity, dt, core.linearDamping, core.angularDamping, rBody.accelScale, core.maxLinearVelocitySq, core.maxAngularVelocitySq,
+ core.linearVelocity, core.angularVelocity, !!(rBody.mInternalFlags & PxcRigidBody::eDISABLE_GRAVITY));
+
+ copyToSolverBodyData(core.linearVelocity, core.angularVelocity, core.inverseMass, core.inverseInertia, core.body2World, core.maxPenBias, core.maxContactImpulse, nodeIndexArray[i],
+ core.contactReportThreshold, solverBodyDataPool[i + 1], core.lockFlags);
+ solverBodyPool[i].solverProgress = 0;
+ solverBodyPool[i].maxSolverNormalProgress = 0;
+ solverBodyPool[i].maxSolverFrictionProgress = 0;
+ }
+ const PxU32 i = bodyCount - 1;
+ PxsBodyCore& core = *bodyArray[i];
+ const PxsRigidBody& rBody = *originalBodyArray[i];
+
+ PxU16 iterWord = core.solverIterationCounts;
+ localMaxPosIter = PxMax<PxU32>(PxU32(iterWord & 0xff), localMaxPosIter);
+ localMaxVelIter = PxMax<PxU32>(PxU32(iterWord >> 8), localMaxVelIter);
+
+ bodyCoreComputeUnconstrainedVelocity(gravity, dt, core.linearDamping, core.angularDamping, rBody.accelScale, core.maxLinearVelocitySq, core.maxAngularVelocitySq,
+ core.linearVelocity, core.angularVelocity, !!(rBody.mInternalFlags & PxcRigidBody::eDISABLE_GRAVITY));
+
+ copyToSolverBodyData(core.linearVelocity, core.angularVelocity, core.inverseMass, core.inverseInertia, core.body2World, core.maxPenBias, core.maxContactImpulse, nodeIndexArray[i],
+ core.contactReportThreshold, solverBodyDataPool[i + 1], core.lockFlags);
+ solverBodyPool[i].solverProgress = 0;
+ solverBodyPool[i].maxSolverNormalProgress = 0;
+ solverBodyPool[i].maxSolverFrictionProgress = 0;
+
+ physx::shdfnd::atomicMax(reinterpret_cast<volatile PxI32*>(maxSolverPositionIterations), PxI32(localMaxPosIter));
+ physx::shdfnd::atomicMax(reinterpret_cast<volatile PxI32*>(maxSolverVelocityIterations), PxI32(localMaxVelIter));
+}
+
+
+void PxsPreIntegrateTask::runInternal()
+{
+ {
+ preIntegrationParallel(mDt, mBodyArray + mStartIndex, mOriginalBodyArray + mStartIndex, mNodeIndexArray + mStartIndex, mNumToIntegrate,
+ mSolverBodies + mStartIndex, mSolverBodyDataPool + mStartIndex,
+ mMaxSolverPositionIterations, mMaxSolverVelocityIterations, mGravity);
+ }
+}
+
+void DynamicsContext::preIntegrationParallel(
+ const PxF32 dt,
+ PxsBodyCore*const* bodyArray, // INOUT: core body attributes
+ PxsRigidBody*const* originalBodyArray, // IN: original bodies (LEGACY - DON'T deref the ptrs!!)
+ PxU32 const* nodeIndexArray, // IN: island node index
+ PxU32 bodyCount, // IN: body count
+ PxSolverBody* solverBodyPool, // IN: solver body pool (space preallocated)
+ PxSolverBodyData* solverBodyDataPool, // IN: solver body data pool (space preallocated)
+ Cm::SpatialVector* /*motionVelocityArray*/, // OUT: motion velocities
+ PxU32& maxSolverPositionIterations,
+ PxU32& maxSolverVelocityIterations,
+ PxBaseTask& task
+ )
+{
+ //TODO - make this based on some variables so we can try different configurations
+ const PxU32 IntegrationPerThread = 256;
+
+ const PxU32 numTasks = ((bodyCount + IntegrationPerThread-1)/IntegrationPerThread);
+ const PxU32 taskBatchSize = 64;
+
+ for(PxU32 i = 0; i < numTasks; i+=taskBatchSize)
+ {
+ const PxU32 nbTasks = PxMin(numTasks - i, taskBatchSize);
+ PxsPreIntegrateTask* tasks = reinterpret_cast<PxsPreIntegrateTask*>(getTaskPool().allocate(sizeof(PxsPreIntegrateTask)*nbTasks));
+ for(PxU32 a = 0; a < nbTasks; ++a)
+ {
+ PxU32 startIndex = (i+a)*IntegrationPerThread;
+ PxU32 nbToIntegrate = PxMin((bodyCount-startIndex), IntegrationPerThread);
+ PxsPreIntegrateTask* pTask = PX_PLACEMENT_NEW(&tasks[a], PxsPreIntegrateTask)(*this, bodyArray,
+ originalBodyArray, nodeIndexArray, solverBodyPool, solverBodyDataPool, dt, bodyCount,
+ &maxSolverPositionIterations, &maxSolverVelocityIterations, startIndex,
+ nbToIntegrate, mGravity);
+
+ pTask->setContinuation(&task);
+ pTask->removeReference();
+ }
+ }
+
+ PxMemZero(solverBodyPool, bodyCount * sizeof(PxSolverBody));
+}
+
+inline void WaitBodyRequiredState(volatile PxU32* state, PxU32 requiredState)
+{
+ while(requiredState != *state );
+}
+
+void solveParallel(SOLVER_PARALLEL_METHOD_ARGS)
+{
+ context.solveParallel(params, islandSim);
+}
+
+
+void DynamicsContext::solveParallel(SolverIslandParams& params, IG::IslandSim& islandSim)
+{
+ PxI32 targetCount = mSolverCore[mFrictionType]->solveVParallelAndWriteBack(params);
+
+ PxI32* solveCount = &params.constraintIndex2;
+
+ //PxI32 targetCount = (PxI32)(params.numConstraintHeaders * (params.velocityIterations + params.positionIterations));
+
+ WAIT_FOR_PROGRESS_NO_TIMER(solveCount, targetCount);
+
+ integrateCoreParallel(params, islandSim);
+}
+
+void DynamicsContext::integrateCoreParallel(SolverIslandParams& params, IG::IslandSim& islandSim)
+{
+ const PxI32 unrollCount = 128;
+
+ PxI32* bodyIntegrationListIndex = &params.bodyIntegrationListIndex;
+
+ PxI32 index = physx::shdfnd::atomicAdd(bodyIntegrationListIndex, unrollCount) - unrollCount;
+
+ const PxI32 numBodies = PxI32(params.bodyListSize);
+ const PxI32 numArtics = PxI32(params.articulationListSize);
+
+ Cm::SpatialVector* PX_RESTRICT motionVelocityArray = params.motionVelocityArray;
+ PxsBodyCore*const* bodyArray = params.bodyArray;
+ PxsRigidBody** PX_RESTRICT rigidBodies = params.rigidBodies;
+ ArticulationSolverDesc* PX_RESTRICT articulationListStart = params.articulationListStart;
+
+
+ PxI32 numIntegrated = 0;
+
+ PxI32 bodyRemainder = unrollCount;
+
+ while(index < numArtics)
+ {
+ const PxI32 remainder = PxMin(numArtics - index, unrollCount);
+ bodyRemainder -= remainder;
+
+ for(PxI32 a = 0; a < remainder; ++a, index++)
+ {
+ const PxI32 i = index;
+ {
+ PX_PROFILE_ZONE("Articulations.integrate", mContextID);
+
+ ArticulationPImpl::updateBodies(articulationListStart[i], mDt);
+ }
+
+ ++numIntegrated;
+ }
+ if(bodyRemainder == 0)
+ {
+ index = physx::shdfnd::atomicAdd(bodyIntegrationListIndex, unrollCount) - unrollCount;
+ bodyRemainder = unrollCount;
+ }
+ }
+
+ index -= numArtics;
+
+ const PxI32 unrollPlusArtics = unrollCount + numArtics;
+
+ PxSolverBody* PX_RESTRICT solverBodies = params.bodyListStart;
+ PxSolverBodyData* PX_RESTRICT solverBodyData = params.bodyDataList + params.solverBodyOffset+1;
+
+ while(index < numBodies)
+ {
+ const PxI32 remainder = PxMin(numBodies - index, bodyRemainder);
+ bodyRemainder -= remainder;
+ for(PxI32 a = 0; a < remainder; ++a, index++)
+ {
+ const PxI32 prefetch = PxMin(index+4, numBodies - 1);
+ Ps::prefetchLine(bodyArray[prefetch]);
+ Ps::prefetchLine(bodyArray[prefetch],128);
+ Ps::prefetchLine(&solverBodies[index],128);
+ Ps::prefetchLine(&motionVelocityArray[index],128);
+ Ps::prefetchLine(&bodyArray[index+32]);
+ Ps::prefetchLine(&rigidBodies[prefetch]);
+
+ PxSolverBodyData& data = solverBodyData[index];
+
+ integrateCore(motionVelocityArray[index].linear, motionVelocityArray[index].angular,
+ solverBodies[index], data, mDt);
+
+ PxsRigidBody& rBody = *rigidBodies[index];
+ PxsBodyCore& core = rBody.getCore();
+ rBody.mLastTransform = core.body2World;
+ core.body2World = data.body2World;
+ core.linearVelocity = data.linearVelocity;
+ core.angularVelocity = data.angularVelocity;
+
+ bool hasStaticTouch = islandSim.getIslandStaticTouchCount(IG::NodeIndex(data.nodeIndex)) != 0;
+ sleepCheck(rigidBodies[index], mDt, mInvDt, mEnableStabilization, mUseAdaptiveForce, motionVelocityArray[index], hasStaticTouch);
+
+ ++numIntegrated;
+ }
+
+ {
+ index = physx::shdfnd::atomicAdd(bodyIntegrationListIndex, unrollCount) - unrollPlusArtics;
+ bodyRemainder = unrollCount;
+ }
+ }
+
+ Ps::memoryBarrier();
+ physx::shdfnd::atomicAdd(&params.numObjectsIntegrated, numIntegrated);
+}
+
+class BlockAllocator : public PxConstraintAllocator
+{
+ PxsConstraintBlockManager& mConstraintBlockManager;
+ PxcConstraintBlockStream& mConstraintBlockStream;
+ FrictionPatchStreamPair& mFrictionPatchStreamPair;
+ PxU32& mTotalConstraintByteSize;
+public:
+
+ BlockAllocator(PxsConstraintBlockManager& constraintBlockManager, PxcConstraintBlockStream& constraintBlockStream, FrictionPatchStreamPair& frictionPatchStreamPair,
+ PxU32& totalConstraintByteSize) :
+ mConstraintBlockManager(constraintBlockManager), mConstraintBlockStream(constraintBlockStream), mFrictionPatchStreamPair(frictionPatchStreamPair),
+ mTotalConstraintByteSize(totalConstraintByteSize)
+ {
+ }
+
+ virtual PxU8* reserveConstraintData(const PxU32 size)
+ {
+ mTotalConstraintByteSize += size;
+ return mConstraintBlockStream.reserve(size, mConstraintBlockManager);
+ }
+
+ virtual PxU8* reserveFrictionData(const PxU32 size)
+ {
+ return mFrictionPatchStreamPair.reserve<PxU8>(size);
+ }
+
+ virtual PxU8* findInputPatches(PxU8* frictionCookie)
+ {
+ return frictionCookie;
+ }
+
+ PX_NOCOPY(BlockAllocator)
+
+};
+
+
+
+static PxU32 createFinalizeContacts_Parallel(PxSolverBodyData* solverBodyData, ThreadContext& mThreadContext, DynamicsContext& context,
+ PxU32 startIndex, PxU32 endIndex, PxsContactManagerOutputIterator& outputs)
+{
+ const PxFrictionType::Enum frictionType = context.getFrictionType();
+ const PxReal bounceThreshold = context.getBounceThreshold();
+ const PxReal frictionOffsetThreshold = context.getFrictionOffsetThreshold();
+ const PxReal dt = context.getDt();
+ const PxReal invDt = context.getInvDt();
+
+ PxSolverConstraintDesc* contactDescPtr = mThreadContext.orderedContactConstraints;
+
+ PxConstraintBatchHeader* headers = mThreadContext.contactConstraintBatchHeaders;
+
+ PxI32 axisConstraintCount = 0;
+ ThreadContext* threadContext = context.getThreadContext();
+ threadContext->mConstraintBlockStream.reset(); //ensure there's no left-over memory that belonged to another island
+
+ PxTransform idt(PxIdentity);
+
+ BlockAllocator blockAllocator(mThreadContext.mConstraintBlockManager, threadContext->mConstraintBlockStream, threadContext->mFrictionPatchStreamPair, threadContext->mConstraintSize);
+
+ const PxReal ccdMaxSeparation = context.getCCDSeparationThreshold();
+
+ for(PxU32 a = startIndex; a < endIndex; ++a)
+ {
+
+ PxConstraintBatchHeader& header = headers[a];
+
+ if(contactDescPtr[header.mStartIndex].constraintLengthOver16 == DY_SC_TYPE_RB_CONTACT)
+ {
+ SolverConstraintPrepState::Enum state = SolverConstraintPrepState::eUNBATCHABLE;
+
+ PxSolverContactDesc blockDescs[4];
+ PxsContactManagerOutput* cmOutputs[4];
+ PxsContactManager* cms[4];
+ for (PxU32 i = 0; i < header.mStride; ++i)
+ {
+ PxSolverConstraintDesc& desc = contactDescPtr[header.mStartIndex + i];
+ PxSolverContactDesc& blockDesc = blockDescs[i];
+ PxsContactManager* cm = reinterpret_cast<PxsContactManager*>(desc.constraint);
+
+ cms[i] = cm;
+
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+
+ cmOutputs[i] = &outputs.getContactManager(unit.mNpIndex);
+
+ PxSolverBodyData& data0 = desc.linkIndexA != 0xffff ? solverBodyData[0] : solverBodyData[desc.bodyADataIndex];
+ PxSolverBodyData& data1 = desc.linkIndexB != 0xffff ? solverBodyData[0] : solverBodyData[desc.bodyBDataIndex];
+
+ blockDesc.data0 = &data0;
+ blockDesc.data1 = &data1;
+
+ PxU8 flags = unit.rigidCore0->mFlags;
+ if (unit.rigidCore1)
+ flags |= PxU8(unit.rigidCore1->mFlags);
+
+ blockDesc.bodyFrame0 = unit.rigidCore0->body2World;
+ blockDesc.bodyFrame1 = unit.rigidCore1 ? unit.rigidCore1->body2World : idt;
+ blockDesc.shapeInteraction = cm->getShapeInteraction();
+ blockDesc.contactForces = cmOutputs[i]->contactForces;
+ blockDesc.desc = &desc;
+ blockDesc.body0 = desc.bodyA;
+ blockDesc.body1 = desc.bodyB;
+ blockDesc.hasForceThresholds = !!(unit.flags & PxcNpWorkUnitFlag::eFORCE_THRESHOLD);
+ blockDesc.disableStrongFriction = !!(unit.flags & PxcNpWorkUnitFlag::eDISABLE_STRONG_FRICTION);
+ blockDesc.bodyState0 = (unit.flags & PxcNpWorkUnitFlag::eARTICULATION_BODY0) ? PxSolverContactDesc::eARTICULATION : PxSolverContactDesc::eDYNAMIC_BODY;
+ blockDesc.bodyState1 = (unit.flags & PxcNpWorkUnitFlag::eARTICULATION_BODY1) ? PxSolverContactDesc::eARTICULATION : (unit.flags & PxcNpWorkUnitFlag::eHAS_KINEMATIC_ACTOR) ? PxSolverContactDesc::eKINEMATIC_BODY :
+ ((unit.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY1) ? PxSolverContactDesc::eDYNAMIC_BODY : PxSolverContactDesc::eSTATIC_BODY);
+ //blockDesc.flags = unit.flags;
+
+ PxReal dominance0 = unit.dominance0 ? 1.f : 0.f;
+ PxReal dominance1 = unit.dominance1 ? 1.f : 0.f;
+
+ blockDesc.mInvMassScales.linear0 = blockDesc.mInvMassScales.angular0 = dominance0;
+ blockDesc.mInvMassScales.linear1 = blockDesc.mInvMassScales.angular1 = dominance1;
+ blockDesc.restDistance = unit.restDistance;
+ blockDesc.frictionPtr = unit.frictionDataPtr;
+ blockDesc.frictionCount = unit.frictionPatchCount;
+ blockDesc.maxCCDSeparation = (flags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD) ? ccdMaxSeparation : PX_MAX_F32;
+
+ }
+
+ if(header.mStride == 4)
+ {
+ //KS - todo - plumb in axisConstraintCount into this method to keep track of the number of axes
+ state = createFinalizeMethods4[frictionType](cmOutputs, *threadContext,
+ blockDescs,
+ invDt,
+ bounceThreshold,
+ frictionOffsetThreshold,
+ context.getCorrelationDistance(),
+ blockAllocator);
+
+ }
+ if(SolverConstraintPrepState::eSUCCESS != state)
+ {
+ for(PxU32 i = 0; i < header.mStride; ++i)
+ {
+ PxSolverConstraintDesc& desc = contactDescPtr[header.mStartIndex+i];
+ PxsContactManager* cm = reinterpret_cast<PxsContactManager*>(desc.constraint);
+ PxcNpWorkUnit& n = cm->getWorkUnit();
+
+ PxsContactManagerOutput& output = outputs.getContactManager(n.mNpIndex);
+
+ createFinalizeMethods[frictionType](blockDescs[i], output, *threadContext,
+ invDt, bounceThreshold, frictionOffsetThreshold, context.getCorrelationDistance(), blockAllocator);
+
+ getContactManagerConstraintDesc(output,*cm,desc);
+ }
+ }
+
+ for (PxU32 i = 0; i < header.mStride; ++i)
+ {
+ PxsContactManager* cm = cms[i];
+
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+ unit.frictionDataPtr = blockDescs[i].frictionPtr;
+ unit.frictionPatchCount = blockDescs[i].frictionCount;
+ axisConstraintCount += blockDescs[i].axisConstraintCount;
+
+ }
+ }
+ else if(contactDescPtr[header.mStartIndex].constraintLengthOver16 == DY_SC_TYPE_RB_1D)
+ {
+
+ SolverConstraintShaderPrepDesc shaderDescs[4];
+ PxSolverConstraintPrepDesc descs[4];
+
+ PxTransform id(PxIdentity);
+
+ for (PxU32 i = 0; i < header.mStride; ++i)
+ {
+ PxSolverConstraintDesc& desc = contactDescPtr[header.mStartIndex + i];
+ const Constraint* constraint = reinterpret_cast<const Constraint*>(desc.constraint);
+
+ SolverConstraintShaderPrepDesc& shaderPrepDesc = shaderDescs[i];
+ PxSolverConstraintPrepDesc& prepDesc = descs[i];
+
+ const PxConstraintSolverPrep solverPrep = constraint->solverPrep;
+ const void* constantBlock = constraint->constantBlock;
+ const PxU32 constantBlockByteSize = constraint->constantBlockSize;
+ const PxTransform& pose0 = (constraint->body0 ? constraint->body0->getPose() : id);
+ const PxTransform& pose1 = (constraint->body1 ? constraint->body1->getPose() : id);
+ const PxSolverBody* sbody0 = desc.bodyA;
+ const PxSolverBody* sbody1 = desc.bodyB;
+ PxSolverBodyData* sbodyData0 = &solverBodyData[desc.linkIndexA != PxSolverConstraintDesc::NO_LINK ? 0 : desc.bodyADataIndex];
+ PxSolverBodyData* sbodyData1 = &solverBodyData[desc.linkIndexB != PxSolverConstraintDesc::NO_LINK ? 0 : desc.bodyBDataIndex];
+
+ shaderPrepDesc.constantBlock = constantBlock;
+ shaderPrepDesc.constantBlockByteSize = constantBlockByteSize;
+ shaderPrepDesc.constraint = constraint;
+ shaderPrepDesc.solverPrep = solverPrep;
+
+ prepDesc.desc = &desc;
+ prepDesc.bodyFrame0 = pose0;
+ prepDesc.bodyFrame1 = pose1;
+ prepDesc.data0 = sbodyData0;
+ prepDesc.data1 = sbodyData1;
+ prepDesc.body0 = sbody0;
+ prepDesc.body1 = sbody1;
+ prepDesc.linBreakForce = constraint->linBreakForce;
+ prepDesc.angBreakForce = constraint->angBreakForce;
+ prepDesc.writeback = &context.getConstraintWriteBackPool()[constraint->index];
+ prepDesc.disablePreprocessing = !!(constraint->flags & PxConstraintFlag::eDISABLE_PREPROCESSING);
+ prepDesc.improvedSlerp = !!(constraint->flags & PxConstraintFlag::eIMPROVED_SLERP);
+ prepDesc.driveLimitsAreForces = !!(constraint->flags & PxConstraintFlag::eDRIVE_LIMITS_ARE_FORCES);
+ prepDesc.minResponseThreshold = constraint->minResponseThreshold;
+ }
+
+#if DY_BATCH_1D
+ SolverConstraintPrepState::Enum state = SolverConstraintPrepState::eUNBATCHABLE;
+ if(header.mStride == 4)
+ {
+ PxU32 totalRows;
+ state = setupSolverConstraint4
+ (shaderDescs, descs, dt, invDt, totalRows,
+ blockAllocator);
+
+ axisConstraintCount += totalRows;
+ }
+ if(state != SolverConstraintPrepState::eSUCCESS)
+#endif
+ {
+ for(PxU32 i = 0; i < header.mStride; ++i)
+ {
+ axisConstraintCount += SetupSolverConstraint(shaderDescs[i], descs[i], blockAllocator, dt, invDt);
+ }
+ }
+ }
+ }
+
+ threadContext->getSimStats().numAxisSolverConstraints += axisConstraintCount;
+
+ context.putThreadContext(threadContext);
+ return PxU32(axisConstraintCount); //Can't write to mThreadContext as it's shared!!!!
+}
+
+class PxsCreateFinalizeContactsTask : public Cm::Task
+{
+ PxsCreateFinalizeContactsTask& operator=(const PxsCreateFinalizeContactsTask&);
+public:
+ PxsCreateFinalizeContactsTask( const PxU32 numConstraints, PxSolverConstraintDesc* descArray, PxSolverBodyData* solverBodyData,
+ ThreadContext& threadContext, DynamicsContext& context, PxU32 startIndex, PxU32 endIndex, PxsContactManagerOutputIterator& outputs) :
+ mNumConstraints(numConstraints), mDescArray(descArray), mSolverBodyData(solverBodyData),
+ mThreadContext(threadContext), mDynamicsContext(context),
+ mOutputs(outputs),
+ mStartIndex(startIndex), mEndIndex(endIndex)
+ {}
+
+ virtual void runInternal()
+ {
+ createFinalizeContacts_Parallel(mSolverBodyData, mThreadContext, mDynamicsContext, mStartIndex, mEndIndex, mOutputs);
+ }
+
+ virtual const char* getName() const
+ {
+ return "PxsDynamics.createFinalizeContacts";
+ }
+
+public:
+ const PxU32 mNumConstraints;
+ PxSolverConstraintDesc* mDescArray;
+ PxSolverBodyData* mSolverBodyData;
+ ThreadContext& mThreadContext;
+ DynamicsContext& mDynamicsContext;
+ PxsContactManagerOutputIterator& mOutputs;
+ PxU32 mStartIndex;
+ PxU32 mEndIndex;
+};
+
+void PxsSolverCreateFinalizeConstraintsTask::runInternal()
+{
+ ThreadContext& mThreadContext = *mIslandContext.mThreadContext;
+
+
+
+ PxU32 descCount = mThreadContext.mNumDifferentBodyConstraints;
+ PxU32 selfConstraintDescCount = mThreadContext.contactDescArraySize - mThreadContext.mNumDifferentBodyConstraints;
+
+ Ps::Array<PxU32>& accumulatedConstraintsPerPartition = mThreadContext.mConstraintsPerPartition;
+
+ PxU32 numHeaders = 0;
+ PxU32 currentPartition = 0;
+ PxU32 maxJ = descCount == 0 ? 0 : accumulatedConstraintsPerPartition[0];
+
+ const PxU32 maxBatchPartition = 0xFFFFFFFF;
+
+ const PxU32 maxBatchSize = mEnhancedDeterminism ? 1u : 4u;
+
+ PxU32 headersPerPartition = 0;
+ for(PxU32 a = 0; a < descCount;)
+ {
+
+
+ PxU32 loopMax = PxMin(maxJ - a, maxBatchSize);
+ PxU16 j = 0;
+ if(loopMax > 0)
+ {
+ PxConstraintBatchHeader& header = mThreadContext.contactConstraintBatchHeaders[numHeaders++];
+
+ j=1;
+ PxSolverConstraintDesc& desc = mThreadContext.orderedContactConstraints[a];
+ if(!isArticulationConstraint(desc) && (desc.constraintLengthOver16 == DY_SC_TYPE_RB_CONTACT ||
+ desc.constraintLengthOver16 == DY_SC_TYPE_RB_1D) && currentPartition < maxBatchPartition)
+ {
+ for(; j < loopMax && desc.constraintLengthOver16 == mThreadContext.orderedContactConstraints[a+j].constraintLengthOver16 &&
+ !isArticulationConstraint(mThreadContext.orderedContactConstraints[a+j]); ++j);
+ }
+ header.mStartIndex = a;
+ header.mStride = j;
+ headersPerPartition++;
+ }
+ if(maxJ == (a + j) && maxJ != descCount)
+ {
+ //Go to next partition!
+ accumulatedConstraintsPerPartition[currentPartition] = headersPerPartition;
+ headersPerPartition = 0;
+ currentPartition++;
+ maxJ = accumulatedConstraintsPerPartition[currentPartition];
+ }
+ a+= j;
+ }
+ if(descCount)
+ accumulatedConstraintsPerPartition[currentPartition] = headersPerPartition;
+
+
+
+ accumulatedConstraintsPerPartition.forceSize_Unsafe(mThreadContext.mMaxPartitions);
+
+ PxU32 numDifferentBodyBatchHeaders = numHeaders;
+
+ for(PxU32 a = 0; a < selfConstraintDescCount; ++a)
+ {
+ PxConstraintBatchHeader& header = mThreadContext.contactConstraintBatchHeaders[numHeaders++];
+ header.mStartIndex = a + descCount;
+ header.mStride = 1;
+ }
+
+ PxU32 numSelfConstraintBatchHeaders = numHeaders - numDifferentBodyBatchHeaders;
+
+ mThreadContext.numDifferentBodyBatchHeaders = numDifferentBodyBatchHeaders;
+ mThreadContext.numSelfConstraintBatchHeaders = numSelfConstraintBatchHeaders;
+ mThreadContext.numContactConstraintBatches = numHeaders;
+
+ PX_UNUSED(descCount);
+
+ {
+ PxSolverConstraintDesc* descBegin = mThreadContext.orderedContactConstraints;
+
+ const PxU32 numThreads = getTaskManager()->getCpuDispatcher()->getWorkerCount();
+
+ //Choose an appropriate number of constraint prep tasks. This must be proportionate to the number of constraints to prep and the number
+ //of worker threads available.
+ const PxU32 TaskBlockSize = 16;
+ const PxU32 TaskBlockLargeSize = 64;
+ const PxU32 BlockAllocationSize = 64;
+
+ PxU32 numTasks = (numHeaders+TaskBlockLargeSize-1)/TaskBlockLargeSize;
+
+ if(numTasks)
+ {
+
+ if(numTasks < numThreads)
+ numTasks = PxMax(1u, (numHeaders+TaskBlockSize-1)/TaskBlockSize);
+
+ const PxU32 constraintsPerTask = (numHeaders + numTasks-1)/numTasks;
+
+ for(PxU32 i = 0; i < numTasks; i+=BlockAllocationSize)
+ {
+ PxU32 blockSize = PxMin(numTasks - i, BlockAllocationSize);
+
+ PxsCreateFinalizeContactsTask* tasks = reinterpret_cast<PxsCreateFinalizeContactsTask*>(mContext.getTaskPool().allocate(sizeof(PxsCreateFinalizeContactsTask)*blockSize));
+
+ for(PxU32 a = 0; a < blockSize; ++a)
+ {
+ PxU32 startIndex = (a + i) * constraintsPerTask;
+ PxU32 endIndex = PxMin(startIndex + constraintsPerTask, numHeaders);
+ PxsCreateFinalizeContactsTask* pTask = PX_PLACEMENT_NEW(&tasks[a], PxsCreateFinalizeContactsTask( descCount, descBegin, mContext.mSolverBodyDataPool.begin(), mThreadContext, mContext, startIndex, endIndex, mOutputs));
+
+ pTask->setContinuation(mCont);
+ pTask->removeReference();
+ }
+ }
+ }
+ }
+}
+
+}
+}
+
+