1034 lines
39 KiB
C++
1034 lines
39 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-2025 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 "PxsContext.h"
|
|
#include "CmFlushPool.h"
|
|
#include "PxsPartitionEdge.h"
|
|
#include "common/PxProfileZone.h"
|
|
|
|
#if PX_SUPPORT_GPU_PHYSX
|
|
#include "PxPhysXGpu.h"
|
|
#endif
|
|
|
|
#include "PxsContactManagerState.h"
|
|
|
|
#include "PxsNphaseImplementationContext.h"
|
|
#include "PxvGeometry.h"
|
|
#include "PxvDynamics.h"
|
|
#include "PxvGlobals.h"
|
|
|
|
#include "PxcNpContactPrepShared.h"
|
|
|
|
using namespace physx;
|
|
|
|
#if PX_VC
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4324)
|
|
#endif
|
|
|
|
// PT: TODO: why the split?
|
|
class PxsCMUpdateTask : public Cm::Task
|
|
{
|
|
public:
|
|
|
|
static const PxU32 BATCH_SIZE = 128;
|
|
//static const PxU32 BATCH_SIZE = 32;
|
|
|
|
PxsCMUpdateTask(PxsContext* context, PxReal dt, PxsContactManager** cmArray, PxsContactManagerOutput* cmOutputs, Gu::Cache* caches, PxU32 cmCount, PxContactModifyCallback* callback) :
|
|
Cm::Task (context->getContextId()),
|
|
mCmArray (cmArray),
|
|
mCmOutputs (cmOutputs),
|
|
mCaches (caches),
|
|
mContext (context),
|
|
mCallback (callback),
|
|
mCmCount (cmCount),
|
|
mDt (dt),
|
|
mNbPatchChanged (0)
|
|
{
|
|
}
|
|
|
|
virtual void release();
|
|
|
|
public:
|
|
PxsContactManager** mCmArray;
|
|
PxsContactManagerOutput* mCmOutputs;
|
|
Gu::Cache* mCaches;
|
|
PxsContext* mContext;
|
|
PxContactModifyCallback* mCallback;
|
|
const PxU32 mCmCount;
|
|
const PxReal mDt; //we could probably retrieve from context to save space?
|
|
PxU32 mNbPatchChanged;
|
|
|
|
PxsContactManagerOutputCounts mPatchChangedOutputCounts[BATCH_SIZE];
|
|
PxsContactManager* mPatchChangedCms[BATCH_SIZE];
|
|
};
|
|
#if PX_VC
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
void PxsCMUpdateTask::release()
|
|
{
|
|
// We used to do Task::release(); here before fixing DE1106 (xbox pure virtual crash)
|
|
// Release in turn causes the dependent tasks to start running
|
|
// The problem was that between the time release was called and by the time we got to the destructor
|
|
// The task chain would get all the way to scene finalization code which would reset the allocation pool
|
|
// And a new task would get allocated at the same address, then we would invoke the destructor on that freshly created task
|
|
// This could potentially cause any number of other problems, it is suprising that it only manifested itself
|
|
// as a pure virtual crash
|
|
PxBaseTask* saveContinuation = mCont;
|
|
this->~PxsCMUpdateTask();
|
|
if (saveContinuation)
|
|
saveContinuation->removeReference();
|
|
}
|
|
|
|
static const bool gUseNewTaskAllocationScheme = false;
|
|
|
|
class PxsCMDiscreteUpdateTask : public PxsCMUpdateTask
|
|
{
|
|
public:
|
|
PxsCMDiscreteUpdateTask(PxsContext* context, PxReal dt, PxsContactManager** cms, PxsContactManagerOutput* cmOutputs, Gu::Cache* caches, PxU32 nbCms,
|
|
PxContactModifyCallback* callback):
|
|
PxsCMUpdateTask(context, dt, cms, cmOutputs, caches, nbCms, callback)
|
|
{}
|
|
|
|
virtual ~PxsCMDiscreteUpdateTask()
|
|
{}
|
|
|
|
void runModifiableContactManagers(PxU32* modifiableIndices, PxU32 nbModifiableManagers, PxcNpThreadContext& threadContext, PxU32& maxPatches_)
|
|
{
|
|
PX_ASSERT(nbModifiableManagers != 0);
|
|
|
|
PxU32 maxPatches = maxPatches_;
|
|
|
|
class PxcContactSet: public PxContactSet
|
|
{
|
|
public:
|
|
PxcContactSet(PxU32 count, PxModifiableContact *contacts)
|
|
{
|
|
mContacts = contacts;
|
|
mCount = count;
|
|
}
|
|
PxModifiableContact* getContacts() { return mContacts; }
|
|
PxU32 getCount() { return mCount; }
|
|
};
|
|
|
|
if(mCallback)
|
|
{
|
|
PX_ALLOCA(mModifiablePairArray, PxContactModifyPair, nbModifiableManagers);
|
|
|
|
PxsTransformCache& transformCache = mContext->getTransformCache();
|
|
|
|
for(PxU32 i = 0; i < nbModifiableManagers; ++i)
|
|
{
|
|
const PxU32 index = modifiableIndices[i];
|
|
const PxsContactManager& cm = *mCmArray[index];
|
|
|
|
const PxsContactManagerOutput& output = mCmOutputs[index];
|
|
|
|
const PxU32 count = output.nbContacts;
|
|
|
|
if(count)
|
|
{
|
|
PxContactModifyPair& p = mModifiablePairArray[i];
|
|
const PxcNpWorkUnit& unit = cm.getWorkUnit();
|
|
|
|
p.shape[0] = gPxvOffsetTable.convertPxsShape2Px(unit.getShapeCore0());
|
|
p.shape[1] = gPxvOffsetTable.convertPxsShape2Px(unit.getShapeCore1());
|
|
|
|
p.actor[0] = unit.mFlags & (PxcNpWorkUnitFlag::eDYNAMIC_BODY0 | PxcNpWorkUnitFlag::eARTICULATION_BODY0) ?
|
|
gPxvOffsetTable.convertPxsRigidCore2PxRigidBody(unit.mRigidCore0)
|
|
: gPxvOffsetTable.convertPxsRigidCore2PxRigidStatic(unit.mRigidCore0);
|
|
|
|
p.actor[1] = unit.mFlags & (PxcNpWorkUnitFlag::eDYNAMIC_BODY1 | PxcNpWorkUnitFlag::eARTICULATION_BODY1) ?
|
|
gPxvOffsetTable.convertPxsRigidCore2PxRigidBody(unit.mRigidCore1)
|
|
: gPxvOffsetTable.convertPxsRigidCore2PxRigidStatic(unit.mRigidCore1);
|
|
|
|
p.transform[0] = transformCache.getTransformCache(unit.mTransformCache0).transform;
|
|
p.transform[1] = transformCache.getTransformCache(unit.mTransformCache1).transform;
|
|
|
|
PxModifiableContact* contacts = reinterpret_cast<PxModifiableContact*>(output.contactPoints);
|
|
static_cast<PxcContactSet&>(p.contacts) = PxcContactSet(count, contacts);
|
|
|
|
const PxReal mi0 = unit.mFlags & (PxcNpWorkUnitFlag::eDYNAMIC_BODY0 | PxcNpWorkUnitFlag::eARTICULATION_BODY0) ? static_cast<const PxsBodyCore*>(unit.mRigidCore0)->maxContactImpulse : PX_MAX_F32;
|
|
const PxReal mi1 = unit.mFlags & (PxcNpWorkUnitFlag::eDYNAMIC_BODY1 | PxcNpWorkUnitFlag::eARTICULATION_BODY1) ? static_cast<const PxsBodyCore*>(unit.mRigidCore1)->maxContactImpulse : PX_MAX_F32;
|
|
const PxReal maxImpulse = PxMin(mi0, mi1);
|
|
for (PxU32 j = 0; j < count; j++)
|
|
contacts[j].maxImpulse = maxImpulse;
|
|
|
|
#if PX_ENABLE_SIM_STATS
|
|
const PxU8 gt0 = PxTo8(unit.getGeomType0()), gt1 = PxTo8(unit.getGeomType1());
|
|
threadContext.mModifiedContactPairs[PxMin(gt0, gt1)][PxMax(gt0, gt1)]++;
|
|
#else
|
|
PX_CATCH_UNDEFINED_ENABLE_SIM_STATS
|
|
#endif
|
|
}
|
|
}
|
|
|
|
{
|
|
PX_PROFILE_ZONE("USERCODE - PxContactModifyCallback::onContactModify", mContext->getContextId());
|
|
mCallback->onContactModify(mModifiablePairArray, nbModifiableManagers);
|
|
}
|
|
}
|
|
|
|
for(PxU32 i = 0; i < nbModifiableManagers; ++i)
|
|
{
|
|
const PxU32 index = modifiableIndices[i];
|
|
PxsContactManager& cm = *mCmArray[index];
|
|
|
|
//Loop through the contacts in the contact stream and update contact count!
|
|
|
|
PxU32 numContacts = 0;
|
|
PxcNpWorkUnit& unit = cm.getWorkUnit();
|
|
PxsContactManagerOutput& output = mCmOutputs[index];
|
|
|
|
PxU32 numPatches = output.nbPatches;
|
|
|
|
if (output.nbContacts)
|
|
{
|
|
//PxU8* compressedContacts = cm.getWorkUnit().compressedContacts;
|
|
//PxModifyContactHeader* header = reinterpret_cast<PxModifyContactHeader*>(compressedContacts);
|
|
PxContactPatch* patches = reinterpret_cast<PxContactPatch*>(output.contactPatches);
|
|
PxModifiableContact* points = reinterpret_cast<PxModifiableContact*>(output.contactPoints);
|
|
|
|
if (patches->internalFlags & PxContactPatch::eREGENERATE_PATCHES)
|
|
{
|
|
//Some data was modified that must trigger patch re-generation...
|
|
for (PxU8 k = 0; k < numPatches; ++k)
|
|
{
|
|
PxU32 startIndex = patches[k].startContactIndex;
|
|
|
|
patches[k].normal = points[startIndex].normal;
|
|
patches[k].dynamicFriction = points[startIndex].dynamicFriction;
|
|
patches[k].staticFriction = points[startIndex].staticFriction;
|
|
patches[k].restitution = points[startIndex].restitution;
|
|
|
|
for (PxU32 j = 1; j < patches[k].nbContacts; ++j)
|
|
{
|
|
if (points[startIndex].normal.dot(points[j + startIndex].normal) < PXC_SAME_NORMAL
|
|
&& points[j + startIndex].maxImpulse > 0.f) //TODO - this needs extending for material indices but we don't support modifying those yet
|
|
{
|
|
//The points are now in a separate friction patch...
|
|
// Shift all patches above index k up by one to make space
|
|
for (PxU32 c = numPatches - 1; c > k; --c)
|
|
{
|
|
patches[c + 1] = patches[c];
|
|
}
|
|
numPatches++;
|
|
patches[k + 1].materialFlags = patches[k].materialFlags;
|
|
patches[k + 1].internalFlags = patches[k].internalFlags;
|
|
patches[k + 1].startContactIndex = PxTo8(j + startIndex);
|
|
patches[k + 1].nbContacts = PxTo8(patches[k].nbContacts - j);
|
|
//Fill in patch information now that final patches are available
|
|
patches[k].nbContacts = PxU8(j);
|
|
break; // we're done with all contacts in patch k because the remaining were just transferrred to patch k+1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
maxPatches = PxMax(maxPatches, PxU32(numPatches));
|
|
|
|
output.nbPatches = PxU8(numPatches);
|
|
|
|
for (PxU32 a = 0; a < output.nbContacts; ++a)
|
|
{
|
|
numContacts += points[a].maxImpulse != 0.f;
|
|
}
|
|
}
|
|
|
|
if (!numContacts)
|
|
{
|
|
output.nbPatches = 0;
|
|
output.nbContacts = 0;
|
|
}
|
|
|
|
if(output.nbPatches != output.prevPatches)
|
|
{
|
|
mPatchChangedCms[mNbPatchChanged] = &cm;
|
|
PxsContactManagerOutputCounts& counts = mPatchChangedOutputCounts[mNbPatchChanged++];
|
|
counts.nbPatches = PxU8(numPatches);
|
|
counts.prevPatches = output.prevPatches;
|
|
counts.statusFlag = output.statusFlag;
|
|
//counts.nbContacts = output.nbContacts16;
|
|
}
|
|
|
|
if(!numContacts)
|
|
{
|
|
//KS - we still need to retain the patch count from the previous frame to detect found/lost events...
|
|
unit.clearCachedState();
|
|
continue;
|
|
}
|
|
|
|
if(threadContext.mContactStreamPool)
|
|
{
|
|
//We need to allocate a new structure inside the contact stream pool
|
|
|
|
const PxU32 patchSize = output.nbPatches * sizeof(PxContactPatch);
|
|
const PxU32 contactSize = output.nbContacts * sizeof(PxExtendedContact);
|
|
const PxU32 frictionSize = output.nbPatches * sizeof(PxFrictionPatch);
|
|
|
|
/*PxI32 increment = (PxI32)(patchSize + contactSize);
|
|
PxI32 index = PxAtomicAdd(&mContactStreamPool->mSharedContactIndex, increment) - increment;
|
|
PxU8* address = mContactStreamPool->mContactStream + index;*/
|
|
bool isOverflown = false;
|
|
|
|
const PxI32 contactIncrement = PxI32(contactSize);
|
|
const PxI32 contactIndex = PxAtomicAdd(&threadContext.mContactStreamPool->mSharedDataIndex, contactIncrement);
|
|
|
|
if (threadContext.mContactStreamPool->isOverflown())
|
|
{
|
|
PX_WARN_ONCE("Contact buffer overflow detected, please increase its size in the scene desc!\n");
|
|
isOverflown = true;
|
|
}
|
|
|
|
PxU8* contactAddress = threadContext.mContactStreamPool->mDataStream + threadContext.mContactStreamPool->mDataStreamSize - contactIndex;
|
|
|
|
const PxI32 patchIncrement = PxI32(patchSize);
|
|
const PxI32 patchIndex = PxAtomicAdd(&threadContext.mPatchStreamPool->mSharedDataIndex, patchIncrement);
|
|
|
|
if (threadContext.mPatchStreamPool->isOverflown())
|
|
{
|
|
PX_WARN_ONCE("Patch buffer overflow detected, please increase its size in the scene desc!\n");
|
|
isOverflown = true;
|
|
}
|
|
|
|
PxU8* patchAddress = threadContext.mPatchStreamPool->mDataStream + threadContext.mPatchStreamPool->mDataStreamSize - patchIndex;
|
|
|
|
PxU32 internalFlags = reinterpret_cast<PxContactPatch*>(output.contactPatches)->internalFlags;
|
|
|
|
|
|
const bool hasIndices = (internalFlags & PxContactPatch::eHAS_FACE_INDICES);
|
|
const PxI32 increment2 = PxI32(output.nbContacts * sizeof(PxReal) + (hasIndices ? output.nbContacts * sizeof(PxU32) : 0));
|
|
const PxI32 index2 = PxAtomicAdd(&threadContext.mForceAndIndiceStreamPool->mSharedDataIndex, increment2);
|
|
|
|
if (threadContext.mForceAndIndiceStreamPool->isOverflown())
|
|
{
|
|
PX_WARN_ONCE("Force buffer overflow detected, please increase its size in the scene desc!\n");
|
|
isOverflown = true;
|
|
}
|
|
|
|
const PxI32 frictionIncrement = PxI32(frictionSize);
|
|
const PxI32 frictionIndex = PxAtomicAdd(&threadContext.mFrictionPatchStreamPool->mSharedDataIndex, frictionIncrement);
|
|
|
|
if (threadContext.mFrictionPatchStreamPool->isOverflown())
|
|
{
|
|
PX_WARN_ONCE("Patch buffer overflow detected, please increase its size in the scene desc!\n");
|
|
isOverflown = true;
|
|
}
|
|
|
|
PxU8* frictionAddress = threadContext.mFrictionPatchStreamPool->mDataStream + threadContext.mFrictionPatchStreamPool->mDataStreamSize - frictionIndex;
|
|
|
|
if (isOverflown)
|
|
{
|
|
output.contactPoints = NULL;
|
|
output.contactPatches = NULL;
|
|
output.contactForces = NULL;
|
|
output.frictionPatches = NULL;
|
|
|
|
output.nbContacts = output.nbPatches = 0;
|
|
}
|
|
else
|
|
{
|
|
output.contactForces = reinterpret_cast<PxReal*>(threadContext.mForceAndIndiceStreamPool->mDataStream + threadContext.mForceAndIndiceStreamPool->mDataStreamSize - index2);
|
|
|
|
PxMemZero(output.contactForces, sizeof(PxReal) * output.nbContacts);
|
|
|
|
PxExtendedContact* contacts = reinterpret_cast<PxExtendedContact*>(contactAddress);
|
|
PxMemCopy(patchAddress, output.contactPatches, sizeof(PxContactPatch) * output.nbPatches);
|
|
|
|
PxContactPatch* newPatches = reinterpret_cast<PxContactPatch*>(patchAddress);
|
|
|
|
internalFlags |= PxContactPatch::eCOMPRESSED_MODIFIED_CONTACT;
|
|
|
|
for(PxU32 a = 0; a < output.nbPatches; ++a)
|
|
{
|
|
newPatches[a].internalFlags = PxU8(internalFlags);
|
|
}
|
|
|
|
//KS - only the first patch will have mass modification properties set. For the GPU solver, this must be propagated to the remaining patches
|
|
for(PxU32 a = 1; a < output.nbPatches; ++a)
|
|
{
|
|
newPatches[a].mMassModification = newPatches->mMassModification;
|
|
}
|
|
|
|
PxModifiableContact* sourceContacts = reinterpret_cast<PxModifiableContact*>(output.contactPoints);
|
|
|
|
for(PxU32 a = 0; a < output.nbContacts; ++a)
|
|
{
|
|
PxExtendedContact& contact = contacts[a];
|
|
const PxModifiableContact& srcContact = sourceContacts[a];
|
|
contact.contact = srcContact.contact;
|
|
contact.separation = srcContact.separation;
|
|
contact.targetVelocity = srcContact.targetVelocity;
|
|
contact.maxImpulse = srcContact.maxImpulse;
|
|
}
|
|
|
|
output.contactPatches = patchAddress;
|
|
output.contactPoints = reinterpret_cast<PxU8*>(contacts);
|
|
|
|
PxMemZero(frictionAddress, frictionSize);
|
|
output.frictionPatches = frictionAddress;
|
|
}
|
|
}
|
|
}
|
|
maxPatches_ = maxPatches;
|
|
}
|
|
|
|
template < void (*NarrowPhase)(PxcNpThreadContext&, const PxcNpWorkUnit&, Gu::Cache&, PxsContactManagerOutput&, PxU64)>
|
|
void processCms(PxcNpThreadContext* threadContext)
|
|
{
|
|
const PxU64 contextID = mContext->getContextId();
|
|
//PX_PROFILE_ZONE("processCms", mContext->getContextId());
|
|
|
|
// PT: use local variables to avoid reading class members N times, if possible
|
|
const PxU32 nb = mCmCount;
|
|
PxsContactManager** PX_RESTRICT cmArray = mCmArray;
|
|
|
|
PxU32 maxPatches = threadContext->mMaxPatches;
|
|
|
|
PxU32 newTouchCMCount = 0, lostTouchCMCount = 0;
|
|
PxBitMap& localChangeTouchCM = threadContext->getLocalChangeTouch();
|
|
|
|
PX_ALLOCA(modifiableIndices, PxU32, nb);
|
|
PxU32 modifiableCount = 0;
|
|
|
|
for(PxU32 i=0;i<nb;i++)
|
|
{
|
|
const PxU32 prefetch1 = PxMin(i + 1, nb - 1);
|
|
const PxU32 prefetch2 = PxMin(i + 2, nb - 1);
|
|
|
|
PxPrefetchLine(cmArray[prefetch2]);
|
|
PxPrefetchLine(&mCmOutputs[prefetch2]);
|
|
PxPrefetchLine(cmArray[prefetch1]->getWorkUnit().getShapeCore0());
|
|
PxPrefetchLine(cmArray[prefetch1]->getWorkUnit().getShapeCore1());
|
|
PxPrefetchLine(&threadContext->mTransformCache->getTransformCache(cmArray[prefetch1]->getWorkUnit().mTransformCache0));
|
|
PxPrefetchLine(&threadContext->mTransformCache->getTransformCache(cmArray[prefetch1]->getWorkUnit().mTransformCache1));
|
|
|
|
PxsContactManager* const cm = cmArray[i];
|
|
|
|
if(cm)
|
|
{
|
|
PxsContactManagerOutput& output = mCmOutputs[i];
|
|
PxcNpWorkUnit& unit = cm->getWorkUnit();
|
|
|
|
output.prevPatches = output.nbPatches;
|
|
|
|
const PxU8 oldStatusFlag = output.statusFlag;
|
|
|
|
const PxU8 oldTouch = PxTo8(oldStatusFlag & PxsContactManagerStatusFlag::eHAS_TOUCH);
|
|
|
|
Gu::Cache& cache = mCaches[i];
|
|
|
|
NarrowPhase(*threadContext, unit, cache, output, contextID);
|
|
|
|
const PxU16 newTouch = PxTo8(output.statusFlag & PxsContactManagerStatusFlag::eHAS_TOUCH);
|
|
|
|
const bool modifiable = output.nbPatches != 0 && unit.mFlags & PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT;
|
|
|
|
if(modifiable)
|
|
{
|
|
modifiableIndices[modifiableCount++] = i;
|
|
}
|
|
else
|
|
{
|
|
maxPatches = PxMax(maxPatches, PxTo32(output.nbPatches));
|
|
|
|
if(output.prevPatches != output.nbPatches)
|
|
{
|
|
mPatchChangedCms[mNbPatchChanged] = cm;
|
|
PxsContactManagerOutputCounts& counts = mPatchChangedOutputCounts[mNbPatchChanged++];
|
|
counts.nbPatches = output.nbPatches;
|
|
counts.prevPatches = output.prevPatches;
|
|
counts.statusFlag = output.statusFlag;
|
|
//counts.nbContacts = output.nbContacts;
|
|
}
|
|
}
|
|
|
|
if (newTouch ^ oldTouch)
|
|
{
|
|
unit.mStatusFlags = PxU8(output.statusFlag | (unit.mStatusFlags & PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH)); //KS - todo - remove the need to access the work unit at all!
|
|
localChangeTouchCM.growAndSet(cmArray[i]->getIndex());
|
|
if(newTouch)
|
|
newTouchCMCount++;
|
|
else
|
|
lostTouchCMCount++;
|
|
}
|
|
else if (!(oldStatusFlag&PxsContactManagerStatusFlag::eTOUCH_KNOWN))
|
|
{
|
|
unit.mStatusFlags = PxU8(output.statusFlag | (unit.mStatusFlags & PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH)); //KS - todo - remove the need to access the work unit at all!
|
|
}
|
|
}
|
|
}
|
|
|
|
if(modifiableCount)
|
|
runModifiableContactManagers(modifiableIndices, modifiableCount, *threadContext, maxPatches);
|
|
|
|
threadContext->addLocalNewTouchCount(newTouchCMCount);
|
|
threadContext->addLocalLostTouchCount(lostTouchCMCount);
|
|
|
|
threadContext->mMaxPatches = maxPatches;
|
|
}
|
|
|
|
virtual void runInternal()
|
|
{
|
|
PX_PROFILE_ZONE("Sim.narrowPhase", mContext->getContextId());
|
|
|
|
PxcNpThreadContext* PX_RESTRICT threadContext = mContext->getNpThreadContext();
|
|
|
|
threadContext->mDt = mDt;
|
|
|
|
const bool pcm = mContext->getPCM();
|
|
threadContext->mPCM = pcm;
|
|
threadContext->mCreateAveragePoint = mContext->getCreateAveragePoint();
|
|
threadContext->mContactCache = mContext->getContactCacheFlag();
|
|
threadContext->mTransformCache = &mContext->getTransformCache();
|
|
threadContext->mContactDistances = mContext->getContactDistances();
|
|
|
|
if(pcm)
|
|
processCms<PxcDiscreteNarrowPhasePCM>(threadContext);
|
|
else
|
|
processCms<PxcDiscreteNarrowPhase>(threadContext);
|
|
|
|
mContext->putNpThreadContext(threadContext);
|
|
}
|
|
|
|
virtual const char* getName() const
|
|
{
|
|
return "PxsContext.contactManagerDiscreteUpdate";
|
|
}
|
|
};
|
|
|
|
static void processContactManagers(PxsContext& context, PxsContactManagers& narrowPhasePairs, PxArray<PxsCMDiscreteUpdateTask*>& tasks, PxReal dt, PxsContactManagerOutput* cmOutputs, PxBaseTask* continuation, PxContactModifyCallback* modifyCallback)
|
|
{
|
|
Cm::FlushPool& taskPool = context.getTaskPool();
|
|
|
|
//Iterate all active contact managers
|
|
taskPool.lock();
|
|
/*const*/ PxU32 nbCmsToProcess = narrowPhasePairs.mContactManagerMapping.size();
|
|
|
|
// PT: TASK-CREATION TAG
|
|
if(!gUseNewTaskAllocationScheme)
|
|
{
|
|
for(PxU32 a=0; a<nbCmsToProcess;)
|
|
{
|
|
void* ptr = taskPool.allocateNotThreadSafe(sizeof(PxsCMDiscreteUpdateTask));
|
|
PxU32 nbToProcess = PxMin(nbCmsToProcess - a, PxsCMUpdateTask::BATCH_SIZE);
|
|
PxsCMDiscreteUpdateTask* task = PX_PLACEMENT_NEW(ptr, PxsCMDiscreteUpdateTask)(&context, dt, narrowPhasePairs.mContactManagerMapping.begin() + a,
|
|
cmOutputs + a, narrowPhasePairs.mCaches.begin() + a, nbToProcess, modifyCallback);
|
|
|
|
a += nbToProcess;
|
|
|
|
task->setContinuation(continuation);
|
|
task->removeReference();
|
|
|
|
tasks.pushBack(task);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// PT:
|
|
const PxU32 numCpuTasks = continuation->getTaskManager()->getCpuDispatcher()->getWorkerCount();
|
|
|
|
PxU32 nbPerTask;
|
|
if(numCpuTasks)
|
|
nbPerTask = nbCmsToProcess > numCpuTasks ? nbCmsToProcess / numCpuTasks : nbCmsToProcess;
|
|
else
|
|
nbPerTask = nbCmsToProcess;
|
|
|
|
// PT: we need to respect that limit even with a single thread, because of hardcoded buffer limits in PxsCMDiscreteUpdateTask.
|
|
if(nbPerTask>PxsCMUpdateTask::BATCH_SIZE)
|
|
nbPerTask = PxsCMUpdateTask::BATCH_SIZE;
|
|
|
|
PxU32 start = 0;
|
|
while(nbCmsToProcess)
|
|
{
|
|
const PxU32 nb = nbCmsToProcess < nbPerTask ? nbCmsToProcess : nbPerTask;
|
|
|
|
void* ptr = taskPool.allocateNotThreadSafe(sizeof(PxsCMDiscreteUpdateTask));
|
|
PxsCMDiscreteUpdateTask* task = PX_PLACEMENT_NEW(ptr, PxsCMDiscreteUpdateTask)(&context, dt, narrowPhasePairs.mContactManagerMapping.begin() + start,
|
|
cmOutputs + start, narrowPhasePairs.mCaches.begin() + start, nb, modifyCallback);
|
|
|
|
task->setContinuation(continuation);
|
|
task->removeReference();
|
|
|
|
tasks.pushBack(task);
|
|
|
|
start += nb;
|
|
nbCmsToProcess -= nb;
|
|
}
|
|
}
|
|
taskPool.unlock();
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::processContactManager(PxReal dt, PxsContactManagerOutput* cmOutputs, PxBaseTask* continuation)
|
|
{
|
|
processContactManagers(mContext, mNarrowPhasePairs, mCmTasks, dt, cmOutputs, continuation, mModifyCallback);
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::processContactManagerSecondPass(PxReal dt, PxBaseTask* continuation)
|
|
{
|
|
processContactManagers(mContext, mNewNarrowPhasePairs, mCmTasks, dt, mNewNarrowPhasePairs.mOutputContactManagers.begin(), continuation, mModifyCallback);
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::updateContactManager(PxReal dt, bool /*hasContactDistanceChanged*/, PxBaseTask* continuation,
|
|
PxBaseTask* firstPassNpContinuation, Cm::FanoutTask* /*updateBoundAndShapeTask*/)
|
|
{
|
|
PX_PROFILE_ZONE("Sim.queueNarrowPhase", mContext.mContextID);
|
|
|
|
firstPassNpContinuation->removeReference();
|
|
|
|
mContext.clearManagerTouchEvents();
|
|
|
|
#if PX_ENABLE_SIM_STATS
|
|
mContext.mSimStats.mNbDiscreteContactPairsTotal = 0;
|
|
mContext.mSimStats.mNbDiscreteContactPairsWithCacheHits = 0;
|
|
mContext.mSimStats.mNbDiscreteContactPairsWithContacts = 0;
|
|
#else
|
|
PX_CATCH_UNDEFINED_ENABLE_SIM_STATS
|
|
#endif
|
|
|
|
//KS - temporarily put this here. TODO - move somewhere better
|
|
mContext.mMaxPatches = 0;
|
|
|
|
processContactManager(dt, mNarrowPhasePairs.mOutputContactManagers.begin(), continuation);
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::secondPassUpdateContactManager(PxReal dt, PxBaseTask* continuation)
|
|
{
|
|
PX_PROFILE_ZONE("Sim.queueNarrowPhase", mContext.mContextID);
|
|
|
|
processContactManagerSecondPass(dt, continuation);
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::destroy()
|
|
{
|
|
this->~PxsNphaseImplementationContext();
|
|
PX_FREE_THIS;
|
|
}
|
|
|
|
/*void PxsNphaseImplementationContext::registerContactManagers(PxsContactManager** cms, Sc::ShapeInteraction** shapeInteractions, PxU32 nbContactManagers, PxU32 maxContactManagerId)
|
|
{
|
|
PX_UNUSED(maxContactManagerId);
|
|
for (PxU32 a = 0; a < nbContactManagers; ++a)
|
|
{
|
|
registerContactManager(cms[a], shapeInteractions[a], 0, 0);
|
|
}
|
|
}*/
|
|
|
|
void PxsNphaseImplementationContext::registerContactManager(PxsContactManager* cm, const Sc::ShapeInteraction* shapeInteraction, PxI32 touching, PxU32 patchCount)
|
|
{
|
|
PX_ASSERT(cm);
|
|
|
|
PxcNpWorkUnit& workUnit = cm->getWorkUnit();
|
|
|
|
const PxGeometryType::Enum geomType0 = workUnit.getGeomType0();
|
|
const PxGeometryType::Enum geomType1 = workUnit.getGeomType1();
|
|
|
|
Gu::Cache cache;
|
|
mContext.createCache(cache, geomType0, geomType1);
|
|
|
|
PxsContactManagerOutput& output = mNewNarrowPhasePairs.mOutputContactManagers.insert();
|
|
PxMemZero(&output, sizeof(output));
|
|
output.nbPatches = PxTo8(patchCount);
|
|
|
|
if(workUnit.mFlags & PxcNpWorkUnitFlag::eOUTPUT_CONSTRAINTS)
|
|
output.statusFlag |= PxsContactManagerStatusFlag::eREQUEST_CONSTRAINTS;
|
|
|
|
if (touching > 0)
|
|
output.statusFlag |= PxsContactManagerStatusFlag::eHAS_TOUCH;
|
|
else if (touching < 0)
|
|
output.statusFlag |= PxsContactManagerStatusFlag::eHAS_NO_TOUCH;
|
|
|
|
output.statusFlag |= PxsContactManagerStatusFlag::eDIRTY_MANAGER;
|
|
|
|
if (workUnit.mStatusFlags & PxcNpWorkUnitStatusFlag::eHAS_TOUCH)
|
|
workUnit.mStatusFlags |= PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH;
|
|
|
|
output.flags = workUnit.mFlags;
|
|
|
|
mNewNarrowPhasePairs.mCaches.pushBack(cache);
|
|
mNewNarrowPhasePairs.mContactManagerMapping.pushBack(cm);
|
|
|
|
if(mGPU)
|
|
{
|
|
mNewNarrowPhasePairs.mShapeInteractionsGPU.pushBack(shapeInteraction);
|
|
mNewNarrowPhasePairs.mRestDistancesGPU.pushBack(cm->getRestDistance());
|
|
mNewNarrowPhasePairs.mTorsionalPropertiesGPU.pushBack(PxsTorsionalFrictionData(workUnit.mTorsionalPatchRadius, workUnit.mMinTorsionalPatchRadius));
|
|
}
|
|
|
|
PxU32 newSz = mNewNarrowPhasePairs.mOutputContactManagers.size();
|
|
workUnit.mNpIndex = mNewNarrowPhasePairs.computeId(newSz - 1) | PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK;
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::removeContactManagersFallback(PxsContactManagerOutput* cmOutputs)
|
|
{
|
|
if (mRemovedContactManagers.size())
|
|
{
|
|
lock();
|
|
PxSort(mRemovedContactManagers.begin(), mRemovedContactManagers.size(), PxGreater<PxU32>());
|
|
|
|
for (PxU32 a = 0; a < mRemovedContactManagers.size(); ++a)
|
|
{
|
|
#if PX_DEBUG
|
|
if (a > 0)
|
|
PX_ASSERT(mRemovedContactManagers[a] < mRemovedContactManagers[a - 1]);
|
|
#endif
|
|
unregisterContactManagerInternal(mRemovedContactManagers[a], mNarrowPhasePairs, cmOutputs);
|
|
}
|
|
|
|
mRemovedContactManagers.forceSize_Unsafe(0);
|
|
unlock();
|
|
}
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::unregisterContactManager(PxsContactManager* cm)
|
|
{
|
|
PxcNpWorkUnit& unit = cm->getWorkUnit();
|
|
|
|
PxU32 index = unit.mNpIndex;
|
|
PX_ASSERT(index != 0xFFffFFff);
|
|
|
|
if (!(index & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))
|
|
{
|
|
unregisterAndForceSize(mNarrowPhasePairs, index);
|
|
}
|
|
else
|
|
{
|
|
//KS - the index in the "new" list will be the index
|
|
unregisterAndForceSize(mNewNarrowPhasePairs, index);
|
|
}
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::refreshContactManager(PxsContactManager* cm)
|
|
{
|
|
PxcNpWorkUnit& unit = cm->getWorkUnit();
|
|
PxU32 index = unit.mNpIndex;
|
|
PX_ASSERT(index != 0xFFffFFff);
|
|
PxsContactManagerOutput output;
|
|
const Sc::ShapeInteraction* interaction;
|
|
if (!(index & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))
|
|
{
|
|
output = mNarrowPhasePairs.mOutputContactManagers[PxsContactManagerBase::computeIndexFromId(index)];
|
|
interaction = mGPU ? mNarrowPhasePairs.mShapeInteractionsGPU[PxsContactManagerBase::computeIndexFromId(index)] : cm->getShapeInteraction();
|
|
unregisterAndForceSize(mNarrowPhasePairs, index);
|
|
}
|
|
else
|
|
{
|
|
output = mNewNarrowPhasePairs.mOutputContactManagers[PxsContactManagerBase::computeIndexFromId(index & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))];
|
|
interaction = mGPU ? mNewNarrowPhasePairs.mShapeInteractionsGPU[PxsContactManagerBase::computeIndexFromId(index & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))] : cm->getShapeInteraction();
|
|
//KS - the index in the "new" list will be the index
|
|
unregisterAndForceSize(mNewNarrowPhasePairs, index);
|
|
}
|
|
PxI32 touching = 0;
|
|
if(output.statusFlag & PxsContactManagerStatusFlag::eHAS_TOUCH)
|
|
touching = 1;
|
|
else if (output.statusFlag & PxsContactManagerStatusFlag::eHAS_NO_TOUCH)
|
|
touching = -1;
|
|
registerContactManager(cm, interaction, touching, output.nbPatches);
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::unregisterContactManagerFallback(PxsContactManager* cm, PxsContactManagerOutput* /*cmOutputs*/)
|
|
{
|
|
PxcNpWorkUnit& unit = cm->getWorkUnit();
|
|
PxU32 index = unit.mNpIndex;
|
|
PX_ASSERT(index != 0xFFffFFff);
|
|
|
|
if (!(index & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))
|
|
{
|
|
mRemovedContactManagers.pushBack(index);
|
|
}
|
|
else
|
|
{
|
|
//KS - the index in the "new" list will be the index
|
|
unregisterAndForceSize(mNewNarrowPhasePairs, index);
|
|
}
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::refreshContactManagerFallback(PxsContactManager* cm, PxsContactManagerOutput* cmOutputs)
|
|
{
|
|
PxcNpWorkUnit& unit = cm->getWorkUnit();
|
|
PxU32 index = unit.mNpIndex;
|
|
PX_ASSERT(index != 0xFFffFFff);
|
|
|
|
PxsContactManagerOutput output;
|
|
const Sc::ShapeInteraction* interaction;
|
|
if (!(index & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))
|
|
{
|
|
output = cmOutputs[PxsContactManagerBase::computeIndexFromId(index)];
|
|
interaction = mGPU ? mNarrowPhasePairs.mShapeInteractionsGPU[PxsContactManagerBase::computeIndexFromId(index & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))] : cm->getShapeInteraction();
|
|
//unregisterContactManagerInternal(index, mNarrowPhasePairs, cmOutputs);
|
|
unregisterContactManagerFallback(cm, cmOutputs);
|
|
}
|
|
else
|
|
{
|
|
//KS - the index in the "new" list will be the index
|
|
output = mNewNarrowPhasePairs.mOutputContactManagers[PxsContactManagerBase::computeIndexFromId(index & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))];
|
|
interaction = mGPU ? mNewNarrowPhasePairs.mShapeInteractionsGPU[PxsContactManagerBase::computeIndexFromId(index & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))] : cm->getShapeInteraction();
|
|
unregisterAndForceSize(mNewNarrowPhasePairs, index);
|
|
}
|
|
|
|
PxI32 touching = 0;
|
|
if(output.statusFlag & PxsContactManagerStatusFlag::eHAS_TOUCH)
|
|
{
|
|
touching = 1;
|
|
unit.mStatusFlags |= PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH;
|
|
}
|
|
else if (output.statusFlag & PxsContactManagerStatusFlag::eHAS_NO_TOUCH)
|
|
touching = -1;
|
|
registerContactManager(cm, interaction, touching, output.nbPatches);
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::appendContactManagers()
|
|
{
|
|
//Copy new pairs to end of old pairs. Clear new flag, update npIndex on CM and clear the new pair buffer
|
|
const PxU32 existingSize = mNarrowPhasePairs.mContactManagerMapping.size();
|
|
const PxU32 nbToAdd = mNewNarrowPhasePairs.mContactManagerMapping.size();
|
|
const PxU32 newSize = existingSize + nbToAdd;
|
|
|
|
if(newSize > mNarrowPhasePairs.mContactManagerMapping.capacity())
|
|
{
|
|
PxU32 newSz = PxMax(256u, PxMax(mNarrowPhasePairs.mContactManagerMapping.capacity()*2, newSize));
|
|
|
|
mNarrowPhasePairs.mContactManagerMapping.reserve(newSz);
|
|
mNarrowPhasePairs.mOutputContactManagers.reserve(newSz);
|
|
mNarrowPhasePairs.mCaches.reserve(newSz);
|
|
if(mGPU)
|
|
{
|
|
mNarrowPhasePairs.mShapeInteractionsGPU.reserve(newSz);
|
|
mNarrowPhasePairs.mRestDistancesGPU.reserve(newSz);
|
|
mNarrowPhasePairs.mTorsionalPropertiesGPU.reserve(newSz);
|
|
}
|
|
}
|
|
|
|
mNarrowPhasePairs.mContactManagerMapping.forceSize_Unsafe(newSize);
|
|
mNarrowPhasePairs.mOutputContactManagers.forceSize_Unsafe(newSize);
|
|
mNarrowPhasePairs.mCaches.forceSize_Unsafe(newSize);
|
|
if(mGPU)
|
|
{
|
|
mNarrowPhasePairs.mShapeInteractionsGPU.forceSize_Unsafe(newSize);
|
|
mNarrowPhasePairs.mRestDistancesGPU.forceSize_Unsafe(newSize);
|
|
mNarrowPhasePairs.mTorsionalPropertiesGPU.forceSize_Unsafe(newSize);
|
|
}
|
|
|
|
PxMemCopy(mNarrowPhasePairs.mContactManagerMapping.begin() + existingSize, mNewNarrowPhasePairs.mContactManagerMapping.begin(), sizeof(PxsContactManager*)*nbToAdd);
|
|
PxMemCopy(mNarrowPhasePairs.mOutputContactManagers.begin() + existingSize, mNewNarrowPhasePairs.mOutputContactManagers.begin(), sizeof(PxsContactManagerOutput)*nbToAdd);
|
|
PxMemCopy(mNarrowPhasePairs.mCaches.begin() + existingSize, mNewNarrowPhasePairs.mCaches.begin(), sizeof(Gu::Cache)*nbToAdd);
|
|
if(mGPU)
|
|
{
|
|
PxMemCopy(mNarrowPhasePairs.mShapeInteractionsGPU.begin() + existingSize, mNewNarrowPhasePairs.mShapeInteractionsGPU.begin(), sizeof(Sc::ShapeInteraction*)*nbToAdd);
|
|
PxMemCopy(mNarrowPhasePairs.mRestDistancesGPU.begin() + existingSize, mNewNarrowPhasePairs.mRestDistancesGPU.begin(), sizeof(PxReal)*nbToAdd);
|
|
PxMemCopy(mNarrowPhasePairs.mTorsionalPropertiesGPU.begin() + existingSize, mNewNarrowPhasePairs.mTorsionalPropertiesGPU.begin(), sizeof(PxsTorsionalFrictionData)*nbToAdd);
|
|
}
|
|
|
|
for(PxU32 a = 0; a < mNewNarrowPhasePairs.mContactManagerMapping.size(); ++a)
|
|
{
|
|
PxsContactManager* cm = mNewNarrowPhasePairs.mContactManagerMapping[a];
|
|
PxcNpWorkUnit& unit = cm->getWorkUnit();
|
|
unit.mNpIndex = mNarrowPhasePairs.computeId(existingSize + a);
|
|
|
|
if(unit.mStatusFlags & PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH)
|
|
{
|
|
unit.mStatusFlags &= (~PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH);
|
|
|
|
processPartitionEdges(mIslandSim->mGpuData, unit);
|
|
}
|
|
}
|
|
|
|
mNewNarrowPhasePairs.clear();
|
|
|
|
appendNewLostPairs();
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::appendContactManagersFallback(PxsContactManagerOutput* cmOutputs)
|
|
{
|
|
PX_PROFILE_ZONE("PxsNphaseImplementationContext.appendContactManagersFallback", mContext.mContextID);
|
|
|
|
//Copy new pairs to end of old pairs. Clear new flag, update npIndex on CM and clear the new pair buffer
|
|
const PxU32 existingSize = mNarrowPhasePairs.mContactManagerMapping.size();
|
|
const PxU32 nbToAdd = mNewNarrowPhasePairs.mContactManagerMapping.size();
|
|
const PxU32 newSize = existingSize + nbToAdd;
|
|
|
|
if(newSize > mNarrowPhasePairs.mContactManagerMapping.capacity())
|
|
{
|
|
PxU32 newSz = PxMax(mNarrowPhasePairs.mContactManagerMapping.capacity()*2, newSize);
|
|
|
|
mNarrowPhasePairs.mContactManagerMapping.reserve(newSz);
|
|
mNarrowPhasePairs.mCaches.reserve(newSz);
|
|
if(mGPU)
|
|
{
|
|
mNarrowPhasePairs.mShapeInteractionsGPU.reserve(newSz);
|
|
mNarrowPhasePairs.mRestDistancesGPU.reserve(newSz);
|
|
mNarrowPhasePairs.mTorsionalPropertiesGPU.reserve(newSz);
|
|
}
|
|
}
|
|
|
|
mNarrowPhasePairs.mContactManagerMapping.forceSize_Unsafe(newSize);
|
|
mNarrowPhasePairs.mCaches.forceSize_Unsafe(newSize);
|
|
if(mGPU)
|
|
{
|
|
mNarrowPhasePairs.mShapeInteractionsGPU.forceSize_Unsafe(newSize);
|
|
mNarrowPhasePairs.mRestDistancesGPU.forceSize_Unsafe(newSize);
|
|
mNarrowPhasePairs.mTorsionalPropertiesGPU.forceSize_Unsafe(newSize);
|
|
}
|
|
|
|
PxMemCopy(mNarrowPhasePairs.mContactManagerMapping.begin() + existingSize, mNewNarrowPhasePairs.mContactManagerMapping.begin(), sizeof(PxsContactManager*)*nbToAdd);
|
|
PxMemCopy(cmOutputs + existingSize, mNewNarrowPhasePairs.mOutputContactManagers.begin(), sizeof(PxsContactManagerOutput)*nbToAdd);
|
|
PxMemCopy(mNarrowPhasePairs.mCaches.begin() + existingSize, mNewNarrowPhasePairs.mCaches.begin(), sizeof(Gu::Cache)*nbToAdd);
|
|
if(mGPU)
|
|
{
|
|
PxMemCopy(mNarrowPhasePairs.mShapeInteractionsGPU.begin() + existingSize, mNewNarrowPhasePairs.mShapeInteractionsGPU.begin(), sizeof(Sc::ShapeInteraction*)*nbToAdd);
|
|
PxMemCopy(mNarrowPhasePairs.mRestDistancesGPU.begin() + existingSize, mNewNarrowPhasePairs.mRestDistancesGPU.begin(), sizeof(PxReal)*nbToAdd);
|
|
PxMemCopy(mNarrowPhasePairs.mTorsionalPropertiesGPU.begin() + existingSize, mNewNarrowPhasePairs.mTorsionalPropertiesGPU.begin(), sizeof(PxsTorsionalFrictionData)*nbToAdd);
|
|
}
|
|
|
|
for(PxU32 a = 0; a < mNewNarrowPhasePairs.mContactManagerMapping.size(); ++a)
|
|
{
|
|
PxsContactManager* cm = mNewNarrowPhasePairs.mContactManagerMapping[a];
|
|
PxcNpWorkUnit& unit = cm->getWorkUnit();
|
|
unit.mNpIndex = mNarrowPhasePairs.computeId(existingSize + a);
|
|
|
|
if(unit.mStatusFlags & PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH)
|
|
{
|
|
unit.mStatusFlags &= (~PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH);
|
|
|
|
processPartitionEdges(mIslandSim->mGpuData, unit);
|
|
}
|
|
}
|
|
|
|
mNewNarrowPhasePairs.clear();
|
|
|
|
appendNewLostPairs();
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::appendNewLostPairs()
|
|
{
|
|
if(mGPU)
|
|
{
|
|
mCmFoundLostOutputCounts.forceSize_Unsafe(0);
|
|
mCmFoundLost.forceSize_Unsafe(0);
|
|
PxU32 count = 0;
|
|
for (PxU32 i = 0, taskSize = mCmTasks.size(); i < taskSize; ++i)
|
|
{
|
|
PxsCMDiscreteUpdateTask* task = mCmTasks[i];
|
|
|
|
const PxU32 patchCount = task->mNbPatchChanged;
|
|
|
|
if (patchCount)
|
|
{
|
|
const PxU32 newSize = mCmFoundLostOutputCounts.size() + patchCount;
|
|
|
|
//KS - TODO - consider switching to 2x loops to avoid frequent allocations. However, we'll probably only grow this rarely,
|
|
//so may not be worth the effort!
|
|
if (mCmFoundLostOutputCounts.capacity() < newSize)
|
|
{
|
|
//Allocate more memory!!!
|
|
const PxU32 newCapacity = PxMax(mCmFoundLostOutputCounts.capacity() * 2, newSize);
|
|
mCmFoundLostOutputCounts.reserve(newCapacity);
|
|
mCmFoundLost.reserve(newCapacity);
|
|
}
|
|
|
|
mCmFoundLostOutputCounts.forceSize_Unsafe(newSize);
|
|
mCmFoundLost.forceSize_Unsafe(newSize);
|
|
|
|
PxMemCopy(&mCmFoundLost[count], task->mPatchChangedCms, sizeof(PxsContactManager*)*patchCount);
|
|
PxMemCopy(&mCmFoundLostOutputCounts[count], task->mPatchChangedOutputCounts, sizeof(PxsContactManagerOutputCounts)*patchCount);
|
|
count += patchCount;
|
|
}
|
|
}
|
|
}
|
|
mCmTasks.forceSize_Unsafe(0);
|
|
}
|
|
|
|
void PxsNphaseImplementationContext::unregisterContactManagerInternal(PxU32 npIndex, PxsContactManagers& managers, PxsContactManagerOutput* cmOutputs)
|
|
{
|
|
// PX_PROFILE_ZONE("unregisterContactManagerInternal", 0);
|
|
|
|
//TODO - remove this element from the list.
|
|
const PxU32 index = PxsContactManagerBase::computeIndexFromId((npIndex & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK)));
|
|
|
|
//Now we replace-with-last and remove the elements...
|
|
|
|
const PxU32 replaceIndex = managers.mContactManagerMapping.size()-1;
|
|
|
|
PxsContactManager* replaceManager = managers.mContactManagerMapping[replaceIndex];
|
|
|
|
mContext.destroyCache(managers.mCaches[index]);
|
|
|
|
managers.mContactManagerMapping[index] = replaceManager;
|
|
managers.mCaches[index] = managers.mCaches[replaceIndex];
|
|
cmOutputs[index] = cmOutputs[replaceIndex];
|
|
if(mGPU)
|
|
{
|
|
managers.mShapeInteractionsGPU[index] = managers.mShapeInteractionsGPU[replaceIndex];
|
|
managers.mRestDistancesGPU[index] = managers.mRestDistancesGPU[replaceIndex];
|
|
managers.mTorsionalPropertiesGPU[index] = managers.mTorsionalPropertiesGPU[replaceIndex];
|
|
}
|
|
managers.mCaches[replaceIndex].reset();
|
|
|
|
PxcNpWorkUnit& replaceUnit = replaceManager->getWorkUnit();
|
|
replaceUnit.mNpIndex = npIndex;
|
|
|
|
if(replaceUnit.mStatusFlags & PxcNpWorkUnitStatusFlag::eHAS_TOUCH)
|
|
processPartitionEdges(mIslandSim->mGpuData, replaceUnit);
|
|
|
|
managers.mContactManagerMapping.forceSize_Unsafe(replaceIndex);
|
|
managers.mCaches.forceSize_Unsafe(replaceIndex);
|
|
if(mGPU)
|
|
{
|
|
managers.mShapeInteractionsGPU.forceSize_Unsafe(replaceIndex);
|
|
managers.mRestDistancesGPU.forceSize_Unsafe(replaceIndex);
|
|
managers.mTorsionalPropertiesGPU.forceSize_Unsafe(replaceIndex);
|
|
}
|
|
}
|
|
|
|
PxsContactManagerOutput& PxsNphaseImplementationContext::getNewContactManagerOutput(PxU32 npId)
|
|
{
|
|
PX_ASSERT(npId & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK);
|
|
return mNewNarrowPhasePairs.mOutputContactManagers[PxsContactManagerBase::computeIndexFromId(npId & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))];
|
|
}
|
|
|
|
PxsContactManagerOutputIterator PxsNphaseImplementationContext::getContactManagerOutputs()
|
|
{
|
|
PxU32 offsets[1] = {0};
|
|
return PxsContactManagerOutputIterator(offsets, 1, mNarrowPhasePairs.mOutputContactManagers.begin());
|
|
}
|
|
|
|
PxvNphaseImplementationFallback* physx::createNphaseImplementationContext(PxsContext& context, IG::IslandSim* islandSim, PxVirtualAllocatorCallback* allocator, bool gpuDynamics)
|
|
{
|
|
// PT: TODO: remove useless placement new
|
|
|
|
PxsNphaseImplementationContext* npImplContext = reinterpret_cast<PxsNphaseImplementationContext*>(
|
|
PX_ALLOC(sizeof(PxsNphaseImplementationContext), "PxsNphaseImplementationContext"));
|
|
|
|
if(npImplContext)
|
|
npImplContext = PX_PLACEMENT_NEW(npImplContext, PxsNphaseImplementationContext)(context, islandSim, allocator, 0, gpuDynamics);
|
|
|
|
return npImplContext;
|
|
}
|
|
|