// This code contains NVIDIA Confidential Information and is disclosed to you // under a form of NVIDIA software license agreement provided separately to you. // // Notice // NVIDIA Corporation and its licensors retain all intellectual property and // proprietary rights in and to this software and related documentation and // any modifications thereto. Any use, reproduction, disclosure, or // distribution of this software and related documentation without an express // license agreement from NVIDIA Corporation is strictly prohibited. // // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. // // Information and code furnished is believed to be accurate and reliable. // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such // information or for any infringement of patents or other rights of third parties that may // result from its use. No license is granted by implication or otherwise under any patent // or patent rights of NVIDIA Corporation. Details are subject to change without notice. // This code supersedes and replaces all information previously supplied. // NVIDIA Corporation products are not authorized for use as critical // components in life support devices or systems without express written approval of // NVIDIA Corporation. // // Copyright (c) 2008-2017 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 "foundation/PxProfiler.h" #include "PxvConfig.h" #include "PxcContactCache.h" #include "PxsRigidBody.h" #include "PxsContactManager.h" #include "PxsContext.h" #include "PxPhysXConfig.h" #include "CmBitMap.h" #include "CmFlushPool.h" #include "PxsMaterialManager.h" #include "PxSceneDesc.h" #include "PxsCCD.h" #include "PxvGeometry.h" #include "PxvManager.h" #include "PxsSimpleIslandManager.h" #if PX_SUPPORT_GPU_PHYSX #include "task/PxGpuDispatcher.h" #include "PxPhysXGpu.h" #endif #include "PxcNpContactPrepShared.h" #include "PxcNpCache.h" using namespace physx; using namespace physx::shdfnd; #define PXS_CONTACTMANAGER_SLABSIZE 1024 #define PXS_MAX_CONTACTMANAGER_SLABS 64 #define PXS_BODYSHAPE_SLABSIZE 1024 #define PXS_MAX_BODYSHAPE_SLABS 16 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(); } PxsContext::PxsContext(const PxSceneDesc& desc, PxTaskManager* taskManager, Cm::FlushPool& taskPool, PxU64 contextID) : mNpThreadContextPool (this), mContactManagerPool ("mContactManagerPool", this, 256, 8192), mManifoldPool ("mManifoldPool", 256), mSphereManifoldPool ("mSphereManifoldPool", 256), mContactModifyCallback (NULL), mNpImplementationContext (NULL), mNpFallbackImplementationContext(NULL), mTaskManager (taskManager), mTaskPool (taskPool), mPCM (desc.flags & PxSceneFlag::eENABLE_PCM), mContactCache (false), mCreateAveragePoint (desc.flags & PxSceneFlag::eENABLE_AVERAGE_POINT), mContextID (contextID) { clearManagerTouchEvents(); mVisualizationCullingBox.setMaximal(); PxMemZero(mVisualizationParams, sizeof(PxReal) * PxVisualizationParameter::eNUM_VALUES); mNpMemBlockPool.init(desc.nbContactDataBlocks, desc.maxNbContactDataBlocks); } PxsContext::~PxsContext() { if(mTransformCache) { mTransformCache->~PxsTransformCache(); PX_FREE(mTransformCache); } mTransformCache = NULL; mContactManagerPool.destroy(); //manually destroy the contact manager pool, otherwise pool deletion order is random and we can get into trouble with references into other pools needed during destruction. } // =========================== Create methods namespace physx { bool gEnablePCMCaching[PxGeometryType::eGEOMETRY_COUNT][PxGeometryType::eGEOMETRY_COUNT] = { //eSPHERE, { false, //eSPHERE false, //ePLANE false, //eCAPSULE false, //eBOX true, //eCONVEXMESH true, //eTRIANGLEMESH true //eHEIGHTFIELD }, //ePLANE { false, //eSPHERE false, //ePLANE true, //eCAPSULE true, //eBOX true, //eCONVEXMESH false, //eTRIANGLEMESH false //eHEIGHTFIELD }, //eCAPSULE, { false, //eSPHERE true, //ePLANE false, //eCAPSULE true, //eBOX true, //eCONVEXMESH true, //eTRIANGLEMESH true //eHEIGHTFIELD }, //eBOX, { false, //eSPHERE true, //ePLANE true, //eCAPSULE true, //eBOX true, //eCONVEXMESH true, //eTRIANGLEMESH true //eHEIGHTFIELD }, //eCONVEXMESH, { true, //eSPHERE true, //ePLANE true, //eCAPSULE true, //eBOX true, //eCONVEXMESH true, //eTRIANGLEMESH true //eHEIGHTFIELD }, //eTRIANGLEMESH, { true, //eSPHERE false, //ePLANE true, //eCAPSULE true, //eBOX true, //eCONVEXMESH false, //eTRIANGLEMESH false //eHEIGHTFIELD }, //eHEIGHTFIELD, { true, //eSPHERE false, //ePLANE true, //eCAPSULE true, //eBOX true, //eCONVEXMESH false, //eTRIANGLEMESH false //eHEIGHTFIELD } }; } void PxsContext::createTransformCache(Ps::VirtualAllocatorCallback& allocatorCallback) { mTransformCache = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(PxsTransformCache), PX_DEBUG_EXP("PxsTransformCache")), PxsTransformCache(allocatorCallback)); } PxsContactManager* PxsContext::createContactManager(PxsContactManager* contactManager, const bool useCCD) { PxsContactManager* cm = contactManager? contactManager : mContactManagerPool.get(); if(cm) { PxcNpWorkUnitClearContactState(cm->getWorkUnit()); PxcNpWorkUnitClearCachedState(cm->getWorkUnit()); if (contactManager == NULL) { if (cm->getIndex() >= mActiveContactManager.size()) { PxU32 newSize = (2 * cm->getIndex() + 256)&~255; mActiveContactManager.resize(newSize); } mActiveContactManager.set(cm->getIndex()); if (useCCD) { if (cm->getIndex() >= mActiveContactManagersWithCCD.size()) { PxU32 newSize = (2 * cm->getIndex() + 256)&~255; mActiveContactManagersWithCCD.resize(newSize); } mActiveContactManagersWithCCD.set(cm->getIndex()); } } } else { PX_WARN_ONCE("Reached limit of contact pairs."); } return cm; } void PxsContext::createCache(Gu::Cache& cache, PxsContactManager* cm, PxU8 geomType0, PxU8 geomType1) { if(cm) { if(mPCM) { if(gEnablePCMCaching[geomType0][geomType1]) { if(geomType0 <= PxGeometryType::eCONVEXMESH && geomType1 <= PxGeometryType::eCONVEXMESH) { if(geomType0 == PxGeometryType::eSPHERE || geomType1 == PxGeometryType::eSPHERE) { Gu::PersistentContactManifold* manifold = mSphereManifoldPool.allocate(); new(manifold) Gu::SpherePersistentContactManifold(); cache.setManifold(manifold); } else { Gu::PersistentContactManifold* manifold = mManifoldPool.allocate(); new(manifold) Gu::LargePersistentContactManifold(); cache.setManifold(manifold); } cache.getManifold().clearManifold(); } else { //ML: raised 1 to indicate the manifold is multiManifold which is for contact gen in mesh/height field //cache.manifold = 1; cache.setMultiManifold(NULL); } } else { //cache.manifold = 0; cache.mCachedData = NULL; cache.mManifoldFlags = 0; } } } } void PxsContext::destroyContactManager(PxsContactManager* cm) { const PxU32 idx = cm->getIndex(); if (cm->getCCD()) mActiveContactManagersWithCCD.growAndReset(idx); mActiveContactManager.growAndReset(idx); mContactManagerTouchEvent.growAndReset(idx); mContactManagerPatchChangeEvent.growAndReset(idx); mContactManagerPool.put(cm); } void PxsContext::destroyCache(Gu::Cache& cache) { if(cache.isManifold()) { if(!cache.isMultiManifold()) { Gu::PersistentContactManifold& manifold = cache.getManifold(); if (manifold.mCapacity == GU_SPHERE_MANIFOLD_CACHE_SIZE) { mSphereManifoldPool.deallocate(static_cast(&manifold)); } else { mManifoldPool.deallocate(static_cast(&manifold)); } } cache.mCachedData = NULL; cache.mManifoldFlags = 0; } } void PxsContext::setScratchBlock(void* addr, PxU32 size) { mScratchAllocator.setBlock(addr, size); } void PxsContext::setContactDistance(Ps::Array* contactDistance) { mContactDistance = contactDistance; } void PxsContext::shiftOrigin(const PxVec3& shift) { // transform cache mTransformCache->shiftTransforms(-shift); #if 0 if (getContactCacheFlag()) { //Iterate all active contact managers Cm::BitMap::Iterator it(mActiveContactManager); PxU32 index = it.getNext(); while(index != Cm::BitMap::Iterator::DONE) { PxsContactManager* cm = mContactManagerPool.findByIndexFast(index); PxcNpWorkUnit& npwUnit = cm->getWorkUnit(); // contact cache if(!npwUnit.pairCache.isManifold()) { PxU8* contactCachePtr = npwUnit.pairCache.mCachedData; if (contactCachePtr) { PxcLocalContactsCache* lcc; PxU8* contacts = PxcNpCacheRead(npwUnit.pairCache, lcc); #ifdef _DEBUG PxcLocalContactsCache testCache; PxU32 testBytes; const PxU8* testPtr = PxcNpCacheRead2(npwUnit.pairCache, testCache, testBytes); #endif lcc->mTransform0.p -= shift; lcc->mTransform1.p -= shift; const PxU32 nbContacts = lcc->mNbCachedContacts; const bool sameNormal = lcc->mSameNormal; const bool useFaceIndices = lcc->mUseFaceIndices; for(PxU32 i=0; i < nbContacts; i++) { if (i != nbContacts-1) Ps::prefetchLine(contacts, 128); if(!i || !sameNormal) contacts += sizeof(PxVec3); PxVec3* cachedPoint = reinterpret_cast(contacts); *cachedPoint -= shift; contacts += sizeof(PxVec3); contacts += sizeof(PxReal); if(useFaceIndices) contacts += 2 * sizeof(PxU32); } #ifdef _DEBUG PX_ASSERT(contacts == (testPtr + testBytes)); #endif } } index = it.getNext(); } } #endif // // adjust visualization culling box // PxBounds3 maximalBounds; maximalBounds.setMaximal(); if ((mVisualizationCullingBox.minimum != maximalBounds.minimum) || (mVisualizationCullingBox.maximum != maximalBounds.maximum)) { mVisualizationCullingBox.minimum -= shift; mVisualizationCullingBox.maximum -= shift; } } void PxsContext::swapStreams() { mNpMemBlockPool.swapNpCacheStreams(); } void PxsContext::mergeCMDiscreteUpdateResults(PxBaseTask* /*continuation*/) { PX_PROFILE_ZONE("Sim.narrowPhaseMerge", mContextID); this->mNpImplementationContext->appendContactManagers(); //Note: the iterator extracts all the items and returns them to the cache on destruction(for thread safety). PxcThreadCoherentCacheIterator threadContextIt(mNpThreadContextPool); for(PxcNpThreadContext* threadContext = threadContextIt.getNext(); threadContext; threadContext = threadContextIt.getNext()) { mCMTouchEventCount[PXS_LOST_TOUCH_COUNT] += threadContext->getLocalLostTouchCount(); mCMTouchEventCount[PXS_NEW_TOUCH_COUNT] += threadContext->getLocalNewTouchCount(); mCMTouchEventCount[PXS_PATCH_FOUND_COUNT] += threadContext->getLocalFoundPatchCount(); mCMTouchEventCount[PXS_PATCH_LOST_COUNT] += threadContext->getLocalLostPatchCount(); #if PX_ENABLE_SIM_STATS for(PxU32 i=0;imDiscreteContactPairs[i][j]); #endif for(PxU32 j=i; jmDiscreteContactPairs[i][j]; const PxU32 nbModified = threadContext->mModifiedContactPairs[i][j]; mSimStats.mNbDiscreteContactPairs[i][j] += nb; mSimStats.mNbModifiedContactPairs[i][j] += nbModified; mSimStats.mNbDiscreteContactPairsTotal += nb; } } mSimStats.mNbDiscreteContactPairsWithCacheHits += threadContext->mNbDiscreteContactPairsWithCacheHits; mSimStats.mNbDiscreteContactPairsWithContacts += threadContext->mNbDiscreteContactPairsWithContacts; mSimStats.mTotalCompressedContactSize += threadContext->mCompressedCacheSize; //KS - this data is not available yet //mSimStats.mTotalConstraintSize += threadContext->mConstraintSize; threadContext->clearStats(); #endif mContactManagerTouchEvent.combineInPlace(threadContext->getLocalChangeTouch()); mContactManagerPatchChangeEvent.combineInPlace(threadContext->getLocalPatchChangeMap()); mTotalCompressedCacheSize += threadContext->mTotalCompressedCacheSize; mMaxPatches = PxMax(mMaxPatches, threadContext->mMaxPatches); threadContext->mTotalCompressedCacheSize = threadContext->mMaxPatches = 0; } } void PxsContext::setCreateContactStream(bool to) { mCreateContactStream = to; PxcThreadCoherentCacheIterator threadContextIt(mNpThreadContextPool); for(PxcNpThreadContext* threadContext = threadContextIt.getNext(); threadContext; threadContext = threadContextIt.getNext()) { threadContext->setCreateContactStream(to); } } void PxsContext::updateContactManager(PxReal dt, bool hasBoundsArrayChanged, bool hasContactDistanceChanged, PxBaseTask* continuation, PxBaseTask* firstPassContinuation) { PX_ASSERT(mNpImplementationContext); mNpImplementationContext->updateContactManager(dt, hasBoundsArrayChanged, hasContactDistanceChanged, continuation, firstPassContinuation); } void PxsContext::secondPassUpdateContactManager(PxReal dt, PxBaseTask* continuation) { PX_ASSERT(mNpImplementationContext); mNpImplementationContext->secondPassUpdateContactManager(dt, continuation); } void PxsContext::fetchUpdateContactManager() { PX_ASSERT(mNpImplementationContext); mNpImplementationContext->fetchUpdateContactManager(); mergeCMDiscreteUpdateResults(NULL); } void PxsContext::resetThreadContexts() { //Note: the iterator extracts all the items and returns them to the cache on destruction(for thread safety). PxcThreadCoherentCacheIterator threadContextIt(mNpThreadContextPool); PxcNpThreadContext* threadContext = threadContextIt.getNext(); while(threadContext != NULL) { threadContext->reset(mContactManagerTouchEvent.size()); threadContext = threadContextIt.getNext(); } } bool PxsContext::getManagerTouchEventCount(int* newTouch, int* lostTouch, int* ccdTouch) const { if(newTouch) *newTouch = int(mCMTouchEventCount[PXS_NEW_TOUCH_COUNT]); if(lostTouch) *lostTouch = int(mCMTouchEventCount[PXS_LOST_TOUCH_COUNT]); if(ccdTouch) *ccdTouch = int(mCMTouchEventCount[PXS_CCD_RETOUCH_COUNT]); return true; } bool PxsContext::fillManagerTouchEvents(PxvContactManagerTouchEvent* newTouch, PxI32& newTouchCount, PxvContactManagerTouchEvent* lostTouch, PxI32& lostTouchCount, PxvContactManagerTouchEvent* ccdTouch, PxI32& ccdTouchCount) { PxU32 index; const PxvContactManagerTouchEvent* newTouchStart = newTouch; const PxvContactManagerTouchEvent* lostTouchStart = lostTouch; const PxvContactManagerTouchEvent* ccdTouchStart = ccdTouch; const PxvContactManagerTouchEvent* newTouchEnd = newTouch + newTouchCount; const PxvContactManagerTouchEvent* lostTouchEnd = lostTouch + lostTouchCount; const PxvContactManagerTouchEvent* ccdTouchEnd = ccdTouch + ccdTouchCount; PX_UNUSED(newTouchEnd); PX_UNUSED(lostTouchEnd); PX_UNUSED(ccdTouchEnd); Cm::BitMap::Iterator it(mContactManagerTouchEvent); while((index = it.getNext()) != Cm::BitMap::Iterator::DONE) { PxsContactManager* cm = mContactManagerPool.findByIndexFast(index); if(cm->getTouchStatus()) { if (!cm->getHasCCDRetouch()) { PX_ASSERT(newTouch < newTouchEnd); newTouch->manager = cm; newTouch->userData = cm->getUserData(); newTouch++; } else { PX_ASSERT(ccdTouch); PX_ASSERT(ccdTouch < ccdTouchEnd); ccdTouch->manager = cm; ccdTouch->userData = cm->getUserData(); cm->clearCCDRetouch(); ccdTouch++; } } else { PX_ASSERT(lostTouch < lostTouchEnd); lostTouch->manager = cm; lostTouch->userData = cm->getUserData(); lostTouch++; } } newTouchCount = PxI32(newTouch - newTouchStart); lostTouchCount = PxI32(lostTouch - lostTouchStart); ccdTouchCount = PxI32(ccdTouch - ccdTouchStart); return true; } bool PxsContext::fillManagerPatchChangedEvents(PxsContactManager** foundPatch, PxU32& foundPatchCount, PxsContactManager** lostPatch, PxU32& lostPatchCount) { Cm::BitMap::Iterator it(mContactManagerPatchChangeEvent); PxsContactManagerOutputIterator outputs = mNpImplementationContext->getContactManagerOutputs(); PxU32 index; PxsContactManager** currFoundPatch = foundPatch; PxsContactManager** currLostPatch = lostPatch; while((index = it.getNext()) != Cm::BitMap::Iterator::DONE) { PxsContactManager* cm = mContactManagerPool.findByIndexFast(index); PxcNpWorkUnit& workUnit = cm->getWorkUnit(); PxsContactManagerOutput& output = outputs.getContactManager(workUnit.mNpIndex); if(output.nbPatches > output.prevPatches) { PX_ASSERT(PxU32(currFoundPatch - foundPatch) < foundPatchCount); *currFoundPatch = cm; currFoundPatch++; } else if(output.nbPatches < output.prevPatches) { PX_ASSERT(PxU32(currLostPatch - lostPatch) < lostPatchCount); *currLostPatch = cm; currLostPatch++; } } foundPatchCount = PxU32(currFoundPatch - foundPatch); lostPatchCount = PxU32(currLostPatch - lostPatch); return true; } void PxsContext::beginUpdate() { #if PX_ENABLE_SIM_STATS mSimStats.clearAll(); #endif } // Contact manager related PxReal PxsContext::getVisualizationParameter(PxVisualizationParameter::Enum param) const { PX_ASSERT(param < PxVisualizationParameter::eNUM_VALUES); return mVisualizationParams[param]; } void PxsContext::setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value) { PX_ASSERT(param < PxVisualizationParameter::eNUM_VALUES); PX_ASSERT(value >= 0.0f); mVisualizationParams[param] = value; }