diff options
Diffstat (limited to 'PhysX_3.4/Source/LowLevel/common/src/pipeline')
11 files changed, 2652 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactCache.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactCache.cpp new file mode 100644 index 00000000..26ea90a5 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactCache.cpp @@ -0,0 +1,393 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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; +} diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactMethodImpl.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactMethodImpl.cpp new file mode 100644 index 00000000..53eb5d88 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactMethodImpl.cpp @@ -0,0 +1,279 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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 "PxGeometry.h" +#include "PxcContactMethodImpl.h" + +namespace physx +{ + +// PT: those prototypes shouldn't be public. Keep them here. + +// Sphere - other +bool PxcContactSphereSphere (GU_CONTACT_METHOD_ARGS); +bool PxcContactSpherePlane (GU_CONTACT_METHOD_ARGS); +bool PxcContactSphereCapsule (GU_CONTACT_METHOD_ARGS); +bool PxcContactSphereBox (GU_CONTACT_METHOD_ARGS); +bool PxcContactSphereConvex (GU_CONTACT_METHOD_ARGS); +bool PxcContactSphereMesh (GU_CONTACT_METHOD_ARGS); +bool PxcContactSphereHeightField (GU_CONTACT_METHOD_ARGS); + +// Plane - other +bool PxcContactPlaneCapsule (GU_CONTACT_METHOD_ARGS); +bool PxcContactPlaneBox (GU_CONTACT_METHOD_ARGS); +bool PxcContactPlaneConvex (GU_CONTACT_METHOD_ARGS); + +// Capsule - other +bool PxcContactCapsuleCapsule (GU_CONTACT_METHOD_ARGS); +bool PxcContactCapsuleBox (GU_CONTACT_METHOD_ARGS); +bool PxcContactCapsuleConvex (GU_CONTACT_METHOD_ARGS); +bool PxcContactCapsuleMesh (GU_CONTACT_METHOD_ARGS); +bool PxcContactCapsuleHeightField (GU_CONTACT_METHOD_ARGS); + +// Box - other +bool PxcContactBoxBox (GU_CONTACT_METHOD_ARGS); +bool PxcContactBoxConvex (GU_CONTACT_METHOD_ARGS); +bool PxcContactBoxMesh (GU_CONTACT_METHOD_ARGS); +bool PxcContactBoxHeightField (GU_CONTACT_METHOD_ARGS); + +// Convex - other +bool PxcContactConvexConvex (GU_CONTACT_METHOD_ARGS); +bool PxcContactConvexMesh (GU_CONTACT_METHOD_ARGS); +bool PxcContactConvexHeightField (GU_CONTACT_METHOD_ARGS); + + +static bool PxcInvalidContactPair (CONTACT_METHOD_ARGS_UNUSED) +{ + return false; +} + +//PCM Sphere - other +bool PxcPCMContactSphereSphere (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactSpherePlane (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactSphereBox (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactSphereCapsule (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactSphereConvex (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactSphereMesh (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactSphereHeightField (GU_CONTACT_METHOD_ARGS); + +// Plane - other +bool PxcPCMContactPlaneCapsule (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactPlaneBox (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactPlaneConvex (GU_CONTACT_METHOD_ARGS); + +//PCM Capsule - other +bool PxcPCMContactCapsuleCapsule (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactCapsuleBox (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactCapsuleConvex (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactCapsuleMesh (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactCapsuleHeightField (GU_CONTACT_METHOD_ARGS); + +//PCM Box - other +bool PxcPCMContactBoxBox (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactBoxConvex (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactBoxMesh (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactBoxHeightField (GU_CONTACT_METHOD_ARGS); + +//PCM Convex +bool PxcPCMContactConvexConvex (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactConvexMesh (GU_CONTACT_METHOD_ARGS); +bool PxcPCMContactConvexHeightField (GU_CONTACT_METHOD_ARGS); + + +#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 + }, + +}; +} diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialHeightField.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialHeightField.cpp new file mode 100644 index 00000000..89b347c2 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialHeightField.cpp @@ -0,0 +1,116 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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 "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; +} + diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMesh.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMesh.cpp new file mode 100644 index 00000000..17b16712 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMesh.cpp @@ -0,0 +1,107 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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 "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; +} diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMethodImpl.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMethodImpl.cpp new file mode 100644 index 00000000..61195bf0 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMethodImpl.cpp @@ -0,0 +1,140 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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 "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 + }, + +}; + +} diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialShape.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialShape.cpp new file mode 100644 index 00000000..1c8c3849 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialShape.cpp @@ -0,0 +1,62 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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 "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; +} +} + diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpBatch.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpBatch.cpp new file mode 100644 index 00000000..7ed87b05 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpBatch.cpp @@ -0,0 +1,413 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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 "PxcNpBatch.h" +#include "PxcNpWorkUnit.h" +#include "PxsContactManager.h" +#include "GuGeometryUnion.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 "PxTriangleMesh.h" +#include "PxsMaterialManager.h" +#include "PxsTransformCache.h" +#include "GuPersistentContactManifold.h" +#include "PxsContactManagerState.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; + + PxU32 forceSize = cmOutput.nbContacts * sizeof(PxReal); + + 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) + { + forceSize = isMeshType ? (forceSize * 2) : 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); + } + } + 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(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; +} + +void physx::PxcDiscreteNarrowPhase(PxcNpThreadContext& context, PxcNpWorkUnit& input, Gu::Cache& cache, PxsContactManagerOutput& output) +{ + //ML : if user doesn't raise the eDETECT_DISCRETE_CONTACT, we should not generate contacts + if(!(input.flags & PxcNpWorkUnitFlag::eDETECT_DISCRETE_CONTACT)) + return; + + 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(!(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 = context.mContactCache && g_CanUseContactCache[type0][type1]; + +#if PX_ENABLE_SIM_STATS + if(output.nbContacts) + context.mNbDiscreteContactPairsWithContacts++; +#endif + const bool isMeshType = type1 > PxGeometryType::eCONVEXMESH; + copyBuffers(output, cache, context, useContactCache, isMeshType); + return; + } + } + + output.statusFlag &= (~PxcNpWorkUnitStatusFlag::eDIRTY_MANAGER); + + 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); + } + + // PT: many cache misses here... + // PT: TODO: refactor this change with runNpBatchPPU + + Ps::prefetchLine(shape1, 0); // PT: at least get rid of L2s for shape1 + + const PxTransform* tm0 = &cachedTransform0->transform; + const PxTransform* tm1 = &cachedTransform1->transform; + PX_ASSERT(tm0->isSane() && tm1->isSane()); + + updateDiscreteContactStats(context, type0, type1); + + 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; + + startContacts(output, context); + + 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); + } + + PxsMaterialInfo materialInfo[ContactBuffer::MAX_CONTACTS]; + + const PxcGetMaterialMethod materialMethod = g_GetMaterialMethodTable[type0][type1]; + PX_ASSERT(materialMethod); + + materialMethod(shape0, shape1, context, materialInfo); + + if(flip) + flipContacts(context, materialInfo); + + const bool isMeshType = type1 > PxGeometryType::eCONVEXMESH; + finishContacts(input, output, context, materialInfo, isMeshType); +} + +void physx::PxcDiscreteNarrowPhasePCM(PxcNpThreadContext& context, PxcNpWorkUnit& cmInput, Gu::Cache& cache, PxsContactManagerOutput& output) +{ + //ML : if user doesn't raise the eDETECT_DISCRETE_CONTACT, we should not generate contacts + if(!(cmInput.flags & PxcNpWorkUnitFlag::eDETECT_DISCRETE_CONTACT)) + return; + + PxGeometryType::Enum type0 = static_cast<PxGeometryType::Enum>(cmInput.geomType0); + PxGeometryType::Enum type1 = static_cast<PxGeometryType::Enum>(cmInput.geomType1); + + const bool flip = type1<type0; + + const PxsCachedTransform* tm0 = &context.mTransformCache->getTransformCache(cmInput.mTransformCache0); + const PxsCachedTransform* tm1 = &context.mTransformCache->getTransformCache(cmInput.mTransformCache1); + + if(!(output.statusFlag & PxcNpWorkUnitStatusFlag::eDIRTY_MANAGER) && !(cmInput.flags & PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT)) + { + const PxU32 body0Dynamic = PxU32(cmInput.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY0); + const PxU32 body1Dynamic = PxU32(cmInput.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY1); + + const PxU32 active0 = PxU32(body0Dynamic && !(tm0->isFrozen())); + const PxU32 active1 = PxU32(body1Dynamic && !(tm1->isFrozen())); + + if(!(active0 || active1)) + { + if(flip) + Ps::swap(type0, type1); + +#if PX_ENABLE_SIM_STATS + if(output.nbContacts) + context.mNbDiscreteContactPairsWithContacts++; +#endif + const bool isMeshType = type1 > PxGeometryType::eCONVEXMESH; + copyBuffers(output, cache, context, false, isMeshType); + return; + } + } + + output.statusFlag &= (~PxcNpWorkUnitStatusFlag::eDIRTY_MANAGER); + + Gu::MultiplePersistentContactManifold& manifold = context.mTempManifold; + bool isMultiManifold = false; + + 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); + } + + PxsShapeCore* shape0 = const_cast<PxsShapeCore*>(cmInput.shapeCore0); + PxsShapeCore* shape1 = const_cast<PxsShapeCore*>(cmInput.shapeCore1); + + if(flip) + { + Ps::swap(tm0, tm1); + Ps::swap(shape0, shape1); + Ps::swap(type0, type1); + } + + const PxReal contactDist0 = context.mContactDistance[cmInput.mTransformCache0]; + const PxReal contactDist1 = context.mContactDistance[cmInput.mTransformCache1]; +// context.mNarrowPhaseParams.mContactDistance = shape0->contactOffset + shape1->contactOffset; + context.mNarrowPhaseParams.mContactDistance = contactDist0 + contactDist1; + + PX_ASSERT(tm0->transform.isSane() && tm1->transform.isSane()); + + updateDiscreteContactStats(context, type0, type1); + + const PxcContactMethod conMethod = g_PCMContactMethodTable[type0][type1]; + PX_ASSERT(conMethod); + + startContacts(output, context); + + conMethod(shape0->geometry, shape1->geometry, tm0->transform, tm1->transform, context.mNarrowPhaseParams, cache, context.mContactBuffer, &context.mRenderOutput); + + PxsMaterialInfo materialInfo[ContactBuffer::MAX_CONTACTS]; + + const PxcGetMaterialMethod materialMethod = g_GetMaterialMethodTable[type0][type1]; + PX_ASSERT(materialMethod); + + materialMethod(shape0, shape1, context, materialInfo); + + if(flip) + flipContacts(context, materialInfo); + + 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(cmInput, output, context, materialInfo, isMeshType); +} diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpCacheStreamPair.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpCacheStreamPair.cpp new file mode 100644 index 00000000..54096677 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpCacheStreamPair.cpp @@ -0,0 +1,75 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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; +} + diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpContactPrepShared.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpContactPrepShared.cpp new file mode 100644 index 00000000..e0fa6262 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpContactPrepShared.cpp @@ -0,0 +1,623 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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; +} + +//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. +bool physx::finishContacts(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 != 0) + statusFlags |= PxsContactManagerStatusFlag::eHAS_TOUCH; + else + statusFlags |= PxsContactManagerStatusFlag::eHAS_NO_TOUCH; + + npOutput.nbContacts = Ps::to8(buffer.count); + + if(buffer.count==0) + { + npOutput.statusFlag = statusFlags; + npOutput.nbContacts = 0; + npOutput.nbPatches = 0; + return true; + } + + +#if PX_ENABLE_SIM_STATS + if(buffer.count) + 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 (!buffer.count || (!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) || (buffer.count == 0); + + //handle buffer overflow + if (buffer.count && !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 + if(buffer.count) + threadContext.mNbDiscreteContactPairsWithContacts--; +#endif + } + + return res; +} diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpMemBlockPool.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpMemBlockPool.cpp new file mode 100644 index 00000000..51eb0110 --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpMemBlockPool.cpp @@ -0,0 +1,351 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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; +} + diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpThreadContext.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpThreadContext.cpp new file mode 100644 index 00000000..9738e5da --- /dev/null +++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpThreadContext.cpp @@ -0,0 +1,93 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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), + 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; +} |