GRK-Projekt-Scena-Podwodna/dependencies/PHYSX/source/lowleveldynamics/src/DyTGSDynamics.cpp
2022-02-11 15:37:18 +01:00

3326 lines
118 KiB
C++

//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2019 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 "common/PxProfileZone.h"
#include "PxsRigidBody.h"
#include "PxsContactManager.h"
#include "DyTGSDynamics.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"
#include "DySolverContext.h"
#include "DyDynamics.h"
#include "DySolverConstraint1D.h"
#include "PxvSimStats.h"
#include "DyTGSContactPrep.h"
#define PX_USE_BLOCK_SOLVER 1
#define PX_USE_BLOCK_1D 1
namespace physx
{
namespace Dy
{
Context* createTGSDynamicsContext(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,
const PxReal lengthScale
)
{
return DynamicsTGSContext::create(memBlockPool, scratchAllocator, taskPool, simStats, taskManager, allocatorCallback, materialManager, accurateIslandSim,
contextID, enableStabilization, useEnhancedDeterminism, useAdaptiveForce, lengthScale);
}
// PT: TODO: consider removing this function. We already have "createDynamicsContext".
DynamicsTGSContext* DynamicsTGSContext::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,
const PxReal lengthScale
)
{
// PT: TODO: inherit from UserAllocated, remove placement new
DynamicsTGSContext* dc = reinterpret_cast<DynamicsTGSContext*>(PX_ALLOC(sizeof(DynamicsTGSContext), "DynamicsTGSContext"));
if (dc)
{
new(dc)DynamicsTGSContext(memBlockPool, scratchAllocator, taskPool, simStats, taskManager, allocatorCallback, materialManager, accurateIslandSim, contextID, enableStabilization, useEnhancedDeterminism, useAdaptiveForce, lengthScale);
}
return dc;
}
void DynamicsTGSContext::destroy()
{
this->~DynamicsTGSContext();
PX_FREE(this);
}
void DynamicsTGSContext::resetThreadContexts()
{
PxcThreadCoherentCacheIterator<ThreadContext, PxcNpMemBlockPool> threadContextIt(mThreadContextPool);
ThreadContext* threadContext = threadContextIt.getNext();
while (threadContext != NULL)
{
threadContext->reset();
threadContext = threadContextIt.getNext();
}
}
PX_FORCE_INLINE PxVec3 safeRecip(const PxVec3& v)
{
return PxVec3(v.x == 0.f ? 0.f : 1.f/v.x, v.y == 0.f ? 0.f : 1.f/v.y, v.z == 0.f ? 0.f : 1.f/v.z);
}
void copyToSolverBodyDataStep(const PxVec3& linearVelocity, const PxVec3& angularVelocity, const PxReal invMass, const PxVec3& invInertia, const PxTransform& globalPose,
const PxReal maxDepenetrationVelocity, const PxReal maxContactImpulse, const PxU32 nodeIndex, const PxReal reportThreshold,
const PxReal maxAngVelSq, PxU32 lockFlags, bool isKinematic,
PxTGSSolverBodyVel& solverVel, PxTGSSolverBodyTxInertia& solverBodyTxInertia, PxTGSSolverBodyData& solverBodyData)
{
const PxMat33 rotation(globalPose.q);
const PxVec3 sqrtInvInertia = computeSafeSqrtInertia(invInertia);
const PxVec3 sqrtBodySpaceInertia = safeRecip(sqrtInvInertia);
Cm::transformInertiaTensor(sqrtInvInertia, rotation, solverBodyTxInertia.sqrtInvInertia);
solverBodyTxInertia.deltaBody2World.p = globalPose.p;
solverBodyTxInertia.deltaBody2World.q = PxQuat(PxIdentity);
PxMat33 sqrtInertia;
Cm::transformInertiaTensor(sqrtBodySpaceInertia, rotation, sqrtInertia);
PxVec3 lv = linearVelocity;
PxVec3 av = angularVelocity;
if (lockFlags)
{
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_X)
lv.x = 0.f;
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Y)
lv.y = 0.f;
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Z)
lv.z = 0.f;
//KS - technically, we can zero the inertia columns and produce stiffer constraints. However, this can cause numerical issues with the
//joint solver, which is fixed by disabling joint preprocessing and setting minResponseThreshold to some reasonable value > 0. However, until
//this is handled automatically, it's probably better not to zero these inertia rows
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_X)
{
av.x = 0.f;
//data.sqrtInvInertia.column0 = PxVec3(0.f);
}
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y)
{
av.y = 0.f;
//data.sqrtInvInertia.column1 = PxVec3(0.f);
}
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z)
{
av.z = 0.f;
//data.sqrtInvInertia.column2 = PxVec3(0.f);
}
}
solverVel.linearVelocity = lv;
solverVel.angularVelocity = sqrtInertia * av;
solverVel.deltaLinDt = PxVec3(0.f);
solverVel.deltaAngDt = PxVec3(0.f);
solverVel.lockFlags = PxU16(lockFlags);
solverVel.isKinematic = isKinematic;
solverVel.maxAngVel = PxSqrt(maxAngVelSq);
solverVel.partitionMask = 0;
solverBodyData.nodeIndex = nodeIndex;
solverBodyData.invMass = invMass;
solverBodyData.penBiasClamp = maxDepenetrationVelocity;
solverBodyData.maxContactImpulse = maxContactImpulse;
solverBodyData.reportThreshold = reportThreshold;
solverBodyData.originalLinearVelocity = lv;
solverBodyData.originalAngularVelocity = av;
PX_ASSERT(lv.isFinite());
PX_ASSERT(av.isFinite());
}
void copyToSolverBodyDataStepKinematic(const PxVec3& linearVelocity, const PxVec3& angularVelocity, const PxTransform& globalPose,
const PxReal maxDepenetrationVelocity, const PxReal maxContactImpulse, const PxU32 nodeIndex, const PxReal reportThreshold,
const PxReal maxAngVelSq,
PxTGSSolverBodyVel& solverVel, PxTGSSolverBodyTxInertia& solverBodyTxInertia, PxTGSSolverBodyData& solverBodyData)
{
const PxMat33 rotation(globalPose.q);
solverBodyTxInertia.deltaBody2World.p = globalPose.p;
solverBodyTxInertia.deltaBody2World.q = PxQuat(PxIdentity);
solverBodyTxInertia.sqrtInvInertia = PxMat33(PxVec3(0.f), PxVec3(0.f), PxVec3(0.f));
solverVel.linearVelocity = PxVec3(0.f);
solverVel.angularVelocity = PxVec3(0.f);
solverVel.deltaLinDt = PxVec3(0.f);
solverVel.deltaAngDt = PxVec3(0.f);
solverVel.lockFlags = 0;
solverVel.isKinematic = true;
solverVel.maxAngVel = PxSqrt(maxAngVelSq);
solverVel.partitionMask = 0;
solverBodyData.nodeIndex = nodeIndex;
solverBodyData.invMass = 0.f;
solverBodyData.penBiasClamp = maxDepenetrationVelocity;
solverBodyData.maxContactImpulse = maxContactImpulse;
solverBodyData.reportThreshold = reportThreshold;
solverBodyData.originalLinearVelocity = linearVelocity;
solverBodyData.originalAngularVelocity = angularVelocity;
}
// =========================== Basic methods
DynamicsTGSContext::DynamicsTGSContext(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,
const PxReal lengthScale
) :
Dy::Context(accurateIslandSim, allocatorCallback, simStats, enableStabilization, useEnhancedDeterminism, useAdaptiveForce, PX_MAX_F32),
mThreadContextPool(memBlockPool),
mMaterialManager(materialManager),
mLengthScale(lengthScale),
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;
PxMemZero(&mWorldSolverBodyVel, sizeof(mWorldSolverBodyVel));
mWorldSolverBodyVel.lockFlags = 0;
mWorldSolverBodyVel.isKinematic = false;
mWorldSolverBodyTxInertia.sqrtInvInertia = PxMat33(PxZero);
mWorldSolverBodyTxInertia.deltaBody2World = PxTransform(PxIdentity);
mWorldSolverBodyData2.penBiasClamp = -PX_MAX_REAL;
mWorldSolverBodyData2.maxContactImpulse = PX_MAX_REAL;
mWorldSolverBodyData2.nodeIndex = IG_INVALID_NODE;
mWorldSolverBodyData2.invMass = 0;
mWorldSolverBodyData2.reportThreshold = PX_MAX_REAL;
mWorldSolverBodyData2.originalLinearVelocity = PxVec3(0.f);
mWorldSolverBodyData2.originalAngularVelocity = PxVec3(0.f);
}
DynamicsTGSContext::~DynamicsTGSContext()
{
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;
}
void DynamicsTGSContext::setDescFromIndices(PxSolverConstraintDesc& desc,
const PxsIndexedInteraction& constraint, const PxU32 solverBodyOffset, PxTGSSolverBodyVel* solverBodies)
{
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)
{
ArticulationV* a = getArticulation(constraint.articulation0);
desc.articulationA = a;
desc.linkIndexA = Ps::to16(getLinkIndex(constraint.articulation0));
desc.bodyADataIndex = 0;
}
else
{
desc.tgsBodyA = constraint.indexType0 == PxsIndexedInteraction::eWORLD ? &mWorldSolverBodyVel
: &solverBodies[PxU32(constraint.solverBody0) + offsetMap[constraint.indexType0] + 1];
desc.bodyADataIndex = constraint.indexType0 == PxsIndexedInteraction::eWORLD ? 0
: PxU32(constraint.solverBody0) + offsetMap[constraint.indexType0] + 1;
desc.linkIndexA = PxSolverConstraintDesc::NO_LINK;
}
if (constraint.indexType1 == PxsIndexedInteraction::eARTICULATION)
{
ArticulationV* b = getArticulation(constraint.articulation1);
desc.articulationB = b;
desc.linkIndexB = Ps::to16(getLinkIndex(constraint.articulation1));
desc.bodyBDataIndex = 0;
}
else
{
desc.tgsBodyB = constraint.indexType1 == PxsIndexedInteraction::eWORLD ? &mWorldSolverBodyVel
: &solverBodies[PxU32(constraint.solverBody1) + offsetMap[constraint.indexType1] + 1];
desc.bodyBDataIndex = constraint.indexType1 == PxsIndexedInteraction::eWORLD ? 0
: PxU32(constraint.solverBody1) + offsetMap[constraint.indexType1] + 1;
desc.linkIndexB = PxSolverConstraintDesc::NO_LINK;
}
}
void DynamicsTGSContext::setDescFromIndices(PxSolverConstraintDesc& desc, IG::EdgeIndex edgeIndex, const IG::SimpleIslandManager& islandManager,
PxU32* bodyRemap, const PxU32 solverBodyOffset, PxTGSSolverBodyVel* solverBodies)
{
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.tgsBodyA = &mWorldSolverBodyVel;
desc.bodyADataIndex = 0;
desc.linkIndexA = PxSolverConstraintDesc::NO_LINK;
}
else
{
const IG::Node& node = islandSim.getNode(node1);
if (node.getNodeType() == IG::Node::eARTICULATION_TYPE)
{
PX_ASSERT(node1.isArticulation());
Dy::ArticulationV* a = islandSim.getLLArticulation(node1);
Dy::ArticulationLinkHandle handle;
PxU8 type;
a->fillIndexedManager(node1.articulationLinkId(), handle, type);
if (type == PxsIndexedInteraction::eARTICULATION)
{
desc.articulationA = a;
desc.linkIndexA = Ps::to16(node1.articulationLinkId());
}
else
{
desc.tgsBodyA = &mWorldSolverBodyVel;
desc.linkIndexA = PxSolverConstraintDesc::NO_LINK;
}
desc.bodyADataIndex = 0;
}
else
{
PX_ASSERT(!node1.isArticulation());
PxU32 activeIndex = islandSim.getActiveNodeIndex(node1);
PxU32 index = node.isKinematic() ? activeIndex : bodyRemap[activeIndex] + solverBodyOffset;
desc.tgsBodyA = &solverBodies[index + 1];
desc.bodyADataIndex = index + 1;
desc.linkIndexA = PxSolverConstraintDesc::NO_LINK;
}
}
IG::NodeIndex node2 = islandSim.getNodeIndex2(edgeIndex);
if (node2.isStaticBody())
{
desc.tgsBodyB = &mWorldSolverBodyVel;
desc.bodyBDataIndex = 0;
desc.linkIndexB = PxSolverConstraintDesc::NO_LINK;
}
else
{
const IG::Node& node = islandSim.getNode(node2);
if (node.getNodeType() == IG::Node::eARTICULATION_TYPE)
{
PX_ASSERT(node2.isArticulation());
Dy::ArticulationV* b = islandSim.getLLArticulation(node2);
Dy::ArticulationLinkHandle handle;
PxU8 type;
b->fillIndexedManager(node2.articulationLinkId(), handle, type);
if (type == PxsIndexedInteraction::eARTICULATION)
{
desc.articulationB = b;
desc.linkIndexB = Ps::to16(node2.articulationLinkId());
}
else
{
desc.tgsBodyB = &mWorldSolverBodyVel;
desc.linkIndexB = PxSolverConstraintDesc::NO_LINK;
}
desc.bodyBDataIndex = 0;
}
else
{
PX_ASSERT(!node2.isArticulation());
PxU32 activeIndex = islandSim.getActiveNodeIndex(node2);
PxU32 index = node.isKinematic() ? activeIndex : bodyRemap[activeIndex] + solverBodyOffset;
desc.tgsBodyB = &solverBodies[index + 1];
desc.bodyBDataIndex = index + 1;
desc.linkIndexB = PxSolverConstraintDesc::NO_LINK;
}
}
}
class DynamicsMergeTask : public Cm::Task
{
PxBaseTask* mSecondContinuation;
public:
DynamicsMergeTask(PxU64 contextId) : Cm::Task(contextId), mSecondContinuation(NULL)
{
}
void setSecondContinuation(PxBaseTask* task) { task->addReference(); mSecondContinuation = task; }
virtual const char* getName() const { return "MergeTask"; }
virtual void runInternal()
{
}
virtual void release()
{
mSecondContinuation->removeReference();
Cm::Task::release();
}
};
class KinematicCopyTGSTask : public Cm::Task
{
const IG::NodeIndex* const mKinematicIndices;
const PxU32 mNbKinematics;
const IG::IslandSim& mIslandSim;
PxTGSSolverBodyVel* mVels;
PxTGSSolverBodyTxInertia* mInertia;
PxTGSSolverBodyData* mBodyData;
PX_NOCOPY(KinematicCopyTGSTask)
public:
static const PxU32 NbKinematicsPerTask = 1024;
KinematicCopyTGSTask(const IG::NodeIndex* const kinematicIndices,
const PxU32 nbKinematics, const IG::IslandSim& islandSim, PxTGSSolverBodyVel* vels,
PxTGSSolverBodyTxInertia* inertias, PxTGSSolverBodyData* datas, PxU64 contextID) : Cm::Task(contextID),
mKinematicIndices(kinematicIndices), mNbKinematics(nbKinematics),
mIslandSim(islandSim), mVels(vels), mInertia(inertias), mBodyData(datas)
{
}
virtual const char* getName() const { return "KinematicCopyTask"; }
virtual void runInternal()
{
for (PxU32 i = 0; i<mNbKinematics; i++)
{
PxsRigidBody* rigidBody = mIslandSim.getRigidBody(mKinematicIndices[i]);
const PxsBodyCore& core = rigidBody->getCore();
copyToSolverBodyDataStepKinematic(core.linearVelocity, core.angularVelocity, core.body2World, core.maxPenBias,
core.maxContactImpulse, mKinematicIndices[i].index(), core.contactReportThreshold, core.maxAngularVelocitySq,
mVels[i], mInertia[i], mBodyData[i]);
rigidBody->saveLastCCDTransform();
}
}
};
class UpdateContinuationTGSTask : public Cm::Task
{
DynamicsTGSContext& mContext;
IG::SimpleIslandManager& mSimpleIslandManager;
PxBaseTask* mLostTouchTask;
PX_NOCOPY(UpdateContinuationTGSTask)
public:
UpdateContinuationTGSTask(DynamicsTGSContext& context,
IG::SimpleIslandManager& simpleIslandManager,
PxBaseTask* lostTouchTask,
PxU64 contextID) : Cm::Task(contextID), mContext(context), mSimpleIslandManager(simpleIslandManager),
mLostTouchTask(lostTouchTask)
{
}
virtual const char* getName() const { return "UpdateContinuationTask";}
virtual void runInternal()
{
mContext.updatePostKinematic(mSimpleIslandManager, mCont, mLostTouchTask);
//Allow lost touch task to run once all tasks have be scheduled
mLostTouchTask->removeReference();
}
};
void DynamicsTGSContext::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;
//const PxU32 nbSubsteps = 16;
mDt = dt;
mInvDt = 1.f / 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;
}
//Block to make sure it doesn't run before stage2 of update!
lostTouchTask->addReference();
UpdateContinuationTGSTask* task = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(UpdateContinuationTGSTask)), UpdateContinuationTGSTask)
(*this, simpleIslandManager, lostTouchTask, mContextID);
task->setContinuation(continuation);
//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(mWorldSolverBodyVel.linearVelocity == PxVec3(0.f));
PX_ASSERT(mWorldSolverBodyVel.angularVelocity == PxVec3(0.f));
PX_ASSERT(mWorldSolverBodyVel.linearVelocity.isFinite());
PX_ASSERT(mWorldSolverBodyVel.angularVelocity.isFinite());
mWorldSolverBodyVel.linearVelocity = mWorldSolverBodyVel.angularVelocity = 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 > mSolverBodyVelPool.capacity())
{
mSolverBodyRemapTable.reserve((kinematicCount + bodyCount + 31 + 1) & ~31);
mSolverBodyVelPool.reserve((kinematicCount + bodyCount +31 + 1) & ~31);
mSolverBodyTxInertiaPool.reserve((kinematicCount + bodyCount +31 + 1) & ~31);
mSolverBodyDataPool2.reserve((kinematicCount + bodyCount +31 + 1) & ~31);
}
{
mSolverBodyVelPool.resize(kinematicCount + bodyCount +1);
mSolverBodyTxInertiaPool.resize(kinematicCount + bodyCount +1);
mSolverBodyDataPool2.resize(kinematicCount + bodyCount +1);
mSolverBodyRemapTable.resize(kinematicCount + bodyCount + 1);
}
// integrate and copy all the kinematics - overkill, since not all kinematics
// need solver bodies
mSolverBodyVelPool[0] = mWorldSolverBodyVel;
mSolverBodyTxInertiaPool[0] = mWorldSolverBodyTxInertia;
mSolverBodyDataPool2[0] = mWorldSolverBodyData2;
{
PX_PROFILE_ZONE("Dynamics.updateKinematics", mContextID);
for (PxU32 i = 0; i < kinematicCount; i+= KinematicCopyTGSTask::NbKinematicsPerTask)
{
const PxU32 nbToProcess = PxMin(kinematicCount - i, KinematicCopyTGSTask::NbKinematicsPerTask);
KinematicCopyTGSTask* kinematicTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(KinematicCopyTGSTask)), KinematicCopyTGSTask)
(kinematicIndices + i, nbToProcess, islandSim, &mSolverBodyVelPool[i+1],
&mSolverBodyTxInertiaPool[i + 1], &mSolverBodyDataPool2[i + 1], mContextID);
kinematicTask->setContinuation(task);
kinematicTask->removeReference();
}
}
}
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);
mContactConstraintBatchHeaders.forceSize_Unsafe(0);
mContactConstraintBatchHeaders.reserve((totalConstraintCount + 63) & (~63));
mContactConstraintBatchHeaders.forceSize_Unsafe(totalConstraintCount);
mTempSolverConstraintDescPool.forceSize_Unsafe(0);
mTempSolverConstraintDescPool.reserve((totalConstraintCount + 63) & (~63));
mTempSolverConstraintDescPool.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));
//flip exceeded force threshold buffer
mCurrentIndex = 1 - mCurrentIndex;
task->removeReference();
}
void DynamicsTGSContext::updatePostKinematic(IG::SimpleIslandManager& simpleIslandManager, PxBaseTask* continuation, PxBaseTask* lostTouchTask)
{
const IG::IslandSim& islandSim = simpleIslandManager.getAccurateIslandSim();
const IG::IslandId*const islandIds = islandSim.getActiveIslands();
DynamicsMergeTask* mergeTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(DynamicsMergeTask)), DynamicsMergeTask)(mContextID);
mergeTask->setContinuation(continuation);
mergeTask->setSecondContinuation(lostTouchTask);
//PxReal dt = mDt;
PxU32 currentIsland = 0;
PxU32 currentBodyIndex = 0;
PxU32 currentArticulation = 0;
PxU32 currentContact = 0;
PxU32 constraintIndex = 0;
const PxU32 minIslandSize = mSolverBatchSize;
const PxU32 islandCount = islandSim.getNbActiveIslands();
const PxU32 articulationBatchSize = mSolverArticBatchSize;
//while(start<sentinel)
while (currentIsland < islandCount)
{
SolverIslandObjectsStep 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.constraintBatchHeaders = mContactConstraintBatchHeaders.begin() + constraintIndex;
objectStarts.tempConstraintDescs = mTempSolverConstraintDescPool.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;
while (nbBodies < minIslandSize && currentIsland < islandCount && nbArticulations < articulationBatchSize)
{
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;
solveIsland(objectStarts, counts,
mKinematicCount + currentBodyIndex, simpleIslandManager, mSolverBodyRemapTable.begin(), mMaterialManager, mOutputIterator,
mergeTask);
currentBodyIndex += nbBodies;
currentArticulation += nbArticulations;
currentContact += nbContactManagers;
constraintIndex += constraintCount;
}
mergeTask->removeReference();
}
void DynamicsTGSContext::prepareBodiesAndConstraints(const SolverIslandObjectsStep& objects,
IG::SimpleIslandManager& islandManager,
IslandContextStep& islandContext)
{
Dy::ThreadContext& mThreadContext = *islandContext.mThreadContext;
mThreadContext.mMaxSolverPositionIterations = 0;
mThreadContext.mMaxSolverVelocityIterations = 0;
mThreadContext.mAxisConstraintCount = 0;
mThreadContext.mContactDescPtr = mThreadContext.contactConstraintDescArray;
mThreadContext.mFrictionDescPtr = mThreadContext.frictionConstraintDescArray.begin();
mThreadContext.mNumDifferentBodyConstraints = 0;
mThreadContext.mNumStaticConstraints = 0;
mThreadContext.mNumSelfConstraints = 0;
mThreadContext.mNumDifferentBodyFrictionConstraints = 0;
mThreadContext.mNumSelfConstraintFrictionBlocks = 0;
mThreadContext.mNumSelfFrictionConstraints = 0;
mThreadContext.numContactConstraintBatches = 0;
mThreadContext.contactDescArraySize = 0;
mThreadContext.motionVelocityArray = objects.motionVelocities;
mThreadContext.mBodyCoreArray = objects.bodyCoreArray;
mThreadContext.mRigidBodyArray = objects.bodies;
mThreadContext.mArticulationArray = objects.articulations;
mThreadContext.bodyRemapTable = objects.bodyRemapTable;
mThreadContext.mNodeIndexArray = objects.nodeIndexArray;
const PxU32 frictionConstraintCount = 0;
mThreadContext.resizeArrays(frictionConstraintCount, islandContext.mCounts.articulations);
PxsBodyCore** PX_RESTRICT bodyArrayPtr = mThreadContext.mBodyCoreArray;
PxsRigidBody** PX_RESTRICT rigidBodyPtr = mThreadContext.mRigidBodyArray;
ArticulationV** PX_RESTRICT articulationPtr = mThreadContext.mArticulationArray;
PxU32* PX_RESTRICT bodyRemapTable = mThreadContext.bodyRemapTable;
PxU32* PX_RESTRICT nodeIndexArray = mThreadContext.mNodeIndexArray;
PxU32 nbIslands = objects.numIslands;
const IG::IslandId* const islandIds = objects.islandIds;
const IG::IslandSim& islandSim = islandManager.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 < (islandContext.mCounts.bodies + mKinematicCount + 1));
rigidBodyPtr[bodyIndex] = rigid;
bodyArrayPtr[bodyIndex] = &rigid->getCore();
nodeIndexArray[bodyIndex] = currentIndex.index();
bodyRemapTable[islandSim.getActiveNodeIndex(currentIndex)] = bodyIndex++;
}
currentIndex = node.mNextNode;
}
}
PxsIndexedContactManager* indexedManagers = objects.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 = islandManager.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)
{
const PxU32 linkId = nodeIndex1.articulationLinkId();
node1.getArticulation()->fillIndexedManager(linkId, indexedManager.articulation0, indexedManager.indexType0);
}
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 < (islandContext.mCounts.bodies + 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)
{
const PxU32 linkId = nodeIndex2.articulationLinkId();
node2.getArticulation()->fillIndexedManager(linkId, indexedManager.articulation1, indexedManager.indexType1);
}
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 < (islandContext.mCounts.bodies + mKinematicCount + 1));
}
}
}
contactEdgeIndex = edge.mNextIslandEdge;
}
}
islandContext.mCounts.contactManagers = currentContactIndex;
}
struct ConstraintLess
{
bool operator()(const PxSolverConstraintDesc& left, const PxSolverConstraintDesc& right) const
{
return reinterpret_cast<Constraint*>(left.constraint)->index > reinterpret_cast<Constraint*>(right.constraint)->index;
}
};
void DynamicsTGSContext::setupDescs(IslandContextStep& mIslandContext, const SolverIslandObjectsStep& mObjects, IG::SimpleIslandManager& mIslandManager,
PxU32* mBodyRemapTable, PxU32 mSolverBodyOffset, PxsContactManagerOutputIterator& outputs)
{
PX_UNUSED(outputs);
ThreadContext& mThreadContext = *mIslandContext.mThreadContext;
PxSolverConstraintDesc* contactDescPtr = mObjects.constraintDescs;
//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);
setDescFromIndices(desc, edgeId, mIslandManager, mBodyRemapTable, mSolverBodyOffset,
mSolverBodyVelPool.begin());
desc.constraint = reinterpret_cast<PxU8*>(constraint);
desc.constraintLengthOver16 = DY_SC_TYPE_RB_1D;
contactDescPtr++;
edgeId = edge.mNextIslandEdge;
}
}
Ps::sort(mObjects.constraintDescs, PxU32(contactDescPtr - mObjects.constraintDescs), ConstraintLess());
if (mIslandContext.mCounts.contactManagers)
{
{
for (PxU32 a = 0; a < mIslandContext.mCounts.contactManagers; ++a)
{
//PxsContactManagerOutput& output = outputs.getContactManager(mObjects.contactManagers[a].contactManager->getWorkUnit().mNpIndex);
//if (output.nbContacts > 0)
{
PxSolverConstraintDesc& desc = *contactDescPtr;
setDescFromIndices(desc, mObjects.contactManagers[a], mSolverBodyOffset, mSolverBodyVelPool.begin());
desc.constraint = reinterpret_cast<PxU8*>(mObjects.contactManagers[a].contactManager);
desc.constraintLengthOver16 = DY_SC_TYPE_RB_CONTACT;
contactDescPtr++;
}
//else
//{
// //Clear friction state!
// mObjects.contactManagers[a].contactManager->getWorkUnit().frictionDataPtr = NULL;
// mObjects.contactManagers[a].contactManager->getWorkUnit().frictionPatchCount = 0;
//}
}
}
}
mThreadContext.contactDescArraySize = PxU32(contactDescPtr - mObjects.constraintDescs);
}
void DynamicsTGSContext::preIntegrateBodies(PxsBodyCore** bodyArray, PxsRigidBody** originalBodyArray,
PxTGSSolverBodyVel* solverBodyVelPool, PxTGSSolverBodyTxInertia* solverBodyTxInertia, PxTGSSolverBodyData* solverBodyDataPool2, PxU32* nodeIndexArray, const PxU32 bodyCount, const PxVec3& gravity, const PxReal dt, PxU32& posIters, PxU32& velIters, PxU32 /*iteration*/)
{
PX_PROFILE_ZONE("PreIntegrate", 0);
PxU32 localMaxPosIter = 0;
PxU32 localMaxVelIter = 0;
for (PxU32 i = 0; i < bodyCount; ++i)
{
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, core.disableGravity!=0);
copyToSolverBodyDataStep(core.linearVelocity, core.angularVelocity, core.inverseMass, core.inverseInertia, core.body2World, core.maxPenBias, core.maxContactImpulse, nodeIndexArray[i],
core.contactReportThreshold, core.maxAngularVelocitySq, core.lockFlags, false,
solverBodyVelPool[i+1], solverBodyTxInertia[i+1], solverBodyDataPool2[i+1]);
}
posIters = localMaxPosIter;
velIters = localMaxVelIter;
}
void DynamicsTGSContext::createSolverConstraints(PxSolverConstraintDesc* contactDescPtr, PxConstraintBatchHeader* headers, const PxU32 nbHeaders,
PxsContactManagerOutputIterator& outputs, Dy::ThreadContext& islandThreadContext, Dy::ThreadContext& threadContext, PxReal stepDt, PxReal totalDt, PxReal invStepDt,
PxU32 /*nbSubsteps*/)
{
PX_UNUSED(totalDt);
//PX_PROFILE_ZONE("CreateConstraints", 0);
PxTransform idt(PxIdentity);
BlockAllocator blockAllocator(islandThreadContext.mConstraintBlockManager, threadContext.mConstraintBlockStream, threadContext.mFrictionPatchStreamPair, threadContext.mConstraintSize);
PxTGSSolverBodyTxInertia* txInertias = mSolverBodyTxInertiaPool.begin();
PxTGSSolverBodyData* solverBodyDatas = mSolverBodyDataPool2.begin();
const PxReal invTotalDt = 1.f / totalDt;
for (PxU32 h = 0; h < nbHeaders; ++h)
{
PxConstraintBatchHeader& hdr = headers[h];
PxU32 startIdx = hdr.startIndex;
PxU32 endIdx = startIdx + hdr.stride;
if (contactDescPtr[startIdx].constraintLengthOver16 == DY_SC_TYPE_RB_CONTACT)
{
PxTGSSolverContactDesc blockDescs[4];
PxsContactManagerOutput* cmOutputs[4];
PxsContactManager* cms[4];
for (PxU32 a = startIdx, i = 0; a < endIdx; ++a, i++)
{
PxSolverConstraintDesc& desc = contactDescPtr[a];
PxsContactManager* cm = reinterpret_cast<PxsContactManager*>(desc.constraint);
PxTGSSolverContactDesc& blockDesc = blockDescs[i];
cms[i] = cm;
PxcNpWorkUnit& unit = cm->getWorkUnit();
PxsContactManagerOutput* cmOutput = &outputs.getContactManager(unit.mNpIndex);
cmOutputs[i] = cmOutput;
PxTGSSolverBodyVel& b0 = *desc.tgsBodyA;
PxTGSSolverBodyVel& b1 = *desc.tgsBodyB;
PxTGSSolverBodyTxInertia& txI0 = txInertias[desc.bodyADataIndex];
PxTGSSolverBodyTxInertia& txI1 = txInertias[desc.bodyBDataIndex];
PxTGSSolverBodyData& data0 = solverBodyDatas[desc.bodyADataIndex];
PxTGSSolverBodyData& data1 = solverBodyDatas[desc.bodyBDataIndex];
blockDesc.body0 = &b0;
blockDesc.body1 = &b1;
PxU8 flags = unit.rigidCore0->mFlags;
if (unit.rigidCore1)
flags |= PxU8(unit.rigidCore1->mFlags);
blockDesc.bodyFrame0 = unit.rigidCore0->body2World;
blockDesc.bodyFrame1 = unit.rigidCore1->body2World;
blockDesc.shapeInteraction = cm->getShapeInteraction();
blockDesc.contactForces = cmOutput->contactForces;
blockDesc.desc = &desc;
blockDesc.body0 = &b0;
blockDesc.body1 = &b1;
blockDesc.body0TxI = &txI0;
blockDesc.body1TxI = &txI1;
blockDesc.bodyData0 = &data0;
blockDesc.bodyData1 = &data1;
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;
if (unit.flags & PxcNpWorkUnitFlag::eARTICULATION_BODY1)
{
//kinematic link
if (desc.linkIndexB == 0xffff)
{
blockDesc.bodyState1 = PxSolverContactDesc::eSTATIC_BODY;
}
else
{
blockDesc.bodyState1 = PxSolverContactDesc::eARTICULATION;
}
}
else
{
blockDesc.bodyState1 = (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 maxImpulse0 = (unit.flags & PxcNpWorkUnitFlag::eARTICULATION_BODY0) ? static_cast<const PxsBodyCore*>(unit.rigidCore0)->maxContactImpulse : data0.maxContactImpulse;
PxReal maxImpulse1 = (unit.flags & PxcNpWorkUnitFlag::eARTICULATION_BODY1) ? static_cast<const PxsBodyCore*>(unit.rigidCore1)->maxContactImpulse : data1.maxContactImpulse;
PxReal dominance0 = unit.dominance0 ? 1.f : 0.f;
PxReal dominance1 = unit.dominance1 ? 1.f : 0.f;
blockDesc.invMassScales.linear0 = blockDesc.invMassScales.angular0 = dominance0;
blockDesc.invMassScales.linear1 = blockDesc.invMassScales.angular1 = dominance1;
blockDesc.restDistance = unit.restDistance;
blockDesc.frictionPtr = unit.frictionDataPtr;
blockDesc.frictionCount = unit.frictionPatchCount;
blockDesc.maxCCDSeparation = PX_MAX_F32;
blockDesc.maxImpulse = PxMin(maxImpulse0, maxImpulse1);
blockDesc.torsionalPatchRadius = unit.mTorsionalPatchRadius;
blockDesc.minTorsionalPatchRadius = unit.mMinTorsionalPatchRadius;
}
SolverConstraintPrepState::Enum buildState = SolverConstraintPrepState::eUNBATCHABLE;
#if PX_USE_BLOCK_SOLVER
if (hdr.stride == 4)
{
buildState = createFinalizeSolverContacts4Step(
cmOutputs,
threadContext,
blockDescs,
invStepDt,
invTotalDt,
mBounceThreshold,
mFrictionOffsetThreshold,
mCorrelationDistance,
mSolverOffsetSlop,
blockAllocator);
}
#endif
if (buildState != SolverConstraintPrepState::eSUCCESS)
{
for (PxU32 a = startIdx, i = 0; a < endIdx; ++a, i++)
{
PxSolverConstraintDesc& desc = contactDescPtr[a];
PxsContactManager* cm = reinterpret_cast<PxsContactManager*>(desc.constraint);
//PxcNpWorkUnit& n = cm->getWorkUnit();
PxsContactManagerOutput& output = *cmOutputs[i];
//PX_ASSERT(output.nbContacts != 0);
createFinalizeSolverContactsStep(blockDescs[i], output, threadContext,
invStepDt, invTotalDt, mBounceThreshold, mFrictionOffsetThreshold, mCorrelationDistance, blockAllocator);
getContactManagerConstraintDesc(output, *cm, desc);
//PX_ASSERT(desc.constraint != NULL);
}
}
for (PxU32 i = 0; i < hdr.stride; ++i)
{
PxsContactManager* cm = cms[i];
PxcNpWorkUnit& unit = cm->getWorkUnit();
unit.frictionDataPtr = blockDescs[i].frictionPtr;
unit.frictionPatchCount = blockDescs[i].frictionCount;
}
}
else if (contactDescPtr[startIdx].constraintLengthOver16 == DY_SC_TYPE_RB_1D)
{
SolverConstraintShaderPrepDesc shaderPrepDescs[4];
PxTGSSolverConstraintPrepDesc prepDescs[4];
for (PxU32 a = startIdx, i = 0; a < endIdx; ++a, i++)
{
SolverConstraintShaderPrepDesc& shaderPrepDesc = shaderPrepDescs[i];
PxTGSSolverConstraintPrepDesc& prepDesc = prepDescs[i];
PxTransform id(PxIdentity);
{
PxSolverConstraintDesc& desc = contactDescPtr[a];
const Constraint* constraint = reinterpret_cast<const Constraint*>(desc.constraint);
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 PxTGSSolverBodyVel* sbody0 = desc.tgsBodyA;
const PxTGSSolverBodyVel* sbody1 = desc.tgsBodyB;
PxTGSSolverBodyTxInertia& txI0 = txInertias[desc.bodyADataIndex];
PxTGSSolverBodyTxInertia& txI1 = txInertias[desc.bodyBDataIndex];
PxTGSSolverBodyData& data0 = solverBodyDatas[desc.bodyADataIndex];
PxTGSSolverBodyData& data1 = solverBodyDatas[desc.bodyBDataIndex];
shaderPrepDesc.constantBlock = constantBlock;
shaderPrepDesc.constantBlockByteSize = constantBlockByteSize;
shaderPrepDesc.constraint = constraint;
shaderPrepDesc.solverPrep = solverPrep;
prepDesc.desc = &desc;
prepDesc.bodyFrame0 = pose0;
prepDesc.bodyFrame1 = pose1;
prepDesc.body0 = sbody0;
prepDesc.body1 = sbody1;
prepDesc.body0TxI = &txI0;
prepDesc.body1TxI = &txI1;
prepDesc.bodyData0 = &data0;
prepDesc.bodyData1 = &data1;
prepDesc.linBreakForce = constraint->linBreakForce;
prepDesc.angBreakForce = constraint->angBreakForce;
prepDesc.writeback = &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.extendedLimits = !!(constraint->flags & PxConstraintFlag::eENABLE_EXTENDED_LIMITS);
prepDesc.minResponseThreshold = constraint->minResponseThreshold;
prepDesc.bodyState0 = desc.linkIndexA == PxSolverConstraintDesc::NO_LINK ? PxSolverContactDesc::eDYNAMIC_BODY : PxSolverContactDesc::eARTICULATION;
prepDesc.bodyState1 = desc.linkIndexB == PxSolverConstraintDesc::NO_LINK ? PxSolverContactDesc::eDYNAMIC_BODY : PxSolverContactDesc::eARTICULATION;
}
}
SolverConstraintPrepState::Enum buildState = SolverConstraintPrepState::eUNBATCHABLE;
#if PX_USE_BLOCK_SOLVER
#if PX_USE_BLOCK_1D
if (hdr.stride == 4)
{
PxU32 totalRows;
buildState = setupSolverConstraintStep4
(shaderPrepDescs, prepDescs, stepDt, totalDt, invStepDt, invTotalDt, totalRows, blockAllocator, mLengthScale);
}
#endif
#endif
if (buildState != SolverConstraintPrepState::eSUCCESS)
{
for (PxU32 a = startIdx, i = 0; a < endIdx; ++a, i++)
{
PxReal clampedInvDt = invStepDt;
SetupSolverConstraintStep(shaderPrepDescs[i], prepDescs[i], blockAllocator, stepDt, totalDt, clampedInvDt, invTotalDt, mLengthScale);
}
}
}
}
}
void solveContactBlock(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertias, const PxReal minPenetration, const PxReal elapsedTime, SolverContext& cache);
void solve1DBlock(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertias, const PxReal minPenetration, const PxReal elapsedTime, SolverContext& cache);
void solveExtContactBlock(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertia, const PxReal minPenetration, const PxReal elapsedTime, SolverContext& cache);
void solveExt1DBlock(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertias, const PxReal minPenetration, const PxReal elapsedTime, SolverContext& cache);
void solveContact4(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* PX_RESTRICT desc, const PxTGSSolverBodyTxInertia* const txInertias,
const PxReal minPenetration, const PxReal elapsedTime, SolverContext& cache);
void solve1D4(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* PX_RESTRICT desc, const PxTGSSolverBodyTxInertia* const txInertias,
const PxReal minPenetration, const PxReal elapsedTime, SolverContext& cache);
TGSSolveBlockMethod g_SolveTGSMethods[] =
{
0,
solveContactBlock, // DY_SC_TYPE_RB_CONTACT
solve1DBlock, // DY_SC_TYPE_RB_1D
solveExtContactBlock, // DY_SC_TYPE_EXT_CONTACT
solveExt1DBlock, // DY_SC_TYPE_EXT_1D
solveContactBlock, // DY_SC_TYPE_STATIC_CONTACT
solveContactBlock, // DY_SC_TYPE_NOFRICTION_RB_CONTACT
solveContact4, // DY_SC_TYPE_BLOCK_RB_CONTACT
solveContact4, // DY_SC_TYPE_BLOCK_STATIC_RB_CONTACT
solve1D4, // DY_SC_TYPE_BLOCK_1D,
};
void writeBackContact(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc, SolverContext* cache);
void writeBack1D(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc, SolverContext* cache);
void writeBackContact4(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* PX_RESTRICT desc, SolverContext* cache);
void writeBack1D4(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* PX_RESTRICT desc, SolverContext* cache);
TGSWriteBackMethod g_WritebackTGSMethods[] =
{
0,
writeBackContact, // DY_SC_TYPE_RB_CONTACT
writeBack1D, // DY_SC_TYPE_RB_1D
writeBackContact, // DY_SC_TYPE_EXT_CONTACT
writeBack1D, // DY_SC_TYPE_EXT_1D
writeBackContact, // DY_SC_TYPE_STATIC_CONTACT
writeBackContact, // DY_SC_TYPE_NOFRICTION_RB_CONTACT
writeBackContact4, // DY_SC_TYPE_BLOCK_RB_CONTACT
writeBackContact4, // DY_SC_TYPE_BLOCK_STATIC_RB_CONTACT
writeBack1D4, // DY_SC_TYPE_BLOCK_1D,
};
void solveConclude1DBlock(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertias, const PxReal elapsedTime, SolverContext& cache);
void solveConcludeContactBlock(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertias, const PxReal elapsedTime, SolverContext& cache);
void solveConcludeContact4(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertias, const PxReal elapsedTime, SolverContext& cache);
void solveConclude1D4(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertias, const PxReal elapsedTime, SolverContext& cache);
void solveConcludeContactExtBlock(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertias, const PxReal elapsedTime, SolverContext& cache);
void solveConclude1DBlockExt(const PxConstraintBatchHeader& hdr, const PxSolverConstraintDesc* desc,
const PxTGSSolverBodyTxInertia* const txInertias, const PxReal elapsedTime, SolverContext& cache);
TGSSolveConcludeMethod g_SolveConcludeTGSMethods[] =
{
0,
solveConcludeContactBlock, // DY_SC_TYPE_RB_CONTACT
solveConclude1DBlock, // DY_SC_TYPE_RB_1D
solveConcludeContactExtBlock, // DY_SC_TYPE_EXT_CONTACT
solveConclude1DBlockExt, // DY_SC_TYPE_EXT_1D
solveConcludeContactBlock, // DY_SC_TYPE_STATIC_CONTACT
solveConcludeContactBlock, // DY_SC_TYPE_NOFRICTION_RB_CONTACT
solveConcludeContact4, // DY_SC_TYPE_BLOCK_RB_CONTACT
solveConcludeContact4, // DY_SC_TYPE_BLOCK_STATIC_RB_CONTACT
solveConclude1D4, // DY_SC_TYPE_BLOCK_1D,
};
void DynamicsTGSContext::solveConstraintsIteration(const PxSolverConstraintDesc* const contactDescPtr, const PxConstraintBatchHeader* const batchHeaders, const PxU32 nbHeaders,
PxReal invStepDt, const PxTGSSolverBodyTxInertia* const solverTxInertia, const PxReal elapsedTime, const PxReal minPenetration, SolverContext& cache)
{
PX_UNUSED(invStepDt);
PX_UNUSED(solverTxInertia);
for (PxU32 h = 0; h < nbHeaders; ++h)
{
const PxConstraintBatchHeader& hdr = batchHeaders[h];
g_SolveTGSMethods[hdr.constraintType](hdr, contactDescPtr, solverTxInertia, minPenetration, elapsedTime, cache);
}
}
void DynamicsTGSContext::parallelSolveConstraints(const PxSolverConstraintDesc* const contactDescPtr, const PxConstraintBatchHeader* const batchHeaders, const PxU32 nbHeaders,
PxTGSSolverBodyTxInertia* solverTxInertia, const PxReal elapsedTime, const PxReal minPenetration,
SolverContext& cache)
{
PX_UNUSED(solverTxInertia);
for (PxU32 h = 0; h < nbHeaders; ++h)
{
const PxConstraintBatchHeader& hdr = batchHeaders[h];
g_SolveTGSMethods[hdr.constraintType](hdr, contactDescPtr, solverTxInertia, minPenetration, elapsedTime, cache);
}
}
void DynamicsTGSContext::writebackConstraintsIteration(const PxConstraintBatchHeader* const hdrs, const PxSolverConstraintDesc* const contactDescPtr, const PxU32 nbHeaders)
{
PX_PROFILE_ZONE("Writeback", 0);
for (PxU32 h = 0; h < nbHeaders; ++h)
{
const PxConstraintBatchHeader& hdr = hdrs[h];
g_WritebackTGSMethods[hdr.constraintType](hdr, contactDescPtr, NULL);
}
}
void DynamicsTGSContext::parallelWritebackConstraintsIteration(const PxSolverConstraintDesc* const contactDescPtr, const PxConstraintBatchHeader* const batchHeaders, const PxU32 nbHeaders)
{
for (PxU32 h = 0; h < nbHeaders; ++h)
{
const PxConstraintBatchHeader& hdr = batchHeaders[h];
g_WritebackTGSMethods[hdr.constraintType](hdr, contactDescPtr, NULL);
}
}
void DynamicsTGSContext::solveConcludeConstraintsIteration(const PxSolverConstraintDesc* const contactDescPtr,
const PxConstraintBatchHeader* const batchHeaders, const PxU32 nbHeaders, PxTGSSolverBodyTxInertia* solverTxInertia,
const PxReal elapsedTime, SolverContext& cache)
{
for (PxU32 h = 0; h < nbHeaders; ++h)
{
const PxConstraintBatchHeader& hdr = batchHeaders[h];
g_SolveConcludeTGSMethods[hdr.constraintType](hdr, contactDescPtr, solverTxInertia, elapsedTime, cache);
}
}
void integrateCoreStep(PxTGSSolverBodyVel& vel, PxTGSSolverBodyTxInertia& txInertia, const PxF32 dt)
{
PxU32 lockFlags = vel.lockFlags;
if (lockFlags)
{
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_X)
vel.linearVelocity.x = 0.f;
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Y)
vel.linearVelocity.y = 0.f;
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Z)
vel.linearVelocity.z = 0.f;
//The angular velocity should be 0 because it is now impossible to make it rotate around that axis!
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_X)
vel.angularVelocity.x = 0.f;
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y)
vel.angularVelocity.y = 0.f;
if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z)
vel.angularVelocity.z = 0.f;
}
PxVec3 linearMotionVel = vel.linearVelocity;
const PxVec3 delta = linearMotionVel * dt;
PxVec3 unmolestedAngVel = vel.angularVelocity;
PxVec3 angularMotionVel = txInertia.sqrtInvInertia * vel.angularVelocity;
PxReal w2 = angularMotionVel.magnitudeSquared();
txInertia.deltaBody2World.p += delta;
PX_ASSERT(txInertia.deltaBody2World.p.isFinite());
// Integrate the rotation using closed form quaternion integrator
if (w2 != 0.0f)
{
PxReal w = PxSqrt(w2);
//KS - we allow a little bit more angular velocity than the default
//maxAngVel member otherwise the simulation feels a little flimsy
/*const PxReal maxW = PxMax(50.f, vel.maxAngVel);
if (w > maxW)
{
PxReal ratio = maxW / w;
vel.angularVelocity *= ratio;
}*/
const PxReal v = dt * w * 0.5f;
PxReal s, q;
Ps::sincos(v, s, q);
s /= w;
const PxVec3 pqr = angularMotionVel * s;
const PxQuat quatVel(pqr.x, pqr.y, pqr.z, 0);
PxQuat result = quatVel * txInertia.deltaBody2World.q;
result += txInertia.deltaBody2World.q * q;
txInertia.deltaBody2World.q = result.getNormalized();
PX_ASSERT(txInertia.deltaBody2World.q.isSane());
PX_ASSERT(txInertia.deltaBody2World.q.isFinite());
//Accumulate the angular rotations in a space we can project the angular constraints to
}
vel.deltaAngDt += unmolestedAngVel * dt;
vel.deltaLinDt += delta;
/*solverBodyData.body2World = txInertia.body2World;
solverBodyData.deltaLinDt = vel.deltaLinDt;
solverBodyData.deltaAngDt = vel.deltaAngDt;*/
}
void DynamicsTGSContext::integrateBodies(const SolverIslandObjectsStep& /*objects*/,
const PxU32 count, PxTGSSolverBodyVel* PX_RESTRICT vels, PxTGSSolverBodyTxInertia* PX_RESTRICT txInertias, const PxTGSSolverBodyData*const PX_RESTRICT /*bodyDatas*/, PxReal dt)
{
for (PxU32 k = 0; k < count; k++)
{
integrateCoreStep(vels[k+1], txInertias[k+1], dt);
}
}
void DynamicsTGSContext::parallelIntegrateBodies(PxTGSSolverBodyVel* vels, PxTGSSolverBodyTxInertia* txInertias,
const PxTGSSolverBodyData* const /*bodyDatas*/, const PxU32 count, PxReal dt)
{
for (PxU32 k = 0; k < count; k++)
{
integrateCoreStep(vels[k+1], txInertias[k+1], dt);
}
}
void DynamicsTGSContext::copyBackBodies(const SolverIslandObjectsStep& objects,
PxTGSSolverBodyVel* vels, PxTGSSolverBodyTxInertia* txInertias,
PxTGSSolverBodyData* solverBodyDatas, PxReal invDt, IG::IslandSim& islandSim,
PxU32 startIdx, PxU32 endIdx)
{
for (PxU32 k = startIdx; k < endIdx; k++)
{
//PxStepSolverBody& solverBodyData = solverBodyData2[k + 1];
PxTGSSolverBodyVel& solverBodyVel = vels[k + 1];
PxTGSSolverBodyTxInertia& solverBodyTxI = txInertias[k + 1];
PxTGSSolverBodyData& solverBodyData = solverBodyDatas[k + 1];
Cm::SpatialVector motionVel(solverBodyVel.deltaLinDt*invDt, solverBodyTxI.sqrtInvInertia*(solverBodyVel.deltaAngDt*invDt));
PxsRigidBody& rBody = *objects.bodies[k];
PxsBodyCore& core = rBody.getCore();
rBody.mLastTransform = core.body2World;
core.body2World.q = (solverBodyTxI.deltaBody2World.q * core.body2World.q).getNormalized();
core.body2World.p = solverBodyTxI.deltaBody2World.p;
core.linearVelocity = (solverBodyVel.linearVelocity);
core.angularVelocity = solverBodyTxI.sqrtInvInertia*(solverBodyVel.angularVelocity);
bool hasStaticTouch = islandSim.getIslandStaticTouchCount(IG::NodeIndex(solverBodyData.nodeIndex)) != 0;
sleepCheck(&rBody, mDt, invDt, mEnableStabilization, mUseAdaptiveForce, motionVel,
hasStaticTouch);
}
}
void DynamicsTGSContext::stepArticulations(Dy::ThreadContext& threadContext, const PxsIslandIndices& counts, PxReal dt)
{
for (PxU32 a = 0; a < counts.articulations; ++a)
{
ArticulationSolverDesc& d = threadContext.getArticulations()[a];
//if(d.articulation->numTotalConstraints > 0)
//d.articulation->solveInternalConstraints(dt, 1.f / dt, threadContext.mZVector.begin(), threadContext.mDeltaV.begin(), false);
ArticulationPImpl::updateDeltaMotion(d, dt, threadContext.mDeltaV.begin());
}
}
void DynamicsTGSContext::updateArticulations(Dy::ThreadContext& threadContext, const PxU32 startIdx, const PxU32 endIdx, PxReal dt)
{
for (PxU32 a = startIdx; a < endIdx; ++a)
{
ArticulationSolverDesc& d = threadContext.getArticulations()[a];
ArticulationPImpl::updateBodiesTGS(d, dt);
}
}
class ArticulationTask : public Cm::Task
{
Dy::DynamicsTGSContext& mContext;
ArticulationSolverDesc* mDescs;
PxU32 mNbDescs;
PxVec3 mGravity;
PxReal mDt;
PX_NOCOPY(ArticulationTask)
public:
static const PxU32 MaxNbPerTask = 32;
ArticulationTask(Dy::DynamicsTGSContext& context, ArticulationSolverDesc* descs, const PxU32 nbDescs, const PxVec3& gravity,
PxReal dt, PxU64 contextId) : Cm::Task(contextId), mContext(context),
mDescs(descs), mNbDescs(nbDescs), mGravity(gravity), mDt(dt)
{
}
virtual const char* getName() const { return "ArticulationTask"; }
virtual void runInternal()
{
PxU32 maxLinks = 0;
for (PxU32 i = 0; i < mNbDescs; i++)
{
maxLinks = PxMax(maxLinks, PxU32(mDescs[i].linkCount));
}
Dy::ThreadContext& threadContext = *mContext.getThreadContext();
threadContext.mZVector.forceSize_Unsafe(0);
threadContext.mZVector.reserve(maxLinks);
threadContext.mZVector.forceSize_Unsafe(maxLinks);
threadContext.mDeltaV.forceSize_Unsafe(0);
threadContext.mDeltaV.reserve(maxLinks);
threadContext.mDeltaV.forceSize_Unsafe(maxLinks);
for (PxU32 a = 0; a < mNbDescs; ++a)
{
ArticulationPImpl::computeUnconstrainedVelocitiesTGS(mDescs[a], mDt,
mGravity, getContextId(), threadContext.mZVector.begin(), threadContext.mDeltaV.begin());
}
mContext.putThreadContext(&threadContext);
}
};
void DynamicsTGSContext::setupArticulations(IslandContextStep& islandContext, const PxVec3& gravity, const PxReal dt, PxU32& posIters,
PxU32& velIters, PxBaseTask* continuation)
{
Dy::ArticulationV** articulations = islandContext.mThreadContext->mArticulationArray;
PxU32 nbArticulations = islandContext.mCounts.articulations;
PxU32 maxVelIters = 0;
PxU32 maxPosIters = 0;
PxU32 maxArticulationLength = 0;
PxU32 maxSolverArticLength = 0;
//PxU32 startIdx = 0;
for (PxU32 a = 0; a < nbArticulations; a+= ArticulationTask::MaxNbPerTask)
{
const PxU32 endIdx = PxMin(nbArticulations, a + ArticulationTask::MaxNbPerTask);
for (PxU32 b = a; b < endIdx; ++b)
{
ArticulationSolverDesc& desc = islandContext.mThreadContext->getArticulations()[b];
articulations[b]->getSolverDesc(desc);
maxArticulationLength = PxMax(maxArticulationLength, PxU32(desc.totalDataSize));
maxSolverArticLength = PxMax(maxSolverArticLength, PxU32(desc.solverDataSize));
const PxU16 iterWord = articulations[b]->getIterationCounts();
maxVelIters = PxMax<PxU32>(PxU32(iterWord >> 8), maxVelIters);
maxPosIters = PxMax<PxU32>(PxU32(iterWord & 0xff), maxPosIters);
}
Dy::ThreadContext* threadContext = islandContext.mThreadContext;
ArticulationTask* task = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(ArticulationTask)), ArticulationTask)(*this, threadContext->getArticulations().begin() + a,
endIdx - a, gravity, dt, getContextId());
task->setContinuation(continuation);
task->removeReference();
//startIdx += descCount;
}
velIters = PxMax(maxVelIters, velIters);
posIters = PxMax(maxPosIters, posIters);
}
PxU32 DynamicsTGSContext::setupArticulationInternalConstraints(IslandContextStep& islandContext, PxReal dt, PxReal invStepDt, PxSolverConstraintDesc* constraintDescs)
{
Dy::ArticulationV** articulations = islandContext.mThreadContext->mArticulationArray;
PxU32 nbArticulations = islandContext.mCounts.articulations;
ThreadContext* threadContext = getThreadContext();
threadContext->mConstraintBlockStream.reset();
PxU32 startIdx = 0;
PxU32 totalDescCount = 0;
Cm::SpatialVectorF Z[64];
for (PxU32 a = 0; a < nbArticulations; ++a)
{
ArticulationSolverDesc& desc = islandContext.mThreadContext->getArticulations()[a];
articulations[a]->getSolverDesc(desc);
PxU32 acCount;
PxU32 descCount = ArticulationPImpl::setupSolverInternalConstraintsTGS(desc, threadContext->mConstraintBlockStream, constraintDescs+startIdx,
islandContext.mStepDt, invStepDt, dt, acCount, islandContext.mThreadContext->mConstraintBlockManager, Z);
desc.numInternalConstraints = Ps::to8(descCount);
totalDescCount += descCount;
startIdx += DY_ARTICULATION_MAX_SIZE;
}
putThreadContext(threadContext);
islandContext.mThreadContext->contactDescArraySize += totalDescCount;
return totalDescCount;
}
class SetupDescsTask : public Cm::Task
{
Dy::IslandContextStep& mIslandContext;
const SolverIslandObjectsStep& mObjects;
IG::SimpleIslandManager& mIslandManager;
PxU32* mBodyRemapTable;
PxU32 mSolverBodyOffset;
PxsContactManagerOutputIterator& mOutputs;
DynamicsTGSContext& mContext;
PX_NOCOPY(SetupDescsTask)
public:
SetupDescsTask(IslandContextStep& islandContext, const SolverIslandObjectsStep& objects, IG::SimpleIslandManager& islandManager,
PxU32* bodyRemapTable, PxU32 solverBodyOffset, PxsContactManagerOutputIterator& outputs, DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mIslandContext(islandContext), mObjects(objects), mIslandManager(islandManager), mBodyRemapTable(bodyRemapTable), mSolverBodyOffset(solverBodyOffset),
mOutputs(outputs), mContext(context)
{
}
virtual const char* getName() const { return "SetupDescsTask"; }
virtual void runInternal()
{
mContext.setupDescs(mIslandContext, mObjects, mIslandManager, mBodyRemapTable, mSolverBodyOffset, mOutputs);
mIslandContext.mArticulationOffset = mIslandContext.mThreadContext->contactDescArraySize;
}
};
class PreIntegrateParallelTask : public Cm::Task
{
PxsBodyCore** mBodyArray;
PxsRigidBody** mOriginalBodyArray;
PxTGSSolverBodyVel* mSolverBodyVelPool;
PxTGSSolverBodyTxInertia* mSolverBodyTxInertia;
PxTGSSolverBodyData* mSolverBodyDataPool2;
PxU32* mNodeIndexArray;
const PxU32 mBodyCount;
const PxVec3& mGravity;
const PxReal mDt;
PxU32& mPosIters;
PxU32& mVelIters;
DynamicsTGSContext& mContext;
PX_NOCOPY(PreIntegrateParallelTask)
public:
PreIntegrateParallelTask(PxsBodyCore** bodyArray, PxsRigidBody** originalBodyArray,
PxTGSSolverBodyVel* solverBodyVelPool, PxTGSSolverBodyTxInertia* solverBodyTxInertia, PxTGSSolverBodyData* solverBodyDataPool2,
PxU32* nodeIndexArray, const PxU32 bodyCount, const PxVec3& gravity, const PxReal dt, PxU32& posIters, PxU32& velIters,
DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mBodyArray(bodyArray), mOriginalBodyArray(originalBodyArray), mSolverBodyVelPool(solverBodyVelPool),
mSolverBodyTxInertia(solverBodyTxInertia), mSolverBodyDataPool2(solverBodyDataPool2), mNodeIndexArray(nodeIndexArray),
mBodyCount(bodyCount), mGravity(gravity), mDt(dt), mPosIters(posIters), mVelIters(velIters), mContext(context)
{
}
virtual const char* getName() const { return "PreIntegrateParallelTask"; }
virtual void runInternal()
{
PxU32 posIters = 0;
PxU32 velIters = 0;
mContext.preIntegrateBodies(mBodyArray, mOriginalBodyArray, mSolverBodyVelPool, mSolverBodyTxInertia, mSolverBodyDataPool2, mNodeIndexArray, mBodyCount, mGravity, mDt, posIters, velIters, 0);
Ps::atomicMax(reinterpret_cast<PxI32*>(&mPosIters), PxI32(posIters));
Ps::atomicMax(reinterpret_cast<PxI32*>(&mVelIters), PxI32(velIters));
}
};
class PreIntegrateTask : public Cm::Task
{
PxsBodyCore** mBodyArray;
PxsRigidBody** mOriginalBodyArray;
PxTGSSolverBodyVel* mSolverBodyVelPool;
PxTGSSolverBodyTxInertia* mSolverBodyTxInertia;
PxTGSSolverBodyData* mSolverBodyDataPool2;
PxU32* mNodeIndexArray;
const PxU32 mBodyCount;
const PxVec3& mGravity;
const PxReal mDt;
PxU32& mPosIters;
PxU32& mVelIters;
DynamicsTGSContext& mContext;
PX_NOCOPY(PreIntegrateTask)
public:
PreIntegrateTask(PxsBodyCore** bodyArray, PxsRigidBody** originalBodyArray,
PxTGSSolverBodyVel* solverBodyVelPool, PxTGSSolverBodyTxInertia* solverBodyTxInertia, PxTGSSolverBodyData* solverBodyDataPool2,
PxU32* nodeIndexArray, const PxU32 bodyCount, const PxVec3& gravity, const PxReal dt, PxU32& posIters, PxU32& velIters,
DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mBodyArray(bodyArray), mOriginalBodyArray(originalBodyArray), mSolverBodyVelPool(solverBodyVelPool),
mSolverBodyTxInertia(solverBodyTxInertia), mSolverBodyDataPool2(solverBodyDataPool2), mNodeIndexArray(nodeIndexArray),
mBodyCount(bodyCount), mGravity(gravity), mDt(dt), mPosIters(posIters), mVelIters(velIters), mContext(context)
{
}
virtual const char* getName() const { return "PreIntegrateTask"; }
virtual void runInternal()
{
const PxU32 BodiesPerTask = 512;
if (mBodyCount <= BodiesPerTask)
{
PxU32 posIters = 0;
PxU32 velIters = 0;
mContext.preIntegrateBodies(mBodyArray, mOriginalBodyArray, mSolverBodyVelPool, mSolverBodyTxInertia, mSolverBodyDataPool2, mNodeIndexArray, mBodyCount, mGravity, mDt, posIters, velIters, 0);
Ps::atomicMax(reinterpret_cast<PxI32*>(&mPosIters), PxI32(posIters));
Ps::atomicMax(reinterpret_cast<PxI32*>(&mVelIters), PxI32(velIters));
}
else
{
for (PxU32 i = 0; i < mBodyCount; i += BodiesPerTask)
{
const PxU32 nbToProcess = PxMin(mBodyCount - i, BodiesPerTask);
PreIntegrateParallelTask* task = PX_PLACEMENT_NEW(mContext.getTaskPool().allocate(sizeof(PreIntegrateParallelTask)), PreIntegrateParallelTask)
(mBodyArray+i, mOriginalBodyArray+i, mSolverBodyVelPool+i, mSolverBodyTxInertia+i, mSolverBodyDataPool2+i,mNodeIndexArray+i,
nbToProcess, mGravity, mDt, mPosIters, mVelIters, mContext);
task->setContinuation(mCont);
task->removeReference();
}
}
}
};
class SetStepperTask : public Cm::Task
{
Dy::IslandContextStep& mIslandContext;
Dy::DynamicsTGSContext& mContext;
PxBaseTask* mAdditionalContinuation;
PX_NOCOPY(SetStepperTask)
public:
SetStepperTask(Dy::IslandContextStep& islandContext,
DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mIslandContext(islandContext), mContext(context),
mAdditionalContinuation(NULL)
{
}
virtual const char* getName() const { return "SetStepperTask"; }
void setAdditionalContinuation(PxBaseTask* cont)
{
mAdditionalContinuation = cont;
cont->addReference();
}
virtual void runInternal()
{
PxReal dt = mContext.getDt();
//ML: TGS can't work well with high velocity iteration counts, so we should limit the velocity iteration counts to be DY_MAX_ITERATION_COUNT. However,
//we should put the extra iterations to the position iteration count so the users will see some behaviour improvements
const PxU32 newVelIters = PxMin(mIslandContext.mVelIters, PxU32(DY_MAX_VELOCITY_COUNT));
const PxU32 remainVelIters = mIslandContext.mVelIters - newVelIters;
mIslandContext.mVelIters = newVelIters;
mIslandContext.mPosIters = mIslandContext.mPosIters + remainVelIters;
mIslandContext.mStepDt = dt / PxReal(mIslandContext.mPosIters);
mIslandContext.mInvStepDt = 1.f/mIslandContext.mStepDt;//PxMin(1000.f, 1.f / mIslandContext.mStepDt);
}
virtual void release()
{
Cm::Task::release();
mAdditionalContinuation->removeReference();
}
};
class SetupArticulationTask : public Cm::Task
{
IslandContextStep& mIslandContext;
const PxVec3& mGravity;
const PxReal mDt;
PxU32& mPosIters;
PxU32& mVelIters;
DynamicsTGSContext& mContext;
PX_NOCOPY(SetupArticulationTask)
public:
SetupArticulationTask(IslandContextStep& islandContext, const PxVec3& gravity, const PxReal dt, PxU32& posIters,
PxU32& velIters, DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mIslandContext(islandContext), mGravity(gravity), mDt(dt), mPosIters(posIters), mVelIters(velIters), mContext(context)
{
}
virtual const char* getName() const { return "SetupArticulationTask"; }
virtual void runInternal()
{
PxU32 posIters = 0, velIters = 0;
mContext.setupArticulations(mIslandContext, mGravity, mDt, posIters, velIters, mCont);
Ps::atomicMax(reinterpret_cast<PxI32*>(&mPosIters), PxI32(posIters));
Ps::atomicMax(reinterpret_cast<PxI32*>(&mVelIters), PxI32(velIters));
}
};
class SetupArticulationInternalConstraintsTask : public Cm::Task
{
IslandContextStep& mIslandContext;
const PxReal mDt;
const PxReal mInvDt;
PxSolverConstraintDesc* mConstraintDescs;
DynamicsTGSContext& mContext;
PX_NOCOPY(SetupArticulationInternalConstraintsTask)
public:
SetupArticulationInternalConstraintsTask(IslandContextStep& islandContext, PxReal dt, PxReal invDt, PxSolverConstraintDesc* constraintDescs, DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mIslandContext(islandContext), mDt(dt), mInvDt(invDt), mConstraintDescs(constraintDescs), mContext(context)
{
}
virtual const char* getName() const { return "SetupArticulationInternalConstraintsTask"; }
virtual void runInternal()
{
mContext.setupArticulationInternalConstraints(mIslandContext, mDt, mIslandContext.mInvStepDt, mConstraintDescs + mIslandContext.mArticulationOffset);
}
};
class SetupSolverConstraintsSubTask : public Cm::Task
{
PxSolverConstraintDesc* mContactDescPtr;
PxConstraintBatchHeader* mHeaders;
const PxU32 mNbHeaders;
PxsContactManagerOutputIterator& mOutputs;
PxReal mStepDt;
PxReal mTotalDt;
PxReal mInvStepDt;
PxReal mInvDtTotal;
PxU32 mNbSubsteps;
DynamicsTGSContext& mContext;
ThreadContext& mIslandThreadContext;
PX_NOCOPY(SetupSolverConstraintsSubTask)
public:
static const PxU32 MaxPerTask = 64;
SetupSolverConstraintsSubTask(PxSolverConstraintDesc* contactDescPtr, PxConstraintBatchHeader* headers, const PxU32 nbHeaders,
PxsContactManagerOutputIterator& outputs, PxReal stepDt, PxReal totalDt, PxReal invStepDt, PxReal invDtTotal, PxU32 nbSubsteps, ThreadContext& islandThreadContext, DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mContactDescPtr(contactDescPtr), mHeaders(headers), mNbHeaders(nbHeaders), mOutputs(outputs), mStepDt(stepDt), mTotalDt(totalDt), mInvStepDt(invStepDt),
mInvDtTotal(invDtTotal), mNbSubsteps(nbSubsteps), mContext(context), mIslandThreadContext(islandThreadContext)
{
}
virtual const char* getName() const { return "SetupSolverConstraintsSubTask"; }
virtual void runInternal()
{
ThreadContext* tempContext = mContext.getThreadContext();
tempContext->mConstraintBlockStream.reset();
mContext.createSolverConstraints(mContactDescPtr, mHeaders, mNbHeaders, mOutputs, mIslandThreadContext, *tempContext, mStepDt, mTotalDt, mInvStepDt,
mNbSubsteps);
mContext.putThreadContext(tempContext);
}
};
class PxsCreateArticConstraintsSubTask : public Cm::Task
{
PxsCreateArticConstraintsSubTask& operator=(const PxsCreateArticConstraintsSubTask&);
public:
static const PxU32 NbArticsPerTask = 64;
PxsCreateArticConstraintsSubTask(Dy::ArticulationV** articulations, const PxU32 nbArticulations,
PxTGSSolverBodyData* solverBodyData, PxTGSSolverBodyTxInertia* solverBodyTxInertia,
ThreadContext& threadContext, DynamicsTGSContext& context, PxsContactManagerOutputIterator& outputs,
Dy::IslandContextStep& islandContext) :
Cm::Task(context.getContextId()),
mArticulations(articulations),
mNbArticulations(nbArticulations),
mSolverBodyData(solverBodyData),
mSolverBodyTxInertia(solverBodyTxInertia),
mThreadContext(threadContext), mDynamicsContext(context),
mOutputs(outputs),
mIslandContext(islandContext)
{}
virtual void runInternal()
{
const PxReal correlationDist = mDynamicsContext.getCorrelationDistance();
const PxReal bounceThreshold = mDynamicsContext.getBounceThreshold();
const PxReal frictionOffsetThreshold = mDynamicsContext.getFrictionOffsetThreshold();
const PxReal dt = mDynamicsContext.getDt();
const PxReal invDt = PxMin(mDynamicsContext.getMaxBiasCoefficient(), mDynamicsContext.getInvDt());
ThreadContext* threadContext = mDynamicsContext.getThreadContext();
threadContext->mConstraintBlockStream.reset(); //ensure there's no left-over memory that belonged to another island
/*threadContext->mZVector.forceSize_Unsafe(0);
threadContext->mZVector.reserve(mThreadContext.mMaxArticulationLinks);
threadContext->mZVector.forceSize_Unsafe(mThreadContext.mMaxArticulationLinks);*/
for (PxU32 i = 0; i < mNbArticulations; ++i)
{
mArticulations[i]->prepareStaticConstraintsTGS(mIslandContext.mStepDt, dt, mIslandContext.mInvStepDt, invDt, mOutputs, *threadContext, correlationDist, bounceThreshold, frictionOffsetThreshold,
mSolverBodyData, mSolverBodyTxInertia, mThreadContext.mConstraintBlockManager, mDynamicsContext.getConstraintWriteBackPool().begin(),
mIslandContext.mPosIters, mDynamicsContext.getLengthScale());
}
mDynamicsContext.putThreadContext(threadContext);
}
virtual const char* getName() const
{
return "PxsDynamics.PxsCreateArticConstraintsSubTask";
}
public:
Dy::ArticulationV** mArticulations;
PxU32 mNbArticulations;
PxTGSSolverBodyData* mSolverBodyData;
PxTGSSolverBodyTxInertia* mSolverBodyTxInertia;
ThreadContext& mThreadContext;
DynamicsTGSContext& mDynamicsContext;
PxsContactManagerOutputIterator& mOutputs;
IslandContextStep& mIslandContext;
};
class SetupSolverConstraintsTask : public Cm::Task
{
IslandContextStep& mIslandContext;
PxSolverConstraintDesc* mContactDescPtr;
PxsContactManagerOutputIterator& mOutputs;
Dy::ThreadContext& mThreadContext;
PxReal mTotalDt;
DynamicsTGSContext& mContext;
PX_NOCOPY(SetupSolverConstraintsTask)
public:
SetupSolverConstraintsTask(IslandContextStep& islandContext, PxSolverConstraintDesc* contactDescPtr,
PxsContactManagerOutputIterator& outputs, Dy::ThreadContext& threadContext, PxReal totalDt, DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mIslandContext(islandContext), mContactDescPtr(contactDescPtr), mOutputs(outputs), mThreadContext(threadContext),
mTotalDt(totalDt), mContext(context)
{
}
virtual const char* getName() const { return "SetupSolverConstraintsTask"; }
virtual void runInternal()
{
Dy::ThreadContext& threadContext = *mIslandContext.mThreadContext;
const PxU32 nbBatches = threadContext.numContactConstraintBatches;
PxConstraintBatchHeader* hdr = mIslandContext.mObjects.constraintBatchHeaders;
//for (PxU32 a = 0; a < mIslandContext.mArticulationOffset; a += SetupSolverConstraintsSubTask::MaxPerTask)
for (PxU32 a = 0; a < nbBatches; a += SetupSolverConstraintsSubTask::MaxPerTask)
{
const PxU32 nbConstraints = PxMin(nbBatches - a, SetupSolverConstraintsSubTask::MaxPerTask);
SetupSolverConstraintsSubTask* task = PX_PLACEMENT_NEW(mContext.mTaskPool.allocate(sizeof(SetupSolverConstraintsSubTask)), SetupSolverConstraintsSubTask)
(mContactDescPtr, hdr + a, nbConstraints, mOutputs, mIslandContext.mStepDt, mTotalDt, mIslandContext.mInvStepDt, mContext.mInvDt, mIslandContext.mPosIters, mThreadContext, mContext);
task->setContinuation(mCont);
task->removeReference();
}
const PxU32 articCount = mIslandContext.mCounts.articulations;
for (PxU32 i = 0; i < articCount; i += PxsCreateArticConstraintsSubTask::NbArticsPerTask)
{
const PxU32 nbToProcess = PxMin(articCount - i, PxsCreateArticConstraintsSubTask::NbArticsPerTask);
PxsCreateArticConstraintsSubTask* task = PX_PLACEMENT_NEW(mContext.getTaskPool().allocate(sizeof(PxsCreateArticConstraintsSubTask)), PxsCreateArticConstraintsSubTask)
(mThreadContext.mArticulationArray + i, nbToProcess, mContext.mSolverBodyDataPool2.begin(), mContext.mSolverBodyTxInertiaPool.begin(), mThreadContext, mContext, mOutputs,
mIslandContext);
task->setContinuation(mCont);
task->removeReference();
}
}
};
static bool isArticulationConstraint(PxSolverConstraintDesc& desc)
{
return desc.linkIndexA != PxSolverConstraintDesc::NO_LINK ||
desc.linkIndexB != PxSolverConstraintDesc::NO_LINK;
}
class PartitionTask : public Cm::Task
{
IslandContextStep& mIslandContext;
PxSolverConstraintDesc* mContactDescPtr;
PxTGSSolverBodyVel* mSolverBodyData;
Dy::ThreadContext& mThreadContext;
DynamicsTGSContext& mContext;
PX_NOCOPY(PartitionTask)
public:
PartitionTask(IslandContextStep& islandContext, PxSolverConstraintDesc* contactDescPtr, PxTGSSolverBodyVel* solverBodyData,
Dy::ThreadContext& threadContext, DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mIslandContext(islandContext), mContactDescPtr(contactDescPtr), mSolverBodyData(solverBodyData), mThreadContext(threadContext),
mContext(context)
{
}
virtual const char* getName() const { return "PartitionTask"; }
virtual void runInternal()
{
ArticulationSolverDesc* artics = mThreadContext.getArticulations().begin();
if (mIslandContext.mCounts.articulations)
{
PxU32 nbArticConstraints = artics[0].numInternalConstraints + mIslandContext.mArticulationOffset;
PxSolverConstraintDesc* currDesc = mContactDescPtr;
for (PxU32 a = 1, startIdx = mIslandContext.mArticulationOffset+DY_ARTICULATION_MAX_SIZE; a < mIslandContext.mCounts.articulations; ++a, startIdx += DY_ARTICULATION_MAX_SIZE)
{
//Compact pairs...
const PxU32 nbInternalConstraints = artics[a].numInternalConstraints;
const PxU32 endIdx = startIdx + nbInternalConstraints;
for (PxU32 b = startIdx; b < endIdx; ++b)
{
currDesc[nbArticConstraints++] = currDesc[b];
}
}
}
PxU32 totalDescCount = mThreadContext.contactDescArraySize;
mThreadContext.mConstraintsPerPartition.forceSize_Unsafe(0);
mThreadContext.mConstraintsPerPartition.resize(1);
mThreadContext.mConstraintsPerPartition[0] = 0;
//TGSConstraintPartitionArgs args;
//args.enhancedDeterminism = false;
//args.mBodies = mSolverBodyData;
//args.mArticulationPtrs = artics;
//args.mContactConstraintDescriptors = mContactDescPtr;
//args.mNumArticulationPtrs = mThreadContext.getArticulations().size();
//args.mNumBodies = mIslandContext.mCounts.bodies;
//args.mNumContactConstraintDescriptors = totalDescCount;
//args.mOrderedContactConstraintDescriptors = mIslandContext.mObjects.orderedConstraintDescs;
//args.mTempContactConstraintDescriptors = mIslandContext.mObjects.tempConstraintDescs;
//args.mNumDifferentBodyConstraints = args.mNumSelfConstraints = args.mNumSelfConstraintBlocks = 0;
//args.mConstraintsPerPartition = &mThreadContext.mConstraintsPerPartition;
//args.mBitField = &mThreadContext.mPartitionNormalizationBitmap;
////Partition constraints
//mThreadContext.mMaxPartitions = partitionContactConstraintsStep(args);
//mThreadContext.mNumDifferentBodyConstraints = args.mNumDifferentBodyConstraints;
//mThreadContext.mNumSelfConstraints = args.mNumSelfConstraints;
ConstraintPartitionArgs args;
args.mBodies = reinterpret_cast<PxU8*>(mSolverBodyData);
args.mStride = sizeof(PxTGSSolverBodyVel);
args.mArticulationPtrs = artics;
args.mContactConstraintDescriptors = mContactDescPtr;
args.mNumArticulationPtrs = mThreadContext.getArticulations().size();
args.mNumBodies = mIslandContext.mCounts.bodies;
args.mNumContactConstraintDescriptors = totalDescCount;
args.mOrderedContactConstraintDescriptors = mIslandContext.mObjects.orderedConstraintDescs;
args.mTempContactConstraintDescriptors = mIslandContext.mObjects.tempConstraintDescs;
args.mNumDifferentBodyConstraints = args.mNumSelfConstraints = args.mNumStaticConstraints = 0;
args.mConstraintsPerPartition = &mThreadContext.mConstraintsPerPartition;
args.mBitField = &mThreadContext.mPartitionNormalizationBitmap;
args.enhancedDeterminism = false;
mThreadContext.mMaxPartitions = partitionContactConstraints(args);
mThreadContext.mNumDifferentBodyConstraints = args.mNumDifferentBodyConstraints;
mThreadContext.mNumSelfConstraints = args.mNumSelfConstraints;
mThreadContext.mNumStaticConstraints = args.mNumStaticConstraints;
{
PxU32 descCount = mThreadContext.mNumDifferentBodyConstraints;
PxU32 selfConstraintDescCount = mThreadContext.contactDescArraySize - (mThreadContext.mNumDifferentBodyConstraints + mThreadContext.mNumStaticConstraints);
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 = args.enhancedDeterminism ? 1u : 4u;
PxConstraintBatchHeader* batchHeaders = mIslandContext.mObjects.constraintBatchHeaders;
PxSolverConstraintDesc* orderedConstraints = mIslandContext.mObjects.orderedConstraintDescs;
PxU32 headersPerPartition = 0;
for (PxU32 a = 0; a < descCount;)
{
PxU32 loopMax = PxMin(maxJ - a, maxBatchSize);
PxU16 j = 0;
if (loopMax > 0)
{
PxConstraintBatchHeader& header = batchHeaders[numHeaders++];
j = 1;
PxSolverConstraintDesc& desc = orderedConstraints[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 == orderedConstraints[a + j].constraintLengthOver16 &&
!isArticulationConstraint(orderedConstraints[a + j]); ++j);
}
header.startIndex = a;
header.stride = j;
header.constraintType = desc.constraintLengthOver16;
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 = batchHeaders[numHeaders++];
header.startIndex = a + descCount;
header.stride = 1;
header.constraintType = DY_SC_TYPE_EXT_1D;
}
PxU32 numSelfConstraintBatchHeaders = numHeaders - numDifferentBodyBatchHeaders;
mThreadContext.numDifferentBodyBatchHeaders = numDifferentBodyBatchHeaders;
mThreadContext.numSelfConstraintBatchHeaders = numSelfConstraintBatchHeaders;
mThreadContext.numContactConstraintBatches = numHeaders;
}
}
};
class ParallelSolveTask : public Cm::Task
{
IslandContextStep& mIslandContext;
const SolverIslandObjectsStep& mObjects;
const PxsIslandIndices& mCounts;
ThreadContext& mThreadContext;
DynamicsTGSContext& mContext;
PX_NOCOPY(ParallelSolveTask)
public:
ParallelSolveTask(IslandContextStep& islandContext, const SolverIslandObjectsStep& objects, const PxsIslandIndices& counts, ThreadContext& threadContext,
DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mIslandContext(islandContext), mObjects(objects), mCounts(counts), mThreadContext(threadContext), mContext(context)
{
}
virtual const char* getName() const { return "ParallelSolveTask"; }
virtual void runInternal()
{
mContext.iterativeSolveIslandParallel(mObjects, mCounts, mThreadContext, mIslandContext.mStepDt, mIslandContext.mPosIters, mIslandContext.mVelIters,
&mIslandContext.mSharedSolverIndex, &mIslandContext.mSharedRigidBodyIndex, &mIslandContext.mSharedArticulationIndex,
&mIslandContext.mSolvedCount, &mIslandContext.mRigidBodyIntegratedCount, &mIslandContext.mArticulationIntegratedCount,
4, 128);
}
};
class SolveIslandTask : public Cm::Task
{
IslandContextStep& mIslandContext;
const SolverIslandObjectsStep& mObjects;
const PxsIslandIndices& mCounts;
ThreadContext& mThreadContext;
DynamicsTGSContext& mContext;
PX_NOCOPY(SolveIslandTask)
public:
SolveIslandTask(IslandContextStep& islandContext, const SolverIslandObjectsStep& objects, const PxsIslandIndices& counts, ThreadContext& threadContext,
DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mIslandContext(islandContext), mObjects(objects), mCounts(counts), mThreadContext(threadContext), mContext(context)
{
}
virtual const char* getName() const { return "SolveIslandTask"; }
virtual void runInternal()
{
PxU32 j = 0, i = 0;
PxU32 numBatches = 0;
PxU32 currIndex = 0;
PxU32 totalCount = 0;
PxSolverConstraintDesc* contactDescBegin = mObjects.orderedConstraintDescs;
PxSolverConstraintDesc* contactDescPtr = contactDescBegin;
PxConstraintBatchHeader* headers = mObjects.constraintBatchHeaders;
PxU32 totalPartitions = 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 = headers[b];
PxU16 stride = _header.stride, newStride = _header.stride;
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)
{
headers[numBatches].startIndex = startIndex;
headers[numBatches].stride = 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;
}
}
}
headers[numBatches].constraintType = type;
numBatches++;
numBatchesInPartition++;
}
}
currIndex += mThreadContext.mConstraintsPerPartition[a];
mThreadContext.mConstraintsPerPartition[totalPartitions] = numBatchesInPartition;
if (numBatchesInPartition)
totalPartitions++;
totalCount += numBatchesInPartition;
}
currIndex = totalCount;
//Decision whether to spawn multi-threaded solver or single-threaded solver...
mThreadContext.mConstraintsPerPartition.forceSize_Unsafe(totalPartitions);
mThreadContext.numContactConstraintBatches = totalCount;
PxU32 maxLinks = 0;
for (PxU32 a = 0; a < mCounts.articulations; ++a)
{
ArticulationSolverDesc& desc = mThreadContext.getArticulations()[a];
maxLinks = PxMax(maxLinks, PxU32(desc.linkCount));
}
mThreadContext.mZVector.forceSize_Unsafe(0);
mThreadContext.mZVector.reserve(maxLinks);
mThreadContext.mZVector.forceSize_Unsafe(maxLinks);
mThreadContext.mDeltaV.forceSize_Unsafe(0);
mThreadContext.mDeltaV.reserve(maxLinks);
mThreadContext.mDeltaV.forceSize_Unsafe(maxLinks);
SolverContext cache;
cache.Z = mThreadContext.mZVector.begin();
cache.deltaV = mThreadContext.mDeltaV.begin();
if (mThreadContext.mConstraintsPerPartition.size())
{
const PxU32 threadCount = this->getTaskManager()->getCpuDispatcher()->getWorkerCount();
const PxU32 nbHeadersPerPartition = ((currIndex + mThreadContext.mConstraintsPerPartition.size() - 1) / mThreadContext.mConstraintsPerPartition.size());
const PxU32 NbBatchesPerThread = 8;
const PxU32 nbIdealThreads = (nbHeadersPerPartition + NbBatchesPerThread-1) / NbBatchesPerThread;
if (threadCount < 2 || nbIdealThreads < 2)
mContext.iterativeSolveIsland(mObjects, mCounts, mThreadContext, mIslandContext.mStepDt, mIslandContext.mInvStepDt,
mIslandContext.mPosIters, mIslandContext.mVelIters, cache);
else
{
mIslandContext.mSharedSolverIndex = 0;
mIslandContext.mSolvedCount = 0;
mIslandContext.mSharedRigidBodyIndex = 0;
mIslandContext.mRigidBodyIntegratedCount = 0;
mIslandContext.mSharedArticulationIndex = 0;
mIslandContext.mArticulationIntegratedCount = 0;
PxU32 nbThreads = PxMin(threadCount, nbIdealThreads);
ParallelSolveTask* tasks = reinterpret_cast<ParallelSolveTask*>(mContext.getTaskPool().allocate(sizeof(ParallelSolveTask)*nbThreads));
for (PxU32 a = 0; a < nbThreads; ++a)
{
PX_PLACEMENT_NEW(&tasks[a], ParallelSolveTask)(mIslandContext, mObjects, mCounts, mThreadContext, mContext);
tasks[a].setContinuation(mCont);
tasks[a].removeReference();
}
}
}
else
{
mContext.iterativeSolveIsland(mObjects, mCounts, mThreadContext, mIslandContext.mStepDt,
mIslandContext.mInvStepDt, mIslandContext.mPosIters, mIslandContext.mVelIters, cache);
}
}
};
class EndIslandTask : public Cm::Task
{
ThreadContext& mThreadContext;
DynamicsTGSContext& mContext;
PX_NOCOPY(EndIslandTask)
public:
EndIslandTask(ThreadContext& threadContext, DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mThreadContext(threadContext), mContext(context)
{
}
virtual const char* getName() const { return "EndIslandTask"; }
virtual void runInternal()
{
mContext.endIsland(mThreadContext);
}
};
class FinishSolveIslandTask : public Cm::Task
{
ThreadContext& mThreadContext;
const SolverIslandObjectsStep& mObjects;
const PxsIslandIndices& mCounts;
IG::SimpleIslandManager& mIslandManager;
DynamicsTGSContext& mContext;
PX_NOCOPY(FinishSolveIslandTask)
public:
FinishSolveIslandTask(ThreadContext& threadContext, const SolverIslandObjectsStep& objects,
const PxsIslandIndices& counts, IG::SimpleIslandManager& islandManager, DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mThreadContext(threadContext), mObjects(objects), mCounts(counts), mIslandManager(islandManager), mContext(context)
{
}
virtual const char* getName() const { return "FinishSolveIslandTask"; }
virtual void runInternal()
{
mContext.finishSolveIsland(mThreadContext, mObjects, mCounts, mIslandManager, mCont);
}
};
void DynamicsTGSContext::iterativeSolveIsland(const SolverIslandObjectsStep& objects, const PxsIslandIndices& counts, ThreadContext& mThreadContext,
const PxReal stepDt, const PxReal invStepDt, const PxU32 posIters, const PxU32 velIters, SolverContext& cache)
{
PX_PROFILE_ZONE("Dynamics:solveIsland", 0);
PxReal elapsedTime = 0.f;
PxReal recipStepDt = 1.f/stepDt;
const PxU32 bodyOffset = objects.solverBodyOffset;
if (mThreadContext.numContactConstraintBatches == 0)
{
for (PxU32 i = 0; i < counts.articulations; ++i)
{
elapsedTime = 0.f;
ArticulationSolverDesc& d = mThreadContext.getArticulations()[i];
for (PxU32 a = 0; a < posIters; a++)
{
d.articulation->solveInternalConstraints(stepDt, recipStepDt, mThreadContext.mZVector.begin(), mThreadContext.mDeltaV.begin(), false, true, elapsedTime);
ArticulationPImpl::updateDeltaMotion(d, stepDt, mThreadContext.mDeltaV.begin());
elapsedTime += stepDt;
}
ArticulationPImpl::saveVelocityTGS(d, mInvDt);
for (PxU32 a = 0; a < velIters; ++a)
{
d.articulation->solveInternalConstraints(stepDt, recipStepDt, mThreadContext.mZVector.begin(), mThreadContext.mDeltaV.begin(), true, true, elapsedTime);
}
d.articulation->writebackInternalConstraints(true);
}
integrateBodies(objects, counts.bodies, mSolverBodyVelPool.begin() + bodyOffset, mSolverBodyTxInertiaPool.begin() + bodyOffset, mSolverBodyDataPool2.begin() + bodyOffset, mDt);
return;
}
for (PxU32 a = 1; a < posIters; a++)
{
for (PxU32 i = 0; i < counts.articulations; ++i)
{
ArticulationSolverDesc& d = mThreadContext.getArticulations()[i];
d.articulation->solveInternalConstraints(stepDt, recipStepDt, mThreadContext.mZVector.begin(), mThreadContext.mDeltaV.begin(), false, true, elapsedTime);
}
solveConstraintsIteration(objects.orderedConstraintDescs, objects.constraintBatchHeaders, mThreadContext.numContactConstraintBatches, invStepDt,
mSolverBodyTxInertiaPool.begin(), elapsedTime, -PX_MAX_F32, cache);
integrateBodies(objects, counts.bodies, mSolverBodyVelPool.begin() + bodyOffset, mSolverBodyTxInertiaPool.begin() + bodyOffset, mSolverBodyDataPool2.begin() + bodyOffset, stepDt);
stepArticulations(mThreadContext, counts, stepDt);
elapsedTime += stepDt;
}
for (PxU32 i = 0; i < counts.articulations; ++i)
{
ArticulationSolverDesc& d = mThreadContext.getArticulations()[i];
d.articulation->solveInternalConstraints(stepDt, recipStepDt, mThreadContext.mZVector.begin(), mThreadContext.mDeltaV.begin(), false, true, elapsedTime);
}
solveConcludeConstraintsIteration(objects.orderedConstraintDescs, objects.constraintBatchHeaders, mThreadContext.numContactConstraintBatches,
mSolverBodyTxInertiaPool.begin(), elapsedTime, cache);
elapsedTime += stepDt;
const PxReal invDt = mInvDt;
integrateBodies(objects, counts.bodies, mSolverBodyVelPool.begin() + bodyOffset, mSolverBodyTxInertiaPool.begin() + bodyOffset, mSolverBodyDataPool2.begin() + bodyOffset, stepDt);
stepArticulations(mThreadContext, counts, stepDt);
for(PxU32 a = 0; a < counts.articulations; ++a)
{
Dy::ArticulationSolverDesc& desc = mThreadContext.getArticulations()[a];
//ArticulationPImpl::updateDeltaMotion(desc, stepDt, mThreadContext.mDeltaV.begin());
ArticulationPImpl::saveVelocityTGS(desc, invDt);
}
for (PxU32 a = 0; a < velIters; ++a)
{
for (PxU32 i = 0; i < counts.articulations; ++i)
{
ArticulationSolverDesc& d = mThreadContext.getArticulations()[i];
d.articulation->solveInternalConstraints(stepDt, recipStepDt, mThreadContext.mZVector.begin(), mThreadContext.mDeltaV.begin(), false, true, elapsedTime);
}
solveConstraintsIteration(objects.orderedConstraintDescs, objects.constraintBatchHeaders, mThreadContext.numContactConstraintBatches, invStepDt,
mSolverBodyTxInertiaPool.begin(), elapsedTime, 0.f, cache);
}
writebackConstraintsIteration(objects.constraintBatchHeaders, objects.orderedConstraintDescs, mThreadContext.numContactConstraintBatches);
for (PxU32 i = 0; i < counts.articulations; ++i)
{
ArticulationSolverDesc& d = mThreadContext.getArticulations()[i];
d.articulation->writebackInternalConstraints(true);
}
}
void DynamicsTGSContext::iterativeSolveIslandParallel(const SolverIslandObjectsStep& objects, const PxsIslandIndices& counts, ThreadContext& mThreadContext,
const PxReal stepDt, const PxU32 posIters, const PxU32 velIters, PxI32* solverCounts, PxI32* integrationCounts, PxI32* articulationIntegrationCounts,
PxI32* solverProgressCount, PxI32* integrationProgressCount, PxI32* articulationProgressCount, PxU32 solverUnrollSize, PxU32 integrationUnrollSize)
{
PX_PROFILE_ZONE("Dynamics:solveIslandParallel", 0);
Dy::ThreadContext& threadContext = *getThreadContext();
PxU32 startSolveIdx = PxU32(Ps::atomicAdd(solverCounts, PxI32(solverUnrollSize))) - solverUnrollSize;
PxU32 nbSolveRemaining = solverUnrollSize;
PxU32 startIntegrateIdx = PxU32(Ps::atomicAdd(integrationCounts, PxI32(integrationUnrollSize))) - integrationUnrollSize;
PxU32 nbIntegrateRemaining = integrationUnrollSize;
//For now, just do articulations 1 at a time. Might need to tweak this later depending on performance
PxU32 startArticulationIdx = PxU32(Ps::atomicAdd(articulationIntegrationCounts, PxI32(1))) - 1;
PxU32 targetSolverProgressCount = 0, targetIntegrationProgressCount = 0, targetArticulationProgressCount = 0;
const PxU32 nbSolverBatches = mThreadContext.numContactConstraintBatches;
const PxU32 nbBodies = counts.bodies;// + mKinematicCount;
const PxU32 nbArticulations = counts.articulations;
PxSolverConstraintDesc* contactDescs = objects.orderedConstraintDescs;
PxConstraintBatchHeader* batchHeaders = objects.constraintBatchHeaders;
PxTGSSolverBodyVel* solverVels = mSolverBodyVelPool.begin();
PxTGSSolverBodyTxInertia* solverTxInertias = mSolverBodyTxInertiaPool.begin();
const PxTGSSolverBodyData*const solverBodyData = mSolverBodyDataPool2.begin();
PxU32* constraintsPerPartitions = mThreadContext.mConstraintsPerPartition.begin();
const PxU32 nbPartitions = mThreadContext.mConstraintsPerPartition.size();
const PxU32 bodyOffset = objects.solverBodyOffset;
threadContext.mZVector.reserve(mThreadContext.mZVector.size());
threadContext.mDeltaV.reserve(mThreadContext.mZVector.size());
SolverContext cache;
cache.Z = threadContext.mZVector.begin();
cache.deltaV = threadContext.mDeltaV.begin();
PxReal elapsedTime = 0.f;
PxReal invStepDt = 1.f/ stepDt;
for (PxU32 a = 1; a < posIters; ++a, targetIntegrationProgressCount += nbBodies, targetArticulationProgressCount += nbArticulations)
{
WAIT_FOR_PROGRESS(integrationProgressCount, PxI32(targetIntegrationProgressCount));
WAIT_FOR_PROGRESS(articulationProgressCount, PxI32(targetArticulationProgressCount));
PxU32 artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
PxU32 nbArticsProcessed = 0;
while (artIcStartIdx < nbArticulations)
{
ArticulationSolverDesc& d = mThreadContext.getArticulations()[artIcStartIdx];
d.articulation->solveInternalConstraints(stepDt, invStepDt, threadContext.mZVector.begin(),
threadContext.mDeltaV.begin(), false, true, elapsedTime);
//ArticulationPImpl::updateDeltaMotion(d, stepDt, cache.deltaV);
nbArticsProcessed++;
startArticulationIdx = PxU32(Ps::atomicAdd(articulationIntegrationCounts, PxI32(1))) - 1;
artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
}
if (nbArticsProcessed)
Ps::atomicAdd(articulationProgressCount, PxI32(nbArticsProcessed));
targetArticulationProgressCount += nbArticulations;
WAIT_FOR_PROGRESS(articulationProgressCount, PxI32(targetArticulationProgressCount));
PxU32 offset = 0;
for (PxU32 b = 0; b < nbPartitions; ++b)
{
WAIT_FOR_PROGRESS(solverProgressCount, PxI32(targetSolverProgressCount));
//Find the startIdx in the partition to process
PxU32 startIdx = startSolveIdx - targetSolverProgressCount;
const PxU32 nbBatches = constraintsPerPartitions[b];
PxU32 nbSolved = 0;
while (startIdx < nbBatches)
{
PxU32 nbToSolve = PxMin(nbBatches - startIdx, nbSolveRemaining);
parallelSolveConstraints(contactDescs, batchHeaders + startIdx + offset, nbToSolve,
solverTxInertias, elapsedTime, -PX_MAX_F32, cache);
nbSolveRemaining -= nbToSolve;
startSolveIdx += nbToSolve;
startIdx += nbToSolve;
nbSolved += nbToSolve;
if (nbSolveRemaining == 0)
{
startSolveIdx = PxU32(Ps::atomicAdd(solverCounts, PxI32(solverUnrollSize))) - solverUnrollSize;
nbSolveRemaining = solverUnrollSize;
startIdx = startSolveIdx - targetSolverProgressCount;
}
}
if (nbSolved)
Ps::atomicAdd(solverProgressCount, PxI32(nbSolved));
targetSolverProgressCount += nbBatches;
offset += nbBatches;
}
WAIT_FOR_PROGRESS(solverProgressCount, PxI32(targetSolverProgressCount));
PxU32 integStartIdx = startIntegrateIdx - targetIntegrationProgressCount;
PxU32 nbIntegrated = 0;
while (integStartIdx < nbBodies)
{
PxU32 nbToIntegrate = PxMin(nbBodies - integStartIdx, nbIntegrateRemaining);
parallelIntegrateBodies(solverVels + integStartIdx + bodyOffset, solverTxInertias + integStartIdx + bodyOffset,
solverBodyData + integStartIdx + bodyOffset, nbToIntegrate, stepDt);
nbIntegrateRemaining -= nbToIntegrate;
startIntegrateIdx += nbToIntegrate;
integStartIdx += nbToIntegrate;
nbIntegrated += nbToIntegrate;
if (nbIntegrateRemaining == 0)
{
startIntegrateIdx = PxU32(Ps::atomicAdd(integrationCounts, PxI32(integrationUnrollSize))) - integrationUnrollSize;
nbIntegrateRemaining = integrationUnrollSize;
integStartIdx = startIntegrateIdx - targetIntegrationProgressCount;
}
}
if (nbIntegrated)
Ps::atomicAdd(integrationProgressCount, PxI32(nbIntegrated));
artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
nbArticsProcessed = 0;
while (artIcStartIdx < nbArticulations)
{
ArticulationSolverDesc& d = mThreadContext.getArticulations()[artIcStartIdx];
ArticulationPImpl::updateDeltaMotion(d, stepDt, cache.deltaV);
nbArticsProcessed++;
startArticulationIdx = PxU32(Ps::atomicAdd(articulationIntegrationCounts, PxI32(1))) - 1;
artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
}
if (nbArticsProcessed)
Ps::atomicAdd(articulationProgressCount, PxI32(nbArticsProcessed));
elapsedTime += stepDt;
}
{
WAIT_FOR_PROGRESS(integrationProgressCount, PxI32(targetIntegrationProgressCount));
WAIT_FOR_PROGRESS(articulationProgressCount, PxI32(targetArticulationProgressCount));
PxU32 artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
PxU32 nbArticsProcessed = 0;
while (artIcStartIdx < nbArticulations)
{
ArticulationSolverDesc& d = mThreadContext.getArticulations()[artIcStartIdx];
d.articulation->solveInternalConstraints(stepDt, invStepDt, threadContext.mZVector.begin(),
threadContext.mDeltaV.begin(), false, true, elapsedTime);
nbArticsProcessed++;
startArticulationIdx = PxU32(Ps::atomicAdd(articulationIntegrationCounts, PxI32(1))) - 1;
artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
}
if (nbArticsProcessed)
Ps::atomicAdd(articulationProgressCount, PxI32(nbArticsProcessed));
targetArticulationProgressCount += nbArticulations;
WAIT_FOR_PROGRESS(articulationProgressCount, PxI32(targetArticulationProgressCount));
PxU32 offset = 0;
for (PxU32 b = 0; b < nbPartitions; ++b)
{
WAIT_FOR_PROGRESS(solverProgressCount, PxI32(targetSolverProgressCount));
//Find the startIdx in the partition to process
PxU32 startIdx = startSolveIdx - targetSolverProgressCount;
const PxU32 nbBatches = constraintsPerPartitions[b];
PxU32 nbSolved = 0;
while (startIdx < nbBatches)
{
PxU32 nbToSolve = PxMin(nbBatches - startIdx, nbSolveRemaining);
solveConcludeConstraintsIteration(contactDescs, batchHeaders + startIdx + offset, nbToSolve,
solverTxInertias, elapsedTime, cache);
nbSolveRemaining -= nbToSolve;
startSolveIdx += nbToSolve;
startIdx += nbToSolve;
nbSolved += nbToSolve;
if (nbSolveRemaining == 0)
{
startSolveIdx = PxU32(Ps::atomicAdd(solverCounts, PxI32(solverUnrollSize))) - solverUnrollSize;
nbSolveRemaining = solverUnrollSize;
startIdx = startSolveIdx - targetSolverProgressCount;
}
}
if (nbSolved)
Ps::atomicAdd(solverProgressCount, PxI32(nbSolved));
targetSolverProgressCount += nbBatches;
offset += nbBatches;
}
WAIT_FOR_PROGRESS(solverProgressCount, PxI32(targetSolverProgressCount));
const PxReal invDt = mInvDt;
//const PxReal invDtPt25 = mInvDt * 0.25f;
PxU32 integStartIdx = startIntegrateIdx - targetIntegrationProgressCount;
PxU32 nbIntegrated = 0;
while (integStartIdx < nbBodies)
{
PxU32 nbToIntegrate = PxMin(nbBodies - integStartIdx, nbIntegrateRemaining);
parallelIntegrateBodies(solverVels + integStartIdx + bodyOffset, solverTxInertias + integStartIdx + bodyOffset,
solverBodyData + integStartIdx + bodyOffset, nbToIntegrate, stepDt);
nbIntegrateRemaining -= nbToIntegrate;
startIntegrateIdx += nbToIntegrate;
integStartIdx += nbToIntegrate;
nbIntegrated += nbToIntegrate;
if (nbIntegrateRemaining == 0)
{
startIntegrateIdx = PxU32(Ps::atomicAdd(integrationCounts, PxI32(integrationUnrollSize))) - integrationUnrollSize;
nbIntegrateRemaining = integrationUnrollSize;
integStartIdx = startIntegrateIdx - targetIntegrationProgressCount;
}
}
if (nbIntegrated)
Ps::atomicAdd(integrationProgressCount, PxI32(nbIntegrated));
artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
nbArticsProcessed = 0;
while (artIcStartIdx < nbArticulations)
{
ArticulationSolverDesc& d = mThreadContext.getArticulations()[artIcStartIdx];
ArticulationPImpl::updateDeltaMotion(d, stepDt, cache.deltaV);
ArticulationPImpl::saveVelocityTGS(d, invDt);
nbArticsProcessed++;
startArticulationIdx = PxU32(Ps::atomicAdd(articulationIntegrationCounts, PxI32(1))) - 1;
artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
}
if (nbArticsProcessed)
Ps::atomicAdd(articulationProgressCount, PxI32(nbArticsProcessed));
elapsedTime += stepDt;
targetIntegrationProgressCount += nbBodies;
targetArticulationProgressCount += nbArticulations;
putThreadContext(&threadContext);
}
//Write back constraints...
WAIT_FOR_PROGRESS(integrationProgressCount, PxI32(targetIntegrationProgressCount));
WAIT_FOR_PROGRESS(articulationProgressCount, PxI32(targetArticulationProgressCount));
for (PxU32 a = 0; a < velIters; ++a)
{
WAIT_FOR_PROGRESS(solverProgressCount, PxI32(targetSolverProgressCount));
const bool lastIter = (velIters - a) == 1;
PxU32 artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
PxU32 nbArticsProcessed = 0;
while (artIcStartIdx < nbArticulations)
{
ArticulationSolverDesc& d = mThreadContext.getArticulations()[artIcStartIdx];
d.articulation->solveInternalConstraints(stepDt, invStepDt, threadContext.mZVector.begin(),
threadContext.mDeltaV.begin(), true, true, elapsedTime);
if(lastIter)
d.articulation->writebackInternalConstraints(true);
nbArticsProcessed++;
startArticulationIdx = PxU32(Ps::atomicAdd(articulationIntegrationCounts, PxI32(1))) - 1;
artIcStartIdx = startArticulationIdx - targetArticulationProgressCount;
}
if (nbArticsProcessed)
Ps::atomicAdd(articulationProgressCount, PxI32(nbArticsProcessed));
targetArticulationProgressCount += nbArticulations;
WAIT_FOR_PROGRESS(articulationProgressCount, PxI32(targetArticulationProgressCount));
PxU32 offset = 0;
for (PxU32 b = 0; b < nbPartitions; ++b)
{
WAIT_FOR_PROGRESS(solverProgressCount, PxI32(targetSolverProgressCount));
//Find the startIdx in the partition to process
PxU32 startIdx = startSolveIdx - targetSolverProgressCount;
const PxU32 nbBatches = constraintsPerPartitions[b];
PxU32 nbSolved = 0;
while (startIdx < nbBatches)
{
PxU32 nbToSolve = PxMin(nbBatches - startIdx, nbSolveRemaining);
parallelSolveConstraints(contactDescs, batchHeaders + startIdx + offset, nbToSolve,
solverTxInertias, elapsedTime, 0.f, cache);
nbSolveRemaining -= nbToSolve;
startSolveIdx += nbToSolve;
startIdx += nbToSolve;
nbSolved += nbToSolve;
if (nbSolveRemaining == 0)
{
startSolveIdx = PxU32(Ps::atomicAdd(solverCounts, PxI32(solverUnrollSize))) - solverUnrollSize;
nbSolveRemaining = solverUnrollSize;
startIdx = startSolveIdx - targetSolverProgressCount;
}
}
if (nbSolved)
Ps::atomicAdd(solverProgressCount, PxI32(nbSolved));
targetSolverProgressCount += nbBatches;
offset += nbBatches;
}
}
{
WAIT_FOR_PROGRESS(solverProgressCount, PxI32(targetSolverProgressCount));
{
//Find the startIdx in the partition to process
PxU32 startIdx = startSolveIdx - targetSolverProgressCount;
const PxU32 nbBatches = nbSolverBatches;
PxU32 nbSolved = 0;
while (startIdx < nbBatches)
{
PxU32 nbToSolve = PxMin(nbBatches - startIdx, nbSolveRemaining);
parallelWritebackConstraintsIteration(contactDescs, batchHeaders + startIdx, nbToSolve);
nbSolveRemaining -= nbToSolve;
startSolveIdx += nbToSolve;
startIdx += nbToSolve;
nbSolved += nbToSolve;
if (nbSolveRemaining == 0)
{
startSolveIdx = PxU32(Ps::atomicAdd(solverCounts, PxI32(solverUnrollSize))) - solverUnrollSize;
nbSolveRemaining = solverUnrollSize;
startIdx = startSolveIdx - targetSolverProgressCount;
}
}
if (nbSolved)
Ps::atomicAdd(solverProgressCount, PxI32(nbSolved));
targetSolverProgressCount += nbBatches;
}
}
}
class CopyBackTask : public Cm::Task
{
const SolverIslandObjectsStep& mObjects;
PxTGSSolverBodyVel* mVels;
PxTGSSolverBodyTxInertia* mTxInertias;
PxTGSSolverBodyData* mSolverBodyDatas;
const PxReal mInvDt;
IG::IslandSim& mIslandSim;
const PxU32 mStartIdx;
const PxU32 mEndIdx;
DynamicsTGSContext& mContext;
PX_NOCOPY(CopyBackTask)
public:
CopyBackTask(const SolverIslandObjectsStep& objects,
PxTGSSolverBodyVel* vels, PxTGSSolverBodyTxInertia* txInertias,
PxTGSSolverBodyData* solverBodyDatas, PxReal invDt, IG::IslandSim& islandSim,
PxU32 startIdx, PxU32 endIdx, DynamicsTGSContext& context) : Cm::Task(context.getContextId()),
mObjects(objects), mVels(vels), mTxInertias(txInertias), mSolverBodyDatas(solverBodyDatas), mInvDt(invDt),
mIslandSim(islandSim), mStartIdx(startIdx), mEndIdx(endIdx), mContext(context)
{
}
virtual const char* getName() const { return "CopyBackTask"; }
virtual void runInternal()
{
mContext.copyBackBodies(mObjects, mVels, mTxInertias, mSolverBodyDatas, mInvDt, mIslandSim, mStartIdx, mEndIdx);
}
};
class UpdateArticTask : public Cm::Task
{
Dy::ThreadContext& mThreadContext;
PxU32 mStartIdx;
PxU32 mEndIdx;
PxReal mDt;
DynamicsTGSContext& mContext;
PX_NOCOPY(UpdateArticTask)
public:
UpdateArticTask(Dy::ThreadContext& threadContext, PxU32 startIdx, PxU32 endIdx, PxReal dt, DynamicsTGSContext& context) :
Cm::Task(context.getContextId()),
mThreadContext(threadContext), mStartIdx(startIdx), mEndIdx(endIdx), mDt(dt), mContext(context)
{
}
virtual const char* getName() const { return "UpdateArticTask"; }
virtual void runInternal()
{
mContext.updateArticulations(mThreadContext, mStartIdx, mEndIdx, mDt);
}
};
void DynamicsTGSContext::finishSolveIsland(ThreadContext& mThreadContext, const SolverIslandObjectsStep& objects,
const PxsIslandIndices& counts, IG::SimpleIslandManager& islandManager, PxBaseTask* continuation)
{
mThreadContext.mConstraintBlockManager.reset();
mThreadContext.mConstraintBlockStream.reset();
const PxU32 NbBodiesPerTask = 512;
for (PxU32 a = 0; a < counts.bodies; a += NbBodiesPerTask)
{
CopyBackTask* task = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(CopyBackTask)), CopyBackTask)
(objects, mSolverBodyVelPool.begin() + objects.solverBodyOffset,
mSolverBodyTxInertiaPool.begin() + objects.solverBodyOffset, mSolverBodyDataPool2.begin() + objects.solverBodyOffset,
mInvDt, islandManager.getAccurateIslandSim(), a, PxMin(a + NbBodiesPerTask, counts.bodies),*this);
task->setContinuation(continuation);
task->removeReference();
}
const PxU32 NbArticsPerTask = 64;
for (PxU32 a = 0; a < counts.articulations; a += NbArticsPerTask)
{
UpdateArticTask* task = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(UpdateArticTask)), UpdateArticTask)
(mThreadContext, a, PxMin(counts.articulations, a+NbArticsPerTask), mDt, *this);
task->setContinuation(continuation);
task->removeReference();
}
}
void DynamicsTGSContext::endIsland(ThreadContext& mThreadContext)
{
putThreadContext(&mThreadContext);
}
void DynamicsTGSContext::solveIsland(const SolverIslandObjectsStep& objects,
const PxsIslandIndices& counts,
const PxU32 solverBodyOffset,
IG::SimpleIslandManager& islandManager,
PxU32* bodyRemapTable, PxsMaterialManager* materialManager,
PxsContactManagerOutputIterator& iterator,
PxBaseTask* continuation)
{
PX_UNUSED(continuation);
PX_UNUSED(iterator);
PX_UNUSED(materialManager);
PX_UNUSED(bodyRemapTable);
PX_UNUSED(islandManager);
ThreadContext& mThreadContext = *getThreadContext();
IslandContextStep& islandContext = *reinterpret_cast<IslandContextStep*>(mTaskPool.allocate(sizeof(IslandContextStep)));
islandContext.mThreadContext = &mThreadContext;
islandContext.mCounts = counts;
islandContext.mObjects = objects;
islandContext.mPosIters = 0;
islandContext.mVelIters = 0;
islandContext.mObjects.solverBodyOffset = solverBodyOffset;
prepareBodiesAndConstraints(islandContext.mObjects, islandManager, islandContext);
////Create task chain...
SetupDescsTask* descTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(SetupDescsTask)), SetupDescsTask)(islandContext, islandContext.mObjects, islandManager,
bodyRemapTable, solverBodyOffset, iterator, *this);
PreIntegrateTask* intTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(PreIntegrateTask)), PreIntegrateTask)(islandContext.mObjects.bodyCoreArray, islandContext.mObjects.bodies,
mSolverBodyVelPool.begin() + solverBodyOffset,
mSolverBodyTxInertiaPool.begin() + solverBodyOffset, mSolverBodyDataPool2.begin() + solverBodyOffset,
mThreadContext.mNodeIndexArray, islandContext.mCounts.bodies, mGravity, mDt, islandContext.mPosIters,
islandContext.mVelIters, *this);
SetupArticulationTask* articTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(SetupArticulationTask)), SetupArticulationTask)(islandContext, mGravity,
mDt, islandContext.mPosIters, islandContext.mVelIters, *this);
SetStepperTask* stepperTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(SetStepperTask)), SetStepperTask)(islandContext, *this);
SetupArticulationInternalConstraintsTask* articConTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(SetupArticulationInternalConstraintsTask)), SetupArticulationInternalConstraintsTask)
(islandContext, mDt, mInvDt, islandContext.mObjects.constraintDescs, *this);
PartitionTask* partitionTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(PartitionTask)), PartitionTask)
(islandContext, islandContext.mObjects.constraintDescs, mSolverBodyVelPool.begin()+solverBodyOffset+1, mThreadContext,
*this);
SetupSolverConstraintsTask* constraintTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(SetupSolverConstraintsTask)), SetupSolverConstraintsTask)
(islandContext, islandContext.mObjects.orderedConstraintDescs, iterator, mThreadContext,
mDt, *this);
SolveIslandTask* solveTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(SolveIslandTask)), SolveIslandTask)(islandContext, islandContext.mObjects, islandContext.mCounts, mThreadContext, *this);
FinishSolveIslandTask* finishTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(FinishSolveIslandTask)), FinishSolveIslandTask)(mThreadContext, islandContext.mObjects, islandContext.mCounts, islandManager, *this);
EndIslandTask* endTask = PX_PLACEMENT_NEW(mTaskPool.allocate(sizeof(EndIslandTask)), EndIslandTask)(mThreadContext, *this);
endTask->setContinuation(continuation);
finishTask->setContinuation(endTask);
solveTask->setContinuation(finishTask);
constraintTask->setContinuation(solveTask);
partitionTask->setContinuation(constraintTask);
articConTask->setContinuation(partitionTask);
//Stepper triggers both articCon and constraintTask
stepperTask->setContinuation(articConTask);
stepperTask->setAdditionalContinuation(constraintTask);
articTask->setContinuation(stepperTask);
intTask->setContinuation(stepperTask);
descTask->setContinuation(stepperTask);
endTask->removeReference();
finishTask->removeReference();
solveTask->removeReference();
constraintTask->removeReference();
partitionTask->removeReference();
articConTask->removeReference();
stepperTask->removeReference();
articTask->removeReference();
intTask->removeReference();
descTask->removeReference();
//Launch a setupDescs task
//setupDescs(islandContext, objects, islandManager, bodyRemapTable, mKinematicCount, iterator);
//
////Launch a preIntegrateBodies task
//preIntegrateBodies(objects.bodyCoreArray, objects.bodies, mThreadContext.solverBodyData.begin() + mKinematicCount,
// mThreadContext.mNodeIndexArray, counts.bodies, mGravity, mDt, islandContext.mPosIters, islandContext.mVelIters, 0);
//const PxU32 articConstraintOffset = mThreadContext.contactDescArraySize;
//islandContext.mArticulationOffset = mThreadContext.contactDescArraySize;
////Launch an articulation setup task
//setupArticulations(islandContext, mGravity, mDt, islandContext.mPosIters, islandContext.mVelIters);
//PxU32 substeps = islandContext.mPosIters;
//PxReal stepDt = mDt / PxReal(substeps);
//PxReal invStepDt = PxMin(1000.f, mInvDt*PxReal(substeps));
//islandContext.mStepDt = stepDt;
//islandContext.mInvStepDt = invStepDt;
////Setup articulation constraints - needs to be refactored for compaction etc.
//setupArticulationInternalConstraints(islandContext, mDt, invStepDt, objects.constraintDescs + articConstraintOffset);
//createSolverConstraints(objects.constraintDescs, articConstraintOffset, mThreadContext.solverBodyData.begin(), iterator, mThreadContext,
// mDt, invStepDt, substeps);
//iterativeSolveIsland(objects, counts, mThreadContext, stepDt, invStepDt, islandContext.mPosIters, islandContext.mVelIters);
//endIsland(mThreadContext, objects, counts, islandManager);
}
void DynamicsTGSContext::updateBodyCore(PxBaseTask* continuation)
{
PX_UNUSED(continuation);
}
void DynamicsTGSContext::mergeResults()
{
}
}
}