// 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 "CmPhysXCommon.h" #include "BpBroadPhaseSapAux.h" #include "PsFoundation.h" namespace physx { namespace Bp { PX_FORCE_INLINE void PxBpHandleSwap(BpHandle& a, BpHandle& b) { const BpHandle c = a; a = b; b = c; } PX_FORCE_INLINE void Sort(BpHandle& id0, BpHandle& id1) { if(id0>id1) PxBpHandleSwap(id0, id1); } PX_FORCE_INLINE bool DifferentPair(const BroadPhasePair& p, BpHandle id0, BpHandle id1) { return (id0!=p.mVolA) || (id1!=p.mVolB); } PX_FORCE_INLINE int Hash32Bits_1(int key) { key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; } PX_FORCE_INLINE PxU32 Hash(BpHandle id0, BpHandle id1) { return PxU32(Hash32Bits_1( int(PxU32(id0)|(PxU32(id1)<<16)) )); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SapPairManager::SapPairManager() : mHashTable (NULL), mNext (NULL), mHashSize (0), mHashCapacity (0), mMinAllowedHashCapacity (0), mActivePairs (NULL), mActivePairStates (NULL), mNbActivePairs (0), mActivePairsCapacity (0), mMask (0) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SapPairManager::~SapPairManager() { PX_ASSERT(NULL==mHashTable); PX_ASSERT(NULL==mNext); PX_ASSERT(NULL==mActivePairs); PX_ASSERT(NULL==mActivePairStates); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SapPairManager::init(const PxU32 size) { mHashTable=reinterpret_cast(PX_ALLOC(ALIGN_SIZE_16(sizeof(BpHandle)*size), "BpHandle")); mNext=reinterpret_cast(PX_ALLOC(ALIGN_SIZE_16(sizeof(BpHandle)*size), "BpHandle")); mActivePairs=reinterpret_cast(PX_ALLOC(ALIGN_SIZE_16(sizeof(BroadPhasePair)*size), "BroadPhasePair")); mActivePairStates=reinterpret_cast(PX_ALLOC(ALIGN_SIZE_16(sizeof(PxU8)*size), "BroadPhaseContextSap ActivePairStates")); mHashCapacity=size; mMinAllowedHashCapacity = size; mActivePairsCapacity=size; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SapPairManager::release() { PX_FREE(mHashTable); PX_FREE(mNext); PX_FREE(mActivePairs); PX_FREE(mActivePairStates); mHashTable = NULL; mNext = NULL; mActivePairs = NULL; mActivePairStates = NULL; mNext = 0; mHashSize = 0; mHashCapacity = 0; mMinAllowedHashCapacity = 0; mNbActivePairs = 0; mActivePairsCapacity = 0; mMask = 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const BroadPhasePair* SapPairManager::FindPair(BpHandle id0, BpHandle id1) const { if(0==mHashSize) return NULL; // Nothing has been allocated yet // Order the ids Sort(id0, id1); // Compute hash value for this pair PxU32 HashValue = Hash(id0, id1) & mMask; PX_ASSERT(HashValue the pair is persistent PX_ASSERT(Offset the pair is persistent PX_ASSERT(Offset= mHashSize) { // Get more entries mHashSize = Ps::nextPowerOfTwo(mNbActivePairs+1); mMask = mHashSize-1; reallocPairs(mHashSize>mHashCapacity); // Recompute hash value with new hash size HashValue = Hash(id0, id1) & mMask; } PX_ASSERT(mNbActivePairsmVolA = id0; // ### CMOVs would be nice here p->mVolB = id1; mActivePairStates[mNbActivePairs]=state; PX_ASSERT(mNbActivePairsmVolA, Last->mVolB) & mMask; // Walk the hash table to fix mNext PX_ASSERT(LastHashValuemVolA==id0); PX_ASSERT(P->mVolB==id1); RemovePair(id0, id1, HashValue, GetPairIndex(P)); shrinkMemory(); return true; } bool SapPairManager::RemovePairs(const Cm::BitMap& removedAABBs) { PxU32 i=0; while(i mMinAllowedHashCapacity) || (mHashSize <= (mHashCapacity >> 2)) || (mHashSize <= (mActivePairsCapacity >> 2))); } void SapPairManager::reallocPairs(const bool allocRequired) { if(allocRequired) { PX_FREE(mHashTable); mHashCapacity=mHashSize; mActivePairsCapacity=mHashSize; mHashTable = reinterpret_cast(PX_ALLOC(mHashSize*sizeof(BpHandle), "BpHandle")); for(PxU32 i=0;i(PX_ALLOC(mHashSize * sizeof(BroadPhasePair), "BroadPhasePair")); PX_ASSERT(NewPairs); BpHandle* NewNext = reinterpret_cast(PX_ALLOC(mHashSize * sizeof(BpHandle), "BpHandle")); PX_ASSERT(NewNext); PxU8* NewPairStates = reinterpret_cast(PX_ALLOC(mHashSize * sizeof(PxU8), "SapPairStates")); PX_ASSERT(NewPairStates); // Copy old data if needed if(mNbActivePairs) { PxMemCopy(NewPairs, mActivePairs, mNbActivePairs*sizeof(BroadPhasePair)); PxMemCopy(NewPairStates, mActivePairStates, mNbActivePairs*sizeof(PxU8)); } // ### check it's actually needed... probably only for pairs whose hash value was cut by the and // yeah, since Hash(id0, id1) is a constant // However it might not be needed to recompute them => only less efficient but still ok for(PxU32 i=0;i only less efficient but still ok for(PxU32 i=0;i0); const PxU32 newMaxNumPairs=2*maxNumPairs; BroadPhasePair* newPairs=reinterpret_cast(PX_ALLOC(sizeof(BroadPhasePair)*newMaxNumPairs, "BroadPhasePair")); PxMemCopy(newPairs, pairs, sizeof(BroadPhasePair)*maxNumPairs); PX_FREE(pairs); pairs=newPairs; maxNumPairs=newMaxNumPairs; } void ComputeCreatedDeletedPairsLists (const BpHandle* PX_RESTRICT boxGroups, const BpHandle* PX_RESTRICT dataArray, const PxU32 dataArraySize, PxcScratchAllocator* scratchAllocator, BroadPhasePairReport*& createdPairsList, PxU32& numCreatedPairs, PxU32& maxNumCreatedPairs, BroadPhasePairReport*& deletedPairsList, PxU32& numDeletedPairs, PxU32& maxNumDeletedPairs, PxU32& numActualDeletedPairs, SapPairManager& pairManager) { #if BP_SAP_TEST_GROUP_ID_CREATEUPDATE PX_UNUSED(boxGroups); #endif for(PxU32 i=0;i(scratchAllocator->alloc(sizeof(BroadPhasePairReport)*2*maxNumDeletedPairs, true)); PxMemCopy(newDeletedPairsList, deletedPairsList, sizeof(BroadPhasePairReport)*maxNumDeletedPairs); scratchAllocator->free(deletedPairsList); deletedPairsList = newDeletedPairsList; maxNumDeletedPairs = 2*maxNumDeletedPairs; } PX_ASSERT(numDeletedPairsmUserData != 0xcdcdcdcd); deletedPairsList[numDeletedPairs]=BroadPhasePairReport(UP->mVolA,UP->mVolB, UP->mUserData, ID); numDeletedPairs++; } } else { pairManager.ClearInArray(UP); // Add => already there... Might want to create user data, though if(pairManager.IsNew(UP)) { #if !BP_SAP_TEST_GROUP_ID_CREATEUPDATE if(boxGroups[UP->mVolA]!=boxGroups[UP->mVolB]) #endif { if(numCreatedPairs==maxNumCreatedPairs) { BroadPhasePairReport* newCreatedPairsList = reinterpret_cast(scratchAllocator->alloc(sizeof(BroadPhasePairReport)*2*maxNumCreatedPairs, true)); PxMemCopy(newCreatedPairsList, createdPairsList, sizeof(BroadPhasePairReport)*maxNumCreatedPairs); scratchAllocator->free(createdPairsList); createdPairsList = newCreatedPairsList; maxNumCreatedPairs = 2*maxNumCreatedPairs; } PX_ASSERT(numCreatedPairsmVolA,UP->mVolB, UP->mUserData, ID); numCreatedPairs++; } pairManager.ClearNew(UP); } } } //Record pairs that are to be deleted because they were simultaneously created and removed //from different axis sorts. numActualDeletedPairs=numDeletedPairs; for(PxU32 i=0;i(scratchAllocator->alloc(sizeof(BroadPhasePairReport)*2*maxNumDeletedPairs, true)); PxMemCopy(newDeletedPairsList, deletedPairsList, sizeof(BroadPhasePairReport)*maxNumDeletedPairs); scratchAllocator->free(deletedPairsList); deletedPairsList = newDeletedPairsList; maxNumDeletedPairs = 2*maxNumDeletedPairs; } PX_ASSERT(numActualDeletedPairs<=maxNumDeletedPairs); deletedPairsList[numActualDeletedPairs]=BroadPhasePairReport(UP->mVolA,UP->mVolB, NULL, ID); //KS - should we even get here???? numActualDeletedPairs++; } } // // #### try batch removal here // for(PxU32 i=0;i i && boxGroups[deletedPairsList[numDeletedPairs-1].mVolA] == boxGroups[deletedPairsList[numDeletedPairs-1].mVolB]) { numDeletedPairs--; } deletedPairsList[i]=deletedPairsList[numDeletedPairs-1]; numDeletedPairs--; } } #endif } void DeletePairsLists(const PxU32 numActualDeletedPairs, BroadPhasePairReport* deletedPairsList, SapPairManager& pairManager) { // #### try batch removal here for(PxU32 i=0;iset(boxId); globalAABBMinX = PxMin(globalAABBMinX, PxU32(asapBoxes[axis0][boxId].mMinMax[0])); globalAABBMinY = PxMin(globalAABBMinY, PxU32(asapBoxes[axis1][boxId].mMinMax[0])); globalAABBMinZ = PxMin(globalAABBMinZ, PxU32(asapBoxes[axis2][boxId].mMinMax[0])); globalAABBMaxX = PxMax(globalAABBMaxX, PxU32(asapBoxes[axis0][boxId].mMinMax[1])); globalAABBMaxY = PxMax(globalAABBMaxY, PxU32(asapBoxes[axis1][boxId].mMinMax[1])); globalAABBMaxZ = PxMax(globalAABBMaxZ, PxU32(asapBoxes[axis2][boxId].mMinMax[1])); } PxU32 oldStaticCount=0; PxU32 newStaticCount=0; //Assign the sorted end pts to the appropriate arrays. for(PxU32 i=1;itest(boxId)) { if(Intersect3D( globalAABBMinX, globalAABBMaxX, globalAABBMinY, globalAABBMaxY, globalAABBMinZ, globalAABBMaxZ, asapBoxes[axis0][boxId].mMinMax[0],asapBoxes[axis0][boxId].mMinMax[1],asapBoxes[axis1][boxId].mMinMax[0],asapBoxes[axis1][boxId].mMinMax[1],asapBoxes[axis2][boxId].mMinMax[0],asapBoxes[axis2][boxId].mMinMax[1])) { oldBoxIndicesSorted[oldBoxIndicesCount]=boxId; oldBoxIndicesCount++; oldStaticCount+=asapBoxGroupIds[boxId]; } } else { newBoxIndicesSorted[newBoxIndicesCount]=boxId; newBoxIndicesCount++; newStaticCount+=asapBoxGroupIds[boxId]; } } } allOldBoxesStatics = oldStaticCount ? false : true; allNewBoxesStatics = newStaticCount ? false : true; //Make sure that we've found the correct number of boxes. PX_ASSERT(newBoxIndicesCount==(insertAABBEnd-insertAABBStart)); PX_ASSERT(oldBoxIndicesCount<=((numSortedEndPoints-NUM_SENTINELS)/2)); } void performBoxPruningNewNew (const Gu::Axes& axes, const BpHandle* PX_RESTRICT newBoxIndicesSorted, const PxU32 newBoxIndicesCount, const bool allNewBoxesStatics, BpHandle* PX_RESTRICT minPosList0, SapBox1D** PX_RESTRICT asapBoxes, const BpHandle* PX_RESTRICT asapBoxGroupIds, PxcScratchAllocator* scratchAllocator, SapPairManager& pairManager, BpHandle*& dataArray, PxU32& dataArraySize, PxU32& dataArrayCapacity) { // Checkings if(!newBoxIndicesCount) return; // Catch axes const PxU32 Axis0 = axes.mAxis0; const PxU32 Axis1 = axes.mAxis1; const PxU32 Axis2 = axes.mAxis2; // 1) Build main list using the primary axis for(PxU32 i=0;i