This commit is contained in:
2025-11-28 23:13:44 +05:30
commit a3a8e79709
7360 changed files with 1156074 additions and 0 deletions

View File

@ -0,0 +1,87 @@
//
// 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-2021 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 PXC_CONTACTMETHODIMPL_H
#define PXC_CONTACTMETHODIMPL_H
#include "GuGeometryUnion.h"
#include "CmPhysXCommon.h"
#include "GuContactMethodImpl.h"
namespace physx
{
namespace Cm
{
class RenderOutput;
}
namespace Gu
{
class ContactBuffer;
struct Cache;
struct NarrowPhaseParams;
}
namespace Cm
{
class FastVertex2ShapeScaling;
}
/*!\file
This file contains forward declarations of all implemented contact methods.
*/
/*! Parameter list without names to avoid unused parameter warnings
*/
#define CONTACT_METHOD_ARGS_UNUSED \
const Gu::GeometryUnion&, \
const Gu::GeometryUnion&, \
const PxTransform&, \
const PxTransform&, \
const Gu::NarrowPhaseParams&, \
Gu::Cache&, \
Gu::ContactBuffer&, \
Cm::RenderOutput*
/*!
Method prototype for contact generation routines
*/
typedef bool (*PxcContactMethod) (GU_CONTACT_METHOD_ARGS);
// Matrix of types
extern PxcContactMethod g_ContactMethodTable[][PxGeometryType::eGEOMETRY_COUNT];
extern const bool g_CanUseContactCache[][PxGeometryType::eGEOMETRY_COUNT];
extern PxcContactMethod g_PCMContactMethodTable[][PxGeometryType::eGEOMETRY_COUNT];
extern bool gEnablePCMCaching[][PxGeometryType::eGEOMETRY_COUNT];
}
#endif

View File

@ -0,0 +1,156 @@
//
// 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-2021 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 PXC_CONSTRAINTBLOCKPOOL_H
#define PXC_CONSTRAINTBLOCKPOOL_H
#include "PxvConfig.h"
#include "PsArray.h"
#include "PsMutex.h"
#include "PxcNpMemBlockPool.h"
namespace physx
{
class PxsConstraintBlockManager
{
public:
PxsConstraintBlockManager(PxcNpMemBlockPool & blockPool):
mBlockPool(blockPool)
{
}
PX_FORCE_INLINE void reset()
{
mBlockPool.releaseConstraintBlocks(mTrackingArray);
}
PxcNpMemBlockArray mTrackingArray;
PxcNpMemBlockPool& mBlockPool;
private:
PxsConstraintBlockManager& operator=(const PxsConstraintBlockManager&);
};
class PxcConstraintBlockStream
{
PX_NOCOPY(PxcConstraintBlockStream)
public:
PxcConstraintBlockStream(PxcNpMemBlockPool & blockPool) :
mBlockPool (blockPool),
mBlock (NULL),
mUsed (0)
{
}
PX_FORCE_INLINE PxU8* reserve(PxU32 size, PxsConstraintBlockManager& manager)
{
size = (size+15)&~15;
if(size>PxcNpMemBlock::SIZE)
return mBlockPool.acquireExceptionalConstraintMemory(size);
if(mBlock == NULL || size+mUsed>PxcNpMemBlock::SIZE)
{
mBlock = mBlockPool.acquireConstraintBlock(manager.mTrackingArray);
PX_ASSERT(0==mBlock || mBlock->data == reinterpret_cast<PxU8*>(mBlock));
mUsed = size;
return reinterpret_cast<PxU8*>(mBlock);
}
PX_ASSERT(mBlock && mBlock->data == reinterpret_cast<PxU8*>(mBlock));
PxU8* PX_RESTRICT result = mBlock->data+mUsed;
mUsed += size;
return result;
}
PX_FORCE_INLINE void reset()
{
mBlock = NULL;
mUsed = 0;
}
PX_FORCE_INLINE PxcNpMemBlockPool& getMemBlockPool() { return mBlockPool; }
private:
PxcNpMemBlockPool& mBlockPool;
PxcNpMemBlock* mBlock; // current constraint block
PxU32 mUsed; // number of bytes used in constraint block
//Tracking peak allocations
PxU32 mPeakUsed;
};
class PxcContactBlockStream
{
PX_NOCOPY(PxcContactBlockStream)
public:
PxcContactBlockStream(PxcNpMemBlockPool & blockPool):
mBlockPool(blockPool),
mBlock(NULL),
mUsed(0)
{
}
PX_FORCE_INLINE PxU8* reserve(PxU32 size)
{
size = (size+15)&~15;
if(size>PxcNpMemBlock::SIZE)
return mBlockPool.acquireExceptionalConstraintMemory(size);
PX_ASSERT(size <= PxcNpMemBlock::SIZE);
if(mBlock == NULL || size+mUsed>PxcNpMemBlock::SIZE)
{
mBlock = mBlockPool.acquireContactBlock();
PX_ASSERT(0==mBlock || mBlock->data == reinterpret_cast<PxU8*>(mBlock));
mUsed = size;
return reinterpret_cast<PxU8*>(mBlock);
}
PX_ASSERT(mBlock && mBlock->data == reinterpret_cast<PxU8*>(mBlock));
PxU8* PX_RESTRICT result = mBlock->data+mUsed;
mUsed += size;
return result;
}
PX_FORCE_INLINE void reset()
{
mBlock = NULL;
mUsed = 0;
}
PX_FORCE_INLINE PxcNpMemBlockPool& getMemBlockPool() { return mBlockPool; }
private:
PxcNpMemBlockPool& mBlockPool;
PxcNpMemBlock* mBlock; // current constraint block
PxU32 mUsed; // number of bytes used in constraint block
};
}
#endif

View File

@ -0,0 +1,66 @@
//
// 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-2021 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 PXC_CONTACT_CACHE_H
#define PXC_CONTACT_CACHE_H
#include "foundation/PxTransform.h"
#include "PxvConfig.h"
#include "PxcContactMethodImpl.h"
namespace physx
{
class PxcNpThreadContext;
bool PxcCacheLocalContacts( PxcNpThreadContext& context, Gu::Cache& pairContactCache,
const PxTransform& tm0, const PxTransform& tm1,
const PxcContactMethod conMethod,
const Gu::GeometryUnion& shape0, const Gu::GeometryUnion& shape1);
struct PxcLocalContactsCache
{
PxTransform mTransform0;
PxTransform mTransform1;
PxU16 mNbCachedContacts;
bool mUseFaceIndices;
bool mSameNormal;
PX_FORCE_INLINE void operator = (const PxcLocalContactsCache& other)
{
mTransform0 = other.mTransform0;
mTransform1 = other.mTransform1;
mNbCachedContacts = other.mNbCachedContacts;
mUseFaceIndices = other.mUseFaceIndices;
mSameNormal = other.mSameNormal;
}
};
}
#endif // PXC_CONTACT_CACHE_H

View File

@ -0,0 +1,69 @@
//
// 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-2021 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 PXC_MATERIALMETHOD_H
#define PXC_MATERIALMETHOD_H
#include "geometry/PxGeometry.h"
#include "CmPhysXCommon.h"
namespace physx
{
struct PxsShapeCore;
struct PxsMaterialInfo;
class PxcNpThreadContext;
#define MATERIAL_METHOD_ARGS \
const PxsShapeCore* shape0, \
const PxsShapeCore* shape1, \
PxcNpThreadContext& pairContext, \
PxsMaterialInfo* materialInfo
#define SINGLE_MATERIAL_METHOD_ARGS \
const PxsShapeCore* shape, \
const PxU32 index, \
PxcNpThreadContext& pairContext, \
PxsMaterialInfo* materialInfo
/*!
Method prototype for fetch material routines
*/
typedef bool (*PxcGetMaterialMethod) (MATERIAL_METHOD_ARGS);
typedef bool (*PxcGetSingleMaterialMethod) (SINGLE_MATERIAL_METHOD_ARGS);
extern PxcGetMaterialMethod g_GetMaterialMethodTable[][PxGeometryType::eGEOMETRY_COUNT];
extern PxcGetSingleMaterialMethod g_GetSingleMaterialMethodTable[PxGeometryType::eGEOMETRY_COUNT];
}
#endif

View File

@ -0,0 +1,50 @@
//
// 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-2021 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 PXC_NP_BATCH_H
#define PXC_NP_BATCH_H
#include "PxvConfig.h"
namespace physx
{
struct PxcNpWorkUnit;
class PxcNpThreadContext;
struct PxsContactManagerOutput;
namespace Gu
{
struct Cache;
}
void PxcDiscreteNarrowPhase(PxcNpThreadContext& context, const PxcNpWorkUnit& cmInput, Gu::Cache& cache, PxsContactManagerOutput& output);
void PxcDiscreteNarrowPhasePCM(PxcNpThreadContext& context, const PxcNpWorkUnit& cmInput, Gu::Cache& cache, PxsContactManagerOutput& output);
}
#endif

View File

@ -0,0 +1,154 @@
//
// 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-2021 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 PXC_NPCACHE_H
#define PXC_NPCACHE_H
#include "foundation/PxMemory.h"
#include "PsIntrinsics.h"
#include "PxcNpCacheStreamPair.h"
#include "PsPool.h"
#include "PsFoundation.h"
#include "GuContactMethodImpl.h"
#include "PsUtilities.h"
namespace physx
{
template <typename T>
void PxcNpCacheWrite(PxcNpCacheStreamPair& streams,
Gu::Cache& cache,
const T& payload,
PxU32 bytes,
const PxU8* data)
{
const PxU32 payloadSize = (sizeof(payload)+3)&~3;
cache.mCachedSize = Ps::to16((payloadSize + 4 + bytes + 0xF)&~0xF);
PxU8* ls = streams.reserve(cache.mCachedSize);
cache.mCachedData = ls;
if(ls==NULL || (reinterpret_cast<PxU8*>(-1))==ls)
{
if(ls==NULL)
{
PX_WARN_ONCE(
"Reached limit set by PxSceneDesc::maxNbContactDataBlocks - ran out of buffer space for narrow phase. "
"Either accept dropped contacts or increase buffer size allocated for narrow phase by increasing PxSceneDesc::maxNbContactDataBlocks.");
return;
}
else
{
PX_WARN_ONCE(
"Attempting to allocate more than 16K of contact data for a single contact pair in narrowphase. "
"Either accept dropped contacts or simplify collision geometry.");
cache.mCachedData = NULL;
ls = NULL;
return;
}
}
*reinterpret_cast<T*>(ls) = payload;
*reinterpret_cast<PxU32*>(ls+payloadSize) = bytes;
if(data)
PxMemCopy(ls+payloadSize+sizeof(PxU32), data, bytes);
}
template <typename T>
PxU8* PxcNpCacheWriteInitiate(PxcNpCacheStreamPair& streams, Gu::Cache& cache, const T& payload, PxU32 bytes)
{
PX_UNUSED(payload);
const PxU32 payloadSize = (sizeof(payload)+3)&~3;
cache.mCachedSize = Ps::to16((payloadSize + 4 + bytes + 0xF)&~0xF);
PxU8* ls = streams.reserve(cache.mCachedSize);
cache.mCachedData = ls;
if(NULL==ls || reinterpret_cast<PxU8*>(-1)==ls)
{
if(NULL==ls)
{
PX_WARN_ONCE(
"Reached limit set by PxSceneDesc::maxNbContactDataBlocks - ran out of buffer space for narrow phase. "
"Either accept dropped contacts or increase buffer size allocated for narrow phase by increasing PxSceneDesc::maxNbContactDataBlocks.");
}
else
{
PX_WARN_ONCE(
"Attempting to allocate more than 16K of contact data for a single contact pair in narrowphase. "
"Either accept dropped contacts or simplify collision geometry.");
cache.mCachedData = NULL;
ls = NULL;
}
}
return ls;
}
template <typename T>
PX_FORCE_INLINE void PxcNpCacheWriteFinalize(PxU8* ls, const T& payload, PxU32 bytes, const PxU8* data)
{
const PxU32 payloadSize = (sizeof(payload)+3)&~3;
*reinterpret_cast<T*>(ls) = payload;
*reinterpret_cast<PxU32*>(ls+payloadSize) = bytes;
if(data)
PxMemCopy(ls+payloadSize+sizeof(PxU32), data, bytes);
}
template <typename T>
PX_FORCE_INLINE PxU8* PxcNpCacheRead(Gu::Cache& cache, T*& payload)
{
PxU8* ls = cache.mCachedData;
payload = reinterpret_cast<T*>(ls);
const PxU32 payloadSize = (sizeof(T)+3)&~3;
return reinterpret_cast<PxU8*>(ls+payloadSize+sizeof(PxU32));
}
template <typename T>
const PxU8* PxcNpCacheRead2(Gu::Cache& cache, T& payload, PxU32& bytes)
{
const PxU8* ls = cache.mCachedData;
if(ls==NULL)
{
bytes = 0;
return NULL;
}
const PxU32 payloadSize = (sizeof(payload)+3)&~3;
payload = *reinterpret_cast<const T*>(ls);
bytes = *reinterpret_cast<const PxU32*>(ls+payloadSize);
PX_ASSERT(cache.mCachedSize == ((payloadSize + 4 + bytes+0xF)&~0xF));
return reinterpret_cast<const PxU8*>(ls+payloadSize+sizeof(PxU32));
}
}
#endif // #ifndef PXC_NPCACHE_H

View File

@ -0,0 +1,63 @@
//
// 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-2021 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 PXC_NPCACHESTREAMPAIR_H
#define PXC_NPCACHESTREAMPAIR_H
#include "foundation/PxSimpleTypes.h"
#include "PxvConfig.h"
#include "PxcNpMemBlockPool.h"
namespace physx
{
static const PxU32 PXC_NPCACHE_BLOCK_SIZE = 16384;
struct PxcNpCacheStreamPair
{
public:
PxcNpCacheStreamPair(PxcNpMemBlockPool& blockPool);
// reserve can fail and return null.
PxU8* reserve(PxU32 byteCount);
void reset();
private:
PxcNpMemBlockPool& mBlockPool;
PxcNpMemBlock* mBlock;
PxU32 mUsed;
private:
PxcNpCacheStreamPair& operator=(const PxcNpCacheStreamPair&);
};
}
#endif

View File

@ -0,0 +1,57 @@
//
// 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-2021 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 PXC_NPCONTACTPREPSHARED_H
#define PXC_NPCONTACTPREPSHARED_H
namespace physx
{
class PxcNpThreadContext;
struct PxsMaterialInfo;
class PxsMaterialManager;
class PxsConstraintBlockManager;
class PxcConstraintBlockStream;
struct PxsContactManagerOutput;
namespace Gu
{
struct ContactPoint;
}
static const PxReal PXC_SAME_NORMAL = 0.999f; //Around 6 degrees
PxU32 writeCompressedContact(const Gu::ContactPoint* const PX_RESTRICT contactPoints, const PxU32 numContactPoints, PxcNpThreadContext* threadContext,
PxU8& writtenContactCount, PxU8*& outContactPatches, PxU8*& outContactPoints, PxU16& compressedContactSize, PxReal*& contactForces, PxU32 contactForceByteSize,
const PxsMaterialManager* materialManager, bool hasModifiableContacts, bool forceNoResponse, PxsMaterialInfo* PX_RESTRICT pMaterial, PxU8& numPatches,
PxU32 additionalHeaderSize = 0, PxsConstraintBlockManager* manager = NULL, PxcConstraintBlockStream* blockStream = NULL, bool insertAveragePoint = false,
PxcDataStreamPool* pool = NULL, PxcDataStreamPool* patchStreamPool = NULL, PxcDataStreamPool* forcePool = NULL, const bool isMeshType = false);
}
#endif

