// 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. #ifndef PXG_AABBMANAGER_H #define PXG_AABBMANAGER_H #include "BpAABBManagerBase.h" #include "PxgCudaBuffer.h" #include "PxgAggregate.h" #include "CmIDPool.h" #include "PxgBroadPhasePairReport.h" #include "PxgAggregateDesc.h" #include "CmTask.h" #include "foundation/PxPinnedArray.h" namespace physx { class PxgCudaKernelWranglerManager; class PxCudaContextManager; class PxgCudaBroadPhaseSap; struct PxGpuDynamicsMemoryConfig; class PxgAABBManager; class PxSceneDesc; struct PxBoundTransformUpdate { PxU32 indexTo; PxU32 indexFrom; //MSB stores info if the bound is new. New is copied from cpu array, not new - from gpu array }; class PxgProcessFoundPairTask : public Cm::Task { PxgAABBManager* mManager; public: PxgProcessFoundPairTask(PxgAABBManager* manager) : Cm::Task(0), mManager(manager) { } virtual void runInternal(); virtual const char* getName() const { return "PxgProcessFoundPairTask"; } }; class PxgProcessLostPairTask : public Cm::Task { PxgAABBManager* mManager; public: PxgProcessLostPairTask(PxgAABBManager* manager) : Cm::Task(0), mManager(manager) { } virtual void runInternal(); virtual const char* getName() const { return "PxgProcessLostPairTask"; } }; class PxgAABBManager : public Bp::AABBManagerBase { public: PxgAABBManager(PxgCudaKernelWranglerManager* gpuKernelWrangler, PxCudaContextManager* cudaContextManager, PxgHeapMemoryAllocatorManager* heapMemoryManager, const PxGpuDynamicsMemoryConfig& config, Bp::BroadPhase& bp, Bp::BoundsArray& boundsArray, PxFloatArrayPinned& contactDistance, PxU32 maxNbAggregates, PxU32 maxNbShapes, PxVirtualAllocator& allocator, PxU64 contextID, PxPairFilteringMode::Enum kineKineFilteringMode, PxPairFilteringMode::Enum staticKineFilteringMode); virtual ~PxgAABBManager() {} // AABBManagerBase virtual void destroy() PX_OVERRIDE; virtual Bp::AggregateHandle createAggregate(Bp::BoundsIndex index, Bp::FilterGroup::Enum group, void* userData, PxU32 maxNumShapes, PxAggregateFilterHint filterHint, PxU32 envID) PX_OVERRIDE; virtual bool destroyAggregate(Bp::BoundsIndex& index, Bp::FilterGroup::Enum& group, Bp::AggregateHandle aggregateHandle) PX_OVERRIDE; virtual bool addBounds(Bp::BoundsIndex index, PxReal contactDistance, Bp::FilterGroup::Enum group, void* userData, Bp::AggregateHandle aggregateHandle, Bp::ElementType::Enum volumeType, PxU32 envID) PX_OVERRIDE; virtual bool removeBounds(Bp::BoundsIndex index) PX_OVERRIDE; virtual void updateBPFirstPass(PxU32 numCpuTasks, Cm::FlushPool& flushPool, bool hasContactDistanceUpdated, PxBaseTask* continuation) PX_OVERRIDE; virtual void updateBPSecondPass(PxcScratchAllocator* scratchAllocator, PxBaseTask* continuation) PX_OVERRIDE; virtual void postBroadPhase(PxBaseTask*, Cm::FlushPool& flushPool) PX_OVERRIDE; virtual void reallocateChangedAABBMgActorHandleMap(const PxU32 size) PX_OVERRIDE; virtual void visualize(PxRenderOutput& out) PX_OVERRIDE; virtual void releaseDeferredAggregateIds() PX_OVERRIDE; virtual void setGPUStateChanged() PX_OVERRIDE { mGPUStateChanged = true; } virtual void setPersistentStateChanged() PX_OVERRIDE { mPersistentStateChanged = true; } //~AABBManagerBase PxgCudaBuffer mVolumDataBuf; void markAggregateBoundsBitmap(); void processFoundPairs(); void processLostPairs(); // PX_FORCE_INLINE PxBitMapPinned& getAggregatedBoundMap() { return mAggregatedBoundMap; } PX_FORCE_INLINE CUdeviceptr getAggregatedBounds() { return mAggregatedBoundsBuf.getDevicePtr(); } PX_FORCE_INLINE CUdeviceptr getAddedHandles() { return mAddedHandleBuf.getDevicePtr(); } PX_FORCE_INLINE CUdeviceptr getRemovedHandles() { return mRemovedHandleBuf.getDevicePtr(); } PX_FORCE_INLINE CUdeviceptr getChangedAABBMgrHandles() { return mChangedAABBMgrHandlesBuf.getDevicePtr(); } PX_FORCE_INLINE PxU32 getChangedAABBMgrHandlesWordCount() { return mChangedHandleMap.getWordCount(); } private: void preBpUpdate_GPU(); void gpuDmaDataUp(); void clearDirtyAggs(); void resizeFoundAndLostPairs(); void computeAggregateBounds(); void updateDescriptor(CUstream bpStream); PxgCudaKernelWranglerManager* mGpuKernelWranglerManager; PxCudaContextManager* mCudaContextManager; PxCudaContext* mCudaContext; PxgHeapMemoryAllocatorManager* mHeapMemoryManager; PxArray mAggregates; //cpu mirror PxPinnedArray mAggregatePairs; PxPinnedArray mDirtyAggregateIndices; PxPinnedArray mDirtyAggregates; //found and lost pairs for agg vs agg and agg vs actor PxPinnedArray mFoundPairs; PxPinnedArray mLostPairs; PxInt32ArrayPinned mDirtyBoundIndices; PxInt32ArrayPinned mDirtyBoundStartIndices; //start index of each aggregate in the dirty bound indices list PxInt32ArrayPinned mRemovedAggregatedBounds; PxInt32ArrayPinned mAddedAggregatedBounds; Cm::DeferredIDPool mAggregatesIdPool; //generate the remap id between pxgbodysim and pxgaggregate PxBitMap mDirtyAggregateBitMap; PxBitMapPinned mAggregatedBoundMap; PxArray mAggregateBufferArray; PxgAggregateDesc* mAggregateDesc; PxgCudaBuffer mAggregateBuf; PxgCudaBuffer mAggregatePairsBuf; PxgCudaBuffer mDirtyAggregateIndiceBuf; PxgCudaBuffer mDirtyAggregateBuf; PxgCudaBuffer mDirtyBoundIndicesBuf; PxgCudaBuffer mDirtyBoundStartIndicesBuf; PxgCudaBuffer mRemovedAggregatedBoundsBuf; PxgCudaBuffer mAddedAggregatedBoundsBuf; PxgCudaBuffer mAggPairBuf; //persistent pairs PxgCudaBuffer mNumAggPairBuf; // number of app pairs PxgCudaBuffer mAggregateDescBuf; PxgCudaBuffer mFoundPairsBuf; PxgCudaBuffer mLostPairsBuf; PxgCudaBuffer mFreeIDPool; PxgCudaBuffer mFreeIDs; PxgCudaBuffer mRemoveBitmap; PxgCudaBuffer mRemoveHistogram; PxgCudaBuffer mAggregatedBoundsBuf; PxgCudaBuffer mAddedHandleBuf; PxgCudaBuffer mRemovedHandleBuf; PxgCudaBuffer mChangedAABBMgrHandlesBuf; PxU32 mNumAggregatesSlots; PxU32 mMaxFoundLostPairs; PxU32 mMaxAggPairs; PxgProcessFoundPairTask mFoundPairTask; PxgProcessLostPairTask mLostPairTask; // PT: this flag is set: // - via setGPUStateChanged(): // - in PxgSimulationCore::applyActorData() when body data is changed // - in FEMClothShapeSim::updateBoundsInAABBMgr() // - in ParticleSystemShapeSim::updateBoundsInAABBMgr // - in SoftBodyShapeSim::updateBoundsInAABBMgr() // - when mOriginShifted is false and hasActive is true in PxgAABBManager::updateBPFirstPass // // It is unclear whether we need to set the flag in all of these cases. // // The flag is used: // - in PxgAABBManager::preBpUpdate_GPU // - to skip DMA of mChangedHandleMap // - in PxgAABBManager::updateBPSecondPass // - in the GPU broadphase (passed there as part of the updateData structure) // - TODO: investigate what happens there // - to skip kernel launches of AGG_ADD_AGGPAIRS_STAGE_1/AGG_ADD_AGGPAIRS_STAGE_2 bool mGPUStateChanged; //non-rigid body, direct API calls // PT: this flag is set: // - via setPersistentStateChanged(): // - when a contact distance changes // - when an aggregate is removed (PxgAABBManager::destroyAggregate) // - when an object is added (PxgAABBManager::addBounds) // - when an aggregated is added (PxgAABBManager::addBounds) // - when an object is removed (PxgAABBManager::removeBounds) // - when an aggregated is removed (PxgAABBManager::removeBounds) // - in PxgAABBManager::updateBPFirstPass if hasContactDistanceUpdated is true // - when mOriginShifted is true, during PxgAABBManager::updateBPFirstPass // // It is unclear whether we need to set the flag in all of these cases. // // The flag is used: // - in PxgAABBManager::preBpUpdate_GPU // - to skip DMAs of mAddedHandleMap/mRemovedHandleMap // - to skip DMA of mAggregatedBoundMap / mVolumeData // - to skip the preBroadphase call // - to skip DMA of mChangedHandleMap // - in PxgAABBManager::updateBPSecondPass // - in the GPU broadphase (passed there as part of the updateData structure) // - TODO: investigate what happens there // - to skip kernel launches of AGG_ADD_AGGPAIRS_STAGE_1/AGG_ADD_AGGPAIRS_STAGE_2 bool mPersistentStateChanged; }; class PxgBoundsArray : public Bp::BoundsArray { PX_NOCOPY(PxgBoundsArray) public: PxgBoundsArray(PxVirtualAllocator& allocator) : BoundsArray(allocator) , mIsFirstCopy(true) , mChanges(allocator) { } virtual ~PxgBoundsArray() PX_OVERRIDE { mChanges.clear(); } void updateBounds(const PxTransform& transform, const PxGeometry& geom, PxU32 index, PxU32 indexFrom) PX_OVERRIDE PX_FINAL { if(indexFrom == index) // new, needs to be copied from CPU { Gu::computeBounds(mBounds[index], geom, transform, 0.0f, 1.0f); updateChanges(index, indexFrom, true); } else { updateChanges(index, indexFrom, false); } } void setBounds(const PxBounds3& bounds, PxU32 index) PX_OVERRIDE PX_FINAL { mBounds[index] = bounds; updateChanges(index, index, true); } PX_FORCE_INLINE PxU32 getNumberOfChanges() { return mChanges.size(); } PX_FORCE_INLINE PxArray& getStagingBuffer() { return mChanges; } PX_FORCE_INLINE void resetChanges() { mChanges.reset(); } PX_FORCE_INLINE bool isFirstCopy() { return mIsFirstCopy; } PX_FORCE_INLINE void setCopied() { mIsFirstCopy = false; } private: PX_FORCE_INLINE void updateChanges(PxU32 indexTo, PxU32 indexFrom, bool isNew) { if(!mIsFirstCopy) { PxBoundTransformUpdate update; update.indexTo = indexTo; update.indexFrom = indexFrom & 0x7FFFFFFF; if(isNew) { update.indexFrom |= (1U << 31); } mChanges.pushBack(update); } } bool mIsFirstCopy; PxArray mChanges; }; } #endif