View File

@ -0,0 +1,119 @@
//
// 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-2021 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 PXC_NP_MEM_BLOCK_POOL_H
#define PXC_NP_MEM_BLOCK_POOL_H
#include "PxvConfig.h"
#include "PsArray.h"
#include "PxcScratchAllocator.h"
namespace physx
{
struct PxcNpMemBlock
{
enum
{
SIZE = 16384
};
PxU8 data[SIZE];
};
typedef Ps::Array<PxcNpMemBlock*> PxcNpMemBlockArray;
class PxcNpMemBlockPool
{
PX_NOCOPY(PxcNpMemBlockPool)
public:
PxcNpMemBlockPool(PxcScratchAllocator& allocator);
~PxcNpMemBlockPool();
void init(PxU32 initial16KDataBlocks, PxU32 maxBlocks);
void flush();
void setBlockCount(PxU32 count);
PxU32 getUsedBlockCount() const;
PxU32 getMaxUsedBlockCount() const;
PxU32 getPeakConstraintBlockCount() const;
void releaseUnusedBlocks();
PxcNpMemBlock* acquireConstraintBlock();
PxcNpMemBlock* acquireConstraintBlock(PxcNpMemBlockArray& memBlocks);
PxcNpMemBlock* acquireContactBlock();
PxcNpMemBlock* acquireFrictionBlock();
PxcNpMemBlock* acquireNpCacheBlock();
PxU8* acquireExceptionalConstraintMemory(PxU32 size);
void acquireConstraintMemory();
void releaseConstraintMemory();
void releaseConstraintBlocks(PxcNpMemBlockArray& memBlocks);
void releaseContacts();
void swapFrictionStreams();
void swapNpCacheStreams();
void flushUnused();
private:
Ps::Mutex mLock;
PxcNpMemBlockArray mConstraints;
PxcNpMemBlockArray mContacts[2];
PxcNpMemBlockArray mFriction[2];
PxcNpMemBlockArray mNpCache[2];
PxcNpMemBlockArray mScratchBlocks;
Ps::Array<PxU8*> mExceptionalConstraints;
PxcNpMemBlockArray mUnused;
PxU32 mNpCacheActiveStream;
PxU32 mFrictionActiveStream;
PxU32 mCCDCacheActiveStream;
PxU32 mContactIndex;
PxU32 mAllocatedBlocks;
PxU32 mMaxBlocks;
PxU32 mInitialBlocks;
PxU32 mUsedBlocks;
PxU32 mMaxUsedBlocks;
PxcNpMemBlock* mScratchBlockAddr;
PxU32 mNbScratchBlocks;
PxcScratchAllocator& mScratchAllocator;
PxU32 mPeakConstraintAllocations;
PxU32 mConstraintAllocations;
PxcNpMemBlock* acquire(PxcNpMemBlockArray& trackingArray, PxU32* allocationCount = NULL, PxU32* peakAllocationCount = NULL, bool isScratchAllocation = false);
void release(PxcNpMemBlockArray& deadArray, PxU32* allocationCount = NULL);
};
}
#endif

View File

@ -0,0 +1,212 @@
//
// 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-2021 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 PXC_NPTHREADCONTEXT_H
#define PXC_NPTHREADCONTEXT_H
#include "geometry/PxGeometry.h"
#include "geomutils/GuContactBuffer.h"
#include "PxvConfig.h"
#include "CmScaling.h"
#include "CmRenderOutput.h"
#include "PxcNpCacheStreamPair.h"
#include "PxcConstraintBlockStream.h"
#include "PxcThreadCoherentCache.h"
#include "CmBitMap.h"
#include "../pcm/GuPersistentContactManifold.h"
namespace physx
{
class PxsTransformCache;
class PxsMaterialManager;
namespace Sc
{
class BodySim;
}
/*!
Per-thread context used by contact generation routines.
*/
struct PxcDataStreamPool
{
PxU8* mDataStream;
PxI32 mSharedDataIndex;
PxU32 mDataStreamSize;
PxU32 mSharedDataIndexGPU;
bool isOverflown() const
{
//FD: my expectaton is that reading those variables is atomic, shared indices are non-decreasing,
//so we can only get a false overflow alert because of concurrency issues, which is not a big deal as it means
//it did overflow a bit later
return mSharedDataIndex + mSharedDataIndexGPU >= mDataStreamSize;
}
};
struct PxcNpContext
{
private:
PX_NOCOPY(PxcNpContext)
public:
PxcNpContext() :
mNpMemBlockPool (mScratchAllocator),
mMeshContactMargin (0.0f),
mToleranceLength (0.0f),
mCreateContactStream (false),
mContactStreamPool (NULL),
mPatchStreamPool (NULL),
mForceAndIndiceStreamPool(NULL),
mMaterialManager (NULL)
{
}
PxcScratchAllocator mScratchAllocator;
PxcNpMemBlockPool mNpMemBlockPool;
PxReal mMeshContactMargin;
PxReal mToleranceLength;
Cm::RenderBuffer mRenderBuffer;
bool mCreateContactStream; // flag to enforce that contacts are stored persistently per workunit. Used for PVD.
PxcDataStreamPool* mContactStreamPool;
PxcDataStreamPool* mPatchStreamPool;
PxcDataStreamPool* mForceAndIndiceStreamPool;
PxcDataStreamPool* mConstraintWriteBackStreamPool;
PxsMaterialManager* mMaterialManager;
PX_FORCE_INLINE PxReal getToleranceLength() const { return mToleranceLength; }
PX_FORCE_INLINE void setToleranceLength(PxReal x) { mToleranceLength = x; }
PX_FORCE_INLINE PxReal getMeshContactMargin() const { return mMeshContactMargin; }
PX_FORCE_INLINE void setMeshContactMargin(PxReal x) { mMeshContactMargin = x; }
PX_FORCE_INLINE bool getCreateContactStream() { return mCreateContactStream; }
PX_FORCE_INLINE PxcNpMemBlockPool& getNpMemBlockPool() { return mNpMemBlockPool; }
PX_FORCE_INLINE const PxcNpMemBlockPool& getNpMemBlockPool() const { return mNpMemBlockPool; }
PX_FORCE_INLINE void setMaterialManager(PxsMaterialManager* m){ mMaterialManager = m; }
PX_FORCE_INLINE PxsMaterialManager* getMaterialManager() const { return mMaterialManager; }
Cm::RenderOutput getRenderOutput() { return Cm::RenderOutput(mRenderBuffer); }
};
class PxcNpThreadContext : public PxcThreadCoherentCache<PxcNpThreadContext, PxcNpContext>::EntryBase
{
PX_NOCOPY(PxcNpThreadContext)
public:
PxcNpThreadContext(PxcNpContext* params);
~PxcNpThreadContext();
#if PX_ENABLE_SIM_STATS
void clearStats();
#endif
PX_FORCE_INLINE void setCreateContactStream(bool to) { mCreateContactStream = to; }
PX_FORCE_INLINE void addLocalNewTouchCount(PxU32 newTouchCMCount) { mLocalNewTouchCount += newTouchCMCount; }
PX_FORCE_INLINE void addLocalLostTouchCount(PxU32 lostTouchCMCount) { mLocalLostTouchCount += lostTouchCMCount; }
PX_FORCE_INLINE PxU32 getLocalNewTouchCount() const { return mLocalNewTouchCount; }
PX_FORCE_INLINE PxU32 getLocalLostTouchCount() const { return mLocalLostTouchCount; }
PX_FORCE_INLINE void addLocalFoundPatchCount(PxU32 foundPatchCount) { mLocalFoundPatchCount += foundPatchCount; }
PX_FORCE_INLINE void addLocalLostPatchCount(PxU32 lostPatchCount) { mLocalLostPatchCount += lostPatchCount; }
PX_FORCE_INLINE PxU32 getLocalFoundPatchCount() const { return mLocalFoundPatchCount; }
PX_FORCE_INLINE PxU32 getLocalLostPatchCount() const { return mLocalLostPatchCount; }
PX_FORCE_INLINE Cm::BitMap& getLocalChangeTouch() { return mLocalChangeTouch; }
PX_FORCE_INLINE Cm::BitMap& getLocalPatchChangeMap() { return mLocalPatchCountChange; }
void reset(PxU32 cmCount);
// debugging
Cm::RenderOutput mRenderOutput;
// dsequeira: Need to think about this block pool allocation a bit more. Ideally we'd be
// taking blocks from a single pool, except that we want to be able to selectively reclaim
// blocks if the user needs to defragment, depending on which artifacts they're willing
// to tolerate, such that the blocks we don't reclaim are contiguous.
#if PX_ENABLE_SIM_STATS
PxU32 mDiscreteContactPairs [PxGeometryType::eGEOMETRY_COUNT][PxGeometryType::eGEOMETRY_COUNT];
PxU32 mModifiedContactPairs [PxGeometryType::eGEOMETRY_COUNT][PxGeometryType::eGEOMETRY_COUNT];
#endif
PxcContactBlockStream mContactBlockStream; // constraint block pool
PxcNpCacheStreamPair mNpCacheStreamPair; // narrow phase pairwise data cache
// Everything below here is scratch state. Most of it can even overlap.
// temporary contact buffer
Gu::ContactBuffer mContactBuffer;
PX_ALIGN(16, Gu::MultiplePersistentContactManifold mTempManifold);
Gu::NarrowPhaseParams mNarrowPhaseParams;
// DS: this stuff got moved here from the PxcNpPairContext. As Pierre says:
////////// PT: those members shouldn't be there in the end, it's not necessary
Ps::Array<Sc::BodySim*> mBodySimPool;
PxsTransformCache* mTransformCache;
PxReal* mContactDistance;
bool mPCM;
bool mContactCache;
bool mCreateContactStream; // flag to enforce that contacts are stored persistently per workunit. Used for PVD.
bool mCreateAveragePoint; // flag to enforce whether we create average points
#if PX_ENABLE_SIM_STATS
PxU32 mCompressedCacheSize;
PxU32 mNbDiscreteContactPairsWithCacheHits;
PxU32 mNbDiscreteContactPairsWithContacts;
#endif
PxReal mDt; // AP: still needed for ccd
PxU32 mCCDPass;
PxU32 mCCDFaceIndex;
PxU32 mMaxPatches;
//PxU32 mTotalContactCount;
PxU32 mTotalCompressedCacheSize;
//PxU32 mTotalPatchCount;
PxcDataStreamPool* mContactStreamPool;
PxcDataStreamPool* mPatchStreamPool;
PxcDataStreamPool* mForceAndIndiceStreamPool; //this stream is used to store the force buffer and triangle index if we are performing mesh/heightfield contact gen
PxcDataStreamPool* mConstraintWriteBackStreamPool;
PxsMaterialManager* mMaterialManager;
private:
// change touch handling.
Cm::BitMap mLocalChangeTouch;
Cm::BitMap mLocalPatchCountChange;
PxU32 mLocalNewTouchCount;
PxU32 mLocalLostTouchCount;
PxU32 mLocalFoundPatchCount;
PxU32 mLocalLostPatchCount;
};
}
#endif

View File

@ -0,0 +1,155 @@
//
// 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-2021 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 PXC_NPWORKUNIT_H
#define PXC_NPWORKUNIT_H
#include "PxcNpThreadContext.h"
#include "PxcMaterialMethodImpl.h"
#include "PxcNpCache.h"
namespace physx
{
struct PxsRigidCore;
struct PxsShapeCore;
struct PxcNpWorkUnitFlag
{
enum Enum
{
eOUTPUT_CONTACTS = 1,
eOUTPUT_CONSTRAINTS = 2,
eDISABLE_STRONG_FRICTION = 4,
eARTICULATION_BODY0 = 8,
eARTICULATION_BODY1 = 16,
eDYNAMIC_BODY0 = 32,
eDYNAMIC_BODY1 = 64,
eMODIFIABLE_CONTACT = 128,
eFORCE_THRESHOLD = 256,
eDETECT_DISCRETE_CONTACT = 512,
eHAS_KINEMATIC_ACTOR = 1024,
eDISABLE_RESPONSE = 2048,
eDETECT_CCD_CONTACTS = 4096
};
};
struct PxcNpWorkUnitStatusFlag
{
enum Enum
{
eHAS_NO_TOUCH = (1 << 0),
eHAS_TOUCH = (1 << 1),
//eHAS_SOLVER_CONSTRAINTS = (1 << 2),
eREQUEST_CONSTRAINTS = (1 << 3),
eHAS_CCD_RETOUCH = (1 << 4), // Marks pairs that are touching at a CCD pass and were touching at discrete collision or at a previous CCD pass already
// but we can not tell whether they lost contact in a pass before. We send them as pure eNOTIFY_TOUCH_CCD events to the
// contact report callback if requested.
eDIRTY_MANAGER = (1 << 5),
eREFRESHED_WITH_TOUCH = (1 << 6),
eTOUCH_KNOWN = eHAS_NO_TOUCH | eHAS_TOUCH // The touch status is known (if narrowphase never ran for a pair then no flag will be set)
};
};
// PT: TODO: fix the inconsistent namings (mXXX) in this class
struct PxcNpWorkUnit
{
const PxsRigidCore* rigidCore0; // INPUT //4 //8
const PxsRigidCore* rigidCore1; // INPUT //8 //16
const PxsShapeCore* shapeCore0; // INPUT //12 //24
const PxsShapeCore* shapeCore1; // INPUT //16 //32
PxU8* ccdContacts; // OUTPUT //20 //40
PxU8* frictionDataPtr; // INOUT //24 //48
PxU16 flags; // INPUT //26 //50
PxU8 frictionPatchCount; // INOUT //27 //51
PxU8 statusFlags; // OUTPUT (see PxcNpWorkUnitStatusFlag) //28 //52
PxU8 dominance0; // INPUT //29 //53
PxU8 dominance1; // INPUT //30 //54
PxU8 geomType0; // INPUT //31 //55
PxU8 geomType1; // INPUT //32 //56
PxU32 index; // INPUT //36 //60
PxReal restDistance; // INPUT //40 //64
PxU32 mTransformCache0; // //44 //68
PxU32 mTransformCache1; // //48 //72
PxU32 mEdgeIndex; //inout the island gen edge index //52 //76
PxU32 mNpIndex; //INPUT //56 //80
PxReal mTorsionalPatchRadius; //60 //84
PxReal mMinTorsionalPatchRadius; //64 //88
};
/*
* A struct to record the number of work units a particular constraint pointer references.
* This is created at the beginning of the constriant data and is used to bypass constraint preparation when the
* bodies are not moving a lot. In this case, we can recycle the constraints and save ourselves some cycles.
*/
struct PxcNpWorkUnitBatch
{
PxcNpWorkUnit* mUnits[4];
PxU32 mSize;
};
//#if !defined(PX_P64)
//PX_COMPILE_TIME_ASSERT(0 == (sizeof(PxcNpWorkUnit) & 0x0f));
//#endif
PX_FORCE_INLINE void PxcNpWorkUnitClearContactState(PxcNpWorkUnit& n)
{
n.ccdContacts = NULL;
}
PX_FORCE_INLINE void PxcNpWorkUnitClearCachedState(PxcNpWorkUnit& n)
{
n.frictionDataPtr = 0;
n.frictionPatchCount = 0;
n.ccdContacts = NULL;
}
PX_FORCE_INLINE void PxcNpWorkUnitClearFrictionCachedState(PxcNpWorkUnit& n)
{
n.frictionDataPtr = 0;
n.frictionPatchCount = 0;
n.ccdContacts = NULL;
}
#if !defined(PX_P64)
//PX_COMPILE_TIME_ASSERT(sizeof(PxcNpWorkUnit)==128);
#endif
}
#endif

View File

@ -0,0 +1,138 @@
//
// 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-2021 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 PXC_SCRATCHALLOCATOR_H
#define PXC_SCRATCHALLOCATOR_H
#include "foundation/PxAssert.h"
#include "PxvConfig.h"
#include "PsMutex.h"
#include "PsArray.h"
#include "PsAllocator.h"
namespace physx
{
class PxcScratchAllocator
{
PX_NOCOPY(PxcScratchAllocator)
public:
PxcScratchAllocator() : mStack(PX_DEBUG_EXP("PxcScratchAllocator")), mStart(NULL), mSize(0)
{
mStack.reserve(64);
mStack.pushBack(0);
}
void setBlock(void* addr, PxU32 size)
{
// if the stack is not empty then some scratch memory was not freed on the previous frame. That's
// likely indicative of a problem, because when the scratch block is too small the memory will have
// come from the heap
PX_ASSERT(mStack.size()==1);
mStack.popBack();
mStart = reinterpret_cast<PxU8*>(addr);
mSize = size;
mStack.pushBack(mStart + size);
}
void* allocAll(PxU32& size)
{
Ps::Mutex::ScopedLock lock(mLock);
PX_ASSERT(mStack.size()>0);
size = PxU32(mStack.back()-mStart);
if(size==0)
return NULL;
mStack.pushBack(mStart);
return mStart;
}
void* alloc(PxU32 requestedSize, bool fallBackToHeap = false)
{
requestedSize = (requestedSize+15)&~15;
Ps::Mutex::ScopedLock lock(mLock);
PX_ASSERT(mStack.size()>=1);
PxU8* top = mStack.back();
if(top - mStart >= ptrdiff_t(requestedSize))
{
PxU8* addr = top - requestedSize;
mStack.pushBack(addr);
return addr;
}
if(!fallBackToHeap)
return NULL;
return PX_ALLOC(requestedSize, "Scratch Block Fallback");
}
void free(void* addr)
{
PX_ASSERT(addr!=NULL);
if(!isScratchAddr(addr))
{
PX_FREE(addr);
return;
}
Ps::Mutex::ScopedLock lock(mLock);
PX_ASSERT(mStack.size()>1);
PxU32 i=mStack.size()-1;
while(mStack[i]<addr)
i--;
PX_ASSERT(mStack[i]==addr);
mStack.remove(i);
}
bool isScratchAddr(void* addr) const
{
PxU8* a = reinterpret_cast<PxU8*>(addr);
return a>= mStart && a<mStart+mSize;
}
private:
Ps::Mutex mLock;
Ps::Array<PxU8*> mStack;
PxU8* mStart;
PxU32 mSize;
};
}
#endif

View File

@ -0,0 +1,150 @@
//
// 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-2021 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 PXC_THREADCOHERENTCACHE_H
#define PXC_THREADCOHERENTCACHE_H
#include "PsMutex.h"
#include "PsAllocator.h"
#include "PsSList.h"
namespace physx
{
class PxsContext;
/*!
Controls a pool of large objects which must be thread safe.
Tries to return the object most recently used by the thread(for better cache coherancy).
Assumes the object has a default contructor.
(Note the semantics are different to a pool because we dont want to construct/destroy each time
an object is requested, which may be expensive).
TODO: add thread coherancy.
*/
template<class T, class Params>
class PxcThreadCoherentCache : public Ps::AlignedAllocator<16, Ps::ReflectionAllocator<T> >
{
typedef Ps::AlignedAllocator<16, Ps::ReflectionAllocator<T> > Allocator;
PX_NOCOPY(PxcThreadCoherentCache)
public:
typedef Ps::SListEntry EntryBase;
PX_INLINE PxcThreadCoherentCache(Params* params, const Allocator& alloc = Allocator()) : Allocator(alloc), mParams(params)
{
}
PX_INLINE ~PxcThreadCoherentCache()
{
T* np = static_cast<T*>(root.pop());
while(np!=NULL)
{
np->~T();
Allocator::deallocate(np);
np = static_cast<T*>(root.pop());
}
}
PX_INLINE T* get()
{
T* rv = static_cast<T*>(root.pop());
if(rv==NULL)
{
rv = reinterpret_cast<T*>(Allocator::allocate(sizeof(T), __FILE__, __LINE__));
new (rv) T(mParams);
}
return rv;
}
PX_INLINE void put(T* item)
{
root.push(*item);
}
private:
Ps::SList root;
Params* mParams;
template<class T2, class P2>
friend class PxcThreadCoherentCacheIterator;
};
/*!
Used to iterate over all objects controlled by the cache.
Note: The iterator flushes the cache(extracts all items on construction and adds them back on
destruction so we can iterate the list in a safe manner).
*/
template<class T, class Params>
class PxcThreadCoherentCacheIterator
{
public:
PxcThreadCoherentCacheIterator(PxcThreadCoherentCache<T, Params>& cache) : mCache(cache)
{
mNext = cache.root.flush();
mFirst = mNext;
}
~PxcThreadCoherentCacheIterator()
{
Ps::SListEntry* np = mFirst;
while(np != NULL)
{
Ps::SListEntry* npNext = np->next();
mCache.root.push(*np);
np = npNext;
}
}
PX_INLINE T* getNext()
{
if(mNext == NULL)
return NULL;
T* rv = static_cast<T*>(mNext);
mNext = mNext->next();
return rv;
}
private:
PxcThreadCoherentCacheIterator<T, Params>& operator=(const PxcThreadCoherentCacheIterator<T, Params>&);
PxcThreadCoherentCache<T, Params> &mCache;
Ps::SListEntry* mNext;
Ps::SListEntry* mFirst;
};
}
#endif

View File

@ -0,0 +1,393 @@
//
// 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-2021 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 "PxcContactCache.h"
#include "PxsContactManager.h"
#include "PsUtilities.h"
#include "PxcNpCache.h"
using namespace physx;
using namespace Gu;
//#define ENABLE_CONTACT_CACHE_STATS
#ifdef ENABLE_CONTACT_CACHE_STATS
static PxU32 gNbCalls;
static PxU32 gNbHits;
#endif
void PxcClearContactCacheStats()
{
#ifdef ENABLE_CONTACT_CACHE_STATS
gNbCalls = 0;
gNbHits = 0;
#endif
}
void PxcDisplayContactCacheStats()
{
#ifdef ENABLE_CONTACT_CACHE_STATS
pxPrintf("%d|%d (%f)\n", gNbHits, gNbCalls, gNbCalls ? float(gNbHits)/float(gNbCalls) : 0.0f);
#endif
}
namespace physx
{
const bool g_CanUseContactCache[][PxGeometryType::eGEOMETRY_COUNT] =
{
//PxGeometryType::eSPHERE
{
false, //PxcContactSphereSphere
false, //PxcContactSpherePlane
true, //PxcContactSphereCapsule
false, //PxcContactSphereBox
true, //PxcContactSphereConvex
true, //PxcContactSphereMesh
true, //PxcContactSphereHeightField
},
//PxGeometryType::ePLANE
{
false, //-
false, //PxcInvalidContactPair
true, //PxcContactPlaneCapsule
true, //PxcContactPlaneBox
true, //PxcContactPlaneConvex
false, //PxcInvalidContactPair
false, //PxcInvalidContactPair
},
//PxGeometryType::eCAPSULE
{
false, //-
false, //-
true, //PxcContactCapsuleCapsule
true, //PxcContactCapsuleBox
true, //PxcContactCapsuleConvex
true, //PxcContactCapsuleMesh
true, //PxcContactCapsuleHeightField
},
//PxGeometryType::eBOX
{
false, //-
false, //-
false, //-
true, //PxcContactBoxBox
true, //PxcContactBoxConvex
true, //PxcContactBoxMesh
true, //PxcContactBoxHeightField
},
//PxGeometryType::eCONVEXMESH
{
false, //-
false, //-
false, //-
false, //-
true, //PxcContactConvexConvex
true, //PxcContactConvexMesh2
true, //PxcContactConvexHeightField
},
//PxGeometryType::eTRIANGLEMESH
{
false, //-
false, //-
false, //-
false, //-
false, //-
false, //PxcInvalidContactPair
false, //PxcInvalidContactPair
},
//PxGeometryType::eHEIGHTFIELD
{
false, //-
false, //-
false, //-
false, //-
false, //-
false, //-
false, //PxcInvalidContactPair
},
};
}
static PX_FORCE_INLINE void updateContact( Gu::ContactPoint& dst, const PxcLocalContactsCache& contactsData,
const Cm::Matrix34& world0, const Cm::Matrix34& world1,
const PxVec3& point, const PxVec3& normal, float separation)
{
const PxVec3 tmp0 = contactsData.mTransform0.transformInv(point);
const PxVec3 worldpt0 = world0.transform(tmp0);
const PxVec3 tmp1 = contactsData.mTransform1.transformInv(point);
const PxVec3 worldpt1 = world1.transform(tmp1);
const PxVec3 motion = worldpt0 - worldpt1;
dst.normal = normal;
dst.point = (worldpt0 + worldpt1)*0.5f;
//dst.point = point;
dst.separation = separation + motion.dot(normal);
}
static PX_FORCE_INLINE void prefetchData128(PxU8* PX_RESTRICT ptr, PxU32 size)
{
// PT: always prefetch the cache line containing our address (which unfortunately won't be aligned to 128 most of the time)
Ps::prefetchLine(ptr, 0);
// PT: compute start offset of our data within its cache line
const PxU32 startOffset = PxU32(size_t(ptr)&127);
// PT: prefetch next cache line if needed
if(startOffset+size>128)
Ps::prefetchLine(ptr+128, 0);
}
static PX_FORCE_INLINE PxU8* outputToCache(PxU8* PX_RESTRICT bytes, const PxVec3& v)
{
*reinterpret_cast<PxVec3*>(bytes) = v;
return bytes + sizeof(PxVec3);
}
static PX_FORCE_INLINE PxU8* outputToCache(PxU8* PX_RESTRICT bytes, PxReal v)
{
*reinterpret_cast<PxReal*>(bytes) = v;
return bytes + sizeof(PxReal);
}
static PX_FORCE_INLINE PxU8* outputToCache(PxU8* PX_RESTRICT bytes, PxU32 v)
{
*reinterpret_cast<PxU32*>(bytes) = v;
return bytes + sizeof(PxU32);
}
//PxU32 gContactCache_NbCalls = 0;
//PxU32 gContactCache_NbHits = 0;
static PX_FORCE_INLINE PxReal maxComponentDeltaPos(const PxTransform& t0, const PxTransform& t1)
{
PxReal delta = PxAbs(t0.p.x - t1.p.x);
delta = PxMax(delta, PxAbs(t0.p.y - t1.p.y));
delta = PxMax(delta, PxAbs(t0.p.z - t1.p.z));
return delta;
}
static PX_FORCE_INLINE PxReal maxComponentDeltaRot(const PxTransform& t0, const PxTransform& t1)
{
PxReal delta = PxAbs(t0.q.x - t1.q.x);
delta = PxMax(delta, PxAbs(t0.q.y - t1.q.y));
delta = PxMax(delta, PxAbs(t0.q.z - t1.q.z));
delta = PxMax(delta, PxAbs(t0.q.w - t1.q.w));
return delta;
}
bool physx::PxcCacheLocalContacts( PxcNpThreadContext& context, Gu::Cache& pairContactCache,
const PxTransform& tm0, const PxTransform& tm1,
const PxcContactMethod conMethod,
const Gu::GeometryUnion& shape0, const Gu::GeometryUnion& shape1)
{
const Gu::NarrowPhaseParams& params = context.mNarrowPhaseParams;
// gContactCache_NbCalls++;
if(pairContactCache.mCachedData)
prefetchData128(pairContactCache.mCachedData, pairContactCache.mCachedSize);
ContactBuffer& contactBuffer = context.mContactBuffer;
contactBuffer.reset();
PxcLocalContactsCache contactsData;
PxU32 nbCachedBytes;
const PxU8* cachedBytes = PxcNpCacheRead2(pairContactCache, contactsData, nbCachedBytes);
pairContactCache.mCachedData = NULL;
pairContactCache.mCachedSize = 0;
#ifdef ENABLE_CONTACT_CACHE_STATS
gNbCalls++;
#endif
const PxU32 payloadSize = (sizeof(PxcLocalContactsCache)+3)&~3;
if(cachedBytes)
{
// PT: we used to store the relative TM but it's better to save memory and recompute it
const PxTransform t0to1 = tm1.transformInv(tm0);
const PxTransform relTM = contactsData.mTransform1.transformInv(contactsData.mTransform0);
const PxReal epsilon = 0.01f;
if( maxComponentDeltaPos(t0to1, relTM)<epsilon*params.mToleranceLength
&& maxComponentDeltaRot(t0to1, relTM)<epsilon)
{
// gContactCache_NbHits++;
const PxU32 nbContacts = contactsData.mNbCachedContacts;
PxU8* ls = PxcNpCacheWriteInitiate(context.mNpCacheStreamPair, pairContactCache, contactsData, nbCachedBytes);
prefetchData128(ls, (payloadSize + 4 + nbCachedBytes + 0xF)&~0xF);
contactBuffer.count = nbContacts;
if(nbContacts)
{
Gu::ContactPoint* PX_RESTRICT dst = contactBuffer.contacts;
const Cm::Matrix34 world1(tm1);
const Cm::Matrix34 world0(tm0);
const bool sameNormal = contactsData.mSameNormal;
const PxU8* contacts = reinterpret_cast<const PxU8*>(cachedBytes);
const PxVec3* normal0 = NULL;
for(PxU32 i=0;i<nbContacts;i++)
{
if(i!=nbContacts-1)
Ps::prefetchLine(contacts, 128);
const PxVec3* cachedNormal;
if(!i || !sameNormal)
{
cachedNormal = reinterpret_cast<const PxVec3*>(contacts); contacts += sizeof(PxVec3);
normal0 = cachedNormal;
}
else
{
cachedNormal = normal0;
}
const PxVec3* cachedPoint = reinterpret_cast<const PxVec3*>(contacts); contacts += sizeof(PxVec3);
const PxReal* cachedPD = reinterpret_cast<const PxReal*>(contacts); contacts += sizeof(PxReal);
updateContact(*dst, contactsData, world0, world1, *cachedPoint, *cachedNormal, *cachedPD);
if(contactsData.mUseFaceIndices)
{
const PxU32* cachedIndex1 = reinterpret_cast<const PxU32*>(contacts); contacts += sizeof(PxU32);
dst->internalFaceIndex1 = *cachedIndex1;
}
else
{
dst->internalFaceIndex1 = PXC_CONTACT_NO_FACE_INDEX;
}
dst++;
}
}
if(ls)
PxcNpCacheWriteFinalize(ls, contactsData, nbCachedBytes, cachedBytes);
#ifdef ENABLE_CONTACT_CACHE_STATS
gNbHits++;
#endif
return true;
}
else
{
// PT: if we reach this point we cached the contacts but we couldn't use them next frame
// => waste of time and memory
}
}
conMethod(shape0, shape1, tm0, tm1, params, pairContactCache, context.mContactBuffer, &context.mRenderOutput);
//if(contactBuffer.count)
{
contactsData.mTransform0 = tm0;
contactsData.mTransform1 = tm1;
PxU32 nbBytes = 0;
const PxU8* bytes = NULL;
const PxU32 count = contactBuffer.count;
if(count)
{
const bool useFaceIndices = contactBuffer.contacts[0].internalFaceIndex1!=PXC_CONTACT_NO_FACE_INDEX;
contactsData.mNbCachedContacts = Ps::to16(count);
contactsData.mUseFaceIndices = useFaceIndices;
const Gu::ContactPoint* PX_RESTRICT srcContacts = contactBuffer.contacts;
// PT: this loop should not be here. We should output the contacts directly compressed, as we used to.
bool sameNormal = true;
{
const PxVec3 normal0 = srcContacts->normal;
for(PxU32 i=1;i<count;i++)
{
if(srcContacts[i].normal!=normal0)
{
sameNormal = false;
break;
}
}
}
contactsData.mSameNormal = sameNormal;
if(!sameNormal)
{
const PxU32 sizeof_CachedContactPoint = sizeof(PxVec3) + sizeof(PxVec3) + sizeof(PxReal);
const PxU32 sizeof_CachedContactPointAndFaceIndices = sizeof_CachedContactPoint + sizeof(PxU32);
const PxU32 sizeOfItem = useFaceIndices ? sizeof_CachedContactPointAndFaceIndices : sizeof_CachedContactPoint;
nbBytes = count * sizeOfItem;
}
else
{
const PxU32 sizeof_CachedContactPoint = sizeof(PxVec3) + sizeof(PxReal);
const PxU32 sizeof_CachedContactPointAndFaceIndices = sizeof_CachedContactPoint + sizeof(PxU32);
const PxU32 sizeOfItem = useFaceIndices ? sizeof_CachedContactPointAndFaceIndices : sizeof_CachedContactPoint;
nbBytes = sizeof(PxVec3) + count * sizeOfItem;
}
PxU8* ls = PxcNpCacheWriteInitiate(context.mNpCacheStreamPair, pairContactCache, contactsData, nbBytes);
if(ls)
{
*reinterpret_cast<PxcLocalContactsCache*>(ls) = contactsData;
*reinterpret_cast<PxU32*>(ls+payloadSize) = nbBytes;
bytes = ls+payloadSize+sizeof(PxU32);
PxU8* dest = const_cast<PxU8*>(bytes);
for(PxU32 i=0;i<count;i++)
{
if(!i || !sameNormal)
dest = outputToCache(dest, srcContacts[i].normal);
dest = outputToCache(dest, srcContacts[i].point);
dest = outputToCache(dest, srcContacts[i].separation);
if(useFaceIndices)
{
dest = outputToCache(dest, srcContacts[i].internalFaceIndex1);
}
}
PX_ASSERT(size_t(dest) - size_t(bytes)==nbBytes);
}
else
{
contactsData.mNbCachedContacts = 0;
PxcNpCacheWrite(context.mNpCacheStreamPair, pairContactCache, contactsData, 0, bytes);
}
}
else
{
contactsData.mNbCachedContacts = 0;
contactsData.mUseFaceIndices = false;
PxcNpCacheWrite(context.mNpCacheStreamPair, pairContactCache, contactsData, nbBytes, bytes);
}
}
return false;
}

View File

@ -0,0 +1,265 @@
//
// 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-2021 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 "geometry/PxGeometry.h"
#include "PxcContactMethodImpl.h"
namespace physx
{
static bool PxcInvalidContactPair (CONTACT_METHOD_ARGS_UNUSED) { return false; }
// PT: IMPORTANT: do NOT remove the indirection! Using the Gu functions directly in the table produces massive perf problems.
static bool PxcContactSphereSphere (GU_CONTACT_METHOD_ARGS) { return contactSphereSphere(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactSphereCapsule (GU_CONTACT_METHOD_ARGS) { return contactSphereCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactSphereBox (GU_CONTACT_METHOD_ARGS) { return contactSphereBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactSpherePlane (GU_CONTACT_METHOD_ARGS) { return contactSpherePlane(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactSphereConvex (GU_CONTACT_METHOD_ARGS) { return contactCapsuleConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactSphereMesh (GU_CONTACT_METHOD_ARGS) { return contactSphereMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactSphereHeightField (GU_CONTACT_METHOD_ARGS) { return contactSphereHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactPlaneBox (GU_CONTACT_METHOD_ARGS) { return contactPlaneBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactPlaneCapsule (GU_CONTACT_METHOD_ARGS) { return contactPlaneCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactPlaneConvex (GU_CONTACT_METHOD_ARGS) { return contactPlaneConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactCapsuleCapsule (GU_CONTACT_METHOD_ARGS) { return contactCapsuleCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactCapsuleBox (GU_CONTACT_METHOD_ARGS) { return contactCapsuleBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactCapsuleConvex (GU_CONTACT_METHOD_ARGS) { return contactCapsuleConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactCapsuleMesh (GU_CONTACT_METHOD_ARGS) { return contactCapsuleMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactCapsuleHeightField(GU_CONTACT_METHOD_ARGS) { return contactCapsuleHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactBoxBox (GU_CONTACT_METHOD_ARGS) { return contactBoxBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactBoxConvex (GU_CONTACT_METHOD_ARGS) { return contactBoxConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactBoxMesh (GU_CONTACT_METHOD_ARGS) { return contactBoxMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactBoxHeightField (GU_CONTACT_METHOD_ARGS) { return contactBoxHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactConvexConvex (GU_CONTACT_METHOD_ARGS) { return contactConvexConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactConvexMesh (GU_CONTACT_METHOD_ARGS) { return contactConvexMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcContactConvexHeightField (GU_CONTACT_METHOD_ARGS) { return contactConvexHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactSphereSphere (GU_CONTACT_METHOD_ARGS) { return pcmContactSphereSphere(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactSpherePlane (GU_CONTACT_METHOD_ARGS) { return pcmContactSpherePlane(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactSphereBox (GU_CONTACT_METHOD_ARGS) { return pcmContactSphereBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactSphereCapsule (GU_CONTACT_METHOD_ARGS) { return pcmContactSphereCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactSphereConvex (GU_CONTACT_METHOD_ARGS) { return pcmContactSphereConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactSphereMesh (GU_CONTACT_METHOD_ARGS) { return pcmContactSphereMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactSphereHeightField (GU_CONTACT_METHOD_ARGS) { return pcmContactSphereHeightField(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactPlaneCapsule (GU_CONTACT_METHOD_ARGS) { return pcmContactPlaneCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactPlaneBox (GU_CONTACT_METHOD_ARGS) { return pcmContactPlaneBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactPlaneConvex (GU_CONTACT_METHOD_ARGS) { return pcmContactPlaneConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactCapsuleCapsule (GU_CONTACT_METHOD_ARGS) { return pcmContactCapsuleCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactCapsuleBox (GU_CONTACT_METHOD_ARGS) { return pcmContactCapsuleBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactCapsuleConvex (GU_CONTACT_METHOD_ARGS) { return pcmContactCapsuleConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactCapsuleMesh (GU_CONTACT_METHOD_ARGS) { return pcmContactCapsuleMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactCapsuleHeightField (GU_CONTACT_METHOD_ARGS) { return pcmContactCapsuleHeightField(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactBoxBox (GU_CONTACT_METHOD_ARGS) { return pcmContactBoxBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactBoxConvex (GU_CONTACT_METHOD_ARGS) { return pcmContactBoxConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactBoxMesh (GU_CONTACT_METHOD_ARGS) { return pcmContactBoxMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactBoxHeightField (GU_CONTACT_METHOD_ARGS) { return pcmContactBoxHeightField(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactConvexConvex (GU_CONTACT_METHOD_ARGS) { return pcmContactConvexConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactConvexMesh (GU_CONTACT_METHOD_ARGS) { return pcmContactConvexMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
static bool PxcPCMContactConvexHeightField (GU_CONTACT_METHOD_ARGS) { return pcmContactConvexHeightField(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput); }
#define DYNAMIC_CONTACT_REGISTRATION(x) PxcInvalidContactPair
//#define DYNAMIC_CONTACT_REGISTRATION(x) x
//Table of contact methods for different shape-type combinations
PxcContactMethod g_ContactMethodTable[][PxGeometryType::eGEOMETRY_COUNT] =
{
//PxGeometryType::eSPHERE
{
PxcContactSphereSphere, //PxGeometryType::eSPHERE
PxcContactSpherePlane, //PxGeometryType::ePLANE
PxcContactSphereCapsule, //PxGeometryType::eCAPSULE
PxcContactSphereBox, //PxGeometryType::eBOX
PxcContactSphereConvex, //PxGeometryType::eCONVEXMESH
PxcContactSphereMesh, //PxGeometryType::eTRIANGLEMESH
DYNAMIC_CONTACT_REGISTRATION(PxcContactSphereHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::ePLANE
{
0, //PxGeometryType::eSPHERE
PxcInvalidContactPair, //PxGeometryType::ePLANE
PxcContactPlaneCapsule, //PxGeometryType::eCAPSULE
PxcContactPlaneBox, //PxGeometryType::eBOX
PxcContactPlaneConvex, //PxGeometryType::eCONVEXMESH
PxcInvalidContactPair, //PxGeometryType::eTRIANGLEMESH
PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eCAPSULE
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
PxcContactCapsuleCapsule, //PxGeometryType::eCAPSULE
PxcContactCapsuleBox, //PxGeometryType::eBOX
PxcContactCapsuleConvex, //PxGeometryType::eCONVEXMESH
PxcContactCapsuleMesh, //PxGeometryType::eTRIANGLEMESH
DYNAMIC_CONTACT_REGISTRATION(PxcContactCapsuleHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::eBOX
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
PxcContactBoxBox, //PxGeometryType::eBOX
PxcContactBoxConvex, //PxGeometryType::eCONVEXMESH
PxcContactBoxMesh, //PxGeometryType::eTRIANGLEMESH
DYNAMIC_CONTACT_REGISTRATION(PxcContactBoxHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::eCONVEXMESH
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
PxcContactConvexConvex, //PxGeometryType::eCONVEXMESH
PxcContactConvexMesh, //PxGeometryType::eTRIANGLEMESH
DYNAMIC_CONTACT_REGISTRATION(PxcContactConvexHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::eTRIANGLEMESH
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
0, //PxGeometryType::eCONVEXMESH
PxcInvalidContactPair, //PxGeometryType::eTRIANGLEMESH
PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eHEIGHTFIELD
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
0, //PxGeometryType::eCONVEXMESH
0, //PxGeometryType::eTRIANGLEMESH
PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
},
};
//#if PERSISTENT_CONTACT_MANIFOLD
//Table of contact methods for different shape-type combinations
PxcContactMethod g_PCMContactMethodTable[][PxGeometryType::eGEOMETRY_COUNT] =
{
//PxGeometryType::eSPHERE
{
PxcPCMContactSphereSphere, //PxGeometryType::eSPHERE
PxcPCMContactSpherePlane, //PxGeometryType::ePLANE
PxcPCMContactSphereCapsule, //PxGeometryType::eCAPSULE
PxcPCMContactSphereBox, //PxGeometryType::eBOX
PxcPCMContactSphereConvex, //PxGeometryType::eCONVEXMESH
PxcPCMContactSphereMesh, //PxGeometryType::eTRIANGLEMESH
DYNAMIC_CONTACT_REGISTRATION(PxcPCMContactSphereHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::ePLANE
{
0, //PxGeometryType::eSPHERE
PxcInvalidContactPair, //PxGeometryType::ePLANE
PxcPCMContactPlaneCapsule, //PxGeometryType::eCAPSULE
PxcPCMContactPlaneBox, //PxGeometryType::eBOX
PxcPCMContactPlaneConvex, //PxGeometryType::eCONVEXMESH
PxcInvalidContactPair, //PxGeometryType::eTRIANGLEMESH
PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eCAPSULE
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
PxcPCMContactCapsuleCapsule, //PxGeometryType::eCAPSULE
PxcPCMContactCapsuleBox, //PxGeometryType::eBOX
PxcPCMContactCapsuleConvex, //PxGeometryType::eCONVEXMESH
PxcPCMContactCapsuleMesh, //PxGeometryType::eTRIANGLEMESH
DYNAMIC_CONTACT_REGISTRATION(PxcPCMContactCapsuleHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::eBOX
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
PxcPCMContactBoxBox, //PxGeometryType::eBOX
PxcPCMContactBoxConvex, //PxGeometryType::eCONVEXMESH
PxcPCMContactBoxMesh, //PxGeometryType::eTRIANGLEMESH
DYNAMIC_CONTACT_REGISTRATION(PxcPCMContactBoxHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::eCONVEXMESH
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
PxcPCMContactConvexConvex, //PxGeometryType::eCONVEXMESH
PxcPCMContactConvexMesh, //PxGeometryType::eTRIANGLEMESH
DYNAMIC_CONTACT_REGISTRATION(PxcPCMContactConvexHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::eTRIANGLEMESH
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
0, //PxGeometryType::eCONVEXMESH
PxcInvalidContactPair, //PxGeometryType::eTRIANGLEMESH
PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eHEIGHTFIELD
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
0, //PxGeometryType::eCONVEXMESH
0, //PxGeometryType::eTRIANGLEMESH
PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
},
};
void PxvRegisterHeightFields()
{
g_ContactMethodTable[PxGeometryType::eSPHERE][PxGeometryType::eHEIGHTFIELD] = PxcContactSphereHeightField;
g_ContactMethodTable[PxGeometryType::eCAPSULE][PxGeometryType::eHEIGHTFIELD] = PxcContactCapsuleHeightField;
g_ContactMethodTable[PxGeometryType::eBOX][PxGeometryType::eHEIGHTFIELD] = PxcContactBoxHeightField;
g_ContactMethodTable[PxGeometryType::eCONVEXMESH][PxGeometryType::eHEIGHTFIELD] = PxcContactConvexHeightField;
g_PCMContactMethodTable[PxGeometryType::eSPHERE][PxGeometryType::eHEIGHTFIELD] = PxcPCMContactSphereHeightField;
g_PCMContactMethodTable[PxGeometryType::eCAPSULE][PxGeometryType::eHEIGHTFIELD] = PxcPCMContactCapsuleHeightField;
g_PCMContactMethodTable[PxGeometryType::eBOX][PxGeometryType::eHEIGHTFIELD] = PxcPCMContactBoxHeightField;
g_PCMContactMethodTable[PxGeometryType::eCONVEXMESH][PxGeometryType::eHEIGHTFIELD] = PxcPCMContactConvexHeightField;
}
}

View File

@ -0,0 +1,117 @@
//
// 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-2021 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 "geometry/PxTriangleMesh.h"
#include "PxvGeometry.h"
#include "PxsMaterialManager.h"
#include "PxcNpThreadContext.h"
#include "GuHeightField.h"
using namespace physx;
using namespace Gu;
namespace physx
{
bool PxcGetMaterialShapeHeightField(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo);
bool PxcGetMaterialHeightField(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo);
PxU32 GetMaterialIndex(const Gu::HeightFieldData* hfData, PxU32 triangleIndex);
}
physx::PxU32 physx::GetMaterialIndex(const Gu::HeightFieldData* hfData, PxU32 triangleIndex)
{
const PxU32 sampleIndex = triangleIndex >> 1;
const bool isFirstTriangle = (triangleIndex & 0x1) == 0;
//get sample
const PxHeightFieldSample* hf = &hfData->samples[sampleIndex];
return isFirstTriangle ? hf->materialIndex0 : hf->materialIndex1;
}
bool physx::PxcGetMaterialHeightField(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
{
PX_ASSERT(index == 1);
PX_UNUSED(index);
const ContactBuffer& contactBuffer = context.mContactBuffer;
const PxHeightFieldGeometryLL& hfGeom = shape->geometry.get<const PxHeightFieldGeometryLL>();
if(hfGeom.materials.numIndices <= 1)
{
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
(&materialInfo[i].mMaterialIndex0)[index] = shape->materialIndex;
}
}
else
{
const PxU16* materialIndices = hfGeom.materials.indices;
const Gu::HeightFieldData* hf = hfGeom.heightFieldData;
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
const Gu::ContactPoint& contact = contactBuffer.contacts[i];
const PxU32 localMaterialIndex = GetMaterialIndex(hf, contact.internalFaceIndex1);
(&materialInfo[i].mMaterialIndex0)[index] = materialIndices[localMaterialIndex];
}
}
return true;
}
bool physx::PxcGetMaterialShapeHeightField(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
{
const ContactBuffer& contactBuffer = context.mContactBuffer;
const PxHeightFieldGeometryLL& hfGeom = shape1->geometry.get<const PxHeightFieldGeometryLL>();
if(hfGeom.materials.numIndices <= 1)
{
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
materialInfo[i].mMaterialIndex1 = shape1->materialIndex;
}
}
else
{
const PxU16* materialIndices = hfGeom.materials.indices;
const Gu::HeightFieldData* hf = hfGeom.heightFieldData;
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
const Gu::ContactPoint& contact = contactBuffer.contacts[i];
materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
//contact.featureIndex0 = shape0->materialIndex;
const PxU32 localMaterialIndex = GetMaterialIndex(hf, contact.internalFaceIndex1);
//contact.featureIndex1 = materialIndices[localMaterialIndex];
PX_ASSERT(localMaterialIndex<hfGeom.materials.numIndices);
materialInfo[i].mMaterialIndex1 = materialIndices[localMaterialIndex];
}
}
return true;
}

View File

@ -0,0 +1,108 @@
//
// 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-2021 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 "geometry/PxTriangleMesh.h"
#include "PxvGeometry.h"
#include "PxsMaterialManager.h"
#include "PxcNpThreadContext.h"
#include "GuHeightField.h"
#include "GuTriangleMesh.h"
using namespace physx;
using namespace Gu;
namespace physx
{
bool PxcGetMaterialShapeMesh(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo);
bool PxcGetMaterialMesh(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo);
}
bool physx::PxcGetMaterialMesh(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
{
PX_ASSERT(index == 1);
PX_UNUSED(index);
ContactBuffer& contactBuffer = context.mContactBuffer;
const PxTriangleMeshGeometryLL& shapeMesh = shape->geometry.get<const PxTriangleMeshGeometryLL>();
if(shapeMesh.materials.numIndices <= 1)
{
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
(&materialInfo[i].mMaterialIndex0)[index] = shape->materialIndex;
}
}
else
{
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
Gu::ContactPoint& contact = contactBuffer.contacts[i];
const PxU16* eaMaterialIndices = shapeMesh.materialIndices;
const PxU32 localMaterialIndex = eaMaterialIndices[contact.internalFaceIndex1];//shapeMesh.triangleMesh->getTriangleMaterialIndex(contact.featureIndex1);
(&materialInfo[i].mMaterialIndex0)[index] = shapeMesh.materials.indices[localMaterialIndex];
}
}
return true;
}
bool physx::PxcGetMaterialShapeMesh(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
{
ContactBuffer& contactBuffer = context.mContactBuffer;
const PxTriangleMeshGeometryLL& shapeMesh = shape1->geometry.get<const PxTriangleMeshGeometryLL>();
// const Gu::TriangleMesh* meshData = shapeMesh.meshData;
if(shapeMesh.materials.numIndices <= 1)
{
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
materialInfo[i].mMaterialIndex1 = shape1->materialIndex;
}
}
else
{
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
Gu::ContactPoint& contact = contactBuffer.contacts[i];
//contact.featureIndex0 = shape0->materialIndex;
materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
const PxU16* eaMaterialIndices = shapeMesh.materialIndices;
const PxU32 localMaterialIndex = eaMaterialIndices[contact.internalFaceIndex1];//shapeMesh.triangleMesh->getTriangleMaterialIndex(contact.featureIndex1);
//contact.featureIndex1 = shapeMesh.materials.indices[localMaterialIndex];
materialInfo[i].mMaterialIndex1 = shapeMesh.materials.indices[localMaterialIndex];
}
}
return true;
}

View File

@ -0,0 +1,140 @@
//
// 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-2021 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 "geometry/PxGeometry.h"
#include "PxcMaterialMethodImpl.h"
namespace physx
{
bool PxcGetMaterialShapeShape (MATERIAL_METHOD_ARGS);
bool PxcGetMaterialShapeMesh (MATERIAL_METHOD_ARGS);
bool PxcGetMaterialShapeHeightField (MATERIAL_METHOD_ARGS);
bool PxcGetMaterialShape (SINGLE_MATERIAL_METHOD_ARGS);
bool PxcGetMaterialMesh (SINGLE_MATERIAL_METHOD_ARGS);
bool PxcGetMaterialHeightField (SINGLE_MATERIAL_METHOD_ARGS);
PxcGetSingleMaterialMethod g_GetSingleMaterialMethodTable[PxGeometryType::eGEOMETRY_COUNT] =
{
PxcGetMaterialShape, //PxGeometryType::eSPHERE
PxcGetMaterialShape, //PxGeometryType::ePLANE
PxcGetMaterialShape, //PxGeometryType::eCAPSULE
PxcGetMaterialShape, //PxGeometryType::eBOX
PxcGetMaterialShape, //PxGeometryType::eCONVEXMESH
PxcGetMaterialMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
PxcGetMaterialHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
};
//Table of contact methods for different shape-type combinations
PxcGetMaterialMethod g_GetMaterialMethodTable[][PxGeometryType::eGEOMETRY_COUNT] =
{
//PxGeometryType::eSPHERE
{
PxcGetMaterialShapeShape, //PxGeometryType::eSPHERE
PxcGetMaterialShapeShape, //PxGeometryType::ePLANE
PxcGetMaterialShapeShape, //PxGeometryType::eCAPSULE
PxcGetMaterialShapeShape, //PxGeometryType::eBOX
PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
PxcGetMaterialShapeMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
PxcGetMaterialShapeHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::ePLANE
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
PxcGetMaterialShapeShape, //PxGeometryType::eCAPSULE
PxcGetMaterialShapeShape, //PxGeometryType::eBOX
PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
0, //PxGeometryType::eTRIANGLEMESH
0, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eCAPSULE
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
PxcGetMaterialShapeShape, //PxGeometryType::eCAPSULE
PxcGetMaterialShapeShape, //PxGeometryType::eBOX
PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
PxcGetMaterialShapeMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
PxcGetMaterialShapeHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::eBOX
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
PxcGetMaterialShapeShape, //PxGeometryType::eBOX
PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
PxcGetMaterialShapeMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
PxcGetMaterialShapeHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::eCONVEXMESH
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
PxcGetMaterialShapeMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
PxcGetMaterialShapeHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
},
//PxGeometryType::eTRIANGLEMESH
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
0, //PxGeometryType::eCONVEXMESH
0, //PxGeometryType::eTRIANGLEMESH
0, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eHEIGHTFIELD
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
0, //PxGeometryType::eCONVEXMESH
0, //PxGeometryType::eTRIANGLEMESH
0, //PxGeometryType::eHEIGHTFIELD
},
};
}

View File

@ -0,0 +1,63 @@
//
// 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-2021 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 "geometry/PxTriangleMesh.h"
#include "PxvGeometry.h"
#include "PxsMaterialManager.h"
#include "PxcNpThreadContext.h"
#include "GuHeightField.h"
using namespace physx;
using namespace Gu;
namespace physx
{
bool PxcGetMaterialShape(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
{
ContactBuffer& contactBuffer = context.mContactBuffer;
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
(&materialInfo[i].mMaterialIndex0)[index] = shape->materialIndex;
}
return true;
}
bool PxcGetMaterialShapeShape(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
{
ContactBuffer& contactBuffer = context.mContactBuffer;
for(PxU32 i=0; i< contactBuffer.count; ++i)
{
materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
materialInfo[i].mMaterialIndex1 = shape1->materialIndex;
}
return true;
}
}

View File

@ -0,0 +1,445 @@
//
// 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-2021 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 "geometry/PxTriangleMesh.h"
#include "PxcNpBatch.h"
#include "PxcNpWorkUnit.h"
#include "PxcContactCache.h"
#include "PxcMaterialMethodImpl.h"
#include "PxcNpContactPrepShared.h"
#include "PxvDynamics.h" // for PxsBodyCore
#include "PxvGeometry.h" // for PxsShapeCore
#include "CmFlushPool.h"
#include "CmTask.h"
#include "PxsContactManager.h"
#include "PxsMaterialManager.h"
#include "PxsTransformCache.h"
#include "PxsContactManagerState.h"
#include "GuGeometryUnion.h"
#include "GuPersistentContactManifold.h"
#include "PsFoundation.h"
using namespace physx;
using namespace Gu;
static void startContacts(PxsContactManagerOutput& output, PxcNpThreadContext& context)
{
context.mContactBuffer.reset();
output.contactForces = NULL;
output.contactPatches = NULL;
output.contactPoints = NULL;
output.nbContacts = 0;
output.nbPatches = 0;
output.statusFlag = 0;
}
static void flipContacts(PxcNpThreadContext& threadContext, PxsMaterialInfo* PX_RESTRICT materialInfo)
{
ContactBuffer& buffer = threadContext.mContactBuffer;
for(PxU32 i=0; i<buffer.count; ++i)
{
Gu::ContactPoint& contactPoint = buffer.contacts[i];
contactPoint.normal = -contactPoint.normal;
Ps::swap(materialInfo[i].mMaterialIndex0, materialInfo[i].mMaterialIndex1);
}
}
static PX_FORCE_INLINE void updateDiscreteContactStats(PxcNpThreadContext& context, PxGeometryType::Enum type0, PxGeometryType::Enum type1)
{
#if PX_ENABLE_SIM_STATS
PX_ASSERT(type0<=type1);
context.mDiscreteContactPairs[type0][type1]++;
#endif
}
static bool copyBuffers(PxsContactManagerOutput& cmOutput, Gu::Cache& cache, PxcNpThreadContext& context, const bool useContactCache, const bool isMeshType)
{
bool ret = false;
//Copy the contact stream from previous buffer to current buffer...
PxU32 oldSize = sizeof(PxContact) * cmOutput.nbContacts + sizeof(PxContactPatch)*cmOutput.nbPatches;
if(oldSize)
{
ret = true;
PxU8* oldPatches = cmOutput.contactPatches;
PxU8* oldContacts = cmOutput.contactPoints;
PxReal* oldForces = cmOutput.contactForces;
PxU32 forceSize = cmOutput.nbContacts * sizeof(PxReal);
if(isMeshType)
forceSize += cmOutput.nbContacts * sizeof(PxU32);
PxU8* PX_RESTRICT contactPatches = NULL;
PxU8* PX_RESTRICT contactPoints = NULL;
PxReal* forceBuffer = NULL;
bool isOverflown = false;
//ML: if we are using contactStreamPool, which means we are running the GPU codepath
if(context.mContactStreamPool)
{
const PxU32 patchSize = cmOutput.nbPatches * sizeof(PxContactPatch);
const PxU32 contactSize = cmOutput.nbContacts * sizeof(PxContact);
PxU32 index = PxU32(Ps::atomicAdd(&context.mContactStreamPool->mSharedDataIndex, PxI32(contactSize)));
if(context.mContactStreamPool->isOverflown())
{
PX_WARN_ONCE("Contact buffer overflow detected, please increase its size in the scene desc!\n");
isOverflown = true;
}
contactPoints = context.mContactStreamPool->mDataStream + context.mContactStreamPool->mDataStreamSize - index;
const PxU32 patchIndex = PxU32(Ps::atomicAdd(&context.mPatchStreamPool->mSharedDataIndex, PxI32(patchSize)));
if(context.mPatchStreamPool->isOverflown())
{
PX_WARN_ONCE("Patch buffer overflow detected, please increase its size in the scene desc!\n");
isOverflown = true;
}
contactPatches = context.mPatchStreamPool->mDataStream + context.mPatchStreamPool->mDataStreamSize - patchIndex;
if(forceSize)
{
index = PxU32(Ps::atomicAdd(&context.mForceAndIndiceStreamPool->mSharedDataIndex, PxI32(forceSize)));
if(context.mForceAndIndiceStreamPool->isOverflown())
{
PX_WARN_ONCE("Force buffer overflow detected, please increase its size in the scene desc!\n");
isOverflown = true;
}
forceBuffer = reinterpret_cast<PxReal*>(context.mForceAndIndiceStreamPool->mDataStream + context.mForceAndIndiceStreamPool->mDataStreamSize - index);
}
if(isOverflown)
{
contactPatches = NULL;
contactPoints = NULL;
forceBuffer = NULL;
cmOutput.nbContacts = cmOutput.nbPatches = 0;
}
else
{
PxMemCopy(contactPatches, oldPatches, patchSize);
PxMemCopy(contactPoints, oldContacts, contactSize);
if (isMeshType)
{
PxMemCopy(forceBuffer + cmOutput.nbContacts, oldForces + cmOutput.nbContacts, sizeof(PxU32) * cmOutput.nbContacts);
}
}
}
else
{
const PxU32 alignedOldSize = (oldSize + 0xf) & 0xfffffff0;
PxU8* data = context.mContactBlockStream.reserve(alignedOldSize + forceSize);
if(forceSize)
forceBuffer = reinterpret_cast<PxReal*>(data + alignedOldSize);
contactPatches = data;
contactPoints = data + cmOutput.nbPatches * sizeof(PxContactPatch);
PxMemCopy(data, oldPatches, oldSize);
if (isMeshType)
{
PxMemCopy(forceBuffer + cmOutput.nbContacts, oldForces + cmOutput.nbContacts, sizeof(PxU32) * cmOutput.nbContacts);
}
}
if(forceSize)
PxMemZero(forceBuffer, forceSize);
cmOutput.contactPatches= contactPatches;
cmOutput.contactPoints = contactPoints;
cmOutput.contactForces = forceBuffer;
}
if(cache.mCachedSize)
{
if(cache.isMultiManifold())
{
PX_ASSERT((cache.mCachedSize & 0xF) == 0);
PxU8* newData = context.mNpCacheStreamPair.reserve(cache.mCachedSize);
PX_ASSERT((reinterpret_cast<uintptr_t>(newData)& 0xF) == 0);
PxMemCopy(newData, & cache.getMultipleManifold(), cache.mCachedSize);
cache.setMultiManifold(newData);
}
else if(useContactCache)
{
//Copy cache information as well...
const PxU8* cachedData = cache.mCachedData;
PxU8* newData = context.mNpCacheStreamPair.reserve(PxU32(cache.mCachedSize + 0xf) & 0xfff0);
PxMemCopy(newData, cachedData, cache.mCachedSize);
cache.mCachedData = newData;
}
}
return ret;
}
//ML: isMeshType is used in the GPU codepath. If the collision pair is mesh/heightfield vs primitives, we need to allocate enough memory for the mForceAndIndiceStreamPool in the threadContext.
static bool finishContacts(const PxcNpWorkUnit& input, PxsContactManagerOutput& npOutput, PxcNpThreadContext& threadContext, PxsMaterialInfo* PX_RESTRICT pMaterials, const bool isMeshType)
{
ContactBuffer& buffer = threadContext.mContactBuffer;
PX_ASSERT((npOutput.statusFlag & PxsContactManagerStatusFlag::eTOUCH_KNOWN) != PxsContactManagerStatusFlag::eTOUCH_KNOWN);
PxU8 statusFlags = PxU16(npOutput.statusFlag & (~PxsContactManagerStatusFlag::eTOUCH_KNOWN));
if(buffer.count)
statusFlags |= PxsContactManagerStatusFlag::eHAS_TOUCH;
else
statusFlags |= PxsContactManagerStatusFlag::eHAS_NO_TOUCH;
npOutput.nbContacts = Ps::to8(buffer.count);
if(!buffer.count)
{
npOutput.statusFlag = statusFlags;
npOutput.nbContacts = 0;
npOutput.nbPatches = 0;
return true;
}
PX_ASSERT(buffer.count);
#if PX_ENABLE_SIM_STATS
threadContext.mNbDiscreteContactPairsWithContacts++;
#endif
npOutput.statusFlag = statusFlags;
PxU32 contactForceByteSize = buffer.count * sizeof(PxReal);
//Regardless of the flags, we need to now record the compressed contact stream
PxU16 compressedContactSize;
const bool createReports =
input.flags & PxcNpWorkUnitFlag::eOUTPUT_CONTACTS
|| threadContext.mCreateContactStream
|| (input.flags & PxcNpWorkUnitFlag::eFORCE_THRESHOLD);
if((!isMeshType && !createReports))
contactForceByteSize = 0;
bool res = (writeCompressedContact(buffer.contacts, buffer.count, &threadContext, npOutput.nbContacts, npOutput.contactPatches, npOutput.contactPoints, compressedContactSize,
reinterpret_cast<PxReal*&>(npOutput.contactForces), contactForceByteSize, threadContext.mMaterialManager, ((input.flags & PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT) != 0),
false, pMaterials, npOutput.nbPatches, 0, NULL, NULL, threadContext.mCreateAveragePoint, threadContext.mContactStreamPool,
threadContext.mPatchStreamPool, threadContext.mForceAndIndiceStreamPool, isMeshType) != 0);
//handle buffer overflow
if(!npOutput.nbContacts)
{
PxU8 thisStatusFlags = PxU16(npOutput.statusFlag & (~PxsContactManagerStatusFlag::eTOUCH_KNOWN));
thisStatusFlags |= PxsContactManagerStatusFlag::eHAS_NO_TOUCH;
npOutput.statusFlag = thisStatusFlags;
npOutput.nbContacts = 0;
npOutput.nbPatches = 0;
#if PX_ENABLE_SIM_STATS
threadContext.mNbDiscreteContactPairsWithContacts--;
#endif
}
return res;
}
template<bool useContactCacheT>
static PX_FORCE_INLINE bool checkContactsMustBeGenerated(PxcNpThreadContext& context, const PxcNpWorkUnit& input, Gu::Cache& cache, PxsContactManagerOutput& output,
const PxsCachedTransform* cachedTransform0, const PxsCachedTransform* cachedTransform1,
const bool flip, PxGeometryType::Enum type0, PxGeometryType::Enum type1)
{
PX_ASSERT(cachedTransform0->transform.isSane() && cachedTransform1->transform.isSane());
//ML : if user doesn't raise the eDETECT_DISCRETE_CONTACT, we should not generate contacts
if(!(input.flags & PxcNpWorkUnitFlag::eDETECT_DISCRETE_CONTACT))
return false;
if(!(output.statusFlag & PxcNpWorkUnitStatusFlag::eDIRTY_MANAGER) && !(input.flags & PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT))
{
const PxU32 body0Dynamic = PxU32(input.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY0);
const PxU32 body1Dynamic = PxU32(input.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY1);
const PxU32 active0 = PxU32(body0Dynamic && !cachedTransform0->isFrozen());
const PxU32 active1 = PxU32(body1Dynamic && !cachedTransform1->isFrozen());
if(!(active0 || active1))
{
if(flip)
Ps::swap(type0, type1);
const bool useContactCache = useContactCacheT ? context.mContactCache && g_CanUseContactCache[type0][type1] : false;
#if PX_ENABLE_SIM_STATS
if(output.nbContacts)
context.mNbDiscreteContactPairsWithContacts++;
#endif
const bool isMeshType = type1 > PxGeometryType::eCONVEXMESH;
copyBuffers(output, cache, context, useContactCache, isMeshType);
return false;
}
}
output.statusFlag &= (~PxcNpWorkUnitStatusFlag::eDIRTY_MANAGER);
const PxReal contactDist0 = context.mContactDistance[input.mTransformCache0];
const PxReal contactDist1 = context.mContactDistance[input.mTransformCache1];
//context.mNarrowPhaseParams.mContactDistance = shape0->contactOffset + shape1->contactOffset;
context.mNarrowPhaseParams.mContactDistance = contactDist0 + contactDist1;
return true;
}
template<bool useLegacyCodepath>
static PX_FORCE_INLINE void discreteNarrowPhase(PxcNpThreadContext& context, const PxcNpWorkUnit& input, Gu::Cache& cache, PxsContactManagerOutput& output)
{
PxGeometryType::Enum type0 = static_cast<PxGeometryType::Enum>(input.geomType0);
PxGeometryType::Enum type1 = static_cast<PxGeometryType::Enum>(input.geomType1);
const bool flip = (type1<type0);
const PxsCachedTransform* cachedTransform0 = &context.mTransformCache->getTransformCache(input.mTransformCache0);
const PxsCachedTransform* cachedTransform1 = &context.mTransformCache->getTransformCache(input.mTransformCache1);
if(!checkContactsMustBeGenerated<useLegacyCodepath>(context, input, cache, output, cachedTransform0, cachedTransform1, flip, type0, type1))
return;
PxsShapeCore* shape0 = const_cast<PxsShapeCore*>(input.shapeCore0);
PxsShapeCore* shape1 = const_cast<PxsShapeCore*>(input.shapeCore1);
if(flip)
{
Ps::swap(type0, type1);
Ps::swap(shape0, shape1);
Ps::swap(cachedTransform0, cachedTransform1);
}
PxsMaterialInfo materialInfo[ContactBuffer::MAX_CONTACTS];
Gu::MultiplePersistentContactManifold& manifold = context.mTempManifold;
bool isMultiManifold = false;
if(!useLegacyCodepath)
{
if(cache.isMultiManifold())
{
//We are using a multi-manifold. This is cached in a reduced npCache...
isMultiManifold = true;
uintptr_t address = uintptr_t(&cache.getMultipleManifold());
manifold.fromBuffer(reinterpret_cast<PxU8*>(address));
cache.setMultiManifold(&manifold);
}
else if(cache.isManifold())
{
void* address = reinterpret_cast<void*>(&cache.getManifold());
Ps::prefetch(address);
Ps::prefetch(address, 128);
Ps::prefetch(address, 256);
}
}
updateDiscreteContactStats(context, type0, type1);
startContacts(output, context);
const PxTransform* tm0 = &cachedTransform0->transform;
const PxTransform* tm1 = &cachedTransform1->transform;
PX_ASSERT(tm0->isSane() && tm1->isSane());
if(useLegacyCodepath)
{
// PT: many cache misses here...
Ps::prefetchLine(shape1, 0); // PT: at least get rid of L2s for shape1
const PxcContactMethod conMethod = g_ContactMethodTable[type0][type1];
PX_ASSERT(conMethod);
const bool useContactCache = context.mContactCache && g_CanUseContactCache[type0][type1];
if(useContactCache)
{
#if PX_ENABLE_SIM_STATS
if(PxcCacheLocalContacts(context, cache, *tm0, *tm1, conMethod, shape0->geometry, shape1->geometry))
context.mNbDiscreteContactPairsWithCacheHits++;
#else
PxcCacheLocalContacts(context, n.pairCache, *tm0, *tm1, conMethod, shape0->geometry, shape1->geometry);
#endif
}
else
{
conMethod(shape0->geometry, shape1->geometry, *tm0, *tm1, context.mNarrowPhaseParams, cache, context.mContactBuffer, &context.mRenderOutput);
}
}
else
{
const PxcContactMethod conMethod = g_PCMContactMethodTable[type0][type1];
PX_ASSERT(conMethod);
conMethod(shape0->geometry, shape1->geometry, *tm0, *tm1, context.mNarrowPhaseParams, cache, context.mContactBuffer, &context.mRenderOutput);
}
const PxcGetMaterialMethod materialMethod = g_GetMaterialMethodTable[type0][type1];
// PX_ASSERT(materialMethod);
if(materialMethod)
materialMethod(shape0, shape1, context, materialInfo);
if(flip)
flipContacts(context, materialInfo);
if(!useLegacyCodepath)
{
if(isMultiManifold)
{
//Store the manifold back...
const PxU32 size = (sizeof(MultiPersistentManifoldHeader) +
manifold.mNumManifolds * sizeof(SingleManifoldHeader) +
manifold.mNumTotalContacts * sizeof(Gu::CachedMeshPersistentContact));
PxU8* buffer = context.mNpCacheStreamPair.reserve(size);
PX_ASSERT((reinterpret_cast<uintptr_t>(buffer)& 0xf) == 0);
manifold.toBuffer(buffer);
cache.setMultiManifold(buffer);
cache.mCachedSize = Ps::to16(size);
}
}
const bool isMeshType = type1 > PxGeometryType::eCONVEXMESH;
finishContacts(input, output, context, materialInfo, isMeshType);
}
void physx::PxcDiscreteNarrowPhase(PxcNpThreadContext& context, const PxcNpWorkUnit& input, Gu::Cache& cache, PxsContactManagerOutput& output)
{
discreteNarrowPhase<true>(context, input, cache, output);
}
void physx::PxcDiscreteNarrowPhasePCM(PxcNpThreadContext& context, const PxcNpWorkUnit& input, Gu::Cache& cache, PxsContactManagerOutput& output)
{
discreteNarrowPhase<false>(context, input, cache, output);
}

View File

@ -0,0 +1,75 @@
//
// 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-2021 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 "PxcNpCacheStreamPair.h"
#include "PsUserAllocated.h"
#include "PxcNpMemBlockPool.h"
using namespace physx;
void PxcNpCacheStreamPair::reset()
{
mBlock = NULL;
mUsed = 0;
}
PxcNpCacheStreamPair::PxcNpCacheStreamPair(PxcNpMemBlockPool& blockPool):
mBlockPool(blockPool), mBlock(NULL), mUsed(0)
{
}
// reserve can fail and return null. Read should never fail
PxU8* PxcNpCacheStreamPair::reserve(PxU32 size)
{
size = (size+15)&~15;
if(size>PxcNpMemBlock::SIZE)
{
return reinterpret_cast<PxU8*>(-1);
}
if(mBlock == NULL || mUsed + size > PxcNpMemBlock::SIZE)
{
mBlock = mBlockPool.acquireNpCacheBlock();
mUsed = 0;
}
PxU8* ptr;
if(mBlock == NULL)
ptr = 0;
else
{
ptr = mBlock->data+mUsed;
mUsed += size;
}
return ptr;
}

View File

@ -0,0 +1,554 @@
//
// 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-2021 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/PxPreprocessor.h"
#include "PsMathUtils.h"
#include "PxcNpWorkUnit.h"
#include "PxvDynamics.h"
using namespace physx;
using namespace Gu;
#include "PxsMaterialManager.h"
#include "PxsMaterialCombiner.h"
#include "PxcNpContactPrepShared.h"
#include "PsAtomic.h"
#include "PxsContactManagerState.h"
#include "PsVecMath.h"
using namespace physx;
using namespace Ps::aos;
static PX_FORCE_INLINE void copyContactPoint(PxContact* PX_RESTRICT point, const Gu::ContactPoint* PX_RESTRICT cp)
{
// PT: TODO: consider moving "separation" right after "point" in both structures, to copy both at the same time.
// point->contact = cp->point;
const Vec4V contactV = V4LoadA(&cp->point.x); // PT: V4LoadA safe because 'point' is aligned.
V4StoreU(contactV, &point->contact.x);
point->separation = cp->separation;
}
struct StridePatch
{
PxU8 startIndex;
PxU8 endIndex;
PxU8 nextIndex;
PxU8 totalCount;
bool isRoot;
};
PxU32 physx::writeCompressedContact(const Gu::ContactPoint* const PX_RESTRICT contactPoints, const PxU32 numContactPoints, PxcNpThreadContext* threadContext,
PxU8& writtenContactCount, PxU8*& outContactPatches, PxU8*& outContactPoints, PxU16& compressedContactSize, PxReal*& outContactForces, PxU32 contactForceByteSize,
const PxsMaterialManager* materialManager, bool hasModifiableContacts, bool forceNoResponse, PxsMaterialInfo* PX_RESTRICT pMaterial, PxU8& numPatches,
PxU32 additionalHeaderSize, PxsConstraintBlockManager* manager, PxcConstraintBlockStream* blockStream, bool insertAveragePoint,
PxcDataStreamPool* contactStreamPool, PxcDataStreamPool* patchStreamPool, PxcDataStreamPool* forceStreamPool, const bool isMeshType)
{
if(numContactPoints == 0)
{
writtenContactCount = 0;
outContactPatches = NULL;
outContactPoints = NULL;
outContactForces = NULL;
compressedContactSize = 0;
numPatches = 0;
return 0;
}
//Calculate the size of the contact buffer...
PX_ALLOCA(strPatches, StridePatch, numContactPoints);
StridePatch* stridePatches = &strPatches[0];
PxU32 numStrideHeaders = 1;
/*const bool hasInternalFaceIndex = contactPoints[0].internalFaceIndex0 != PXC_CONTACT_NO_FACE_INDEX ||
contactPoints[0].internalFaceIndex1 != PXC_CONTACT_NO_FACE_INDEX;*/
const bool isModifiable = !forceNoResponse && hasModifiableContacts;
PxU32 totalUniquePatches = 1;
PxU32 totalContactPoints = numContactPoints;
PxU32 strideStart = 0;
bool root = true;
StridePatch* parentRootPatch = NULL;
{
const PxReal closeNormalThresh = PXC_SAME_NORMAL;
//Go through and tag how many patches we have...
PxVec3 normal = contactPoints[0].normal;
PxU16 mat0 = pMaterial[0].mMaterialIndex0;
PxU16 mat1 = pMaterial[0].mMaterialIndex1;
for(PxU32 a = 1; a < numContactPoints; ++a)
{
if(normal.dot(contactPoints[a].normal) < closeNormalThresh ||
pMaterial[a].mMaterialIndex0 != mat0 || pMaterial[a].mMaterialIndex1 != mat1)
{
StridePatch& patch = stridePatches[numStrideHeaders-1];
patch.startIndex = PxU8(strideStart);
patch.endIndex = PxU8(a);
patch.nextIndex = 0xFF;
patch.totalCount = PxU8(a - strideStart);
patch.isRoot = root;
if(parentRootPatch)
parentRootPatch->totalCount += PxU8(a - strideStart);
root = true;
parentRootPatch = NULL;
for(PxU32 b = 1; b < numStrideHeaders; ++b)
{
StridePatch& thisPatch = stridePatches[b-1];
if(thisPatch.isRoot)
{
PxU32 ind = thisPatch.startIndex;
PxReal dp2 = contactPoints[a].normal.dot(contactPoints[ind].normal);
if(dp2 >= closeNormalThresh && pMaterial[a].mMaterialIndex0 == pMaterial[ind].mMaterialIndex0 &&
pMaterial[a].mMaterialIndex1 == pMaterial[ind].mMaterialIndex1)
{
PxU32 nextInd = b-1;
while(stridePatches[nextInd].nextIndex != 0xFF)
nextInd = stridePatches[nextInd].nextIndex;
stridePatches[nextInd].nextIndex = PxU8(numStrideHeaders);
root = false;
parentRootPatch = &stridePatches[b-1];
break;
}
}
}
normal = contactPoints[a].normal;
mat0 = pMaterial[a].mMaterialIndex0;
mat1 = pMaterial[a].mMaterialIndex1;
totalContactPoints = insertAveragePoint && (a - strideStart) > 1 ? totalContactPoints + 1 : totalContactPoints;
strideStart = a;
numStrideHeaders++;
if(root)
totalUniquePatches++;
}
}
totalContactPoints = insertAveragePoint &&(numContactPoints - strideStart) > 1 ? totalContactPoints + 1 : totalContactPoints;
contactForceByteSize = insertAveragePoint && contactForceByteSize != 0 ? contactForceByteSize + sizeof(PxF32) * (totalContactPoints - numContactPoints) : contactForceByteSize;
}
{
StridePatch& patch = stridePatches[numStrideHeaders-1];
patch.startIndex = PxU8(strideStart);
patch.endIndex = PxU8(numContactPoints);
patch.nextIndex = 0xFF;
patch.totalCount = PxU8(numContactPoints - strideStart);
patch.isRoot = root;
if(parentRootPatch)
parentRootPatch->totalCount += PxU8(numContactPoints - strideStart);
}
numPatches = PxU8(totalUniquePatches);
//Calculate the number of patches/points required
const PxU32 patchHeaderSize = sizeof(PxContactPatch) * (isModifiable ? totalContactPoints : totalUniquePatches) + additionalHeaderSize;
const PxU32 pointSize = totalContactPoints * (isModifiable ? sizeof(PxModifiableContact) : sizeof(PxContact));
PxU32 requiredContactSize = pointSize;
PxU32 requiredPatchSize = patchHeaderSize;
PxU32 totalRequiredSize;
PxU8* PX_RESTRICT contactData = NULL;
PxU8* PX_RESTRICT patchData = NULL;
PxReal* PX_RESTRICT forceData = NULL;
PxU32* PX_RESTRICT triangleIndice = NULL;
if(contactStreamPool && !isModifiable && additionalHeaderSize == 0) //If the contacts are modifiable, we **DON'T** allocate them in GPU pinned memory. This will be handled later when they're modified
{
bool isOverflown = false;
PxU32 contactIndex = PxU32(Ps::atomicAdd(&contactStreamPool->mSharedDataIndex, PxI32(requiredContactSize)));
if (contactStreamPool->isOverflown())
{
PX_WARN_ONCE("Contact buffer overflow detected, please increase its size in the scene desc!\n");
isOverflown = true;
}
contactData = contactStreamPool->mDataStream + contactStreamPool->mDataStreamSize - contactIndex;
PxU32 patchIndex = PxU32(Ps::atomicAdd(&patchStreamPool->mSharedDataIndex, PxI32(requiredPatchSize)));
if (patchStreamPool->isOverflown())
{
PX_WARN_ONCE("Patch buffer overflow detected, please increase its size in the scene desc!\n");
isOverflown = true;
}
patchData = patchStreamPool->mDataStream + patchStreamPool->mDataStreamSize - patchIndex;
if(contactForceByteSize)
{
contactForceByteSize = isMeshType ? contactForceByteSize * 2 : contactForceByteSize;
contactIndex = PxU32(Ps::atomicAdd(&forceStreamPool->mSharedDataIndex, PxI32(contactForceByteSize)));
if (forceStreamPool->isOverflown())
{
PX_WARN_ONCE("Force buffer overflow detected, please increase its size in the scene desc!\n");
isOverflown = true;
}
forceData = reinterpret_cast<PxReal*>(forceStreamPool->mDataStream + forceStreamPool->mDataStreamSize - contactIndex);
if (isMeshType)
triangleIndice = reinterpret_cast<PxU32*>(forceData + numContactPoints);
}
totalRequiredSize = requiredContactSize + requiredPatchSize;
if (isOverflown)
{
patchData = NULL;
contactData = NULL;
forceData = NULL;
triangleIndice = NULL;
}
}
else
{
PxU32 alignedRequiredSize = (requiredContactSize + requiredPatchSize + 0xf) & 0xfffffff0;
contactForceByteSize = (isMeshType ? contactForceByteSize * 2 : contactForceByteSize);
PxU32 totalSize = alignedRequiredSize + contactForceByteSize;
PxU8* data = manager ? blockStream->reserve(totalSize, *manager) : threadContext->mContactBlockStream.reserve(totalSize);
patchData = data;
contactData = patchData + requiredPatchSize;
if(contactForceByteSize)
{
forceData = reinterpret_cast<PxReal*>((data + alignedRequiredSize));
if (isMeshType)
triangleIndice = reinterpret_cast<PxU32*>(forceData + numContactPoints);
if(data)
{
PxMemZero(forceData, contactForceByteSize);
}
}
totalRequiredSize = alignedRequiredSize;
}
Ps::prefetchLine(patchData);
Ps::prefetchLine(contactData);
if(patchData == NULL)
{
writtenContactCount = 0;
outContactPatches = NULL;
outContactPoints = NULL;
outContactForces = NULL;
compressedContactSize = 0;
numPatches = 0;
return 0;
}
#if PX_ENABLE_SIM_STATS
if(threadContext)
{
threadContext->mCompressedCacheSize += totalRequiredSize;
threadContext->mTotalCompressedCacheSize += totalRequiredSize;
}
#endif
compressedContactSize = Ps::to16(totalRequiredSize);
//PxU32 startIndex = 0;
//Extract first material
PxU16 origMatIndex0 = pMaterial[0].mMaterialIndex0;
PxU16 origMatIndex1 = pMaterial[0].mMaterialIndex1;
PxReal staticFriction, dynamicFriction, combinedRestitution;
PxU32 materialFlags;
{
const PxsMaterialData& data0 = *materialManager->getMaterial(origMatIndex0);
const PxsMaterialData& data1 = *materialManager->getMaterial(origMatIndex1);
combinedRestitution = PxsMaterialCombiner::combineRestitution(data0, data1);
PxsMaterialCombiner combiner(1.0f, 1.0f);
PxsMaterialCombiner::PxsCombinedMaterial combinedMat = combiner.combineIsotropicFriction(data0, data1);
staticFriction = combinedMat.staFriction;
dynamicFriction = combinedMat.dynFriction;
materialFlags = combinedMat.flags;
}
PxU8* PX_RESTRICT dataPlusOffset = patchData + additionalHeaderSize;
PxContactPatch* PX_RESTRICT patches = reinterpret_cast<PxContactPatch*>(dataPlusOffset);
PxU32* PX_RESTRICT faceIndice = triangleIndice;
outContactPatches = patchData;
outContactPoints = contactData;
outContactForces = forceData;
if(isModifiable)
{
PxU32 flags = PxU32(isModifiable ? PxContactPatch::eMODIFIABLE : 0) |
(forceNoResponse ? PxContactPatch::eFORCE_NO_RESPONSE : 0) |
(isMeshType ? PxContactPatch::eHAS_FACE_INDICES : 0);
PxU32 currentIndex = 0;
PxModifiableContact* PX_RESTRICT point = reinterpret_cast<PxModifiableContact*>(contactData);
for(PxU32 a = 0; a < numStrideHeaders; ++a)
{
StridePatch& rootPatch = stridePatches[a];
if(rootPatch.isRoot)
{
PxContactPatch* PX_RESTRICT patch = patches++;
PxU32 startIndex = rootPatch.startIndex;
const PxU16 matIndex0 = pMaterial[startIndex].mMaterialIndex0;
const PxU16 matIndex1 = pMaterial[startIndex].mMaterialIndex1;
if(matIndex0 != origMatIndex0 || matIndex1 != origMatIndex1)
{
const PxsMaterialData& data0 = *materialManager->getMaterial(matIndex0);
const PxsMaterialData& data1 = *materialManager->getMaterial(matIndex1);
combinedRestitution = PxsMaterialCombiner::combineRestitution(data0, data1);
PxsMaterialCombiner combiner(1.0f, 1.0f);
PxsMaterialCombiner::PxsCombinedMaterial combinedMat = combiner.combineIsotropicFriction(data0, data1);
staticFriction = combinedMat.staFriction;
dynamicFriction = combinedMat.dynFriction;
materialFlags = combinedMat.flags;
origMatIndex0 = matIndex0;
origMatIndex1 = matIndex1;
}
patch->nbContacts = rootPatch.totalCount;
patch->startContactIndex = Ps::to8(currentIndex);
patch->materialFlags = PxU8(materialFlags);
patch->staticFriction = staticFriction;
patch->dynamicFriction = dynamicFriction;
patch->restitution = combinedRestitution;
patch->materialIndex0 = matIndex0;
patch->materialIndex1 = matIndex1;
patch->normal = contactPoints[0].normal;
patch->mMassModification.mInvMassScale0 = 1.0f;
patch->mMassModification.mInvMassScale1 = 1.0f;
patch->mMassModification.mInvInertiaScale0 = 1.0f;
patch->mMassModification.mInvInertiaScale1 = 1.0f;
patch->internalFlags = PxU8(flags);
//const PxU32 endIndex = strideHeader[a];
const PxU32 totalCountThisPatch = rootPatch.totalCount;
if(insertAveragePoint && totalCountThisPatch > 1)
{
PxVec3 avgPt(0.0f);
PxF32 avgPen(0.0f);
PxF32 recipCount = 1.0f/(PxF32(rootPatch.totalCount));
PxU32 index = a;
while(index != 0xFF)
{
StridePatch& p = stridePatches[index];
for(PxU32 b = p.startIndex; b < p.endIndex; ++b)
{
avgPt += contactPoints[b].point;
avgPen += contactPoints[b].separation;
}
index = p.nextIndex;
}
if (faceIndice)
{
StridePatch& p = stridePatches[index];
*faceIndice = contactPoints[p.startIndex].internalFaceIndex1;
faceIndice++;
}
patch->nbContacts++;
point->contact = avgPt * recipCount;
point->separation = avgPen * recipCount;
point->normal = contactPoints[0].normal;
point->maxImpulse = PX_MAX_REAL;
point->targetVelocity = PxVec3(0.0f);
point->staticFriction = staticFriction;
point->dynamicFriction = dynamicFriction;
point->restitution = combinedRestitution;
point->materialFlags = materialFlags;
point->materialIndex0 = matIndex0;
point->materialIndex1 = matIndex1;
point++;
currentIndex++;
Ps::prefetchLine(point, 128);
}
PxU32 index = a;
while(index != 0xFF)
{
StridePatch& p = stridePatches[index];
for(PxU32 b = p.startIndex; b < p.endIndex; ++b)
{
copyContactPoint(point, &contactPoints[b]);
point->normal = contactPoints[b].normal;
point->maxImpulse = PX_MAX_REAL;
point->targetVelocity = PxVec3(0.0f);
point->staticFriction = staticFriction;
point->dynamicFriction = dynamicFriction;
point->restitution = combinedRestitution;
point->materialFlags = materialFlags;
point->materialIndex0 = matIndex0;
point->materialIndex1 = matIndex1;
if (faceIndice)
{
*faceIndice = contactPoints[b].internalFaceIndex1;
faceIndice++;
}
point++;
currentIndex++;
Ps::prefetchLine(point, 128);
}
index = p.nextIndex;
}
}
}
}
else
{
PxU32 flags = PxU32(isMeshType ? PxContactPatch::eHAS_FACE_INDICES : 0);
PxContact* PX_RESTRICT point = reinterpret_cast<PxContact*>(contactData);
PxU32 currentIndex = 0;
{
for(PxU32 a = 0; a < numStrideHeaders; ++a)
{
StridePatch& rootPatch = stridePatches[a];
if(rootPatch.isRoot)
{
const PxU16 matIndex0 = pMaterial[rootPatch.startIndex].mMaterialIndex0;
const PxU16 matIndex1 = pMaterial[rootPatch.startIndex].mMaterialIndex1;
if(matIndex0 != origMatIndex0 || matIndex1 != origMatIndex1)
{
const PxsMaterialData& data0 = *materialManager->getMaterial(matIndex0);
const PxsMaterialData& data1 = *materialManager->getMaterial(matIndex1);
combinedRestitution = PxsMaterialCombiner::combineRestitution(data0, data1);
PxsMaterialCombiner combiner(1.0f, 1.0f);
PxsMaterialCombiner::PxsCombinedMaterial combinedMat = combiner.combineIsotropicFriction(data0, data1);
staticFriction = combinedMat.staFriction;
dynamicFriction = combinedMat.dynFriction;
materialFlags = combinedMat.flags;
origMatIndex0 = matIndex0;
origMatIndex1 = matIndex1;
}
PxContactPatch* PX_RESTRICT patch = patches++;
patch->normal = contactPoints[rootPatch.startIndex].normal;
patch->nbContacts = rootPatch.totalCount;
patch->startContactIndex = Ps::to8(currentIndex);
//KS - we could probably compress this further into the header but the complexity might not be worth it
patch->staticFriction = staticFriction;
patch->dynamicFriction = dynamicFriction;
patch->restitution = combinedRestitution;
patch->materialIndex0 = matIndex0;
patch->materialIndex1 = matIndex1;
patch->materialFlags = PxU8(materialFlags);
patch->internalFlags = PxU8(flags);
patch->mMassModification.mInvMassScale0 = 1.0f;
patch->mMassModification.mInvMassScale1 = 1.0f;
patch->mMassModification.mInvInertiaScale0 = 1.0f;
patch->mMassModification.mInvInertiaScale1 = 1.0f;
if(insertAveragePoint && (rootPatch.totalCount) > 1)
{
patch->nbContacts++;
PxVec3 avgPt(0.0f);
PxF32 avgPen(0.0f);
PxF32 recipCount = 1.0f/(PxF32(rootPatch.totalCount));
PxU32 index = a;
while(index != 0xFF)
{
StridePatch& p = stridePatches[index];
for(PxU32 b = p.startIndex; b < p.endIndex; ++b)
{
avgPt += contactPoints[b].point;
avgPen += contactPoints[b].separation;
}
index = stridePatches[index].nextIndex;
}
if (faceIndice)
{
StridePatch& p = stridePatches[index];
*faceIndice = contactPoints[p.startIndex].internalFaceIndex1;
faceIndice++;
}
point->contact = avgPt * recipCount;
point->separation = avgPen * recipCount;
point++;
currentIndex++;
Ps::prefetchLine(point, 128);
}
PxU32 index = a;
while(index != 0xFF)
{
StridePatch& p = stridePatches[index];
for(PxU32 b = p.startIndex; b < p.endIndex; ++b)
{
copyContactPoint(point, &contactPoints[b]);
if (faceIndice)
{
*faceIndice = contactPoints[b].internalFaceIndex1;
faceIndice++;
}
point++;
currentIndex++;
Ps::prefetchLine(point, 128);
}
index = stridePatches[index].nextIndex;
}
}
}
}
}
writtenContactCount = Ps::to8(totalContactPoints);
return totalRequiredSize;
}

View File

@ -0,0 +1,351 @@
//
// 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-2021 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/PxPreprocessor.h"
#include "foundation/PxMath.h"
#include "PxcNpMemBlockPool.h"
#include "PsUserAllocated.h"
#include "PsInlineArray.h"
#include "PsFoundation.h"
using namespace physx;
PxcNpMemBlockPool::PxcNpMemBlockPool(PxcScratchAllocator& allocator):
mConstraints(PX_DEBUG_EXP("PxcNpMemBlockPool::mConstraints")),
mExceptionalConstraints(PX_DEBUG_EXP("PxcNpMemBlockPool::mExceptionalConstraints")),
mNpCacheActiveStream(0),
mFrictionActiveStream(0),
mCCDCacheActiveStream(0),
mContactIndex(0),
mAllocatedBlocks(0),
mMaxBlocks(0),
mUsedBlocks(0),
mMaxUsedBlocks(0),
mScratchBlockAddr(0),
mNbScratchBlocks(0),
mScratchAllocator(allocator),
mPeakConstraintAllocations(0),
mConstraintAllocations(0)
{
}
void PxcNpMemBlockPool::init(PxU32 initialBlockCount, PxU32 maxBlocks)
{
mMaxBlocks = maxBlocks;
mInitialBlocks = initialBlockCount;
PxU32 reserve = PxMax<PxU32>(initialBlockCount, 64);
mConstraints.reserve(reserve);
mExceptionalConstraints.reserve(16);
mFriction[0].reserve(reserve);
mFriction[1].reserve(reserve);
mNpCache[0].reserve(reserve);
mNpCache[1].reserve(reserve);
mUnused.reserve(reserve);
setBlockCount(initialBlockCount);
}
PxU32 PxcNpMemBlockPool::getUsedBlockCount() const
{
return mUsedBlocks;
}
PxU32 PxcNpMemBlockPool::getMaxUsedBlockCount() const
{
return mMaxUsedBlocks;
}
PxU32 PxcNpMemBlockPool::getPeakConstraintBlockCount() const
{
return mPeakConstraintAllocations;
}
void PxcNpMemBlockPool::setBlockCount(PxU32 blockCount)
{
Ps::Mutex::ScopedLock lock(mLock);
PxU32 current = getUsedBlockCount();
for(PxU32 i=current;i<blockCount;i++)
{
mUnused.pushBack(reinterpret_cast<PxcNpMemBlock *>(PX_ALLOC(PxcNpMemBlock::SIZE, "PxcNpMemBlock")));
mAllocatedBlocks++;
}
}
void PxcNpMemBlockPool::releaseUnusedBlocks()
{
Ps::Mutex::ScopedLock lock(mLock);
while(mUnused.size())
{
PX_FREE(mUnused.popBack());
mAllocatedBlocks--;
}
}
PxcNpMemBlockPool::~PxcNpMemBlockPool()
{
// swapping twice guarantees all blocks are released from the stream pairs
swapFrictionStreams();
swapFrictionStreams();
swapNpCacheStreams();
swapNpCacheStreams();
releaseConstraintMemory();
releaseContacts();
releaseContacts();
PX_ASSERT(mUsedBlocks == 0);
flushUnused();
}
void PxcNpMemBlockPool::acquireConstraintMemory()
{
PxU32 size;
void* addr = mScratchAllocator.allocAll(size);
size = size&~(PxcNpMemBlock::SIZE-1);
PX_ASSERT(mScratchBlocks.size()==0);
mScratchBlockAddr = reinterpret_cast<PxcNpMemBlock*>(addr);
mNbScratchBlocks = size/PxcNpMemBlock::SIZE;
mScratchBlocks.resize(mNbScratchBlocks);
for(PxU32 i=0;i<mNbScratchBlocks;i++)
mScratchBlocks[i] = mScratchBlockAddr+i;
}
void PxcNpMemBlockPool::releaseConstraintMemory()
{
Ps::Mutex::ScopedLock lock(mLock);
mPeakConstraintAllocations = mConstraintAllocations = 0;
while(mConstraints.size())
{
PxcNpMemBlock* block = mConstraints.popBack();
if(mScratchAllocator.isScratchAddr(block))
mScratchBlocks.pushBack(block);
else
{
mUnused.pushBack(block);
PX_ASSERT(mUsedBlocks>0);
mUsedBlocks--;
}
}
for(PxU32 i=0;i<mExceptionalConstraints.size();i++)
PX_FREE(mExceptionalConstraints[i]);
mExceptionalConstraints.clear();
PX_ASSERT(mScratchBlocks.size()==mNbScratchBlocks); // check we released them all
mScratchBlocks.clear();
if(mScratchBlockAddr)
{
mScratchAllocator.free(mScratchBlockAddr);
mScratchBlockAddr = 0;
mNbScratchBlocks = 0;
}
}
PxcNpMemBlock* PxcNpMemBlockPool::acquire(PxcNpMemBlockArray& trackingArray, PxU32* allocationCount, PxU32* peakAllocationCount, bool isScratchAllocation)
{
Ps::Mutex::ScopedLock lock(mLock);
if(allocationCount && peakAllocationCount)
{
*peakAllocationCount = PxMax(*allocationCount + 1, *peakAllocationCount);
(*allocationCount)++;
}
// this is a bit of hack - the logic would be better placed in acquireConstraintBlock, but then we'd have to grab the mutex
// once there to check the scratch block array and once here if we fail - or, we'd need a larger refactor to separate out
// locking and acquisition.
if(isScratchAllocation && mScratchBlocks.size()>0)
{
PxcNpMemBlock* block = mScratchBlocks.popBack();
trackingArray.pushBack(block);
return block;
}
if(mUnused.size())
{
PxcNpMemBlock* block = mUnused.popBack();
trackingArray.pushBack(block);
mMaxUsedBlocks = PxMax<PxU32>(mUsedBlocks+1, mMaxUsedBlocks);
mUsedBlocks++;
return block;
}
if(mAllocatedBlocks == mMaxBlocks)
{
#if PX_CHECKED
Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__,
"Reached maximum number of allocated blocks so 16k block allocation will fail!");
#endif
return NULL;
}
#if PX_CHECKED
if(mInitialBlocks)
{
Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__,
"Number of required 16k memory blocks has exceeded the initial number of blocks. Allocator is being called. Consider increasing the number of pre-allocated 16k blocks.");
}
#endif
// increment here so that if we hit the limit in separate threads we won't overallocated
mAllocatedBlocks++;
PxcNpMemBlock* block = reinterpret_cast<PxcNpMemBlock*>(PX_ALLOC(sizeof(PxcNpMemBlock), "PxcNpMemBlock"));
if(block)
{
trackingArray.pushBack(block);
mMaxUsedBlocks = PxMax<PxU32>(mUsedBlocks+1, mMaxUsedBlocks);
mUsedBlocks++;
}
else
mAllocatedBlocks--;
return block;
}
PxU8* PxcNpMemBlockPool::acquireExceptionalConstraintMemory(PxU32 size)
{
PxU8* memory = reinterpret_cast<PxU8*>(PX_ALLOC(size, "PxcNpExceptionalMemory"));
if(memory)
{
Ps::Mutex::ScopedLock lock(mLock);
mExceptionalConstraints.pushBack(memory);
}
return memory;
}
void PxcNpMemBlockPool::release(PxcNpMemBlockArray& deadArray, PxU32* allocationCount)
{
Ps::Mutex::ScopedLock lock(mLock);
PX_ASSERT(mUsedBlocks >= deadArray.size());
mUsedBlocks -= deadArray.size();
if(allocationCount)
{
*allocationCount -= deadArray.size();
}
while(deadArray.size())
{
PxcNpMemBlock* block = deadArray.popBack();
for(PxU32 a = 0; a < mUnused.size(); ++a)
{
PX_ASSERT(mUnused[a] != block);
}
mUnused.pushBack(block);
}
}
void PxcNpMemBlockPool::flushUnused()
{
while(mUnused.size())
PX_FREE(mUnused.popBack());
}
PxcNpMemBlock* PxcNpMemBlockPool::acquireConstraintBlock()
{
// we track the scratch blocks in the constraint block array, because the code in acquireMultipleConstraintBlocks
// assumes that acquired blocks are listed there.
return acquire(mConstraints);
}
PxcNpMemBlock* PxcNpMemBlockPool::acquireConstraintBlock(PxcNpMemBlockArray& memBlocks)
{
return acquire(memBlocks, &mConstraintAllocations, &mPeakConstraintAllocations, true);
}
PxcNpMemBlock* PxcNpMemBlockPool::acquireContactBlock()
{
return acquire(mContacts[mContactIndex], NULL, NULL, true);
}
void PxcNpMemBlockPool::releaseConstraintBlocks(PxcNpMemBlockArray& memBlocks)
{
Ps::Mutex::ScopedLock lock(mLock);
while(memBlocks.size())
{
PxcNpMemBlock* block = memBlocks.popBack();
if(mScratchAllocator.isScratchAddr(block))
mScratchBlocks.pushBack(block);
else
{
mUnused.pushBack(block);
PX_ASSERT(mUsedBlocks>0);
mUsedBlocks--;
}
}
}
void PxcNpMemBlockPool::releaseContacts()
{
//releaseConstraintBlocks(mContacts);
release(mContacts[1-mContactIndex]);
mContactIndex = 1-mContactIndex;
}
PxcNpMemBlock* PxcNpMemBlockPool::acquireFrictionBlock()
{
return acquire(mFriction[mFrictionActiveStream]);
}
void PxcNpMemBlockPool::swapFrictionStreams()
{
release(mFriction[1-mFrictionActiveStream]);
mFrictionActiveStream = 1-mFrictionActiveStream;
}
PxcNpMemBlock* PxcNpMemBlockPool::acquireNpCacheBlock()
{
return acquire(mNpCache[mNpCacheActiveStream]);
}
void PxcNpMemBlockPool::swapNpCacheStreams()
{
release(mNpCache[1-mNpCacheActiveStream]);
mNpCacheActiveStream = 1-mNpCacheActiveStream;
}

View File

@ -0,0 +1,94 @@
//
// 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-2021 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 "PxcConstraintBlockStream.h"
#include "PxcNpThreadContext.h"
using namespace physx;
PxcNpThreadContext::PxcNpThreadContext(PxcNpContext* params) :
mRenderOutput (params->mRenderBuffer),
mContactBlockStream (params->mNpMemBlockPool),
mNpCacheStreamPair (params->mNpMemBlockPool),
mNarrowPhaseParams (0.0f, params->mMeshContactMargin, params->mToleranceLength),
mBodySimPool (PX_DEBUG_EXP("BodySimPool")),
mPCM (false),
mContactCache (false),
mCreateContactStream (params->mCreateContactStream),
mCreateAveragePoint (false),
#if PX_ENABLE_SIM_STATS
mCompressedCacheSize (0),
mNbDiscreteContactPairsWithCacheHits(0),
mNbDiscreteContactPairsWithContacts (0),
#endif
mMaxPatches (0),
mTotalCompressedCacheSize (0),
mContactStreamPool (params->mContactStreamPool),
mPatchStreamPool (params->mPatchStreamPool),
mForceAndIndiceStreamPool (params->mForceAndIndiceStreamPool),
mMaterialManager (params->mMaterialManager),
mLocalNewTouchCount (0),
mLocalLostTouchCount (0),
mLocalFoundPatchCount (0),
mLocalLostPatchCount (0)
{
#if PX_ENABLE_SIM_STATS
clearStats();
#endif
}
PxcNpThreadContext::~PxcNpThreadContext()
{
}
#if PX_ENABLE_SIM_STATS
void PxcNpThreadContext::clearStats()
{
PxMemSet(mDiscreteContactPairs, 0, sizeof(mDiscreteContactPairs));
PxMemSet(mModifiedContactPairs, 0, sizeof(mModifiedContactPairs));
mCompressedCacheSize = 0;
mNbDiscreteContactPairsWithCacheHits = 0;
mNbDiscreteContactPairsWithContacts = 0;
}
#endif
void PxcNpThreadContext::reset(PxU32 cmCount)
{
mContactBlockStream.reset();
mNpCacheStreamPair.reset();
mLocalChangeTouch.clear();
mLocalChangeTouch.resize(cmCount);
mLocalPatchCountChange.clear();
mLocalPatchCountChange.resize(cmCount);
mLocalNewTouchCount = 0;
mLocalLostTouchCount = 0;
mLocalFoundPatchCount = 0;
mLocalLostPatchCount = 0;
}