diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/Common/src | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/Common/src')
38 files changed, 7150 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/Common/src/CmBitMap.h b/PhysX_3.4/Source/Common/src/CmBitMap.h new file mode 100644 index 00000000..fbf6f781 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmBitMap.h @@ -0,0 +1,504 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_BITMAP +#define PX_PHYSICS_COMMON_BITMAP + +#include "foundation/PxAssert.h" +#include "foundation/PxMath.h" +#include "foundation/PxMemory.h" +#include "PsAllocator.h" +#include "PsUserAllocated.h" +#include "PsIntrinsics.h" +#include "PsMathUtils.h" +#include "CmPhysXCommon.h" +#include "PsBitUtils.h" +// PX_SERIALIZATION +#include "PxSerialFramework.h" +//~PX_SERIALIZATION + +namespace physx +{ +namespace Cm +{ + + /*! + Hold a bitmap with operations to set,reset or test given bit. + + We inhibit copy to prevent unintentional copies. If a copy is desired copy() should be used or + alternatively a copy constructor implemented. + */ + template<class Allocator> + class BitMapBase : public Ps::UserAllocated + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + + PX_NOCOPY(BitMapBase) + + public: + + // PX_SERIALIZATION + /* todo: explicit */ BitMapBase(const PxEMPTY) + { + if(mMap) + mWordCount |= PX_SIGN_BITMASK; + } + + void exportExtraData(PxSerializationContext& stream, void*) + { + if(mMap && getWordCount()) + { + stream.alignData(PX_SERIAL_ALIGN); + stream.writeData(mMap, getWordCount()*sizeof(PxU32)); + } + } + void importExtraData(PxDeserializationContext& context) + { + if(mMap && getWordCount()) + mMap = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(getWordCount()); + } + //~PX_SERIALIZATION + + //sschirm: function for placement new. Almost the same as importExtraData above, but lets you set word count and map after default construction + void importData(PxU32 worldCount, PxU32* words) + { + PX_ASSERT(mWordCount == 0 && !mMap); + mMap = words; + mWordCount = worldCount | PX_SIGN_BITMASK; + } + + PX_INLINE BitMapBase(Allocator& allocator) : mMap(0), mWordCount(0), mAllocator(allocator) {} + + PX_INLINE BitMapBase() : mMap(0), mWordCount(0) {} + + PX_INLINE ~BitMapBase() + { + if(mMap && !isInUserMemory()) + mAllocator.deallocate(mMap); + mMap = NULL; + } + + PX_INLINE Allocator& getAllocator() { return mAllocator; } + + PX_INLINE void growAndSet(PxU32 index) + { + extend(index+1); + mMap[index>>5] |= 1<<(index&31); + } + + PX_INLINE void growAndReset(PxU32 index) + { + extend(index+1); + mMap[index>>5] &= ~(1<<(index&31)); + } + + PX_INLINE Ps::IntBool boundedTest(PxU32 index) const + { + return Ps::IntBool(index>>5 >= getWordCount() ? Ps::IntFalse : (mMap[index>>5]&(1<<(index&31)))); + } + + // Special optimized versions, when you _know_ your index is in range + PX_INLINE void set(PxU32 index) + { + PX_ASSERT(index<getWordCount()*32); + mMap[index>>5] |= 1<<(index&31); + } + + PX_INLINE void reset(PxU32 index) + { + PX_ASSERT(index<getWordCount()*32); + mMap[index>>5] &= ~(1<<(index&31)); + } + + PX_INLINE Ps::IntBool test(PxU32 index) const + { + PX_ASSERT(index<getWordCount()*32); + return Ps::IntBool(mMap[index>>5]&(1<<(index&31))); + } + + // nibble == 4 bits + PX_INLINE PxU32 getNibbleFast(PxU32 nibIndex) const + { + PxU32 bitIndex = nibIndex << 2; + PX_ASSERT(bitIndex < getWordCount()*32); + return (mMap[bitIndex >> 5] >> (bitIndex & 31)) & 0xf; + } + + PX_INLINE void andNibbleFast(PxU32 nibIndex, PxU32 mask) + { + //TODO: there has to be a faster way... + PxU32 bitIndex = nibIndex << 2; + PxU32 shift = (bitIndex & 31); + PxU32 nibMask = 0xf << shift; + + PX_ASSERT(bitIndex < getWordCount()*32); + + mMap[bitIndex >> 5] &= ((mask << shift) | ~nibMask); + } + + PX_INLINE void orNibbleFast(PxU32 nibIndex, PxU32 mask) + { + PX_ASSERT(!(mask & ~0xf)); //check extra bits are not set + + PxU32 bitIndex = nibIndex << 2; + PxU32 shift = bitIndex & 31; + + PX_ASSERT(bitIndex < getWordCount()*32); + + mMap[bitIndex >> 5] |= (mask << shift); + } + + void clear() + { + PxMemSet(mMap, 0, getWordCount()*sizeof(PxU32)); + } + + void resizeAndClear(PxU32 newBitCount) + { + extendUninitialized(newBitCount); + PxMemSet(mMap, 0, getWordCount()*sizeof(PxU32)); + } + + void setEmpty() + { + mMap=NULL; + mWordCount=0; + } + + void setWords(PxU32* map, PxU32 wordCount) + { + mMap=map; + mWordCount=wordCount; + mWordCount |= PX_SIGN_BITMASK; + } + + // !!! only sets /last/ bit to value + void resize(PxU32 newBitCount, bool value = false) + { + PX_ASSERT(!value); // only new class supports this + PX_UNUSED(value); + extend(newBitCount); + } + PxU32 size() const { return getWordCount()*32; } + + void copy(const BitMapBase& a) + { + extendUninitialized(a.getWordCount()<<5); + PxMemCopy(mMap, a.mMap, a.getWordCount() * sizeof(PxU32)); + if(getWordCount() > a.getWordCount()) + PxMemSet(mMap + a.getWordCount(), 0, (getWordCount() - a.getWordCount()) * sizeof(PxU32)); + } + + PX_INLINE PxU32 count() const + { + // NOTE: we can probably do this faster, since the last steps in PxcBitCount32 can be defered to + // the end of the seq. + 64/128bits at a time + native bit counting instructions(360 is fast non micro code). + PxU32 count = 0; + PxU32 wordCount = getWordCount(); + for(PxU32 i=0; i<wordCount; i++) + count += Ps::bitCount(mMap[i]); + + return count; + } + + PX_INLINE PxU32 count(PxU32 start, PxU32 length) const + { + PxU32 end = PxMin(getWordCount()<<5,start+length); + PxU32 count = 0; + for(PxU32 i=start; i<end; i++) + count+= (test(i)!=0); + return count; + } + + //! returns 0 if no bits set (!!!) + PxU32 findLast() const + { + for(PxU32 i = getWordCount(); i-- > 0;) + { + if(mMap[i]) + return (i<<5)+Ps::highestSetBit(mMap[i]); + } + return PxU32(0); + } + + + + // the obvious combiners and some used in the SDK + + struct OR { PX_INLINE PxU32 operator()(PxU32 a, PxU32 b) { return a|b; } }; + struct AND { PX_INLINE PxU32 operator()(PxU32 a, PxU32 b) { return a&b; } }; + struct XOR { PX_INLINE PxU32 operator()(PxU32 a, PxU32 b) { return a^b; } }; + + // we use auxiliary functions here so as not to generate combiners for every combination + // of allocators + + template<class Combiner, class _> + PX_INLINE void combineInPlace(const BitMapBase<_>& b) + { + combine1<Combiner>(b.mMap,b.getWordCount()); + } + + template<class Combiner, class _1, class _2> + PX_INLINE void combine(const BitMapBase<_1>& a, const BitMapBase<_2>& b) + { + combine2<Combiner>(a.mMap,a.getWordCount(),b.mMap,b.getWordCount()); + } + + PX_FORCE_INLINE const PxU32* getWords() const { return mMap; } + PX_FORCE_INLINE PxU32* getWords() { return mMap; } + + // PX_SERIALIZATION + PX_FORCE_INLINE PxU32 getWordCount() const { return mWordCount & ~PX_SIGN_BITMASK; } + + // We need one bit to mark arrays that have been deserialized from a user-provided memory block. + PX_FORCE_INLINE PxU32 isInUserMemory() const { return mWordCount & PX_SIGN_BITMASK; } + //~PX_SERIALIZATION + + /*! + Iterate over indices in a bitmap + + This iterator is good because it finds the set bit without looping over the cached bits upto 31 times. + However it does require a variable shift. + */ + + class Iterator + { + public: + static const PxU32 DONE = 0xffffffff; + + PX_INLINE Iterator(const BitMapBase &map) : mBitMap(map) + { + reset(); + } + + PX_INLINE Iterator& operator=(const Iterator& other) + { + PX_ASSERT(&mBitMap == &other.mBitMap); + mBlock = other.mBlock; + mIndex = other.mIndex; + return *this; + } + + PX_INLINE PxU32 getNext() + { + if(mBlock) + { + PxU32 bitIndex = mIndex<<5 | Ps::lowestSetBit(mBlock); + mBlock &= mBlock-1; + PxU32 wordCount = mBitMap.getWordCount(); + while(!mBlock && ++mIndex < wordCount) + mBlock = mBitMap.mMap[mIndex]; + return bitIndex; + } + return DONE; + } + + PX_INLINE void reset() + { + mIndex = mBlock = 0; + PxU32 wordCount = mBitMap.getWordCount(); + while(mIndex < wordCount && ((mBlock = mBitMap.mMap[mIndex]) == 0)) + ++mIndex; + } + private: + PxU32 mBlock, mIndex; + const BitMapBase& mBitMap; + }; + + // DS: faster but less general: hasBits() must be true or getNext() is illegal so it is the calling code's responsibility to ensure that getNext() is not called illegally. + class LoopIterator + { + PX_NOCOPY(LoopIterator) + + public: + PX_FORCE_INLINE LoopIterator(const BitMapBase &map) : mMap(map.getWords()), mBlock(0), mIndex(-1), mWordCount(PxI32(map.getWordCount())) {} + + PX_FORCE_INLINE bool hasBits() + { + PX_ASSERT(mIndex<mWordCount); + while (mBlock == 0) + { + if (++mIndex == mWordCount) + return false; + mBlock = mMap[mIndex]; + } + return true; + } + + PX_FORCE_INLINE PxU32 getNext() + { + PX_ASSERT(mIndex<mWordCount && mBlock != 0); + PxU32 result = PxU32(mIndex) << 5 | Ps::lowestSetBit(mBlock); // will assert if mask is zero + mBlock &= (mBlock - 1); + return result; + } + + private: + const PxU32*const mMap; + PxU32 mBlock; // the word we're currently scanning + PxI32 mIndex; // the index of the word we're currently looking at + PxI32 mWordCount; + }; + + //Class to iterate over the bitmap from a particular start location rather than the beginning of the list + class CircularIterator + { + public: + static const PxU32 DONE = 0xffffffff; + + PX_INLINE CircularIterator(const BitMapBase &map, PxU32 index) : mBitMap(map) + { + mIndex = mBlock = mStartIndex = 0; + const PxU32 wordCount = mBitMap.getWordCount(); + if ((index << 5) < wordCount) + { + mIndex = index << 5; + mStartIndex = mIndex; + } + + if (mIndex < wordCount) + { + mBlock = mBitMap.mMap[mIndex]; + if (mBlock == 0) + { + mIndex = (mIndex + 1) % wordCount; + while (mIndex != mStartIndex && (mBlock = mBitMap.mMap[mIndex]) == 0) + mIndex = (mIndex + 1) % wordCount; + } + } + } + + PX_INLINE PxU32 getNext() + { + if (mBlock) + { + PxU32 bitIndex = mIndex << 5 | Ps::lowestSetBit(mBlock); + mBlock &= mBlock - 1; + PxU32 wordCount = mBitMap.getWordCount(); + while (!mBlock && (mIndex = ((mIndex+1)%wordCount)) != mStartIndex) + mBlock = mBitMap.mMap[mIndex]; + return bitIndex; + } + return DONE; + } + + private: + PxU32 mBlock, mIndex; + PxU32 mStartIndex; + const BitMapBase& mBitMap; + + PX_NOCOPY(CircularIterator) + }; + + + + + protected: + PxU32* mMap; //one bit per index + PxU32 mWordCount; + Allocator mAllocator; + PxU8 mPadding[3]; // PT: "mAllocator" is empty but consumes 1 byte + + void extend(PxU32 size) + { + PxU32 newWordCount = (size+31)>>5; + if(newWordCount > getWordCount()) + { + PxU32* newMap = reinterpret_cast<PxU32*>(mAllocator.allocate(newWordCount*sizeof(PxU32), __FILE__, __LINE__)); + if(mMap) + { + PxMemCopy(newMap, mMap, getWordCount()*sizeof(PxU32)); + if (!isInUserMemory()) + mAllocator.deallocate(mMap); + } + PxMemSet(newMap+getWordCount(), 0, (newWordCount-getWordCount())*sizeof(PxU32)); + mMap = newMap; + // also resets the isInUserMemory bit + mWordCount = newWordCount; + } + } + + void extendUninitialized(PxU32 size) + { + PxU32 newWordCount = (size+31)>>5; + if(newWordCount > getWordCount()) + { + if(mMap && !isInUserMemory()) + mAllocator.deallocate(mMap); + // also resets the isInUserMemory bit + mWordCount = newWordCount; + mMap = reinterpret_cast<PxU32*>(mAllocator.allocate(mWordCount*sizeof(PxU32), __FILE__, __LINE__)); + } + } + + template<class Combiner> + void combine1(const PxU32* words, PxU32 length) + { + extend(length<<5); + PxU32 combineLength = PxMin(getWordCount(), length); + for(PxU32 i=0;i<combineLength;i++) + mMap[i] = Combiner()(mMap[i], words[i]); + } + + template<class Combiner> + void combine2(const PxU32* words1, PxU32 length1, + const PxU32* words2, PxU32 length2) + { + extendUninitialized(PxMax(length1,length2)<<5); + + PxU32 commonSize = PxMin(length1,length2); + + for(PxU32 i=0;i<commonSize;i++) + mMap[i] = Combiner()(words1[i],words2[i]); + + for(PxU32 i=commonSize;i<length1;i++) + mMap[i] = Combiner()(words1[i],0); + + for(PxU32 i=commonSize;i<length2;i++) + mMap[i] = Combiner()(0,words2[i]); + } + + friend class Iterator; + }; + + typedef BitMapBase<Ps::NonTrackingAllocator> BitMap; + typedef BitMapBase<Ps::VirtualAllocator> BitMapPinned; + + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmBoxPruning.cpp b/PhysX_3.4/Source/Common/src/CmBoxPruning.cpp new file mode 100644 index 00000000..a59ecd8d --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmBoxPruning.cpp @@ -0,0 +1,197 @@ +// 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 "CmBoxPruning.h" +#include "CmRadixSortBuffered.h" +#include "PsAllocator.h" + +using namespace physx; +using namespace Gu; +using namespace Cm; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. + * \param nb0 [in] number of boxes in the first set + * \param bounds0 [in] list of boxes for the first set + * \param nb1 [in] number of boxes in the second set + * \param bounds1 [in] list of boxes for the second set + * \param pairs [out] list of overlapping pairs + * \param axes [in] projection order (0,2,1 is often best) + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Cm::BipartiteBoxPruning(const PxBounds3* bounds0, PxU32 nb0, const PxBounds3* bounds1, PxU32 nb1, Ps::Array<PxU32>& pairs, const Axes& axes) +{ + pairs.clear(); + // Checkings + if(nb0 == 0 || nb1 == 0) + return false; + + // Catch axes + PxU32 Axis0 = axes.mAxis0; + PxU32 Axis1 = axes.mAxis1; + PxU32 Axis2 = axes.mAxis2; + + PX_UNUSED(Axis1); + PX_UNUSED(Axis2); + + // Allocate some temporary data + float* MinPosBounds0 = reinterpret_cast<float*>(PX_ALLOC_TEMP(sizeof(float)*nb0, "Gu::BipartiteBoxPruning")); + float* MinPosBounds1 = reinterpret_cast<float*>(PX_ALLOC_TEMP(sizeof(float)*nb1, "Gu::BipartiteBoxPruning")); + + // 1) Build main lists using the primary axis + for(PxU32 i=0;i<nb0;i++) MinPosBounds0[i] = bounds0[i].minimum[Axis0]; + for(PxU32 i=0;i<nb1;i++) MinPosBounds1[i] = bounds1[i].minimum[Axis0]; + + // 2) Sort the lists + //static RadixSort RS0, RS1; // Static for coherence. Crashes on exit + RadixSortBuffered RS0, RS1; // Static for coherence. + + const PxU32* Sorted0 = RS0.Sort(MinPosBounds0, nb0).GetRanks(); + const PxU32* Sorted1 = RS1.Sort(MinPosBounds1, nb1).GetRanks(); + + // 3) Prune the lists + PxU32 Index0, Index1; + + const PxU32* const LastSorted0 = &Sorted0[nb0]; + const PxU32* const LastSorted1 = &Sorted1[nb1]; + const PxU32* RunningAddress0 = Sorted0; + const PxU32* RunningAddress1 = Sorted1; + + while(RunningAddress1<LastSorted1 && Sorted0<LastSorted0) + { + Index0 = *Sorted0++; + + while(RunningAddress1<LastSorted1 && MinPosBounds1[*RunningAddress1]<MinPosBounds0[Index0]) RunningAddress1++; + + const PxU32* RunningAddress2_1 = RunningAddress1; + + while(RunningAddress2_1<LastSorted1 && MinPosBounds1[Index1 = *RunningAddress2_1++]<=bounds0[Index0].maximum[Axis0]) + { + if(bounds0[Index0].intersects(bounds1[Index1])) + { + pairs.pushBack(Index0); + pairs.pushBack(Index1); + } + } + } + + //// + + while(RunningAddress0<LastSorted0 && Sorted1<LastSorted1) + { + Index0 = *Sorted1++; + + while(RunningAddress0<LastSorted0 && MinPosBounds0[*RunningAddress0]<=MinPosBounds1[Index0]) RunningAddress0++; + + const PxU32* RunningAddress2_0 = RunningAddress0; + + while(RunningAddress2_0<LastSorted0 && MinPosBounds0[Index1 = *RunningAddress2_0++]<=bounds1[Index0].maximum[Axis0]) + { + if(bounds0[Index1].intersects(bounds1[Index0])) + { + pairs.pushBack(Index1); + pairs.pushBack(Index0); + } + } + } + + PX_FREE(MinPosBounds1); + PX_FREE(MinPosBounds0); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. + * \param bounds [in] list of boxes + * \param nb [in] number of boxes + * \param pairs [out] list of overlapping pairs + * \param axes [in] projection order (0,2,1 is often best) + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Cm::CompleteBoxPruning(const PxBounds3* bounds, PxU32 nb, Ps::Array<PxU32>& pairs, const Axes& axes) +{ + pairs.clear(); + + // Checkings + if(!nb) + return false; + + // Catch axes + const PxU32 Axis0 = axes.mAxis0; + const PxU32 Axis1 = axes.mAxis1; + const PxU32 Axis2 = axes.mAxis2; + + PX_UNUSED(Axis1); + PX_UNUSED(Axis2); + + // Allocate some temporary data + float* PosList = reinterpret_cast<float*>(PX_ALLOC_TEMP(sizeof(float)*nb, "Cm::CompleteBoxPruning")); + + // 1) Build main list using the primary axis + for(PxU32 i=0;i<nb;i++) PosList[i] = bounds[i].minimum[Axis0]; + + // 2) Sort the list + /*static*/ RadixSortBuffered RS; // Static for coherence + const PxU32* Sorted = RS.Sort(PosList, nb).GetRanks(); + + // 3) Prune the list + const PxU32* const LastSorted = &Sorted[nb]; + const PxU32* RunningAddress = Sorted; + PxU32 Index0, Index1; + while(RunningAddress<LastSorted && Sorted<LastSorted) + { + Index0 = *Sorted++; + + while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]); + + const PxU32* RunningAddress2 = RunningAddress; + + while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=bounds[Index0].maximum[Axis0]) + { + if(Index0!=Index1) + { + if(bounds[Index0].intersects(bounds[Index1])) + { + pairs.pushBack(Index0); + pairs.pushBack(Index1); + } + } + } + } + + PX_FREE(PosList); + + return true; +} + diff --git a/PhysX_3.4/Source/Common/src/CmBoxPruning.h b/PhysX_3.4/Source/Common/src/CmBoxPruning.h new file mode 100644 index 00000000..993b92a5 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmBoxPruning.h @@ -0,0 +1,49 @@ +// 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. + +#ifndef CM_BOXPRUNING_H +#define CM_BOXPRUNING_H + +#include "foundation/PxBounds3.h" +#include "PsArray.h" +#include "CmPhysXCommon.h" +#include "PxPhysXCommonConfig.h" +#include "GuAxes.h" + +namespace physx +{ + +namespace Cm +{ + PX_PHYSX_COMMON_API bool CompleteBoxPruning(const PxBounds3* bounds, PxU32 nb, Ps::Array<PxU32>& pairs, const Gu::Axes& axes); + PX_PHYSX_COMMON_API bool BipartiteBoxPruning(const PxBounds3* bounds0, PxU32 nb0, const PxBounds3* bounds1, PxU32 nb1, Ps::Array<PxU32>& pairs, const Gu::Axes& axes); +} +} + +#endif // CM_BOXPRUNING_H diff --git a/PhysX_3.4/Source/Common/src/CmCollection.cpp b/PhysX_3.4/Source/Common/src/CmCollection.cpp new file mode 100644 index 00000000..dc3634d7 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmCollection.cpp @@ -0,0 +1,217 @@ +// 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 "CmCollection.h" +#include "PsFoundation.h" + +using namespace physx; +using namespace Cm; + +void Collection::add(PxBase& object, PxSerialObjectId id) +{ + PxSerialObjectId originId = getId(object); + if( originId != PX_SERIAL_OBJECT_ID_INVALID) + { + if( originId != id) + { + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "PxCollection::add called for an object that has an associated id already present in the collection!"); + } + return; + } + + if(id != PX_SERIAL_OBJECT_ID_INVALID) + { + if(!mIds.insert(id, &object)) + { + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "PxCollection::add called with an id which is already used in the collection"); + return; + } + } + + mObjects[&object] = id; +} + +void Collection::remove(PxBase& object) +{ + PX_CHECK_AND_RETURN(contains(object), "PxCollection::remove called for an object not contained in the collection!"); + + const ObjectToIdMap::Entry* e = mObjects.find(&object); + if(e) + { + mIds.erase(e->second); + mObjects.erase(&object); + } +} + +bool Collection::contains(PxBase& object) const +{ + return mObjects.find(&object) != NULL; +} + +void Collection::addId(PxBase& object, PxSerialObjectId id) +{ + PX_CHECK_AND_RETURN(contains(object), "PxCollection::addId called for object that is not contained in the collection!"); + PX_CHECK_AND_RETURN(id != PX_SERIAL_OBJECT_ID_INVALID, "PxCollection::addId called with PxSerialObjectId being set to PX_SERIAL_OBJECT_ID_INVALID!"); + PX_CHECK_AND_RETURN(mIds.find(id) == NULL, "PxCollection::addId called with an id which is already used in the collection!"); + + const ObjectToIdMap::Entry* e = mObjects.find(&object); + if(e && e->second != PX_SERIAL_OBJECT_ID_INVALID) + mIds.erase(e->second); + + mIds.insert(id, &object); + mObjects[&object] = id; +} + +void Collection::removeId(PxSerialObjectId id) +{ + PX_CHECK_AND_RETURN(id != PX_SERIAL_OBJECT_ID_INVALID, "PxCollection::removeId called with PxSerialObjectId being set to PX_SERIAL_OBJECT_ID_INVALID!"); + PX_CHECK_AND_RETURN(mIds.find(id), "PxCollection::removeId called with PxSerialObjectId not contained in the collection!"); + const IdToObjectMap::Entry* e = mIds.find(id); + if(e) + { + mObjects[e->second] = PX_SERIAL_OBJECT_ID_INVALID; + mIds.erase(id); + } +} + +PxBase* Collection::find(PxSerialObjectId id) const +{ + PX_CHECK_AND_RETURN_NULL(id != PX_SERIAL_OBJECT_ID_INVALID, "PxCollection::find called with PxSerialObjectId being set to PX_SERIAL_OBJECT_ID_INVALID!"); + const IdToObjectMap::Entry* e = mIds.find(id); + return e ? static_cast<PxBase*>(e->second) : NULL; +} + +void Collection::add(PxCollection& _collection) +{ + Collection& collection = static_cast<Collection&>(_collection); + PX_CHECK_AND_RETURN(this != &collection, "PxCollection::add(PxCollection&) called with itself!"); + + mObjects.reserve(mObjects.capacity() + collection.mObjects.size()); + const ObjectToIdMap::Entry* e = collection.mObjects.getEntries(); + for (PxU32 i = 0; i < collection.mObjects.size(); ++i) + { + PxSerialObjectId id = e[i].second; + if( id != PX_SERIAL_OBJECT_ID_INVALID) + { + if(!mIds.insert(id, e[i].first)) + { + if(mIds[id] != e[i].first) + { + PX_CHECK_MSG( false, "PxCollection::add(PxCollection&) called with conflicting id!"); + mObjects.insert(e[i].first, PX_SERIAL_OBJECT_ID_INVALID); + } + } + else + mObjects[ e[i].first ] = id; + } + else + mObjects.insert(e[i].first, PX_SERIAL_OBJECT_ID_INVALID); + } +} + +void Collection::remove(PxCollection& _collection) +{ + Collection& collection = static_cast<Collection&>(_collection); + PX_CHECK_AND_RETURN(this != &collection, "PxCollection::remove(PxCollection&) called with itself!"); + + const ObjectToIdMap::Entry* e = collection.mObjects.getEntries(); + for (PxU32 i = 0; i < collection.mObjects.size(); ++i) + { + const ObjectToIdMap::Entry* e1 = mObjects.find(e[i].first); + if(e1) + { + mIds.erase(e1->second); + mObjects.erase(e1->first); + } + } +} + +PxU32 Collection::getNbObjects() const +{ + return mObjects.size(); +} + +PxBase& Collection::getObject(PxU32 index) const +{ + PX_ASSERT(index < mObjects.size()); + return *mObjects.getEntries()[index].first; +} + +PxU32 Collection::getObjects(PxBase** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + PX_CHECK_AND_RETURN_NULL(userBuffer != NULL, "PxCollection::getObjects called with userBuffer NULL!"); + PX_CHECK_AND_RETURN_NULL(bufferSize != 0, "PxCollection::getObjects called with bufferSize 0!"); + PxU32 dstIndex = 0; + const ObjectToIdMap::Entry* e = mObjects.getEntries(); + for (PxU32 srcIndex = startIndex; srcIndex < mObjects.size() && dstIndex < bufferSize; ++srcIndex) + userBuffer[dstIndex++] = e[srcIndex].first; + + return dstIndex; +} + +PxU32 Collection::getNbIds() const +{ + return mIds.size(); +} + +PxSerialObjectId Collection::getId(const PxBase& object) const +{ + const ObjectToIdMap::Entry* e = mObjects.find(const_cast<PxBase*>(&object)); + return e ? e->second : PX_SERIAL_OBJECT_ID_INVALID; +} + +PxU32 Collection::getIds(PxSerialObjectId* userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + PX_CHECK_AND_RETURN_NULL(userBuffer != NULL, "PxCollection::getIds called with userBuffer NULL!"); + PX_CHECK_AND_RETURN_NULL(bufferSize != 0, "PxCollection::getIds called with bufferSize 0!"); + PxU32 dstIndex = 0; + + IdToObjectMap::Iterator srcIt = (const_cast<IdToObjectMap&>(mIds)).getIterator(); + + while (!srcIt.done() && dstIndex < bufferSize) + { + if(srcIt->first != PX_SERIAL_OBJECT_ID_INVALID) + { + if(startIndex > 0) + startIndex--; + else + userBuffer[dstIndex++] = srcIt->first; + } + srcIt++; + } + + return dstIndex; +} + +PxCollection* PxCreateCollection() +{ + return PX_NEW(Collection); +} diff --git a/PhysX_3.4/Source/Common/src/CmCollection.h b/PhysX_3.4/Source/Common/src/CmCollection.h new file mode 100644 index 00000000..76f9738e --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmCollection.h @@ -0,0 +1,103 @@ +// 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. + + +#ifndef PX_PHYSICS_CM_COLLECTION +#define PX_PHYSICS_CM_COLLECTION + +#include "CmPhysXCommon.h" +#include "PxCollection.h" +#include "PsHashMap.h" +#include "PsUserAllocated.h" +#include "PsAllocator.h" + +namespace physx +{ +namespace Cm +{ + template <class Key, + class Value, + class HashFn = Ps::Hash<Key>, + class Allocator = Ps::NonTrackingAllocator > + class CollectionHashMap : public Ps::CoalescedHashMap< Key, Value, HashFn, Allocator> + { + typedef physx::shdfnd::internal::HashMapBase< Key, Value, HashFn, Allocator> MapBase; + typedef Ps::Pair<const Key,Value> EntryData; + + public: + CollectionHashMap(PxU32 initialTableSize = 64, float loadFactor = 0.75f): + Ps::CoalescedHashMap< Key, Value, HashFn, Allocator>(initialTableSize,loadFactor) {} + + void insertUnique(const Key& k, const Value& v) + { + PX_PLACEMENT_NEW(MapBase::mBase.insertUnique(k), EntryData)(k,v); + } + }; + + + + class Collection : public PxCollection, public Ps::UserAllocated + { + public: + typedef CollectionHashMap<PxBase*, PxSerialObjectId> ObjectToIdMap; + typedef CollectionHashMap<PxSerialObjectId, PxBase*> IdToObjectMap; + + virtual void add(PxBase& object, PxSerialObjectId ref); + virtual void remove(PxBase& object); + virtual bool contains(PxBase& object) const; + virtual void addId(PxBase& object, PxSerialObjectId id); + virtual void removeId(PxSerialObjectId id); + virtual PxBase* find(PxSerialObjectId ref) const; + virtual void add(PxCollection& collection); + virtual void remove(PxCollection& collection); + virtual PxU32 getNbObjects() const; + virtual PxBase& getObject(PxU32 index) const; + virtual PxU32 getObjects(PxBase** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + virtual PxU32 getNbIds() const; + virtual PxSerialObjectId getId(const PxBase& object) const; + virtual PxU32 getIds(PxSerialObjectId* userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + void release() { PX_DELETE(this); } + + + // Only for internal use. Bypasses virtual calls, specialized behaviour. + PX_INLINE void internalAdd(PxBase* s, PxSerialObjectId id = PX_SERIAL_OBJECT_ID_INVALID) { mObjects.insertUnique(s, id); } + PX_INLINE PxU32 internalGetNbObjects() const { return mObjects.size(); } + PX_INLINE PxBase* internalGetObject(PxU32 i) const { PX_ASSERT(i<mObjects.size()); return mObjects.getEntries()[i].first; } + PX_INLINE const ObjectToIdMap::Entry* internalGetObjects() const { return mObjects.getEntries(); } + + IdToObjectMap mIds; + ObjectToIdMap mObjects; + + }; +} +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmConeLimitHelper.h b/PhysX_3.4/Source/Common/src/CmConeLimitHelper.h new file mode 100644 index 00000000..fa57574a --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmConeLimitHelper.h @@ -0,0 +1,144 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_CONELIMITHELPER +#define PX_PHYSICS_COMMON_CONELIMITHELPER + +// This class contains methods for supporting the tan-quarter swing limit - that +// is the, ellipse defined by tanQ(theta)^2/tanQ(thetaMax)^2 + tanQ(phi)^2/tanQ(phiMax)^2 = 1 +// +// Angles are passed as an PxVec3 swing vector with x = 0 and y and z the swing angles +// around the y and z axes + +#include "CmPhysXCommon.h" +#include "PsMathUtils.h" + +namespace physx +{ +namespace Cm +{ + PX_FORCE_INLINE PxReal tanAdd(PxReal tan1, PxReal tan2) + { + PX_ASSERT(PxAbs(1-tan1*tan2)>1e-6f); + return (tan1+tan2)/(1-tan1*tan2); + } + + // this is here because it's used in both LL and Extensions. However, it + // should STAY IN THE SDK CODE BASE because it's SDK-specific + + class ConeLimitHelper + { + public: + ConeLimitHelper(PxReal tanQSwingY, PxReal tanQSwingZ, PxReal tanQPadding) + : mTanQYMax(tanQSwingY), mTanQZMax(tanQSwingZ), mTanQPadding(tanQPadding) {} + + // whether the point is inside the (inwardly) padded cone - if it is, there's no limit + // constraint + + PX_FORCE_INLINE bool contains(const PxVec3& tanQSwing) + { + PxReal tanQSwingYPadded = tanAdd(PxAbs(tanQSwing.y),mTanQPadding); + PxReal tanQSwingZPadded = tanAdd(PxAbs(tanQSwing.z),mTanQPadding); + return Ps::sqr(tanQSwingYPadded/mTanQYMax)+Ps::sqr(tanQSwingZPadded/mTanQZMax) <= 1; + } + + PX_FORCE_INLINE PxVec3 clamp(const PxVec3& tanQSwing, + PxVec3& normal) + { + PxVec3 p = Ps::ellipseClamp(tanQSwing, PxVec3(0,mTanQYMax,mTanQZMax)); + normal = PxVec3(0, p.y/Ps::sqr(mTanQYMax), p.z/Ps::sqr(mTanQZMax)); +#ifdef PX_PARANOIA_ELLIPSE_CHECK + PxReal err = PxAbs(Ps::sqr(p.y/mTanQYMax) + Ps::sqr(p.z/mTanQZMax) - 1); + PX_ASSERT(err<1e-3); +#endif + + return p; + } + + + // input is a swing quat, such that swing.x = twist.y = twist.z = 0, q = swing * twist + // The routine is agnostic to the sign of q.w (i.e. we don't need the minimal-rotation swing) + + // output is an axis such that positive rotation increases the angle outward from the + // limit (i.e. the image of the x axis), the error is the sine of the angular difference, + // positive if the twist axis is inside the cone + + bool getLimit(const PxQuat& swing, PxVec3& axis, PxReal& error) + { + PX_ASSERT(swing.w>0); + PxVec3 twistAxis = swing.getBasisVector0(); + PxVec3 tanQSwing = PxVec3(0, Ps::tanHalf(swing.z,swing.w), -Ps::tanHalf(swing.y,swing.w)); + if(contains(tanQSwing)) + return false; + + PxVec3 normal, clamped = clamp(tanQSwing, normal); + + // rotation vector and ellipse normal + PxVec3 r(0,-clamped.z,clamped.y), d(0, -normal.z, normal.y); + + // the point on the cone defined by the tanQ swing vector r + PxVec3 p(1.f,0,0); + PxReal r2 = r.dot(r), a = 1-r2, b = 1/(1+r2), b2 = b*b; + PxReal v1 = 2*a*b2; + PxVec3 v2(a, 2*r.z, -2*r.y); // a*p + 2*r.cross(p); + PxVec3 coneLine = v1 * v2 - p; // already normalized + + // the derivative of coneLine in the direction d + PxReal rd = r.dot(d); + PxReal dv1 = -4*rd*(3-r2)*b2*b; + PxVec3 dv2(-2*rd, 2*d.z, -2*d.y); + + PxVec3 coneNormal = v1 * dv2 + dv1 * v2; + + axis = coneLine.cross(coneNormal)/coneNormal.magnitude(); + error = coneLine.cross(axis).dot(twistAxis); + + PX_ASSERT(PxAbs(axis.magnitude()-1)<1e-5f); + +#ifdef PX_PARANOIA_ELLIPSE_CHECK + bool inside = Ps::sqr(tanQSwing.y/mTanQYMax) + Ps::sqr(tanQSwing.z/mTanQZMax) <= 1; + PX_ASSERT(inside && error>-1e-4f || !inside && error<1e-4f); +#endif + + return true; + } + + private: + + + PxReal mTanQYMax, mTanQZMax, mTanQPadding; + }; + + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmFlushPool.h b/PhysX_3.4/Source/Common/src/CmFlushPool.h new file mode 100644 index 00000000..875d09f4 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmFlushPool.h @@ -0,0 +1,157 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_FLUSHPOOL +#define PX_PHYSICS_COMMON_FLUSHPOOL + +#include "foundation/Px.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "PsMutex.h" +#include "PsArray.h" +#include "PsBitUtils.h" + +/* +Pool used to allocate variable sized tasks. It's intended to be cleared after a short period (time step). +*/ + +namespace physx +{ +namespace Cm +{ + static const PxU32 sSpareChunkCount = 2; + + class FlushPool + { + PX_NOCOPY(FlushPool) + public: + FlushPool(PxU32 chunkSize) : mChunks(PX_DEBUG_EXP("FlushPoolChunk")), mChunkIndex(0), mOffset(0), mChunkSize(chunkSize) + { + mChunks.pushBack(static_cast<PxU8*>(PX_ALLOC(mChunkSize, "PxU8"))); + } + + ~FlushPool() + { + for (PxU32 i = 0; i < mChunks.size(); ++i) + PX_FREE(mChunks[i]); + } + + // alignment must be a power of two + void* allocate(PxU32 size, PxU32 alignment=16) + { + Ps::Mutex::ScopedLock lock(mMutex); + return allocateNotThreadSafe(size, alignment); + } + + // alignment must be a power of two + void* allocateNotThreadSafe(PxU32 size, PxU32 alignment=16) + { + PX_ASSERT(shdfnd::isPowerOfTwo(alignment)); + PX_ASSERT(size <= mChunkSize && !mChunks.empty()); + + // padding for alignment + size_t unalignedStart = reinterpret_cast<size_t>(mChunks[mChunkIndex]+mOffset); + PxU32 pad = PxU32(((unalignedStart+alignment-1)&~(size_t(alignment)-1)) - unalignedStart); + + if (mOffset + size + pad > mChunkSize) + { + mChunkIndex++; + mOffset = 0; + if (mChunkIndex >= mChunks.size()) + mChunks.pushBack(static_cast<PxU8*>(PX_ALLOC(mChunkSize, "PxU8"))); + + // update padding to ensure new alloc is aligned + unalignedStart = reinterpret_cast<size_t>(mChunks[mChunkIndex]); + pad = PxU32(((unalignedStart+alignment-1)&~(size_t(alignment)-1)) - unalignedStart); + } + + void* ptr = mChunks[mChunkIndex] + mOffset + pad; + PX_ASSERT((reinterpret_cast<size_t>(ptr)&(size_t(alignment)-1)) == 0); + mOffset += size + pad; + return ptr; + } + + void clear(PxU32 spareChunkCount = sSpareChunkCount) + { + Ps::Mutex::ScopedLock lock(mMutex); + + clearNotThreadSafe(spareChunkCount); + } + + void clearNotThreadSafe(PxU32 spareChunkCount = sSpareChunkCount) + { + PX_UNUSED(spareChunkCount); + + //release memory not used previously + PxU32 targetSize = mChunkIndex+sSpareChunkCount; + while (mChunks.size() > targetSize) + PX_FREE(mChunks.popBack()); + + mChunkIndex = 0; + mOffset = 0; + } + + void resetNotThreadSafe() + { + PxU8* firstChunk = mChunks[0]; + + for (PxU32 i = 1; i < mChunks.size(); ++i) + PX_FREE(mChunks[i]); + + mChunks.clear(); + mChunks.pushBack(firstChunk); + mChunkIndex = 0; + mOffset = 0; + } + + void lock() + { + mMutex.lock(); + } + + void unlock() + { + mMutex.unlock(); + } + + private: + Ps::Mutex mMutex; + Ps::Array<PxU8*> mChunks; + PxU32 mChunkIndex; + PxU32 mOffset; + PxU32 mChunkSize; + }; + + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmIDPool.h b/PhysX_3.4/Source/Common/src/CmIDPool.h new file mode 100644 index 00000000..cce76ab3 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmIDPool.h @@ -0,0 +1,202 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_ID_POOL +#define PX_PHYSICS_COMMON_ID_POOL + +#include "foundation/Px.h" +#include "CmPhysXCommon.h" +#include "PsArray.h" +#include "PsUserAllocated.h" + +namespace physx +{ +namespace Cm +{ + template<class FreeBuffer> + class IDPoolBase : public Ps::UserAllocated + { + protected: + PxU32 mCurrentID; + FreeBuffer mFreeIDs; + public: + IDPoolBase() : mCurrentID(0) {} + + void freeID(PxU32 id) + { + // Allocate on first call + // Add released ID to the array of free IDs + if(id == (mCurrentID - 1)) + --mCurrentID; + else + mFreeIDs.pushBack(id); + } + + void freeAll() + { + mCurrentID = 0; + mFreeIDs.clear(); + } + + PxU32 getNewID() + { + // If recycled IDs are available, use them + const PxU32 size = mFreeIDs.size(); + if(size) + { + // Recycle last ID + return mFreeIDs.popBack(); + } + // Else create a new ID + return mCurrentID++; + } + + PxU32 getNumUsedID() const + { + return mCurrentID - mFreeIDs.size(); + } + + PxU32 getMaxID() const + { + return mCurrentID; + } + + }; + + //This class extends IDPoolBase. This is mainly used for when it is unsafe for the application to free the id immediately so that it can + //defer the free process until it is safe to do so + template<class FreeBuffer> + class DeferredIDPoolBase : public IDPoolBase<FreeBuffer> + { + FreeBuffer mDeferredFreeIDs; + public: + //release an index into the deferred list + void deferredFreeID(PxU32 id) + { + mDeferredFreeIDs.pushBack(id); + } + + //release the deferred indices into the free list + void processDeferredIds() + { + const PxU32 deferredFreeIDCount = mDeferredFreeIDs.size(); + for(PxU32 a = 0; a < deferredFreeIDCount;++a) + { + this->mFreeIDs.pushBack(mDeferredFreeIDs[a]); + } + mDeferredFreeIDs.clear(); + } + + //release all indices + void freeAll() + { + mDeferredFreeIDs.clear(); + IDPoolBase<FreeBuffer>::freeAll(); + } + }; + + //This is spu friendly fixed size array + template <typename T, uint32_t N> + class InlineFixedArray + { + T mArr[N]; + PxU32 mSize; + public: + + InlineFixedArray() : mSize(0) + { + } + + ~InlineFixedArray(){} + + void pushBack(const T& t) + { + PX_ASSERT(mSize < N); + mArr[mSize++] = t; + } + + T popBack() + { + PX_ASSERT(mSize > 0); + return mArr[--mSize]; + } + + void clear() { mSize = 0; } + + T& operator [] (PxU32 index) { PX_ASSERT(index < N); return mArr[index]; } + + const T& operator [] (PxU32 index) const { PX_ASSERT(index < N); return mArr[index]; } + + PxU32 size() const { return mSize; } + }; + + + + //Fix size IDPool + template<PxU32 Capacity> + class InlineIDPool : public IDPoolBase<InlineFixedArray<PxU32, Capacity> > + { + public: + PxU32 getNumRemainingIDs() + { + return Capacity - this->getNumUsedID(); + } + }; + + //Dynamic resize IDPool + class IDPool : public IDPoolBase<Ps::Array<PxU32> > + { + }; + + + //This class is used to recycle indices. It supports deferred release, so that until processDeferredIds is called, + //released indices will not be reallocated. This class will fail if the calling code request more id than the InlineDeferredIDPoll + //has. It is the calling code's responsibility to ensure that this does not happen. + template<PxU32 Capacity> + class InlineDeferredIDPool : public DeferredIDPoolBase<InlineFixedArray<PxU32, Capacity> > + { + public: + PxU32 getNumRemainingIDs() + { + return Capacity - this->getNumUsedID(); + } + }; + + //Dynamic resize DeferredIDPool + class DeferredIDPool : public DeferredIDPoolBase<Ps::Array<PxU32> > + { + + }; + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmIO.h b/PhysX_3.4/Source/Common/src/CmIO.h new file mode 100644 index 00000000..0913a54d --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmIO.h @@ -0,0 +1,136 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_IO +#define PX_PHYSICS_COMMON_IO + +#include "foundation/PxIO.h" +#include "foundation/PxAssert.h" +#include "foundation/PxMemory.h" +#include "CmPhysXCommon.h" + +namespace physx +{ + + // wrappers for IO classes so that we can add extra functionality (byte counting, buffering etc) + +namespace Cm +{ + +class InputStreamReader +{ +public: + + InputStreamReader(PxInputStream& stream) : mStream(stream) { } + PxU32 read(void* dest, PxU32 count) + { + PxU32 readLength = mStream.read(dest, count); + + // zero the buffer if we didn't get all the data + if(readLength<count) + PxMemZero(reinterpret_cast<PxU8*>(dest)+readLength, count-readLength); + + return readLength; + } + + template <typename T> T get() + { + T val; + PxU32 length = mStream.read(&val, sizeof(T)); + PX_ASSERT(length == sizeof(T)); + PX_UNUSED(length); + return val; + } + + +protected: + PxInputStream &mStream; +private: + InputStreamReader& operator=(const InputStreamReader&); +}; + + +class InputDataReader : public InputStreamReader +{ +public: + InputDataReader(PxInputData& data) : InputStreamReader(data) {} + InputDataReader &operator=(const InputDataReader &); + + PxU32 length() const { return getData().getLength(); } + void seek(PxU32 offset) { getData().seek(offset); } + PxU32 tell() { return getData().tell(); } + +private: + PxInputData& getData() { return static_cast<PxInputData&>(mStream); } + const PxInputData& getData() const { return static_cast<const PxInputData&>(mStream); } +}; + + +class OutputStreamWriter +{ +public: + + PX_INLINE OutputStreamWriter(PxOutputStream& stream) + : mStream(stream) + , mCount(0) + {} + + PX_INLINE PxU32 write(const void* src, PxU32 offset) + { + PxU32 count = mStream.write(src, offset); + mCount += count; + return count; + } + + PX_INLINE PxU32 getStoredSize() + { + return mCount; + } + + template<typename T> void put(const T& val) + { + PxU32 length = write(&val, sizeof(T)); + PX_ASSERT(length == sizeof(T)); + PX_UNUSED(length); + } + +private: + + OutputStreamWriter& operator=(const OutputStreamWriter&); + PxOutputStream& mStream; + PxU32 mCount; +}; + + + +} +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmMathUtils.cpp b/PhysX_3.4/Source/Common/src/CmMathUtils.cpp new file mode 100644 index 00000000..72d7586f --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmMathUtils.cpp @@ -0,0 +1,69 @@ +// 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/PxTransform.h" +#include "foundation/PxMathUtils.h" + +namespace physx +{ + + +PX_FOUNDATION_API PxTransform PxTransformFromPlaneEquation(const PxPlane& plane) +{ + PxPlane p = plane; + p.normalize(); + + // special case handling for axis aligned planes + const PxReal halfsqrt2 = 0.707106781; + PxQuat q; + if(2 == (p.n.x == 0.0f) + (p.n.y == 0.0f) + (p.n.z == 0.0f)) // special handling for axis aligned planes + { + if(p.n.x > 0) q = PxQuat(PxIdentity); + else if(p.n.x < 0) q = PxQuat(0, 0, 1.0f, 0); + else q = PxQuat(0.0f, -p.n.z, p.n.y, 1.0f) * halfsqrt2; + } + else q = PxShortestRotation(PxVec3(1.f,0,0), p.n); + + return PxTransform(-p.n * p.d, q); + +} + +PX_FOUNDATION_API PxTransform PxTransformFromSegment(const PxVec3& p0, const PxVec3& p1, PxReal* halfHeight) +{ + const PxVec3 axis = p1-p0; + const PxReal height = axis.magnitude(); + if(halfHeight) + *halfHeight = height/2; + + return PxTransform((p1+p0) * 0.5f, + height<1e-6f ? PxQuat(PxIdentity) : PxShortestRotation(PxVec3(1.f,0,0), axis/height)); +} + +} diff --git a/PhysX_3.4/Source/Common/src/CmMatrix34.h b/PhysX_3.4/Source/Common/src/CmMatrix34.h new file mode 100644 index 00000000..48f4e1f0 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmMatrix34.h @@ -0,0 +1,286 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_MATRIX34 +#define PX_PHYSICS_COMMON_MATRIX34 + +#include "foundation/PxVec3.h" +#include "foundation/PxTransform.h" +#include "foundation/PxMat33.h" + +#include "CmPhysXCommon.h" + +namespace physx +{ +namespace Cm +{ + +/*! +Basic mathematical 3x4 matrix, implemented as a 3x3 rotation matrix and a translation + +See PxMat33 for the format of the rotation matrix. + +*/ + +class Matrix34 +{ +public: + //! Default constructor + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34() + {} + + //! Construct from four base vectors + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34(const PxVec3& b0, const PxVec3& b1, const PxVec3& b2, const PxVec3& b3) + : m(b0, b1, b2), p(b3) + {} + + //! Construct from float[12] + explicit PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34(PxReal values[]): + m(values), p(values[9], values[10], values[11]) + { + } + + //! Construct from a 3x3 matrix + explicit PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34(const PxMat33& other) + : m(other), p(PxZero) + { + } + + //! Construct from a 3x3 matrix and a translation vector + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34(const PxMat33& other, const PxVec3& t) + : m(other), p(t) + {} + + //! Construct from a PxTransform + explicit PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34(const PxTransform& other): + m(other.q), p(other.p) + { + } + + //! Construct from a quaternion + explicit PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34(const PxQuat& q): + m(q), p(PxZero) + { + } + + //! Copy constructor + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34(const Matrix34& other): + m(other.m), p(other.p) + { + } + + //! Assignment operator + PX_CUDA_CALLABLE PX_FORCE_INLINE const Matrix34& operator=(const Matrix34& other) + { + m = other.m; + p = other.p; + return *this; + } + + //! Set to identity matrix + PX_CUDA_CALLABLE PX_FORCE_INLINE void setIdentity() + { + m = PxMat33(PxIdentity); + p = PxVec3(0); + } + + // Simpler operators + //! Equality operator + PX_CUDA_CALLABLE PX_FORCE_INLINE bool operator==(const Matrix34& other) const + { + return m == other.m && p == other.p; + } + + //! Inequality operator + PX_CUDA_CALLABLE PX_FORCE_INLINE bool operator!=(const Matrix34& other) const + { + return !operator==(other); + } + + //! Unary minus + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34 operator-() const + { + return Matrix34(-m, -p); + } + + //! Add + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34 operator+(const Matrix34& other) const + { + return Matrix34(m + other.m, p + other.p); + } + + //! Subtract + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34 operator-(const Matrix34& other) const + { + return Matrix34(m - other.m, p - other.p); + } + + //! Scalar multiplication + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34 operator*(PxReal scalar) const + { + return Matrix34(m*scalar, p*scalar); + } + + friend Matrix34 operator*(PxReal, const Matrix34&); + + //! Matrix multiplication + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34 operator*(const Matrix34& other) const + { + //Rows from this <dot> columns from other + //base0 = rotate(other.m.column0) etc + return Matrix34(m*other.m, m*other.p + p); + } + + //! Matrix multiplication, extend the second matrix + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34 operator*(const PxMat33& other) const + { + //Rows from this <dot> columns from other + //base0 = transform(other.m.column0) etc + return Matrix34(m*other, p); + } + + friend Matrix34 operator*(const PxMat33& a, const Matrix34& b); + + // a <op>= b operators + + //! Equals-add + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34& operator+=(const Matrix34& other) + { + m += other.m; + p += other.p; + return *this; + } + + //! Equals-sub + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34& operator-=(const Matrix34& other) + { + m -= other.m; + p -= other.p; + return *this; + } + + //! Equals scalar multiplication + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34& operator*=(PxReal scalar) + { + m *= scalar; + p *= scalar; + + return *this; + } + + //! Element access, mathematical way! + PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal operator()(PxU32 row, PxU32 col) const + { + return (*this)[col][row]; + } + + //! Element access, mathematical way! + PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal& operator()(PxU32 row, PxU32 col) + { + return (*this)[col][row]; + } + + // Transform etc + + //! Transform vector by matrix, equal to v' = M*v + PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 rotate(const PxVec3& other) const + { + return m*other; + } + + //! Transform vector by transpose of matrix, equal to v' = M^t*v + PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 rotateTranspose(const PxVec3& other) const + { + return m.transformTranspose(other); + } + + //! Transform point by matrix + PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 transform(const PxVec3& other) const + { + return m*other + p; + } + + //! Transform point by transposed matrix + PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 transformTranspose(const PxVec3& other) const + { + return m.transformTranspose(other - p); + } + + //! Transform point by transposed matrix + PX_CUDA_CALLABLE PX_FORCE_INLINE Cm::Matrix34 transformTranspose(const Cm::Matrix34& other) const + { + return Cm::Matrix34(m.transformTranspose(other.m.column0), + m.transformTranspose(other.m.column1), + m.transformTranspose(other.m.column2), + m.transformTranspose(other.p - p)); + } + + + //! Invert matrix treating it as a rotation+translation matrix only + PX_CUDA_CALLABLE PX_FORCE_INLINE Matrix34 getInverseRT() const + { + return Matrix34(m.getTranspose(), m.transformTranspose(-p)); + } + + + // Conversion + //! Set matrix from quaternion + PX_CUDA_CALLABLE PX_FORCE_INLINE void set(const PxQuat& q) + { + m = PxMat33(q); + p = PxVec3(PxZero); + } + + + PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3& operator[](unsigned int num){return (&m.column0)[num];} + PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3& operator[](int num) { return (&m.column0)[num]; } + PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& operator[](unsigned int num) const { return (&m.column0)[num]; } + PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& operator[](int num) const { return (&m.column0)[num]; } + + //Data, see above for format! + + PxMat33 m; + PxVec3 p; + +}; + + +//! Multiply a*b, a is extended +PX_INLINE Matrix34 operator*(const PxMat33& a, const Matrix34& b) +{ + return Matrix34(a * b.m, a * b.p); +} + + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmPhysXCommon.h b/PhysX_3.4/Source/Common/src/CmPhysXCommon.h new file mode 100644 index 00000000..a6e911bb --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmPhysXCommon.h @@ -0,0 +1,89 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON +#define PX_PHYSICS_COMMON + +//! \file Top level internal include file for PhysX SDK + +#include "Ps.h" + +// Enable debug visualization +#define PX_ENABLE_DEBUG_VISUALIZATION 1 + +// Enable simulation statistics generation +#define PX_ENABLE_SIM_STATS 1 + +// PT: typical "invalid" value in various CD algorithms +#define PX_INVALID_U32 0xffffffff +#define PX_INVALID_U16 0xffff + +// PT: this used to be replicated everywhere in the code, causing bugs to sometimes reappear (e.g. TTP 3587). +// It is better to define it in a header and use the same constant everywhere. The original value (1e-05f) +// caused troubles (e.g. TTP 1705, TTP 306). +#define PX_PARALLEL_TOLERANCE 1e-02f + +#define PX_USE_16_BIT_HANDLES 0 + +namespace physx +{ + // alias shared foundation to something usable + namespace Ps = shdfnd; +} + +#if PX_CHECKED + #define PX_CHECK_MSG(exp, msg) (!!(exp) || (physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, msg), 0) ) + #define PX_CHECK(exp) PX_CHECK_MSG(exp, #exp) + #define PX_CHECK_AND_RETURN(exp,msg) { if(!(exp)) { PX_CHECK_MSG(exp, msg); return; } } + #define PX_CHECK_AND_RETURN_NULL(exp,msg) { if(!(exp)) { PX_CHECK_MSG(exp, msg); return 0; } } + #define PX_CHECK_AND_RETURN_VAL(exp,msg,r) { if(!(exp)) { PX_CHECK_MSG(exp, msg); return r; } } +#else + #define PX_CHECK_MSG(exp, msg) + #define PX_CHECK(exp) + #define PX_CHECK_AND_RETURN(exp,msg) + #define PX_CHECK_AND_RETURN_NULL(exp,msg) + #define PX_CHECK_AND_RETURN_VAL(exp,msg,r) +#endif + +#if PX_VC + // VC compiler defines __FUNCTION__ as a string literal so it is possible to concatenate it with another string + // Example: #define PX_CHECK_VALID(x) PX_CHECK_MSG(physx::shdfnd::checkValid(x), __FUNCTION__ ": parameter invalid!") + #define PX_CHECK_VALID(x) PX_CHECK_MSG(physx::shdfnd::checkValid(x), __FUNCTION__) +#elif PX_GCC_FAMILY + // GCC compiler defines __FUNCTION__ as a variable, hence, it is NOT possible concatenate an additional string to it + // In GCC, __FUNCTION__ only returns the function name, using __PRETTY_FUNCTION__ will return the full function definition + #define PX_CHECK_VALID(x) PX_CHECK_MSG(physx::shdfnd::checkValid(x), __PRETTY_FUNCTION__) +#else + // Generic macro for other compilers + #define PX_CHECK_VALID(x) PX_CHECK_MSG(physx::shdfnd::checkValid(x), __FUNCTION__) +#endif + + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmPool.h b/PhysX_3.4/Source/Common/src/CmPool.h new file mode 100644 index 00000000..a83d33ca --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmPool.h @@ -0,0 +1,292 @@ +// 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. + + +#ifndef CM_POOL_H +#define CM_POOL_H + +#include "PsSort.h" +#include "PsMutex.h" +#include "PsBasicTemplates.h" + +#include "CmBitMap.h" +#include "CmPhysXCommon.h" + +namespace physx +{ +namespace Cm +{ + +/*! +Allocator for pools of data structures +Also decodes indices (which can be computed from handles) into objects. To make this +faster, the EltsPerSlab must be a power of two +*/ +template <class T, class ArgumentType> +class PoolList : public Ps::AllocatorTraits<T>::Type +{ + typedef typename Ps::AllocatorTraits<T>::Type Alloc; + PX_NOCOPY(PoolList) +public: + PX_INLINE PoolList(const Alloc& alloc, ArgumentType* argument, PxU32 eltsPerSlab, PxU32 maxSlabs) + : Alloc(alloc), + mEltsPerSlab(eltsPerSlab), + mMaxSlabs(maxSlabs), + mSlabCount(0), + mFreeList(0), + mFreeCount(0), + mSlabs(reinterpret_cast<T**>(Alloc::allocate(maxSlabs * sizeof(T*), __FILE__, __LINE__))), + mArgument(argument) + { + PX_ASSERT(mEltsPerSlab>0); + // either maxSlabs = 1 (non-resizable pool), or elts per slab must be a power of two + PX_ASSERT((maxSlabs==1) || ((maxSlabs < 8192) && (mEltsPerSlab & (mEltsPerSlab-1))) == 0); + mLog2EltsPerSlab = 0; + + if(mMaxSlabs>1) + { + for(mLog2EltsPerSlab=0; mEltsPerSlab!=PxU32(1<<mLog2EltsPerSlab); mLog2EltsPerSlab++) + ; + } + } + + PX_INLINE ~PoolList() + { + destroy(); + } + + PX_INLINE void destroy() + { + // Run all destructors + for(PxU32 i=0;i<mSlabCount;i++) + { + PX_ASSERT(mSlabs); + T* slab = mSlabs[i]; + for(PxU32 j=0;j<mEltsPerSlab;j++) + { + slab[j].~T(); + } + } + + //Deallocate + for(PxU32 i=0;i<mSlabCount;i++) + { + PX_FREE(mSlabs[i]); + mSlabs[i] = NULL; + } + mSlabCount = 0; + + if(mFreeList) + PX_FREE(mFreeList); + mFreeList = NULL; + if(mSlabs) + { + PX_FREE(mSlabs); + mSlabs = NULL; + } + } + + PxU32 preallocate(const PxU32 nbRequired, T** elements) + { + //(1) Allocate and pull out an array of X elements + + PxU32 nbToAllocate = nbRequired > mFreeCount ? nbRequired - mFreeCount : 0; + + PxU32 nbElements = nbRequired - nbToAllocate; + + PxMemCopy(elements, mFreeList + (mFreeCount - nbElements), sizeof(T*) * nbElements); + //PxU32 originalFreeCount = mFreeCount; + mFreeCount -= nbElements; + + if (nbToAllocate) + { + PX_ASSERT(mFreeCount == 0); + + PxU32 nbSlabs = (nbToAllocate + mEltsPerSlab - 1) / mEltsPerSlab; //The number of slabs we need to allocate... + + if (mSlabCount + nbSlabs >= mMaxSlabs) + return nbElements; //Return only nbFromFree because we're not going to allocate any slabs. Seriously, we need to nuke this "maxSlabs" stuff ASAP! + + //allocate our slabs... + + PxU32 freeCount = mFreeCount; + + for (PxU32 i = 0; i < nbSlabs; ++i) + { + + //KS - would be great to allocate this using a single allocation but it will make releasing slabs fail later :( + T * mAddr = reinterpret_cast<T*>(Alloc::allocate(mEltsPerSlab * sizeof(T), __FILE__, __LINE__)); + if (!mAddr) + return nbElements; //Allocation failed so only return the set of elements we could allocate from the free list + + mSlabs[mSlabCount++] = mAddr; + + // Make sure the usage bitmap is up-to-size + if (mUseBitmap.size() < mSlabCount*mEltsPerSlab) + { + mUseBitmap.resize(2 * mSlabCount*mEltsPerSlab); //set last element as not used + if (mFreeList) + PX_FREE(mFreeList); + mFreeList = reinterpret_cast<T**>(Alloc::allocate(2 * mSlabCount * mEltsPerSlab * sizeof(T*), __FILE__, __LINE__)); + } + + PxU32 baseIndex = (mSlabCount-1) * mEltsPerSlab; + + //Now add all these to the mFreeList and elements... + PxI32 idx = PxI32(mEltsPerSlab - 1); + + for (; idx >= PxI32(nbToAllocate); --idx) + { + mFreeList[freeCount++] = new(mAddr + idx) T(mArgument, baseIndex + idx); + } + + PxU32 origElements = nbElements; + T** writeIdx = elements + nbElements; + for (; idx >= 0; --idx) + { + writeIdx[idx] = new(mAddr + idx) T(mArgument, baseIndex + idx); + nbElements++; + } + + nbToAllocate -= (nbElements - origElements); + } + + mFreeCount = freeCount; + } + + PX_ASSERT(nbElements == nbRequired); + + for (PxU32 a = 0; a < nbElements; ++a) + { + mUseBitmap.set(elements[a]->getIndex()); + } + + return nbRequired; + } + + // TODO: would be nice to add templated construct/destroy methods like ObjectPool + + PX_INLINE T* get() + { + if(mFreeCount == 0 && !extend()) + return 0; + T* element = mFreeList[--mFreeCount]; + mUseBitmap.set(element->getIndex()); + return element; + } + + PX_INLINE void put(T* element) + { + PxU32 i = element->getIndex(); + mUseBitmap.reset(i); + mFreeList[mFreeCount++] = element; + } + + /* + WARNING: Unlike findByIndexFast below, this method is NOT safe to use if another thread + is concurrently updating the pool (e.g. through put/get/extend/getIterator), since the + safety boundedTest uses mSlabCount and mUseBitmap. + */ + PX_FORCE_INLINE T* findByIndex(PxU32 index) const + { + if(index>=mSlabCount*mEltsPerSlab || !(mUseBitmap.boundedTest(index))) + return 0; + return mMaxSlabs==1 ? mSlabs[0]+index : mSlabs[index>>mLog2EltsPerSlab] + (index&(mEltsPerSlab-1)); + } + + /* + This call is safe to do while other threads update the pool. + */ + PX_FORCE_INLINE T* findByIndexFast(PxU32 index) const + { + PX_ASSERT(mMaxSlabs != 1); + return mSlabs[index>>mLog2EltsPerSlab] + (index&(mEltsPerSlab-1)); + } + + bool extend() + { + if(mSlabCount == mMaxSlabs) + return false; + T * mAddr = reinterpret_cast<T*>(Alloc::allocate(mEltsPerSlab * sizeof(T), __FILE__, __LINE__)); + if(!mAddr) + return false; + mSlabs[mSlabCount++] = mAddr; + + + + // Make sure the usage bitmap is up-to-size + if(mUseBitmap.size() < mSlabCount*mEltsPerSlab) + { + mUseBitmap.resize(2*mSlabCount*mEltsPerSlab); //set last element as not used + if(mFreeList) + PX_FREE(mFreeList); + mFreeList = reinterpret_cast<T**>(Alloc::allocate(2*mSlabCount * mEltsPerSlab * sizeof(T*), __FILE__, __LINE__)); + } + + // Add to free list in descending order so that lowest indices get allocated first - + // the FW context code currently *relies* on this behavior to grab the zero-index volume + // which can't be allocated to the user. TODO: fix this + + PxU32 baseIndex = (mSlabCount-1) * mEltsPerSlab; + PxU32 freeCount = mFreeCount; + for(PxI32 i=PxI32(mEltsPerSlab-1);i>=0;i--) + mFreeList[freeCount++] = new(mAddr+i) T(mArgument, baseIndex+ i); + + mFreeCount = freeCount; + + return true; + } + + PX_INLINE PxU32 getMaxUsedIndex() const + { + return mUseBitmap.findLast(); + } + + PX_INLINE BitMap::Iterator getIterator() const + { + return BitMap::Iterator(mUseBitmap); + } + +private: + const PxU32 mEltsPerSlab; + const PxU32 mMaxSlabs; + PxU32 mSlabCount; + PxU32 mLog2EltsPerSlab; + T** mFreeList; + PxU32 mFreeCount; + T** mSlabs; + ArgumentType* mArgument; + BitMap mUseBitmap; +}; + + +} +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmPreallocatingPool.h b/PhysX_3.4/Source/Common/src/CmPreallocatingPool.h new file mode 100644 index 00000000..da8bba92 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmPreallocatingPool.h @@ -0,0 +1,435 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_PREALLOCATINGPOOL +#define PX_PHYSICS_COMMON_PREALLOCATINGPOOL + +#include "foundation/Px.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "PsSort.h" +#include "PsArray.h" + +/* +Pool used to allocate variable sized tasks. It's intended to be cleared after a short period (time step). +*/ + +namespace physx +{ +namespace Cm +{ + +class PreallocatingRegion +{ +public: + PX_FORCE_INLINE PreallocatingRegion() : mMemory(NULL), mFirstFree(NULL), mNbElements(0) {} + + void init(PxU32 maxElements, PxU32 elementSize, const char* typeName) + { + mFirstFree = NULL; + mNbElements = 0; + PX_ASSERT(typeName); + PX_UNUSED(typeName); + mMemory = reinterpret_cast<PxU8*>(PX_ALLOC(sizeof(PxU8)*elementSize*maxElements, typeName?typeName:"SceneSim Pool")); // ### addActor alloc + PX_ASSERT(elementSize*maxElements>=sizeof(void*)); + } + + void reset() + { + PX_FREE_AND_RESET(mMemory); + } + + PX_FORCE_INLINE PxU8* allocateMemory(PxU32 maxElements, PxU32 elementSize) + { + if(mFirstFree) + { + PxU8* recycled = reinterpret_cast<PxU8*>(mFirstFree); + + void** recycled32 = reinterpret_cast<void**>(recycled); + mFirstFree = *recycled32; + + return recycled; + } + else + { + if(mNbElements==maxElements) + return NULL; // Out of memory + + const PxU32 freeIndex = mNbElements++; + return mMemory + freeIndex * elementSize; + } + } + + void deallocateMemory(PxU32 maxElements, PxU32 elementSize, PxU8* element) + { + PX_ASSERT(element); + PX_ASSERT(element>=mMemory && element<mMemory + maxElements * elementSize); + PX_UNUSED(elementSize); + PX_UNUSED(maxElements); + + void** recycled32 = reinterpret_cast<void**>(element); + *recycled32 = mFirstFree; + + mFirstFree = element; + } + + PX_FORCE_INLINE bool operator < (const PreallocatingRegion& p) const + { + return mMemory < p.mMemory; + } + + PX_FORCE_INLINE bool operator > (const PreallocatingRegion& p) const + { + return mMemory > p.mMemory; + } + + PxU8* mMemory; + void* mFirstFree; + PxU32 mNbElements; +}; + + + +class PreallocatingRegionManager +{ + public: + PreallocatingRegionManager(PxU32 maxElements, PxU32 elementSize, const char* typeName) + : mMaxElements (maxElements) + , mElementSize (elementSize) + , mActivePoolIndex (0) + , mPools(PX_DEBUG_EXP("MyPoolManagerPools")) + , mNeedsSorting (true) + , mTypeName (typeName) + { + PreallocatingRegion tmp; + tmp.init(maxElements, elementSize, mTypeName); + mPools.pushBack(tmp); + } + + ~PreallocatingRegionManager() + { + const PxU32 nbPools = mPools.size(); + for(PxU32 i=0;i<nbPools;i++) + mPools[i].reset(); + } + + void preAllocate(PxU32 n) + { + if(!n) + return; + + const PxU32 nbPools = mPools.size(); + const PxU32 maxElements = mMaxElements; + const PxU32 elementSize = mElementSize; + PxU32 availableSpace = nbPools * maxElements; + + while(n>availableSpace) + { + PreallocatingRegion tmp; + tmp.init(maxElements, elementSize, mTypeName); + mPools.pushBack(tmp); + + availableSpace += maxElements; + } + } + + PX_FORCE_INLINE PxU8* allocateMemory() + { + PX_ASSERT(mActivePoolIndex<mPools.size()); + PxU8* memory = mPools[mActivePoolIndex].allocateMemory(mMaxElements, mElementSize); + return memory ? memory : searchForMemory(); + } + + void deallocateMemory(PxU8* element) + { + if(!element) + return; + + if(mNeedsSorting) + Ps::sort(mPools.begin(), mPools.size()); + + const PxU32 maxElements = mMaxElements; + const PxU32 elementSize = mElementSize; + const PxU32 slabSize = maxElements * elementSize; + const PxU32 nbPools = mPools.size(); + + // O(log n) search + int first = 0; + int last = int(nbPools-1); + + while(first<=last) + { + const int mid = (first+last)>>1; + + PreallocatingRegion& candidate = mPools[PxU32(mid)]; + if(contains(candidate.mMemory, slabSize, element)) + { + candidate.deallocateMemory(maxElements, elementSize, element); + + // when we sorted earlier we trashed the active index, but at least this region has a free element + if(mNeedsSorting) + mActivePoolIndex = PxU32(mid); + + mNeedsSorting = false; + return; + } + + if(candidate.mMemory<element) + first = mid+1; + else + last = mid-1; + } + + PX_ASSERT(0); + } + + +private: + + PreallocatingRegionManager& operator=(const PreallocatingRegionManager&); + PxU8* searchForMemory() + { + const PxU32 nbPools = mPools.size(); + const PxU32 activePoolIndex = mActivePoolIndex; + const PxU32 maxElements = mMaxElements; + const PxU32 elementSize = mElementSize; + + + for(PxU32 i=0;i<nbPools;i++) + { + if(i==activePoolIndex) + continue; + + PxU8* memory = mPools[i].allocateMemory(maxElements, elementSize); + if(memory) + { + mActivePoolIndex = i; + return memory; + } + } + + mActivePoolIndex = nbPools; + mNeedsSorting = true; + + PreallocatingRegion tmp; + tmp.init(maxElements, elementSize, mTypeName); + + PreallocatingRegion& newPool = mPools.pushBack(tmp); // ### addActor alloc (StaticSim, ShapeSim, SceneQueryShapeData) + return newPool.allocateMemory(maxElements, elementSize); + } + + + + PX_FORCE_INLINE bool contains(PxU8* memory, const PxU32 slabSize, PxU8* element) + { + return element>=memory && element<memory+slabSize; + } + + + + const PxU32 mMaxElements; + const PxU32 mElementSize; + PxU32 mActivePoolIndex; + + Ps::Array<PreallocatingRegion> mPools; + bool mNeedsSorting; + const char* mTypeName; +}; + +template<class T> +class PreallocatingPool : public Ps::UserAllocated +{ + PreallocatingPool<T>& operator=(const PreallocatingPool<T>&); + +public: + PreallocatingPool(PxU32 maxElements, const char* typeName) : mPool(maxElements, sizeof(T), typeName) + { + } + + ~PreallocatingPool() + { + } + + PX_FORCE_INLINE void preAllocate(PxU32 n) + { + mPool.preAllocate(n); + } + + PX_INLINE T* allocate() + { + return reinterpret_cast<T*>(mPool.allocateMemory()); + } + + PX_FORCE_INLINE T* allocateAndPrefetch() + { + T* t = reinterpret_cast<T*>(mPool.allocateMemory()); + Ps::prefetch(t, sizeof(T)); + return t; + } + + PX_INLINE T* construct() + { + T* t = reinterpret_cast<T*>(mPool.allocateMemory()); + return t ? new (t) T() : 0; + } + + template<class A1> + PX_INLINE T* construct(A1& a) + { + T* t = reinterpret_cast<T*>(mPool.allocateMemory()); + return t ? new (t) T(a) : 0; + } + + template<class A1, class A2> + PX_INLINE T* construct(A1& a, A2& b) + { + T* t = reinterpret_cast<T*>(mPool.allocateMemory()); + return t ? new (t) T(a,b) : 0; + } + + template<class A1, class A2, class A3> + PX_INLINE T* construct(A1& a, A2& b, A3& c) + { + T* t = reinterpret_cast<T*>(mPool.allocateMemory()); + return t ? new (t) T(a,b,c) : 0; + } + + template<class A1, class A2, class A3, class A4> + PX_INLINE T* construct(A1& a, A2& b, A3& c, A4& d) + { + T* t = reinterpret_cast<T*>(mPool.allocateMemory()); + return t ? new (t) T(a,b,c,d) : 0; + } + + template<class A1, class A2, class A3, class A4, class A5> + PX_INLINE T* construct(A1& a, A2& b, A3& c, A4& d, A5& e) + { + T* t = reinterpret_cast<T*>(mPool.allocateMemory()); + return t ? new (t) T(a,b,c,d,e) : 0; + } + + //// + + PX_INLINE T* construct(T* t) + { + PX_ASSERT(t); + return new (t) T(); + } + + template<class A1> + PX_INLINE T* construct(T* t, A1& a) + { + PX_ASSERT(t); + return new (t) T(a); + } + + template<class A1, class A2> + PX_INLINE T* construct(T* t, A1& a, A2& b) + { + PX_ASSERT(t); + return new (t) T(a,b); + } + + template<class A1, class A2, class A3> + PX_INLINE T* construct(T* t, A1& a, A2& b, A3& c) + { + PX_ASSERT(t); + return new (t) T(a,b,c); + } + + template<class A1, class A2, class A3, class A4> + PX_INLINE T* construct(T* t, A1& a, A2& b, A3& c, A4& d) + { + PX_ASSERT(t); + return new (t) T(a,b,c,d); + } + + template<class A1, class A2, class A3, class A4, class A5> + PX_INLINE T* construct(T* t, A1& a, A2& b, A3& c, A4& d, A5& e) + { + PX_ASSERT(t); + return new (t) T(a,b,c,d,e); + } + + PX_INLINE void destroy(T* const p) + { + if(p) + { + p->~T(); + mPool.deallocateMemory(reinterpret_cast<PxU8*>(p)); + } + } + + PX_INLINE void releasePreallocated(T* const p) + { + if(p) + mPool.deallocateMemory(reinterpret_cast<PxU8*>(p)); + } +protected: + PreallocatingRegionManager mPool; +}; + +template<class T> +class BufferedPreallocatingPool : public PreallocatingPool<T> +{ + Ps::Array<T*> mDeletedElems; + PX_NOCOPY(BufferedPreallocatingPool<T>) +public: + BufferedPreallocatingPool(PxU32 maxElements, const char* typeName) : PreallocatingPool<T>(maxElements, typeName) + { + } + + PX_INLINE void destroy(T* const p) + { + if (p) + { + p->~T(); + mDeletedElems.pushBack(p); + } + } + + void processPendingDeletedElems() + { + for (PxU32 i = 0; i < mDeletedElems.size(); ++i) + this->mPool.deallocateMemory(reinterpret_cast<PxU8*>(mDeletedElems[i])); + mDeletedElems.clear(); + } + + +}; + + + + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmPriorityQueue.h b/PhysX_3.4/Source/Common/src/CmPriorityQueue.h new file mode 100644 index 00000000..062d5958 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmPriorityQueue.h @@ -0,0 +1,237 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_PRIORITYQUEUE +#define PX_PHYSICS_COMMON_PRIORITYQUEUE + +#include "PsBasicTemplates.h" +#include "CmPhysXCommon.h" +#include "PsAllocator.h" +#include "foundation/PxMemory.h" + +namespace physx +{ +namespace Cm +{ + template<class Element, class Comparator = Ps::Less<Element> > + class PriorityQueueBase : protected Comparator // inherit so that stateless comparators take no space + { + public: + PriorityQueueBase(const Comparator& less, Element* elements) : Comparator(less), mHeapSize(0), mDataPtr(elements) + { + } + + ~PriorityQueueBase() + { + } + + //! Get the element with the highest priority + PX_FORCE_INLINE const Element top() const + { + return mDataPtr[0]; + } + + //! Get the element with the highest priority + PX_FORCE_INLINE Element top() + { + return mDataPtr[0]; + } + + //! Check to whether the priority queue is empty + PX_FORCE_INLINE bool empty() const + { + return (mHeapSize == 0); + } + + //! Empty the priority queue + PX_FORCE_INLINE void clear() + { + mHeapSize = 0; + } + + //! Insert a new element into the priority queue. Only valid when size() is less than Capacity + PX_FORCE_INLINE void push(const Element& value) + { + PxU32 newIndex; + PxU32 parentIndex = parent(mHeapSize); + + for (newIndex = mHeapSize; newIndex > 0 && compare(value, mDataPtr[parentIndex]); newIndex = parentIndex, parentIndex= parent(newIndex)) + { + mDataPtr[ newIndex ] = mDataPtr[parentIndex]; + } + mDataPtr[newIndex] = value; + mHeapSize++; + PX_ASSERT(valid()); + } + + //! Delete the highest priority element. Only valid when non-empty. + PX_FORCE_INLINE Element pop() + { + PX_ASSERT(mHeapSize > 0); + PxU32 i, child; + //try to avoid LHS + PxU32 tempHs = mHeapSize-1; + mHeapSize = tempHs; + Element min = mDataPtr[0]; + Element last = mDataPtr[tempHs]; + + for (i = 0; (child = left(i)) < tempHs; i = child) + { + /* Find highest priority child */ + const PxU32 rightChild = child + 1; + + child += ((rightChild < tempHs) & compare((mDataPtr[rightChild]), (mDataPtr[child]))) ? 1 : 0; + + if(compare(last, mDataPtr[child])) + break; + + mDataPtr[i] = mDataPtr[child]; + } + mDataPtr[ i ] = last; + + PX_ASSERT(valid()); + return min; + } + + //! Make sure the priority queue sort all elements correctly + bool valid() const + { + const Element& min = mDataPtr[0]; + for(PxU32 i=1; i<mHeapSize; ++i) + { + if(compare(mDataPtr[i], min)) + return false; + } + + return true; + } + + //! Return number of elements in the priority queue + PxU32 size() const + { + return mHeapSize; + } + + protected: + + PxU32 mHeapSize; + Element* mDataPtr; + + PX_FORCE_INLINE bool compare(const Element& a, const Element& b) const + { + return Comparator::operator()(a,b); + } + + static PX_FORCE_INLINE PxU32 left(PxU32 nodeIndex) + { + return (nodeIndex << 1) + 1; + } + + static PX_FORCE_INLINE PxU32 parent(PxU32 nodeIndex) + { + return (nodeIndex - 1) >> 1; + } + private: + PriorityQueueBase<Element, Comparator>& operator = (const PriorityQueueBase<Element, Comparator>); + }; + + template <typename Element, PxU32 Capacity, typename Comparator> + class InlinePriorityQueue : public PriorityQueueBase<Element, Comparator> + { + Element mData[Capacity]; + public: + InlinePriorityQueue(const Comparator& less = Comparator()) : PriorityQueueBase<Element, Comparator>(less, mData) + { + } + + PX_FORCE_INLINE void push(Element& elem) + { + PX_ASSERT(this->mHeapSize < Capacity); + PriorityQueueBase<Element, Comparator>::push(elem); + } + private: + InlinePriorityQueue<Element, Capacity, Comparator>& operator = (const InlinePriorityQueue<Element, Capacity, Comparator>); + }; + + template <typename Element, typename Comparator, typename Alloc = typename physx::shdfnd::AllocatorTraits<Element>::Type> + class PriorityQueue : public PriorityQueueBase<Element, Comparator>, protected Alloc + { + PxU32 mCapacity; + public: + PriorityQueue(const Comparator& less = Comparator(), PxU32 initialCapacity = 0, Alloc alloc = Alloc()) + : PriorityQueueBase<Element, Comparator>(less, NULL), Alloc(alloc), mCapacity(initialCapacity) + { + if(initialCapacity > 0) + this->mDataPtr = reinterpret_cast<Element*>(Alloc::allocate(sizeof(Element)*initialCapacity, __FILE__, __LINE__)); + } + + ~PriorityQueue() + { + if(this->mDataPtr) + this->deallocate(this->mDataPtr); + } + + PX_FORCE_INLINE void push(Element& elem) + { + if(this->mHeapSize == mCapacity) + { + reserve((this->mHeapSize+1)*2); + } + PriorityQueueBase<Element, Comparator>::push(elem); + } + + PX_FORCE_INLINE PxU32 capacity() + { + return mCapacity; + } + + PX_FORCE_INLINE void reserve(const PxU32 newCapacity) + { + if(newCapacity > mCapacity) + { + Element* newElems = reinterpret_cast<Element*>(Alloc::allocate(sizeof(Element)*newCapacity, __FILE__, __LINE__)); + if(this->mDataPtr) + { + physx::PxMemCopy(newElems, this->mDataPtr, sizeof(Element) * this->mHeapSize); + Alloc::deallocate(this->mDataPtr); + } + this->mDataPtr = newElems; + mCapacity = newCapacity; + } + } + + private: + PriorityQueue<Element, Comparator, Alloc>& operator = (const PriorityQueue<Element, Comparator, Alloc>); + }; + +} +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmPtrTable.cpp b/PhysX_3.4/Source/Common/src/CmPtrTable.cpp new file mode 100644 index 00000000..9ca54e3a --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmPtrTable.cpp @@ -0,0 +1,209 @@ +// 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/PxAssert.h" +#include "foundation/PxMemory.h" +#include "CmPtrTable.h" +#include "CmUtils.h" +#include "PxMetaData.h" +#include "PsBitUtils.h" + +using namespace physx; +using namespace Cm; + +PtrTable::PtrTable() +: mList(NULL) +, mCount(0) +, mOwnsMemory(true) +, mBufferUsed(false) +{ +} + +PtrTable::~PtrTable() +{ + PX_ASSERT(mOwnsMemory); + PX_ASSERT(mCount == 0); + PX_ASSERT(mList == NULL); +} + +void PtrTable::clear(PtrTableStorageManager& sm) +{ + if(mOwnsMemory && mCount>1) + { + PxU32 implicitCapacity = Ps::nextPowerOfTwo(PxU32(mCount)-1); + sm.deallocate(mList, sizeof(void*)*implicitCapacity); + } + + mList = NULL; + mOwnsMemory = true; + mCount = 0; +} + +PxU32 PtrTable::find(const void* ptr) const +{ + const PxU32 nbPtrs = mCount; + void*const * PX_RESTRICT ptrs = getPtrs(); + + for(PxU32 i=0; i<nbPtrs; i++) + { + if(ptrs[i] == ptr) + return i; + } + + PX_ASSERT(0); + return 0xffffffff; +} + +void PtrTable::exportExtraData(PxSerializationContext& stream) +{ + if(mCount>1) + { + stream.alignData(PX_SERIAL_ALIGN); + stream.writeData(mList, sizeof(void*)*mCount); + } +} + +void PtrTable::importExtraData(PxDeserializationContext& context) +{ + if(mCount>1) + mList = context.readExtraData<void*, PX_SERIAL_ALIGN>(mCount); +} + +void PtrTable::realloc(PxU32 oldCapacity, PxU32 newCapacity, PtrTableStorageManager& sm) +{ + PX_ASSERT((mOwnsMemory && oldCapacity) || (!mOwnsMemory && oldCapacity == 0)); + PX_ASSERT(newCapacity); + + if(mOwnsMemory && sm.canReuse(oldCapacity, newCapacity)) + return; + + void** newMem = sm.allocate(newCapacity * sizeof(void*)); + PxMemCopy(newMem, mList, mCount * sizeof(void*)); + + if(mOwnsMemory) + sm.deallocate(mList, oldCapacity*sizeof(void*)); + + mList = newMem; + mOwnsMemory = true; +} + +void PtrTable::add(void* ptr, PtrTableStorageManager& sm) +{ + if(mCount == 0) // 0 -> 1, easy case + { + PX_ASSERT(mOwnsMemory); + PX_ASSERT(mList == NULL); + PX_ASSERT(!mBufferUsed); + mSingle = ptr; + mCount = 1; + mBufferUsed = true; + return; + } + + if(mCount == 1) // 1 -> 2, easy case + { + PX_ASSERT(mOwnsMemory); + PX_ASSERT(mBufferUsed); + + void* single = mSingle; + mList = sm.allocate(2*sizeof(void*)); + mList[0] = single; + mBufferUsed = false; + mOwnsMemory = true; + } + else + { + PX_ASSERT(!mBufferUsed); + + if(!mOwnsMemory) // don't own the memory, must always alloc + realloc(0, Ps::nextPowerOfTwo(mCount), sm); // we're guaranteed nextPowerOfTwo(x) > x + + else if(Ps::isPowerOfTwo(mCount)) // count is at implicit capacity, so realloc + realloc(mCount, PxU32(mCount)*2, sm); // ... to next higher power of 2 + + PX_ASSERT(mOwnsMemory); + } + + mList[mCount++] = ptr; +} + +void PtrTable::replaceWithLast(PxU32 index, PtrTableStorageManager& sm) +{ + PX_ASSERT(mCount!=0); + + if(mCount == 1) // 1 -> 0 easy case + { + PX_ASSERT(mOwnsMemory); + PX_ASSERT(mBufferUsed); + + mList = NULL; + mCount = 0; + mBufferUsed = false; + } + else if(mCount == 2) // 2 -> 1 easy case + { + PX_ASSERT(!mBufferUsed); + void* ptr = mList[1-index]; + if(mOwnsMemory) + sm.deallocate(mList, 2*sizeof(void*)); + mSingle = ptr; + mCount = 1; + mBufferUsed = true; + mOwnsMemory = true; + } + else + { + PX_ASSERT(!mBufferUsed); + + mList[index] = mList[--mCount]; // remove before adjusting memory + + if(!mOwnsMemory) // don't own the memory, must alloc + realloc(0, Ps::nextPowerOfTwo(PxU32(mCount)-1), sm); // if currently a power of 2, don't jump to the next one + + else if(Ps::isPowerOfTwo(mCount)) // own the memory, and implicit capacity requires that we downsize + realloc(PxU32(mCount)*2, PxU32(mCount), sm); // ... from the next power of 2, which was the old implicit capacity + + PX_ASSERT(mOwnsMemory); + } +} + +void Cm::PtrTable::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PtrTable) + + PX_DEF_BIN_METADATA_ITEM(stream, PtrTable, void, mSingle, PxMetaDataFlag::ePTR) // PT: this is actually a union, beware + PX_DEF_BIN_METADATA_ITEM(stream, PtrTable, PxU16, mCount, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PtrTable, bool, mOwnsMemory, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PtrTable, bool, mBufferUsed, 0) + + //------ Extra-data ------ + + // mList + PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PtrTable, void, mBufferUsed, mCount, PxMetaDataFlag::eCONTROL_FLIP|PxMetaDataFlag::ePTR, PX_SERIAL_ALIGN) +} diff --git a/PhysX_3.4/Source/Common/src/CmPtrTable.h b/PhysX_3.4/Source/Common/src/CmPtrTable.h new file mode 100644 index 00000000..c0eb3b61 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmPtrTable.h @@ -0,0 +1,142 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_PTR_TABLE +#define PX_PHYSICS_COMMON_PTR_TABLE + +#include "PxPhysXCommonConfig.h" +#include "CmPhysXCommon.h" + +namespace physx +{ + +class PxSerializationContext; +class PxDeserializationContext; + + +namespace Cm +{ + +class PtrTableStorageManager +{ + // This will typically be backed by a MultiPool implementation with fallback to the user + // allocator. For MultiPool, when deallocating we want to know what the previously requested size was + // so we can release into the right pool + +public: + + // capacity is in bytes + + virtual void** allocate(PxU32 capacity) = 0; + virtual void deallocate(void** addr, PxU32 originalCapacity) = 0; + + // whether memory allocated at one capacity can (and should) be safely reused at a different capacity + // allows realloc-style reuse by clients. + + virtual bool canReuse(PxU32 originalCapacity, PxU32 newCapacity) = 0; +protected: + virtual ~PtrTableStorageManager() {} +}; + + + +// specialized class to hold an array of pointers with extrinsic storage management, +// serialization-compatible with 3.3.1 PtrTable +// +// note that extrinsic storage implies you *must* clear the table before the destructor runs +// +// capacity is implicit: +// if the memory is not owned (i.e. came from deserialization) then the capacity is exactly mCount +// else if mCount==0, capacity is 0 +// else the capacity is the power of 2 >= mCount +// +// one implication of this is that if we want to add or remove a pointer from unowned memory, we always realloc + +struct PX_PHYSX_COMMON_API PtrTable +{ +//= ATTENTION! ===================================================================================== +// Changing the data layout of this class breaks the binary serialization format. See comments for +// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData +// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION +// accordingly. +//================================================================================================== + + PtrTable(); + ~PtrTable(); + + void add(void* ptr, PtrTableStorageManager& sm); + void replaceWithLast(PxU32 index, PtrTableStorageManager& sm); + void clear(PtrTableStorageManager& sm); + + PxU32 find(const void* ptr) const; + + PX_FORCE_INLINE PxU32 getCount() const { return mCount; } + PX_FORCE_INLINE void*const* getPtrs() const { return mCount == 1 ? &mSingle : mList; } + PX_FORCE_INLINE void** getPtrs() { return mCount == 1 ? &mSingle : mList; } + + + // SERIALIZATION + + // 3.3.1 compatibility fixup: this implementation ALWAYS sets 'ownsMemory' if the size is 0 or 1 + PtrTable(const PxEMPTY) + { + mOwnsMemory = mCount<2; + if(mCount == 0) + mList = NULL; + } + + void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + + static void getBinaryMetaData(physx::PxOutputStream& stream); + +private: + void realloc(PxU32 oldCapacity, PxU32 newCapacity, PtrTableStorageManager& sm); + + union + { + void* mSingle; + void** mList; + }; + + PxU16 mCount; + bool mOwnsMemory; + bool mBufferUsed; // dark magic in serialization requires this, otherwise redundant because it's logically equivalent to mCount == 1. + +}; + +} // namespace Cm +#if !PX_P64_FAMILY +PX_COMPILE_TIME_ASSERT(sizeof(Cm::PtrTable)==8); +#endif + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmQueue.h b/PhysX_3.4/Source/Common/src/CmQueue.h new file mode 100644 index 00000000..20f3191d --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmQueue.h @@ -0,0 +1,152 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_QUEUE +#define PX_PHYSICS_COMMON_QUEUE + +#include "foundation/PxAssert.h" +#include "PsAllocator.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" + +namespace physx +{ +namespace Cm +{ + + template<class T, class AllocType = Ps::NonTrackingAllocator > + class Queue: public Ps::UserAllocated + { + public: + Queue(PxU32 maxEntries); + ~Queue(); + + T popFront(); + T front(); + T popBack(); + T back(); + bool pushBack(const T& element); + bool empty() const; + PxU32 size() const; + + private: + T* mJobQueue; + PxU32 mNum; + PxU32 mHead; + PxU32 mTail; + PxU32 mMaxEntries; + AllocType mAllocator; + }; + + template<class T, class AllocType> + Queue<T, AllocType>::Queue(PxU32 maxEntries): + mNum(0), + mHead(0), + mTail(0), + mMaxEntries(maxEntries) + { + mJobQueue = reinterpret_cast<T*>(mAllocator.allocate(sizeof(T)*mMaxEntries, __FILE__, __LINE__)); + } + + template<class T, class AllocType> + Queue<T, AllocType>::~Queue() + { + if(mJobQueue) + mAllocator.deallocate(mJobQueue); + } + + template<class T, class AllocType> + T Queue<T, AllocType>::popFront() + { + PX_ASSERT(mNum>0); + + mNum--; + T& element = mJobQueue[mTail]; + mTail = (mTail+1) % (mMaxEntries); + return element; + } + + template<class T, class AllocType> + T Queue<T, AllocType>::front() + { + PX_ASSERT(mNum>0); + + return mJobQueue[mTail]; + } + + template<class T, class AllocType> + T Queue<T, AllocType>::popBack() + { + PX_ASSERT(mNum>0); + + mNum--; + mHead = (mHead-1) % (mMaxEntries); + return mJobQueue[mHead]; + } + + template<class T, class AllocType> + T Queue<T, AllocType>::back() + { + PX_ASSERT(mNum>0); + + PxU32 headAccess = (mHead-1) % (mMaxEntries); + return mJobQueue[headAccess]; + } + + template<class T, class AllocType> + bool Queue<T, AllocType>::pushBack(const T& element) + { + if (mNum == mMaxEntries) return false; + mJobQueue[mHead] = element; + + mNum++; + mHead = (mHead+1) % (mMaxEntries); + + return true; + } + + template<class T, class AllocType> + bool Queue<T, AllocType>::empty() const + { + return mNum == 0; + } + + template<class T, class AllocType> + PxU32 Queue<T, AllocType>::size() const + { + return mNum; + } + + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmRadixSort.cpp b/PhysX_3.4/Source/Common/src/CmRadixSort.cpp new file mode 100644 index 00000000..e5417849 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmRadixSort.cpp @@ -0,0 +1,460 @@ +// 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/PxMemory.h" +#include "foundation/PxAssert.h" +#include "CmRadixSort.h" + +using namespace physx; +using namespace Cm; + +#if defined(__BIG_ENDIAN__) || defined(_XBOX) + #define H0_OFFSET 768 + #define H1_OFFSET 512 + #define H2_OFFSET 256 + #define H3_OFFSET 0 + #define BYTES_INC (3-j) +#else + #define H0_OFFSET 0 + #define H1_OFFSET 256 + #define H2_OFFSET 512 + #define H3_OFFSET 768 + #define BYTES_INC j +#endif + +#define CREATE_HISTOGRAMS(type, buffer) \ + /* Clear counters/histograms */ \ + PxMemZero(mHistogram1024, 256*4*sizeof(PxU32)); \ + \ + /* Prepare to count */ \ + const PxU8* PX_RESTRICT p = reinterpret_cast<const PxU8*>(input); \ + const PxU8* PX_RESTRICT pe = &p[nb*4]; \ + PxU32* PX_RESTRICT h0= &mHistogram1024[H0_OFFSET]; /* Histogram for first pass (LSB)*/ \ + PxU32* PX_RESTRICT h1= &mHistogram1024[H1_OFFSET]; /* Histogram for second pass */ \ + PxU32* PX_RESTRICT h2= &mHistogram1024[H2_OFFSET]; /* Histogram for third pass */ \ + PxU32* PX_RESTRICT h3= &mHistogram1024[H3_OFFSET]; /* Histogram for last pass (MSB)*/ \ + \ + bool AlreadySorted = true; /* Optimism... */ \ + \ + if(INVALID_RANKS) \ + { \ + /* Prepare for temporal coherence */ \ + const type* PX_RESTRICT Running = reinterpret_cast<const type*>(buffer); \ + type PrevVal = *Running; \ + \ + while(p!=pe) \ + { \ + /* Read input buffer in previous sorted order */ \ + const type Val = *Running++; \ + /* Check whether already sorted or not */ \ + if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \ + /* Update for next iteration */ \ + PrevVal = Val; \ + \ + /* Create histograms */ \ + h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \ + } \ + \ + /* If all input values are already sorted, we just have to return and leave the */ \ + /* previous list unchanged. That way the routine may take advantage of temporal */ \ + /* coherence, for example when used to sort transparent faces. */ \ + if(AlreadySorted) \ + { \ + mNbHits++; \ + for(PxU32 i=0;i<nb;i++) mRanks[i] = i; \ + return *this; \ + } \ + } \ + else \ + { \ + /* Prepare for temporal coherence */ \ + const PxU32* PX_RESTRICT Indices = mRanks; \ + type PrevVal = type(buffer[*Indices]); \ + \ + while(p!=pe) \ + { \ + /* Read input buffer in previous sorted order */ \ + const type Val = type(buffer[*Indices++]); \ + /* Check whether already sorted or not */ \ + if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \ + /* Update for next iteration */ \ + PrevVal = Val; \ + \ + /* Create histograms */ \ + h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \ + } \ + \ + /* If all input values are already sorted, we just have to return and leave the */ \ + /* previous list unchanged. That way the routine may take advantage of temporal */ \ + /* coherence, for example when used to sort transparent faces. */ \ + if(AlreadySorted) { mNbHits++; return *this; } \ + } \ + \ + /* Else there has been an early out and we must finish computing the histograms */ \ + while(p!=pe) \ + { \ + /* Create histograms without the previous overhead */ \ + h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \ + } + +PX_INLINE const PxU32* CheckPassValidity(PxU32 pass, const PxU32* mHistogram1024, PxU32 nb, const void* input, PxU8& UniqueVal) +{ + // Shortcut to current counters + const PxU32* CurCount = &mHistogram1024[pass<<8]; + + // Check pass validity + + // If all values have the same byte, sorting is useless. + // It may happen when sorting bytes or words instead of dwords. + // This routine actually sorts words faster than dwords, and bytes + // faster than words. Standard running time (O(4*n))is reduced to O(2*n) + // for words and O(n) for bytes. Running time for floats depends on actual values... + + // Get first byte + UniqueVal = *((reinterpret_cast<const PxU8*>(input))+pass); + + // Check that byte's counter + if(CurCount[UniqueVal]==nb) + return NULL; + + return CurCount; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +RadixSort::RadixSort() : mCurrentSize(0), mRanks(NULL), mRanks2(NULL), mHistogram1024(0), mLinks256(0), mTotalCalls(0), mNbHits(0), mDeleteRanks(true) +{ + // Initialize indices + INVALIDATE_RANKS; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +RadixSort::~RadixSort() +{ +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Main sort routine. + * This one is for integer values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data. + * \param input [in] a list of integer values to sort + * \param nb [in] number of values to sort, must be < 2^31 + * \param hint [in] RADIX_SIGNED to handle negative values, RADIX_UNSIGNED if you know your input buffer only contains positive values + * \return Self-Reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +RadixSort& RadixSort::Sort(const PxU32* input, PxU32 nb, RadixHint hint) +{ + PX_ASSERT(mHistogram1024); + PX_ASSERT(mLinks256); + PX_ASSERT(mRanks); + PX_ASSERT(mRanks2); + + // Checkings + if(!input || !nb || nb&0x80000000) return *this; + + // Stats + mTotalCalls++; + + // Create histograms (counters). Counters for all passes are created in one run. + // Pros: read input buffer once instead of four times + // Cons: mHistogram1024 is 4Kb instead of 1Kb + // We must take care of signed/unsigned values for temporal coherence.... I just + // have 2 code paths even if just a single opcode changes. Self-modifying code, someone? + if(hint==RADIX_UNSIGNED) { CREATE_HISTOGRAMS(PxU32, input); } + else { CREATE_HISTOGRAMS(PxI32, input); } + + // Compute #negative values involved if needed + PxU32 NbNegativeValues = 0; + if(hint==RADIX_SIGNED) + { + // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128 + // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte, + // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers. + PxU32* PX_RESTRICT h3= &mHistogram1024[768]; + for(PxU32 i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part + } + + // Radix sort, j is the pass number (0=LSB, 3=MSB) + for(PxU32 j=0;j<4;j++) + { +// CHECK_PASS_VALIDITY(j); + PxU8 UniqueVal; + const PxU32* PX_RESTRICT CurCount = CheckPassValidity(j, mHistogram1024, nb, input, UniqueVal); + + // Sometimes the fourth (negative) pass is skipped because all numbers are negative and the MSB is 0xFF (for example). This is + // not a problem, numbers are correctly sorted anyway. + if(CurCount) + { + PxU32** PX_RESTRICT Links256 = mLinks256; + + // Should we care about negative values? + if(j!=3 || hint==RADIX_UNSIGNED) + { + // Here we deal with positive values only + + // Create offsets + Links256[0] = mRanks2; + for(PxU32 i=1;i<256;i++) + Links256[i] = Links256[i-1] + CurCount[i-1]; + } + else + { + // This is a special case to correctly handle negative integers. They're sorted in the right order but at the wrong place. + + // Create biased offsets, in order for negative numbers to be sorted as well + Links256[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones + for(PxU32 i=1;i<128;i++) + Links256[i] = Links256[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers + + // Fixing the wrong place for negative values + Links256[128] = mRanks2; + for(PxU32 i=129;i<256;i++) + Links256[i] = Links256[i-1] + CurCount[i-1]; + } + + // Perform Radix Sort + const PxU8* PX_RESTRICT InputBytes = reinterpret_cast<const PxU8*>(input); + InputBytes += BYTES_INC; + if(INVALID_RANKS) + { + for(PxU32 i=0;i<nb;i++) + *Links256[InputBytes[i<<2]]++ = i; + VALIDATE_RANKS; + } + else + { + PxU32* PX_RESTRICT Indices = mRanks; + PxU32* PX_RESTRICT IndicesEnd = &mRanks[nb]; + while(Indices!=IndicesEnd) + { + const PxU32 id = *Indices++; + *Links256[InputBytes[id<<2]]++ = id; + } + } + + // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. + PxU32* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; + } + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Main sort routine. + * This one is for floating-point values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data. + * \param input2 [in] a list of floating-point values to sort + * \param nb [in] number of values to sort, must be < 2^31 + * \return Self-Reference + * \warning only sorts IEEE floating-point values + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +RadixSort& RadixSort::Sort(const float* input2, PxU32 nb) +{ + PX_ASSERT(mHistogram1024); + PX_ASSERT(mLinks256); + PX_ASSERT(mRanks); + PX_ASSERT(mRanks2); + + // Checkings + if(!input2 || !nb || nb&0x80000000) return *this; + + // Stats + mTotalCalls++; + + const PxU32* PX_RESTRICT input = reinterpret_cast<const PxU32*>(input2); + + // Allocate histograms & offsets on the stack + //PxU32 mHistogram1024[256*4]; + //PxU32* mLinks256[256]; + + // Create histograms (counters). Counters for all passes are created in one run. + // Pros: read input buffer once instead of four times + // Cons: mHistogram1024 is 4Kb instead of 1Kb + // Floating-point values are always supposed to be signed values, so there's only one code path there. + // Please note the floating point comparison needed for temporal coherence! Although the resulting asm code + // is dreadful, this is surprisingly not such a performance hit - well, I suppose that's a big one on first + // generation Pentiums....We can't make comparison on integer representations because, as Chris said, it just + // wouldn't work with mixed positive/negative values.... + { CREATE_HISTOGRAMS(float, input2); } + + // Compute #negative values involved if needed + PxU32 NbNegativeValues = 0; + // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128 + // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte, + // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers. + // ### is that ok on Apple ?! + PxU32* PX_RESTRICT h3= &mHistogram1024[768]; + for(PxU32 i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part + + // Radix sort, j is the pass number (0=LSB, 3=MSB) + for(PxU32 j=0;j<4;j++) + { + PxU8 UniqueVal; + const PxU32* PX_RESTRICT CurCount = CheckPassValidity(j, mHistogram1024, nb, input, UniqueVal); + // Should we care about negative values? + if(j!=3) + { + // Here we deal with positive values only +// CHECK_PASS_VALIDITY(j); +// const bool PerformPass = CheckPassValidity(j, mHistogram1024, nb, input); + + if(CurCount) + { + PxU32** PX_RESTRICT Links256 = mLinks256; + + // Create offsets + Links256[0] = mRanks2; + for(PxU32 i=1;i<256;i++) + Links256[i] = Links256[i-1] + CurCount[i-1]; + + // Perform Radix Sort + const PxU8* PX_RESTRICT InputBytes = reinterpret_cast<const PxU8*>(input); + InputBytes += BYTES_INC; + if(INVALID_RANKS) + { + for(PxU32 i=0;i<nb;i++) + *Links256[InputBytes[i<<2]]++ = i; + VALIDATE_RANKS; + } + else + { + PxU32* PX_RESTRICT Indices = mRanks; + PxU32* PX_RESTRICT IndicesEnd = &mRanks[nb]; + while(Indices!=IndicesEnd) + { + const PxU32 id = *Indices++; + *Links256[InputBytes[id<<2]]++ = id; + } + } + + // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. + PxU32* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; + } + } + else + { + // This is a special case to correctly handle negative values +// CHECK_PASS_VALIDITY(j); +// const bool PerformPass = CheckPassValidity(j, mHistogram1024, nb, input); + + if(CurCount) + { + PxU32** PX_RESTRICT Links256 = mLinks256; + + // Create biased offsets, in order for negative numbers to be sorted as well + Links256[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones + for(PxU32 i=1;i<128;i++) + Links256[i] = Links256[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers + + // We must reverse the sorting order for negative numbers! + Links256[255] = mRanks2; + for(PxU32 i=0;i<127;i++) + Links256[254-i] = Links256[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values + for(PxU32 i=128;i<256;i++) + Links256[i] += CurCount[i]; // Fixing the wrong place for negative values + + // Perform Radix Sort + if(INVALID_RANKS) + { + for(PxU32 i=0;i<nb;i++) + { + const PxU32 Radix = input[i]>>24; // Radix byte, same as above. AND is useless here (PxU32). + // ### cmp to be killed. Not good. Later. + if(Radix<128) *Links256[Radix]++ = i; // Number is positive, same as above + else *(--Links256[Radix]) = i; // Number is negative, flip the sorting order + } + VALIDATE_RANKS; + } + else + { + const PxU32* PX_RESTRICT Ranks = mRanks; + for(PxU32 i=0;i<nb;i++) + { + const PxU32 Radix = input[Ranks[i]]>>24; // Radix byte, same as above. AND is useless here (PxU32). + // ### cmp to be killed. Not good. Later. + if(Radix<128) *Links256[Radix]++ = Ranks[i]; // Number is positive, same as above + else *(--Links256[Radix]) = Ranks[i]; // Number is negative, flip the sorting order + } + } + // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. + PxU32* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; + } + else + { + // The pass is useless, yet we still have to reverse the order of current list if all values are negative. + if(UniqueVal>=128) + { + if(INVALID_RANKS) + { + // ###Possible? + for(PxU32 i=0;i<nb;i++) mRanks2[i] = nb-i-1; + VALIDATE_RANKS; + } + else + { + for(PxU32 i=0;i<nb;i++) mRanks2[i] = mRanks[nb-i-1]; + } + + // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. + PxU32* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; + } + } + } + } + return *this; +} + +bool RadixSort::SetBuffers(PxU32* ranks0, PxU32* ranks1, PxU32* histogram1024, PxU32** links256) +{ + if(!ranks0 || !ranks1 || !histogram1024 || !links256) return false; + + mRanks = ranks0; + mRanks2 = ranks1; + mHistogram1024 = histogram1024; + mLinks256 = links256; + mDeleteRanks = false; + INVALIDATE_RANKS; + return true; +} + diff --git a/PhysX_3.4/Source/Common/src/CmRadixSort.h b/PhysX_3.4/Source/Common/src/CmRadixSort.h new file mode 100644 index 00000000..4bde7f7a --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmRadixSort.h @@ -0,0 +1,100 @@ +// 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. + +#ifndef CM_RADIX_SORT_H +#define CM_RADIX_SORT_H + +#include "PxPhysXCommonConfig.h" + +namespace physx +{ +namespace Cm +{ + + enum RadixHint + { + RADIX_SIGNED, //!< Input values are signed + RADIX_UNSIGNED, //!< Input values are unsigned + + RADIX_FORCE_DWORD = 0x7fffffff + }; + +#define INVALIDATE_RANKS mCurrentSize|=0x80000000 +#define VALIDATE_RANKS mCurrentSize&=0x7fffffff +#define CURRENT_SIZE (mCurrentSize&0x7fffffff) +#define INVALID_RANKS (mCurrentSize&0x80000000) + + class PX_PHYSX_COMMON_API RadixSort + { + public: + RadixSort(); + virtual ~RadixSort(); + // Sorting methods + RadixSort& Sort(const PxU32* input, PxU32 nb, RadixHint hint=RADIX_SIGNED); + RadixSort& Sort(const float* input, PxU32 nb); + + //! Access to results. mRanks is a list of indices in sorted order, i.e. in the order you may further process your data + PX_FORCE_INLINE const PxU32* GetRanks() const { return mRanks; } + + //! mIndices2 gets trashed on calling the sort routine, but otherwise you can recycle it the way you want. + PX_FORCE_INLINE PxU32* GetRecyclable() const { return mRanks2; } + + //! Returns the total number of calls to the radix sorter. + PX_FORCE_INLINE PxU32 GetNbTotalCalls() const { return mTotalCalls; } + //! Returns the number of eraly exits due to temporal coherence. + PX_FORCE_INLINE PxU32 GetNbHits() const { return mNbHits; } + + bool SetBuffers(PxU32* ranks0, PxU32* ranks1, PxU32* histogram1024, PxU32** links256); + private: + RadixSort(const RadixSort& object); + RadixSort& operator=(const RadixSort& object); + protected: + PxU32 mCurrentSize; //!< Current size of the indices list + PxU32* mRanks; //!< Two lists, swapped each pass + PxU32* mRanks2; + PxU32* mHistogram1024; + PxU32** mLinks256; + // Stats + PxU32 mTotalCalls; //!< Total number of calls to the sort routine + PxU32 mNbHits; //!< Number of early exits due to coherence + + // Stack-radix + bool mDeleteRanks; //!< + }; + + #define StackRadixSort(name, ranks0, ranks1) \ + RadixSort name; \ + PxU32 histogramBuffer[1024]; \ + PxU32* linksBuffer[256]; \ + name.SetBuffers(ranks0, ranks1, histogramBuffer, linksBuffer); +} + +} + +#endif // CM_RADIX_SORT_H diff --git a/PhysX_3.4/Source/Common/src/CmRadixSortBuffered.cpp b/PhysX_3.4/Source/Common/src/CmRadixSortBuffered.cpp new file mode 100644 index 00000000..9efd9fb7 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmRadixSortBuffered.cpp @@ -0,0 +1,142 @@ +// 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 "CmRadixSortBuffered.h" +#include "PsAllocator.h" + +using namespace physx; +using namespace Cm; + +RadixSortBuffered::RadixSortBuffered() +: RadixSort() +{ +} + +RadixSortBuffered::~RadixSortBuffered() +{ + // Release everything + if(mDeleteRanks) + { + PX_FREE_AND_RESET(mRanks2); + PX_FREE_AND_RESET(mRanks); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Resizes the inner lists. + * \param nb [in] new size (number of dwords) + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool RadixSortBuffered::Resize(PxU32 nb) +{ + if(mDeleteRanks) + { + // Free previously used ram + PX_FREE_AND_RESET(mRanks2); + PX_FREE_AND_RESET(mRanks); + + // Get some fresh one + mRanks = reinterpret_cast<PxU32*>(PX_ALLOC(sizeof(PxU32)*nb, "RadixSortBuffered:mRanks")); + mRanks2 = reinterpret_cast<PxU32*>(PX_ALLOC(sizeof(PxU32)*nb, "RadixSortBuffered:mRanks2")); + } + + return true; +} + +PX_INLINE void RadixSortBuffered::CheckResize(PxU32 nb) +{ + PxU32 CurSize = CURRENT_SIZE; + if(nb!=CurSize) + { + if(nb>CurSize) Resize(nb); + mCurrentSize = nb; + INVALIDATE_RANKS; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Main sort routine. + * This one is for integer values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data. + * \param input [in] a list of integer values to sort + * \param nb [in] number of values to sort, must be < 2^31 + * \param hint [in] RADIX_SIGNED to handle negative values, RADIX_UNSIGNED if you know your input buffer only contains positive values + * \return Self-Reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +RadixSortBuffered& RadixSortBuffered::Sort(const PxU32* input, PxU32 nb, RadixHint hint) +{ + // Checkings + if(!input || !nb || nb&0x80000000) return *this; + + // Resize lists if needed + CheckResize(nb); + + //Set histogram buffers. + PxU32 histogram[1024]; + PxU32* links[256]; + mHistogram1024=histogram; + mLinks256=links; + + RadixSort::Sort(input,nb,hint); + return *this; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Main sort routine. + * This one is for floating-point values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data. + * \param input2 [in] a list of floating-point values to sort + * \param nb [in] number of values to sort, must be < 2^31 + * \return Self-Reference + * \warning only sorts IEEE floating-point values + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +RadixSortBuffered& RadixSortBuffered::Sort(const float* input2, PxU32 nb) +{ + // Checkings + if(!input2 || !nb || nb&0x80000000) return *this; + + // Resize lists if needed + CheckResize(nb); + + //Set histogram buffers. + PxU32 histogram[1024]; + PxU32* links[256]; + mHistogram1024=histogram; + mLinks256=links; + + RadixSort::Sort(input2,nb); + return *this; +} + diff --git a/PhysX_3.4/Source/Common/src/CmRadixSortBuffered.h b/PhysX_3.4/Source/Common/src/CmRadixSortBuffered.h new file mode 100644 index 00000000..aa76bfbb --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmRadixSortBuffered.h @@ -0,0 +1,61 @@ +// 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. + +#ifndef CM_RADIX_SORT_BUFFERED_H +#define CM_RADIX_SORT_BUFFERED_H + +#include "CmPhysXCommon.h" +#include "CmRadixSort.h" + +namespace physx +{ +namespace Cm +{ + class PX_PHYSX_COMMON_API RadixSortBuffered : public RadixSort + { + public: + RadixSortBuffered(); + ~RadixSortBuffered(); + + RadixSortBuffered& Sort(const PxU32* input, PxU32 nb, RadixHint hint=RADIX_SIGNED); + RadixSortBuffered& Sort(const float* input, PxU32 nb); + + private: + RadixSortBuffered(const RadixSortBuffered& object); + RadixSortBuffered& operator=(const RadixSortBuffered& object); + + // Internal methods + void CheckResize(PxU32 nb); + bool Resize(PxU32 nb); + }; +} + +} + +#endif // CM_RADIX_SORT_BUFFERED_H diff --git a/PhysX_3.4/Source/Common/src/CmReaderWriterLock.h b/PhysX_3.4/Source/Common/src/CmReaderWriterLock.h new file mode 100644 index 00000000..e1b2a3c5 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmReaderWriterLock.h @@ -0,0 +1,202 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_READERWRITERLOCK +#define PX_PHYSICS_COMMON_READERWRITERLOCK + +//#define PX_RAYCAST_READWRITE_LOCK + +/* +Implements a full reader writer lock, i.e. multiple readers or a single writer. + +Below is an implementation using just a mutex for non win32 platforms. + +Disable the full reader/writer lock by default. Using the full reader writer lock +results in better performance when a lot of parallel raycasts are performed but is +more costly when only a few are performed and slows down serial raycasts. +*/ + +namespace physx +{ +namespace Cm +{ + +#ifdef PX_RAYCAST_READWRITE_LOCK + class ReaderWriterLock + { + public: + + PX_INLINE ReaderWriterLock() + { + hReaderEvent=CreateEvent(NULL,TRUE,FALSE,NULL); + PX_ASSERT(hReaderEvent!=NULL); + + hMutex = CreateEvent(NULL,FALSE,TRUE,NULL); + PX_ASSERT(hMutex!=NULL); + + InitializeCriticalSection(&writerMutex); + counter = -1; + recursionCounter=0; + } + PX_INLINE ~ReaderWriterLock() + { + if(hReaderEvent!=NULL) + CloseHandle(hReaderEvent); + if(hMutex!=NULL) + CloseHandle(hMutex); + DeleteCriticalSection(&writerMutex); + } + + PX_INLINE void lockReader() + { + if(InterlockedIncrement(&counter) == 0) + { + WaitForSingleObject(hMutex, INFINITE); + SetEvent(hReaderEvent); + } + + WaitForSingleObject(hReaderEvent,INFINITE); + } + + PX_INLINE void lockWriter() + { + EnterCriticalSection(&writerMutex); + + //we may already have the global mutex(really an event so we have to handle recursion ourselves) + recursionCounter++; + if(recursionCounter==1) + WaitForSingleObject(hMutex, INFINITE); + } + PX_INLINE void unlockReader() + { + if(InterlockedDecrement(&counter) < 0) + { + ResetEvent(hReaderEvent); + SetEvent(hMutex); + } + } + PX_INLINE void unlockWriter() + { + recursionCounter--; + if(recursionCounter==0) + SetEvent(hMutex); + + LeaveCriticalSection(&writerMutex); + } + + private: + + HANDLE hReaderEvent; + HANDLE hMutex; + CRITICAL_SECTION writerMutex; + LONG counter;//count the number of readers in the lock. + LONG recursionCounter;//handle recursive writer locking + }; +#else + /* + TODO: implement proper reader writer lock for other platforms, eg cell os has a native reader writer lock. + */ + + class ReaderWriterLock + { + PX_NOCOPY(ReaderWriterLock) + public: + + PX_INLINE void lockReader() + { + //lock.lock(); + lock.lockReader(); + } + PX_INLINE void lockWriter() + { + //lock.lock(); + lock.lockWriter(); + } + PX_INLINE void unlockReader() + { + //lock.unlock(); + lock.unlockReader(); + } + PX_INLINE void unlockWriter() + { + //lock.unlock(); + lock.unlockWriter(); + } + + private: + + //Ps::Mutex lock; + + Ps::AtomicRwLock lock; + }; +#endif + + class TakeReaderLock + { + public: + + TakeReaderLock(ReaderWriterLock &l) : lock(l) + { + lock.lockReader(); + } + ~TakeReaderLock() + { + lock.unlockReader(); + } + + private: + TakeReaderLock& operator=(const TakeReaderLock&); + ReaderWriterLock &lock; + }; + + class TakeWriterLock + { + public: + + TakeWriterLock(ReaderWriterLock &l) : lock(l) + { + lock.lockWriter(); + } + ~TakeWriterLock() + { + lock.unlockWriter(); + } + + private: + TakeWriterLock& operator=(const TakeWriterLock&); + ReaderWriterLock &lock; + }; + + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmRefCountable.h b/PhysX_3.4/Source/Common/src/CmRefCountable.h new file mode 100644 index 00000000..44087247 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmRefCountable.h @@ -0,0 +1,102 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_REFCOUNTABLE +#define PX_PHYSICS_COMMON_REFCOUNTABLE + +#include "foundation/PxAssert.h" +#include "PsAtomic.h" + +namespace physx +{ +namespace Cm +{ + + // simple thread-safe reference count + // when the ref count is zero, the object is in an undefined state (pending delete) + + class RefCountable + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + public: +// PX_SERIALIZATION + RefCountable(const PxEMPTY) : mRefCount(1) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + explicit RefCountable(PxU32 initialCount = 1) + : mRefCount(PxI32(initialCount)) + { + PX_ASSERT(mRefCount!=0); + } + + virtual ~RefCountable() {} + + /** + Calls 'delete this;'. It needs to be overloaded for classes also deriving from + PxBase and call 'Cm::deletePxBase(this);' instead. + */ + virtual void onRefCountZero() + { + delete this; + } + + void incRefCount() + { + physx::shdfnd::atomicIncrement(&mRefCount); + // value better be greater than 1, or we've created a ref to an undefined object + PX_ASSERT(mRefCount>1); + } + + void decRefCount() + { + PX_ASSERT(mRefCount>0); + if(physx::shdfnd::atomicDecrement(&mRefCount) == 0) + onRefCountZero(); + } + + PX_FORCE_INLINE PxU32 getRefCount() const + { + return PxU32(mRefCount); + } + private: + volatile PxI32 mRefCount; + }; + + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmRenderBuffer.h b/PhysX_3.4/Source/Common/src/CmRenderBuffer.h new file mode 100644 index 00000000..b07fc1f8 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmRenderBuffer.h @@ -0,0 +1,132 @@ +// 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. + + +#ifndef PX_FOUNDATION_PSRENDERBUFFER_H +#define PX_FOUNDATION_PSRENDERBUFFER_H + +#include "common/PxRenderBuffer.h" +#include "CmPhysXCommon.h" +#include "PsArray.h" +#include "PsUserAllocated.h" + +namespace physx +{ +namespace Cm +{ + /** + Implementation of PxRenderBuffer. + */ + class RenderBuffer : public PxRenderBuffer, public Ps::UserAllocated + { + + template <typename T> + void append(Ps::Array<T>& dst, const T* src, PxU32 count) + { + dst.reserve(dst.size() + count); + for(const T* end=src+count; src<end; ++src) + dst.pushBack(*src); + } + + public: + + RenderBuffer() : + mPoints(PX_DEBUG_EXP("renderBufferPoints")), + mLines(PX_DEBUG_EXP("renderBufferLines")), + mTriangles(PX_DEBUG_EXP("renderBufferTriangles")), + mTexts(PX_DEBUG_EXP("renderBufferTexts")), + mCharBuf(PX_DEBUG_EXP("renderBufferCharBuf")) + {} + + + virtual PxU32 getNbPoints() const { return mPoints.size(); } + virtual const PxDebugPoint* getPoints() const { return mPoints.begin(); } + virtual PxU32 getNbLines() const { return mLines.size(); } + virtual const PxDebugLine* getLines() const { return mLines.begin(); } + virtual PxU32 getNbTriangles() const { return mTriangles.size(); } + virtual const PxDebugTriangle* getTriangles() const { return mTriangles.begin(); } + virtual PxU32 getNbTexts() const { return mTexts.size(); } + virtual const PxDebugText* getTexts() const { return mTexts.begin(); } + + virtual void append(const PxRenderBuffer& other) + { + append(mPoints, other.getPoints(), other.getNbPoints()); + append(mLines, other.getLines(), other.getNbLines()); + append(mTriangles, other.getTriangles(), other.getNbTriangles()); + append(mTexts, other.getTexts(), other.getNbTexts()); + } + + virtual void clear() + { + mPoints.clear(); + mLines.clear(); + mTriangles.clear(); + mTexts.clear(); + mCharBuf.clear(); + } + + bool empty() const + { + return mPoints.empty() && mLines.empty() && mTriangles.empty() && mTexts.empty()&& mCharBuf.empty(); + } + + void shift(const PxVec3& delta) + { + for(PxU32 i=0; i < mPoints.size(); i++) + mPoints[i].pos += delta; + + for(PxU32 i=0; i < mLines.size(); i++) + { + mLines[i].pos0 += delta; + mLines[i].pos1 += delta; + } + + for(PxU32 i=0; i < mTriangles.size(); i++) + { + mTriangles[i].pos0 += delta; + mTriangles[i].pos1 += delta; + mTriangles[i].pos2 += delta; + } + + for(PxU32 i=0; i < mTexts.size(); i++) + mTexts[i].position += delta; + } + + Ps::Array<PxDebugPoint> mPoints; + Ps::Array<PxDebugLine> mLines; + Ps::Array<PxDebugTriangle> mTriangles; + Ps::Array<PxDebugText> mTexts; + Ps::Array<char> mCharBuf; + }; + +} // Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmRenderOutput.cpp b/PhysX_3.4/Source/Common/src/CmRenderOutput.cpp new file mode 100644 index 00000000..2226d137 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmRenderOutput.cpp @@ -0,0 +1,301 @@ +// 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/PxMat44.h" +#include "CmRenderOutput.h" +#include "PsMathUtils.h" +#include "PsString.h" +#include <stdarg.h> + +#if PX_VC +#pragma warning(disable: 4342 ) // behavior change: 'function' called, but a member operator was called in previous versions +#pragma warning(disable: 4996 ) // intentionally suppressing this warning message +#endif + +using namespace physx; +using namespace Cm; + + +namespace physx +{ +namespace Cm +{ + RenderOutput& RenderOutput::operator<<(Primitive prim) + { + mPrim = prim; mVertexCount = 0; return *this; + } + + RenderOutput& RenderOutput::operator<<(PxU32 color) + { + mColor = color; return *this; + } + + RenderOutput& RenderOutput::operator<<(const PxMat44& transform) + { + mTransform = transform; return *this; + } + + RenderOutput& RenderOutput::operator<<(const PxTransform&t) + { + mTransform = PxMat44(t); + return *this; + } + + RenderOutput& RenderOutput::operator<<(PxVec3 vertex) + { + // apply transformation + vertex = mTransform.transform(vertex); + ++mVertexCount; + + // add primitive to render buffer + switch(mPrim) + { + case POINTS: + mBuffer.mPoints.pushBack(PxDebugPoint(vertex, mColor)); break; + case LINES: + if(mVertexCount == 2) + { + mBuffer.mLines.pushBack(PxDebugLine(mVertex0, vertex, mColor)); + mVertexCount = 0; + } + break; + case LINESTRIP: + if(mVertexCount >= 2) + mBuffer.mLines.pushBack(PxDebugLine(mVertex0, vertex, mColor)); + break; + case TRIANGLES: + if(mVertexCount == 3) + { + mBuffer.mTriangles.pushBack(PxDebugTriangle(mVertex1, mVertex0, vertex, mColor)); + mVertexCount = 0; + } + break; + case TRIANGLESTRIP: + if(mVertexCount >= 3) + mBuffer.mTriangles.pushBack(PxDebugTriangle( + (mVertexCount & 0x1) ? mVertex0 : mVertex1, + (mVertexCount & 0x1) ? mVertex1 : mVertex0, vertex, mColor)); + break; + case TEXT: + break; + } + + // cache the last 2 vertices (for strips) + if(1 < mVertexCount) + { + mVertex1 = mVertex0; + mVertex0 = vertex; + } else { + mVertex0 = vertex; + } + return *this; + } + + DebugText::DebugText(const PxVec3& position_, PxReal size_, const char* string, ...) + : position(position_), size(size_) + { + va_list argList; + va_start(argList, string); + if(0 >= Ps::vsnprintf(buffer, sBufferSize-1, string, argList)) + buffer[sBufferSize-1] = 0; // terminate string + va_end(argList); + } + + RenderOutput& RenderOutput::operator<<(const DebugText& text) + { + const PxU32 n = PxU32(strlen(text.buffer)); + const PxU32 newCharBufSize = mBuffer.mCharBuf.size()+n+1; + if(mBuffer.mCharBuf.capacity() < newCharBufSize) + { + char* oldBuf = mBuffer.mCharBuf.begin(); + mBuffer.mCharBuf.reserve(newCharBufSize); + intptr_t diff = mBuffer.mCharBuf.begin() - oldBuf; + for (PxU32 i = 0; i < mBuffer.mTexts.size(); ++i) + mBuffer.mTexts[i].string += diff; + } + mBuffer.mTexts.pushBack(PxDebugText(mTransform.transform(text.position), text.size, mColor, mBuffer.mCharBuf.end())); + for(size_t i=0; i<=n; ++i) + mBuffer.mCharBuf.pushBack(text.buffer[i]); + return *this; + } + + RenderOutput& operator<<(RenderOutput& out, const DebugBox& box) + { + if(box.wireframe) + { + out << RenderOutput::LINESTRIP; + out << PxVec3(box.minimum.x, box.minimum.y, box.minimum.z); + out << PxVec3(box.maximum.x, box.minimum.y, box.minimum.z); + out << PxVec3(box.maximum.x, box.maximum.y, box.minimum.z); + out << PxVec3(box.minimum.x, box.maximum.y, box.minimum.z); + out << PxVec3(box.minimum.x, box.minimum.y, box.minimum.z); + out << PxVec3(box.minimum.x, box.minimum.y, box.maximum.z); + out << PxVec3(box.maximum.x, box.minimum.y, box.maximum.z); + out << PxVec3(box.maximum.x, box.maximum.y, box.maximum.z); + out << PxVec3(box.minimum.x, box.maximum.y, box.maximum.z); + out << PxVec3(box.minimum.x, box.minimum.y, box.maximum.z); + out << RenderOutput::LINES; + out << PxVec3(box.maximum.x, box.minimum.y, box.minimum.z); + out << PxVec3(box.maximum.x, box.minimum.y, box.maximum.z); + out << PxVec3(box.maximum.x, box.maximum.y, box.minimum.z); + out << PxVec3(box.maximum.x, box.maximum.y, box.maximum.z); + out << PxVec3(box.minimum.x, box.maximum.y, box.minimum.z); + out << PxVec3(box.minimum.x, box.maximum.y, box.maximum.z); + } + else + { + out << RenderOutput::TRIANGLESTRIP; + out << PxVec3(box.minimum.x, box.minimum.y, box.minimum.z); // 0 + out << PxVec3(box.minimum.x, box.maximum.y, box.minimum.z); // 2 + out << PxVec3(box.maximum.x, box.minimum.y, box.minimum.z); // 1 + out << PxVec3(box.maximum.x, box.maximum.y, box.minimum.z); // 3 + out << PxVec3(box.maximum.x, box.maximum.y, box.maximum.z); // 7 + out << PxVec3(box.minimum.x, box.maximum.y, box.minimum.z); // 2 + out << PxVec3(box.minimum.x, box.maximum.y, box.maximum.z); // 6 + out << PxVec3(box.minimum.x, box.minimum.y, box.minimum.z); // 0 + out << PxVec3(box.minimum.x, box.minimum.y, box.maximum.z); // 4 + out << PxVec3(box.maximum.x, box.minimum.y, box.minimum.z); // 1 + out << PxVec3(box.maximum.x, box.minimum.y, box.maximum.z); // 5 + out << PxVec3(box.maximum.x, box.maximum.y, box.maximum.z); // 7 + out << PxVec3(box.minimum.x, box.minimum.y, box.maximum.z); // 4 + out << PxVec3(box.minimum.x, box.maximum.y, box.maximum.z); // 6 + } + return out; + } + + RenderOutput& operator<<(RenderOutput& out, const DebugArrow& arrow) + { + PxVec3 t0 = arrow.tip - arrow.base, t1, t2; + + t0.normalize(); + Ps::normalToTangents(t0, t1, t2); + + const PxReal tipAngle = 0.25f; + t1 *= arrow.headLength * tipAngle; + t2 *= arrow.headLength * tipAngle * PxSqrt(3.0f); + PxVec3 headBase = arrow.tip - t0 * arrow.headLength; + + out << RenderOutput::LINES; + out << arrow.base << arrow.tip; + + out << RenderOutput::TRIANGLESTRIP; + out << arrow.tip; + out << headBase + t1 + t1; + out << headBase - t1 - t2; + out << headBase - t1 + t2; + out << arrow.tip; + out << headBase + t1 + t1; + return out; + } + + RenderOutput& operator<<(RenderOutput& out, const DebugBasis& basis) + { + const PxReal headLength = basis.extends.magnitude() * 0.15f; + out << basis.colorX << DebugArrow(PxVec3(0.0f), PxVec3(basis.extends.x, 0, 0), headLength); + out << basis.colorY << DebugArrow(PxVec3(0.0f), PxVec3(0, basis.extends.y, 0), headLength); + out << basis.colorZ << DebugArrow(PxVec3(0.0f), PxVec3(0, 0, basis.extends.z), headLength); + return out; + } + + RenderOutput& operator<<(RenderOutput& out, const DebugCircle& circle) + { + const PxF32 step = PxTwoPi/circle.nSegments; + PxF32 angle = 0; + out << RenderOutput::LINESTRIP; + for(PxU32 i=0; i<circle.nSegments; i++, angle += step) + out << PxVec3(circle.radius * PxSin(angle), circle.radius * PxCos(angle), 0); + out << PxVec3(0, circle.radius, 0); + return out; + } + + RenderOutput& operator<<(RenderOutput& out, const DebugArc& arc) + { + const PxF32 step = (arc.maxAngle - arc.minAngle) / arc.nSegments; + PxF32 angle = arc.minAngle; + out << RenderOutput::LINESTRIP; + for(PxU32 i=0; i<arc.nSegments; i++, angle += step) + out << PxVec3(arc.radius * PxSin(angle), arc.radius * PxCos(angle), 0); + out << PxVec3(arc.radius * PxSin(arc.maxAngle), arc.radius * PxCos(arc.maxAngle), 0); + return out; + } + + // PT: I need those functions available here so that I don't have to duplicate all the code in other modules like the CCT. + // PT: TODO: move other functions here as well + + RenderOutput& RenderOutput::outputCapsule(PxF32 radius, PxF32 halfHeight, const PxMat44& absPose) + { + RenderOutput& out = *this; + + const PxVec3 vleft2(-halfHeight, 0.0f, 0.0f); + PxMat44 left2 = absPose; + left2.column3 += PxVec4(left2.rotate(vleft2), 0.0f); + out << left2 << Cm::DebugArc(100, radius, PxPi, PxTwoPi); + + PxMat44 rotPose = left2; + Ps::swap(rotPose.column1, rotPose.column2); + rotPose.column1 = -rotPose.column1; + out << rotPose << Cm::DebugArc(100, radius, PxPi, PxTwoPi); + + Ps::swap(rotPose.column0, rotPose.column2); + rotPose.column0 = -rotPose.column0; + out << rotPose << Cm::DebugCircle(100, radius); + + const PxVec3 vright2(halfHeight, 0.0f, 0.0f); + PxMat44 right2 = absPose; + right2.column3 += PxVec4(right2.rotate(vright2), 0.0f); + out << right2 << Cm::DebugArc(100, radius, 0.0f, PxPi); + + rotPose = right2; + Ps::swap(rotPose.column1, rotPose.column2); + rotPose.column1 = -rotPose.column1; + out << rotPose << Cm::DebugArc(100, radius, 0.0f, PxPi); + + Ps::swap(rotPose.column0, rotPose.column2); + rotPose.column0 = -rotPose.column0; + out << rotPose << Cm::DebugCircle(100, radius); + + out << absPose; + out.outputSegment( absPose.transform(PxVec3(-halfHeight, radius, 0)), + absPose.transform(PxVec3( halfHeight, radius, 0))); + out.outputSegment( absPose.transform(PxVec3(-halfHeight, -radius, 0)), + absPose.transform(PxVec3( halfHeight, -radius, 0))); + out.outputSegment( absPose.transform(PxVec3(-halfHeight, 0, radius)), + absPose.transform(PxVec3( halfHeight, 0, radius))); + out.outputSegment( absPose.transform(PxVec3(-halfHeight, 0, -radius)), + absPose.transform(PxVec3( halfHeight, 0, -radius))); + + return *this; + } + + + +} // Cm + +} diff --git a/PhysX_3.4/Source/Common/src/CmRenderOutput.h b/PhysX_3.4/Source/Common/src/CmRenderOutput.h new file mode 100644 index 00000000..a121cb27 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmRenderOutput.h @@ -0,0 +1,191 @@ +// 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. + + +#ifndef PX_FOUNDATION_PSRENDEROUTPUT_H +#define PX_FOUNDATION_PSRENDEROUTPUT_H + +#include "foundation/PxMat44.h" +#include "CmRenderBuffer.h" + +namespace physx +{ +namespace Cm +{ + struct DebugText; + +#if PX_VC + #pragma warning(push) + #pragma warning( disable : 4251 ) // class needs to have dll-interface to be used by clients of class +#endif + /** + Output stream to fill RenderBuffer + */ + class PX_PHYSX_COMMON_API RenderOutput + { + public: + + enum Primitive { + POINTS, + LINES, + LINESTRIP, + TRIANGLES, + TRIANGLESTRIP, + TEXT + }; + + RenderOutput(RenderBuffer& buffer) + : mPrim(POINTS), mColor(0), mVertex0(0.0f), mVertex1(0.0f) + , mVertexCount(0), mTransform(PxMat44(PxIdentity)), mBuffer(buffer) + {} + + RenderOutput& operator<<(Primitive prim); + RenderOutput& operator<<(PxU32 color); // 0xbbggrr + RenderOutput& operator<<(const PxMat44& transform); + RenderOutput& operator<<(const PxTransform&); + + RenderOutput& operator<<(PxVec3 vertex); + RenderOutput& operator<<(const DebugText& text); + + PX_FORCE_INLINE PxDebugLine* reserveSegments(PxU32 nbSegments) + { + const PxU32 currentSize = mBuffer.mLines.size(); + mBuffer.mLines.resizeUninitialized(currentSize + nbSegments); + return mBuffer.mLines.begin() + currentSize; + } + + // PT: using the operators is just too slow. + PX_FORCE_INLINE void outputSegment(const PxVec3& v0, const PxVec3& v1) + { + // PT: TODO: replace pushBack with something faster like the versions below + mBuffer.mLines.pushBack(PxDebugLine(v0, v1, mColor)); + + // PT: TODO: use the "pushBackUnsafe" version or replace with ICE containers +/* PxDebugLine& l = mBuffer.mLines.insert(); + l.pos0 = v0; + l.pos1 = v1; + l.color0 = l.color1 = mColor; + + PxDebugLine& l = mBuffer.mLines.pushBackUnsafe(); + l.pos0 = v0; + l.pos1 = v1; + l.color0 = l.color1 = mColor;*/ + } + + RenderOutput& outputCapsule(PxF32 radius, PxF32 halfHeight, const PxMat44& absPose); + + private: + + RenderOutput& operator=(const RenderOutput&); + + Primitive mPrim; + PxU32 mColor; + PxVec3 mVertex0, mVertex1; + PxU32 mVertexCount; + PxMat44 mTransform; + RenderBuffer& mBuffer; + }; + + /** debug render helper types */ + struct PX_PHYSX_COMMON_API DebugText + { + DebugText(const PxVec3& position, PxReal size, const char* string, ...); + static const int sBufferSize = 1008; // sizeof(DebugText)==1kB + char buffer[sBufferSize]; + PxVec3 position; + PxReal size; + }; + + struct DebugBox + { + explicit DebugBox(const PxVec3& extents, bool wireframe_ = true) + : minimum(-extents), maximum(extents), wireframe(wireframe_) {} + + explicit DebugBox(const PxVec3& pos, const PxVec3& extents, bool wireframe_ = true) + : minimum(pos-extents), maximum(pos+extents), wireframe(wireframe_) {} + + explicit DebugBox(const PxBounds3& bounds, bool wireframe_ = true) + : minimum(bounds.minimum), maximum(bounds.maximum), wireframe(wireframe_) {} + + PxVec3 minimum, maximum; + bool wireframe; + }; + PX_PHYSX_COMMON_API RenderOutput& operator<<(RenderOutput& out, const DebugBox& box); + + struct DebugArrow + { + DebugArrow(const PxVec3& pos, const PxVec3& vec) + : base(pos), tip(pos+vec), headLength(vec.magnitude()*0.15f) {} + + DebugArrow(const PxVec3& pos, const PxVec3& vec, PxReal headLength_) + : base(pos), tip(pos+vec), headLength(headLength_) {} + + PxVec3 base, tip; + PxReal headLength; + }; + PX_PHYSX_COMMON_API RenderOutput& operator<<(RenderOutput& out, const DebugArrow& arrow); + + struct DebugBasis + { + DebugBasis(const PxVec3& ext, PxU32 cX = PxDebugColor::eARGB_RED, + PxU32 cY = PxDebugColor::eARGB_GREEN, PxU32 cZ = PxDebugColor::eARGB_BLUE) + : extends(ext), colorX(cX), colorY(cY), colorZ(cZ) {} + PxVec3 extends; + PxU32 colorX, colorY, colorZ; + }; + PX_PHYSX_COMMON_API RenderOutput& operator<<(RenderOutput& out, const DebugBasis& basis); + +#if PX_VC + #pragma warning(pop) +#endif + + struct DebugCircle + { + DebugCircle(PxU32 s, PxReal r) + : nSegments(s), radius(r) {} + PxU32 nSegments; + PxReal radius; + }; + PX_PHYSX_COMMON_API RenderOutput& operator<<(RenderOutput& out, const DebugCircle& circle); + + struct DebugArc + { + DebugArc(PxU32 s, PxReal r, PxReal minAng, PxReal maxAng) + : nSegments(s), radius(r), minAngle(minAng), maxAngle(maxAng) {} + PxU32 nSegments; + PxReal radius; + PxReal minAngle, maxAngle; + }; + PX_PHYSX_COMMON_API RenderOutput& operator<<(RenderOutput& out, const DebugArc& arc); + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmScaling.h b/PhysX_3.4/Source/Common/src/CmScaling.h new file mode 100644 index 00000000..3753b678 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmScaling.h @@ -0,0 +1,227 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_SCALING +#define PX_PHYSICS_COMMON_SCALING + +#include "foundation/PxBounds3.h" +#include "foundation/PxMat33.h" +#include "geometry/PxMeshScale.h" +#include "CmMatrix34.h" +#include "CmUtils.h" +#include "PsMathUtils.h" + +namespace physx +{ +namespace Cm +{ + // class that can perform scaling fast. Relatively large size, generated from PxMeshScale on demand. + // CS: I've removed most usages of this class, because most of the time only one-way transform is needed. + // If you only need a temporary FastVertex2ShapeScaling, setup your transform as PxMat34Legacy and use + // normal matrix multiplication or a transform() overload to convert points and bounds between spaces. + class FastVertex2ShapeScaling + { + public: + PX_INLINE FastVertex2ShapeScaling() + { + //no scaling by default: + vertex2ShapeSkew = PxMat33(PxIdentity); + shape2VertexSkew = PxMat33(PxIdentity); + mFlipNormal = false; + } + + PX_INLINE explicit FastVertex2ShapeScaling(const PxMeshScale& scale) + { + init(scale); + } + + PX_INLINE FastVertex2ShapeScaling(const PxVec3& scale, const PxQuat& rotation) + { + init(scale, rotation); + } + + PX_INLINE void init(const PxMeshScale& scale) + { + init(scale.scale, scale.rotation); + } + + PX_INLINE void setIdentity() + { + vertex2ShapeSkew = PxMat33(PxIdentity); + shape2VertexSkew = PxMat33(PxIdentity); + mFlipNormal = false; + } + + PX_INLINE void init(const PxVec3& scale, const PxQuat& rotation) + { + // TODO: may want to optimize this for cases where we have uniform or axis aligned scaling! + // That would introduce branches and it's unclear to me whether that's faster than just doing the math. + // Lazy computation would be another option, at the cost of introducing even more branches. + + const PxMat33 R(rotation); + vertex2ShapeSkew = R.getTranspose(); + const PxMat33 diagonal = PxMat33::createDiagonal(scale); + vertex2ShapeSkew = vertex2ShapeSkew * diagonal; + vertex2ShapeSkew = vertex2ShapeSkew * R; + + /* + The inverse, is, explicitly: + shape2VertexSkew.setTransposed(R); + shape2VertexSkew.multiplyDiagonal(PxVec3(1.0f/scale.x, 1.0f/scale.y, 1.0f/scale.z)); + shape2VertexSkew *= R; + + It may be competitive to compute the inverse -- though this has a branch in it: + */ + + shape2VertexSkew = vertex2ShapeSkew.getInverse(); + + mFlipNormal = ((scale.x * scale.y * scale.z) < 0.0f); + } + + PX_FORCE_INLINE void flipNormal(PxVec3& v1, PxVec3& v2) const + { + if (mFlipNormal) + { + PxVec3 tmp = v1; v1 = v2; v2 = tmp; + } + } + + PX_FORCE_INLINE PxVec3 operator* (const PxVec3& src) const + { + return vertex2ShapeSkew * src; + } + PX_FORCE_INLINE PxVec3 operator% (const PxVec3& src) const + { + return shape2VertexSkew * src; + } + + PX_FORCE_INLINE const PxMat33& getVertex2ShapeSkew() const + { + return vertex2ShapeSkew; + } + + PX_FORCE_INLINE const PxMat33& getShape2VertexSkew() const + { + return shape2VertexSkew; + } + + PX_INLINE Cm::Matrix34 getVertex2WorldSkew(const Cm::Matrix34& shape2world) const + { + const Cm::Matrix34 vertex2worldSkew = shape2world * getVertex2ShapeSkew(); + //vertex2worldSkew = shape2world * [vertex2shapeSkew, 0] + //[aR at] * [bR bt] = [aR * bR aR * bt + at] NOTE: order of operations important so it works when this ?= left ?= right. + return vertex2worldSkew; + } + + PX_INLINE Cm::Matrix34 getWorld2VertexSkew(const Cm::Matrix34& shape2world) const + { + //world2vertexSkew = shape2vertex * invPQ(shape2world) + //[aR 0] * [bR' -bR'*bt] = [aR * bR' -aR * bR' * bt + 0] + + const PxMat33 rotate( shape2world[0], shape2world[1], shape2world[2] ); + const PxMat33 M = getShape2VertexSkew() * rotate.getTranspose(); + return Cm::Matrix34(M[0], M[1], M[2], -M * shape2world[3]); + } + + //! Transforms a shape space OBB to a vertex space OBB. All 3 params are in and out. + void transformQueryBounds(PxVec3& center, PxVec3& extents, PxMat33& basis) const + { + basis.column0 = shape2VertexSkew * (basis.column0 * extents.x); + basis.column1 = shape2VertexSkew * (basis.column1 * extents.y); + basis.column2 = shape2VertexSkew * (basis.column2 * extents.z); + + center = shape2VertexSkew * center; + extents = Ps::optimizeBoundingBox(basis); + } + + void transformPlaneToShapeSpace(const PxVec3& nIn, const PxReal dIn, PxVec3& nOut, PxReal& dOut) const + { + const PxVec3 tmp = shape2VertexSkew.transformTranspose(nIn); + const PxReal denom = 1.0f / tmp.magnitude(); + nOut = tmp * denom; + dOut = dIn * denom; + } + + PX_FORCE_INLINE bool flipsNormal() const { return mFlipNormal; } + + private: + PxMat33 vertex2ShapeSkew; + PxMat33 shape2VertexSkew; + bool mFlipNormal; + }; + + PX_FORCE_INLINE void getScaledVertices(PxVec3* v, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, bool idtMeshScale, const Cm::FastVertex2ShapeScaling& scaling) + { + if(idtMeshScale) + { + v[0] = v0; + v[1] = v1; + v[2] = v2; + } + else + { + const PxI32 winding = scaling.flipsNormal() ? 1 : 0; + v[0] = scaling * v0; + v[1+winding] = scaling * v1; + v[2-winding] = scaling * v2; + } + } + +} // namespace Cm + + +PX_INLINE Cm::Matrix34 operator*(const PxTransform& transform, const PxMeshScale& scale) +{ + return Cm::Matrix34(PxMat33(transform.q) * scale.toMat33(), transform.p); +} + +PX_INLINE Cm::Matrix34 operator*(const PxMeshScale& scale, const PxTransform& transform) +{ + const PxMat33 scaleMat = scale.toMat33(); + const PxMat33 t = PxMat33(transform.q); + const PxMat33 r = scaleMat * t; + const PxVec3 p = scaleMat * transform.p; + return Cm::Matrix34(r, p); +} + +PX_INLINE Cm::Matrix34 operator*(const Cm::Matrix34& transform, const PxMeshScale& scale) +{ + return Cm::Matrix34(transform.m * scale.toMat33(), transform.p); +} + +PX_INLINE Cm::Matrix34 operator*(const PxMeshScale& scale, const Cm::Matrix34& transform) +{ + const PxMat33 scaleMat = scale.toMat33(); + return Cm::Matrix34(scaleMat * transform.m, scaleMat * transform.p); +} + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmSpatialVector.h b/PhysX_3.4/Source/Common/src/CmSpatialVector.h new file mode 100644 index 00000000..4f140d4e --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmSpatialVector.h @@ -0,0 +1,184 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_VECTOR +#define PX_PHYSICS_COMMON_VECTOR + +#include "foundation/PxVec3.h" +#include "CmPhysXCommon.h" +#include "PsVecMath.h" + +/*! +Combination of two R3 vectors. +*/ + +namespace physx +{ +namespace Cm +{ +PX_ALIGN_PREFIX(16) +class SpatialVector +{ +public: + //! Default constructor + PX_FORCE_INLINE SpatialVector() + {} + + //! Construct from two PxcVectors + PX_FORCE_INLINE SpatialVector(const PxVec3& lin, const PxVec3& ang) + : linear(lin), pad0(0.0f), angular(ang), pad1(0.0f) + { + } + + PX_FORCE_INLINE ~SpatialVector() + {} + + + + // PT: this one is very important. Without it, the Xbox compiler generates weird "float-to-int" and "int-to-float" LHS + // each time we copy a SpatialVector (see for example PIX on "solveSimpleGroupA" without this operator). + PX_FORCE_INLINE void operator = (const SpatialVector& v) + { + linear = v.linear; + pad0 = 0.0f; + angular = v.angular; + pad1 = 0.0f; + } + + + static PX_FORCE_INLINE SpatialVector zero() { return SpatialVector(PxVec3(0),PxVec3(0)); } + + PX_FORCE_INLINE SpatialVector operator+(const SpatialVector& v) const + { + return SpatialVector(linear+v.linear,angular+v.angular); + } + + PX_FORCE_INLINE SpatialVector operator-(const SpatialVector& v) const + { + return SpatialVector(linear-v.linear,angular-v.angular); + } + + PX_FORCE_INLINE SpatialVector operator-() const + { + return SpatialVector(-linear,-angular); + } + + + PX_FORCE_INLINE SpatialVector operator *(PxReal s) const + { + return SpatialVector(linear*s,angular*s); + } + + PX_FORCE_INLINE void operator+=(const SpatialVector& v) + { + linear+=v.linear; + angular+=v.angular; + } + + PX_FORCE_INLINE void operator-=(const SpatialVector& v) + { + linear-=v.linear; + angular-=v.angular; + } + + PX_FORCE_INLINE PxReal magnitude() const + { + return angular.magnitude() + linear.magnitude(); + } + + PX_FORCE_INLINE PxReal dot(const SpatialVector& v) const + { + return linear.dot(v.linear) + angular.dot(v.angular); + } + + PX_FORCE_INLINE bool isFinite() const + { + return linear.isFinite() && angular.isFinite(); + } + + PX_FORCE_INLINE Cm::SpatialVector scale(PxReal l, PxReal a) const + { + return Cm::SpatialVector(linear*l, angular*a); + } + + PxVec3 linear; + PxReal pad0; + PxVec3 angular; + PxReal pad1; +} +PX_ALIGN_SUFFIX(16); + + +PX_ALIGN_PREFIX(16) +struct SpatialVectorV +{ + Ps::aos::Vec3V linear; + Ps::aos::Vec3V angular; + + PX_FORCE_INLINE SpatialVectorV() {} + PX_FORCE_INLINE SpatialVectorV(PxZERO): linear(Ps::aos::V3Zero()), angular(Ps::aos::V3Zero()) {} + PX_FORCE_INLINE SpatialVectorV(const Cm::SpatialVector& v): linear(Ps::aos::V3LoadU(v.linear)), angular(Ps::aos::V3LoadU(v.angular)) {} + PX_FORCE_INLINE SpatialVectorV(const Ps::aos::Vec3VArg l, const Ps::aos::Vec3VArg a): linear(l), angular(a) {} + PX_FORCE_INLINE SpatialVectorV(const SpatialVectorV& other): linear(other.linear), angular(other.angular) {} + PX_FORCE_INLINE SpatialVectorV& operator=(const SpatialVectorV& other) { linear = other.linear; angular = other.angular; return *this; } + + PX_FORCE_INLINE SpatialVectorV operator+(const SpatialVectorV& other) const { return SpatialVectorV(Ps::aos::V3Add(linear,other.linear), + Ps::aos::V3Add(angular, other.angular)); } + + PX_FORCE_INLINE SpatialVectorV& operator+=(const SpatialVectorV& other) { linear = Ps::aos::V3Add(linear,other.linear); + angular = Ps::aos::V3Add(angular, other.angular); + return *this; + } + + PX_FORCE_INLINE SpatialVectorV operator-(const SpatialVectorV& other) const { return SpatialVectorV(Ps::aos::V3Sub(linear,other.linear), + Ps::aos::V3Sub(angular, other.angular)); } + + PX_FORCE_INLINE SpatialVectorV operator-() const { return SpatialVectorV(Ps::aos::V3Neg(linear), Ps::aos::V3Neg(angular)); } + + PX_FORCE_INLINE SpatialVectorV operator*(Ps::aos::FloatVArg r) const { return SpatialVectorV(Ps::aos::V3Scale(linear,r), Ps::aos::V3Scale(angular,r)); } + + PX_FORCE_INLINE SpatialVectorV& operator-=(const SpatialVectorV& other) { linear = Ps::aos::V3Sub(linear,other.linear); + angular = Ps::aos::V3Sub(angular, other.angular); + return *this; + } + + PX_FORCE_INLINE Ps::aos::FloatV dot(const SpatialVectorV& other) const { return Ps::aos::FAdd(Ps::aos::V3Dot(linear, other.linear), Ps::aos::V3Dot(angular, other.angular)); } + + +}PX_ALIGN_SUFFIX(16); + +} // namespace Cm + +PX_COMPILE_TIME_ASSERT(sizeof(Cm::SpatialVector) == 32); +PX_COMPILE_TIME_ASSERT(sizeof(Cm::SpatialVectorV) == 32); + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmTask.h b/PhysX_3.4/Source/Common/src/CmTask.h new file mode 100644 index 00000000..84186b59 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmTask.h @@ -0,0 +1,257 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_TASK +#define PX_PHYSICS_COMMON_TASK + +#include "task/PxTask.h" +#include "CmPhysXCommon.h" +#include "PsUserAllocated.h" +#include "PsAtomic.h" +#include "PsMutex.h" +#include "PsInlineArray.h" +#include "PsFPU.h" + +namespace physx +{ +namespace Cm +{ + // wrapper around the public PxLightCpuTask + // internal SDK tasks should be inherited from + // this and override the runInternal() method + // to ensure that the correct floating point + // state is set / reset during execution + class Task : public physx::PxLightCpuTask + { + public: + + virtual void run() + { + PX_SIMD_GUARD; + runInternal(); + } + + virtual void runInternal()=0; + }; + + // same as Cm::Task but inheriting from physx::PxBaseTask + // instead of PxLightCpuTask + class BaseTask : public physx::PxBaseTask + { + public: + + virtual void run() + { + PX_SIMD_GUARD; + runInternal(); + } + + virtual void runInternal()=0; + }; + + template <class T, void (T::*Fn)(physx::PxBaseTask*) > + class DelegateTask : public Cm::Task, public shdfnd::UserAllocated + { + public: + + DelegateTask(T* obj, const char* name) : + mObj(obj), mName(name) { } + + virtual void runInternal() + { + (mObj->*Fn)(mCont); + } + + virtual const char* getName() const + { + return mName; + } + + void setObject(T* obj) { mObj = obj; } + + private: + T* mObj; + const char* mName; + }; + + + /** + \brief A task that maintains a list of dependent tasks. + + This task maintains a list of dependent tasks that have their reference counts + reduced on completion of the task. + + The refcount is incremented every time a dependent task is added. + */ + class FanoutTask : public Cm::BaseTask + { + PX_NOCOPY(FanoutTask) + public: + FanoutTask(const char* name) : Cm::BaseTask(), mRefCount(0), mName(name), mNotifySubmission(false) {} + + virtual void runInternal() {} + + virtual const char* getName() const { return mName; } + + /** + Swap mDependents with mReferencesToRemove when refcount goes to 0. + */ + virtual void removeReference() + { + shdfnd::Mutex::ScopedLock lock(mMutex); + if (!physx::shdfnd::atomicDecrement(&mRefCount)) + { + // prevents access to mReferencesToRemove until release + physx::shdfnd::atomicIncrement(&mRefCount); + mNotifySubmission = false; + PX_ASSERT(mReferencesToRemove.empty()); + for (PxU32 i = 0; i < mDependents.size(); i++) + mReferencesToRemove.pushBack(mDependents[i]); + mDependents.clear(); + mTm->getCpuDispatcher()->submitTask(*this); + } + } + + /** + \brief Increases reference count + */ + virtual void addReference() + { + shdfnd::Mutex::ScopedLock lock(mMutex); + physx::shdfnd::atomicIncrement(&mRefCount); + mNotifySubmission = true; + } + + /** + \brief Return the ref-count for this task + */ + PX_INLINE PxI32 getReference() const + { + return mRefCount; + } + + /** + Sets the task manager. Doesn't increase the reference count. + */ + PX_INLINE void setTaskManager(physx::PxTaskManager& tm) + { + mTm = &tm; + } + + /** + Adds a dependent task. It also sets the task manager querying it from the dependent task. + The refcount is incremented every time a dependent task is added. + */ + PX_INLINE void addDependent(physx::PxBaseTask& dependent) + { + shdfnd::Mutex::ScopedLock lock(mMutex); + physx::shdfnd::atomicIncrement(&mRefCount); + mTm = dependent.getTaskManager(); + mDependents.pushBack(&dependent); + dependent.addReference(); + mNotifySubmission = true; + } + + /** + Reduces reference counts of the continuation task and the dependent tasks, also + clearing the copy of continuation and dependents task list. + */ + virtual void release() + { + Ps::InlineArray<physx::PxBaseTask*, 10> referencesToRemove; + + { + shdfnd::Mutex::ScopedLock lock(mMutex); + + const PxU32 contCount = mReferencesToRemove.size(); + referencesToRemove.reserve(contCount); + for (PxU32 i=0; i < contCount; ++i) + referencesToRemove.pushBack(mReferencesToRemove[i]); + + mReferencesToRemove.clear(); + // allow access to mReferencesToRemove again + if (mNotifySubmission) + { + removeReference(); + } + else + { + physx::shdfnd::atomicDecrement(&mRefCount); + } + + // the scoped lock needs to get freed before the continuation tasks get (potentially) submitted because + // those continuation tasks might trigger events that delete this task and corrupt the memory of the + // mutex (for example, assume this task is a member of the scene then the submitted tasks cause the simulation + // to finish and then the scene gets released which in turn will delete this task. When this task then finally + // continues the heap memory will be corrupted. + } + + for (PxU32 i=0; i < referencesToRemove.size(); ++i) + referencesToRemove[i]->removeReference(); + } + + protected: + volatile PxI32 mRefCount; + const char* mName; + Ps::InlineArray<physx::PxBaseTask*, 4> mDependents; + Ps::InlineArray<physx::PxBaseTask*, 4> mReferencesToRemove; + bool mNotifySubmission; + Ps::Mutex mMutex; // guarding mDependents and mNotifySubmission + }; + + + /** + \brief Specialization of FanoutTask class in order to provide the delegation mechanism. + */ + template <class T, void (T::*Fn)(physx::PxBaseTask*) > + class DelegateFanoutTask : public FanoutTask, public shdfnd::UserAllocated + { + public: + + DelegateFanoutTask(T* obj, const char* name) : + FanoutTask(name), mObj(obj) { } + + virtual void runInternal() + { + physx::PxBaseTask* continuation = mReferencesToRemove.empty() ? NULL : mReferencesToRemove[0]; + (mObj->*Fn)(continuation); + } + + void setObject(T* obj) { mObj = obj; } + + private: + T* mObj; + }; + +} // namespace Cm + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmTaskPool.h b/PhysX_3.4/Source/Common/src/CmTaskPool.h new file mode 100644 index 00000000..34e6f086 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmTaskPool.h @@ -0,0 +1,143 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_TASKPOOL +#define PX_PHYSICS_COMMON_TASKPOOL + +#include "foundation/Px.h" +#include "PsMutex.h" +#include "PsSList.h" +#include "PsAllocator.h" +#include "PsArray.h" + +class PxTask; + +/* +Implimentation of a thread safe task pool. (PxTask derived classes). + +T is the actual type of the task(currently NphaseTask or GroupSolveTask). +*/ + +namespace Cm +{ + template<class T> class TaskPool : public Ps::AlignedAllocator<16> + { + const static PxU32 TaskPoolSlabSize=64; + + public: + + typedef Ps::SListEntry TaskPoolItem; + + PX_INLINE TaskPool() : slabArray(PX_DEBUG_EXP("taskPoolSlabArray")) + { + //we have to ensure that the list header is 16byte aligned for win64. + freeTasks = (Ps::SList*)allocate(sizeof(Ps::SList), __FILE__, __LINE__); + PX_PLACEMENT_NEW(freeTasks, Ps::SList)(); + + slabArray.reserve(16); + } + + ~TaskPool() + { + Ps::Mutex::ScopedLock lock(slabAllocMutex); + + freeTasks->flush(); + + for(PxU32 i=0;i<slabArray.size();i++) + { + // call destructors + for(PxU32 j=0; j<TaskPoolSlabSize; j++) + slabArray[i][j].~T(); + + deallocate(slabArray[i]); + } + + slabArray.clear(); + + if(freeTasks!=NULL) + { + freeTasks->~SList(); + deallocate(freeTasks); + freeTasks = NULL; + } + } + + T *allocTask() + { + T *rv = static_cast<T *>(freeTasks->pop()); + if(rv == NULL) + return static_cast<T *>(allocateSlab()); + else + return rv; + } + void freeTask(T *task) + { + freeTasks->push(*task); + } + + private: + + T *allocateSlab() + { + //ack, convoluted memory macros. + + //T *newSlab=new T[TaskPoolSlabSize]; + + // we must align this memory. + T *newSlab=(T *)allocate(sizeof(T)*TaskPoolSlabSize, __FILE__, __LINE__); + + new (newSlab) T(); + + //we keep one for the caller + // and build a list of tasks and insert in the free list + for(PxU32 i=1;i<TaskPoolSlabSize;i++) + { + new (&(newSlab[i])) T(); + freeTasks->push(newSlab[i]); + } + + Ps::Mutex::ScopedLock lock(slabAllocMutex); + slabArray.pushBack(newSlab); + + return newSlab; + } + + Ps::Mutex slabAllocMutex; + Ps::Array<T *> slabArray; + + Ps::SList *freeTasks; + + }; + + +} // namespace Cm + + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmTmpMem.h b/PhysX_3.4/Source/Common/src/CmTmpMem.h new file mode 100644 index 00000000..998590b9 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmTmpMem.h @@ -0,0 +1,94 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_TMPMEM +#define PX_PHYSICS_COMMON_TMPMEM + +#include "CmPhysXCommon.h" +#include "PsAllocator.h" + +namespace physx +{ +namespace Cm +{ + // dsequeira: we should be able to use PX_ALLOCA or Ps::InlineArray for this, but both seem slightly flawed: + // + // PX_ALLOCA has non-configurable fallback threshold and uses _alloca, which means the allocation is necessarily + // function-scope rather than block-scope (sometimes useful, mostly not.) + // + // Ps::InlineArray touches all memory on resize (a general flaw in the array class which badly needs fixing) + // + // Todo: fix both the above issues. + + template<typename T, PxU32 stackLimit> + class TmpMem + { + + public: + PX_FORCE_INLINE TmpMem(PxU32 size): + mPtr(size<=stackLimit?mStackBuf : reinterpret_cast<T*>(PX_ALLOC(size*sizeof(T), "char"))) + { + } + + PX_FORCE_INLINE ~TmpMem() + { + if(mPtr!=mStackBuf) + PX_FREE(mPtr); + } + + PX_FORCE_INLINE T& operator*() const + { + return *mPtr; + } + + PX_FORCE_INLINE T* operator->() const + { + return mPtr; + } + + PX_FORCE_INLINE T& operator[](PxU32 index) + { + return mPtr[index]; + } + + T* getBase() + { + return mPtr; + } + + private: + T mStackBuf[stackLimit]; + T* mPtr; + }; +} + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmTransformUtils.h b/PhysX_3.4/Source/Common/src/CmTransformUtils.h new file mode 100644 index 00000000..ddb84b1a --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmTransformUtils.h @@ -0,0 +1,145 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_TRANSFORMUTILS +#define PX_PHYSICS_COMMON_TRANSFORMUTILS + +#include "PsVecMath.h" + +namespace +{ + +using namespace physx::shdfnd::aos; + +// V3PrepareCross would help here, but it's not on all platforms yet... + +PX_FORCE_INLINE void transformFast(const FloatVArg wa, const Vec3VArg va, const Vec3VArg pa, + const FloatVArg wb, const Vec3VArg vb, const Vec3VArg pb, + FloatV& wo, Vec3V& vo, Vec3V& po) +{ + wo = FSub(FMul(wa, wb), V3Dot(va, vb)); + vo = V3ScaleAdd(va, wb, V3ScaleAdd(vb, wa, V3Cross(va, vb))); + + const Vec3V t1 = V3Scale(pb, FScaleAdd(wa, wa, FLoad(-0.5f))); + const Vec3V t2 = V3ScaleAdd(V3Cross(va, pb), wa, t1); + const Vec3V t3 = V3ScaleAdd(va, V3Dot(va, pb), t2); + + po = V3ScaleAdd(t3, FLoad(2.f), pa); +} + +PX_FORCE_INLINE void transformInvFast(const FloatVArg wa, const Vec3VArg va, const Vec3VArg pa, + const FloatVArg wb, const Vec3VArg vb, const Vec3VArg pb, + FloatV& wo, Vec3V& vo, Vec3V& po) +{ + wo = FScaleAdd(wa, wb, V3Dot(va, vb)); + vo = V3NegScaleSub(va, wb, V3ScaleAdd(vb, wa, V3Cross(vb, va))); + + const Vec3V pt = V3Sub(pb, pa); + const Vec3V t1 = V3Scale(pt, FScaleAdd(wa, wa, FLoad(-0.5f))); + const Vec3V t2 = V3ScaleAdd(V3Cross(pt, va), wa, t1); + const Vec3V t3 = V3ScaleAdd(va, V3Dot(va, pt), t2); + po = V3Add(t3,t3); +} + +} + + + + + +namespace physx +{ +namespace Cm +{ + +PX_FORCE_INLINE void getStaticGlobalPoseAligned(const PxTransform& actor2World, const PxTransform& shape2Actor, PxTransform& outTransform) +{ + using namespace shdfnd::aos; + + PX_ASSERT((size_t(&actor2World)&15) == 0); + PX_ASSERT((size_t(&shape2Actor)&15) == 0); + PX_ASSERT((size_t(&outTransform)&15) == 0); + + const Vec3V actor2WorldPos = V3LoadA(actor2World.p); + const QuatV actor2WorldRot = QuatVLoadA(&actor2World.q.x); + + const Vec3V shape2ActorPos = V3LoadA(shape2Actor.p); + const QuatV shape2ActorRot = QuatVLoadA(&shape2Actor.q.x); + + Vec3V v,p; + FloatV w; + + transformFast(V4GetW(actor2WorldRot), Vec3V_From_Vec4V(actor2WorldRot), actor2WorldPos, + V4GetW(shape2ActorRot), Vec3V_From_Vec4V(shape2ActorRot), shape2ActorPos, + w, v, p); + + V3StoreA(p, outTransform.p); + V4StoreA(V4SetW(v,w), &outTransform.q.x); +} + + +PX_FORCE_INLINE void getDynamicGlobalPoseAligned(const PxTransform& body2World, const PxTransform& shape2Actor, const PxTransform& body2Actor, PxTransform& outTransform) +{ + PX_ASSERT((size_t(&body2World)&15) == 0); + PX_ASSERT((size_t(&shape2Actor)&15) == 0); + PX_ASSERT((size_t(&body2Actor)&15) == 0); + PX_ASSERT((size_t(&outTransform)&15) == 0); + + using namespace shdfnd::aos; + + const Vec3V shape2ActorPos = V3LoadA(shape2Actor.p); + const QuatV shape2ActorRot = QuatVLoadA(&shape2Actor.q.x); + + const Vec3V body2ActorPos = V3LoadA(body2Actor.p); + const QuatV body2ActorRot = QuatVLoadA(&body2Actor.q.x); + + const Vec3V body2WorldPos = V3LoadA(body2World.p); + const QuatV body2WorldRot = QuatVLoadA(&body2World.q.x); + + Vec3V v1, p1, v2, p2; + FloatV w1, w2; + + transformInvFast(V4GetW(body2ActorRot), Vec3V_From_Vec4V(body2ActorRot), body2ActorPos, + V4GetW(shape2ActorRot), Vec3V_From_Vec4V(shape2ActorRot), shape2ActorPos, + w1, v1, p1); + + transformFast(V4GetW(body2WorldRot), Vec3V_From_Vec4V(body2WorldRot), body2WorldPos, + w1, v1, p1, + w2, v2, p2); + + V3StoreA(p2, outTransform.p); + V4StoreA(V4SetW(v2, w2), &outTransform.q.x); +} + + +} +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmUtils.h b/PhysX_3.4/Source/Common/src/CmUtils.h new file mode 100644 index 00000000..ad911fd7 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmUtils.h @@ -0,0 +1,293 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_UTILS +#define PX_PHYSICS_COMMON_UTILS + + +#include "foundation/PxVec3.h" +#include "foundation/PxMat33.h" +#include "foundation/PxBounds3.h" +#include "CmPhysXCommon.h" +#include "PxBase.h" +#include "PsInlineArray.h" +#include "PsArray.h" +#include "PsAllocator.h" + +namespace physx +{ +namespace Cm +{ + +template<class DstType, class SrcType> +PX_FORCE_INLINE PxU32 getArrayOfPointers(DstType** PX_RESTRICT userBuffer, PxU32 bufferSize, PxU32 startIndex, SrcType*const* PX_RESTRICT src, PxU32 size) +{ + const PxU32 remainder = PxU32(PxMax<PxI32>(PxI32(size - startIndex), 0)); + const PxU32 writeCount = PxMin(remainder, bufferSize); + src += startIndex; + for(PxU32 i=0;i<writeCount;i++) + userBuffer[i] = static_cast<DstType*>(src[i]); + return writeCount; +} + +PX_INLINE void transformInertiaTensor(const PxVec3& invD, const PxMat33& M, PxMat33& mIInv) +{ + const float axx = invD.x*M(0,0), axy = invD.x*M(1,0), axz = invD.x*M(2,0); + const float byx = invD.y*M(0,1), byy = invD.y*M(1,1), byz = invD.y*M(2,1); + const float czx = invD.z*M(0,2), czy = invD.z*M(1,2), czz = invD.z*M(2,2); + + mIInv(0,0) = axx*M(0,0) + byx*M(0,1) + czx*M(0,2); + mIInv(1,1) = axy*M(1,0) + byy*M(1,1) + czy*M(1,2); + mIInv(2,2) = axz*M(2,0) + byz*M(2,1) + czz*M(2,2); + + mIInv(0,1) = mIInv(1,0) = axx*M(1,0) + byx*M(1,1) + czx*M(1,2); + mIInv(0,2) = mIInv(2,0) = axx*M(2,0) + byx*M(2,1) + czx*M(2,2); + mIInv(1,2) = mIInv(2,1) = axy*M(2,0) + byy*M(2,1) + czy*M(2,2); +} + +// PT: TODO: refactor this with PxBounds3 header +PX_FORCE_INLINE PxVec3 basisExtent(const PxVec3& basis0, const PxVec3& basis1, const PxVec3& basis2, const PxVec3& extent) +{ + // extended basis vectors + const PxVec3 c0 = basis0 * extent.x; + const PxVec3 c1 = basis1 * extent.y; + const PxVec3 c2 = basis2 * extent.z; + + // find combination of base vectors that produces max. distance for each component = sum of abs() + return PxVec3 ( PxAbs(c0.x) + PxAbs(c1.x) + PxAbs(c2.x), + PxAbs(c0.y) + PxAbs(c1.y) + PxAbs(c2.y), + PxAbs(c0.z) + PxAbs(c1.z) + PxAbs(c2.z)); +} + +PX_FORCE_INLINE PxBounds3 basisExtent(const PxVec3& center, const PxVec3& basis0, const PxVec3& basis1, const PxVec3& basis2, const PxVec3& extent) +{ + const PxVec3 w = basisExtent(basis0, basis1, basis2, extent); + return PxBounds3(center - w, center + w); +} + +PX_FORCE_INLINE bool isValid(const PxVec3& c, const PxVec3& e) +{ + return (c.isFinite() && e.isFinite() && (((e.x >= 0.0f) && (e.y >= 0.0f) && (e.z >= 0.0f)) || + ((e.x == -PX_MAX_BOUNDS_EXTENTS) && + (e.y == -PX_MAX_BOUNDS_EXTENTS) && + (e.z == -PX_MAX_BOUNDS_EXTENTS)))); +} + +PX_FORCE_INLINE bool isEmpty(const PxVec3& c, const PxVec3& e) +{ + PX_UNUSED(c); + PX_ASSERT(isValid(c, e)); + return e.x<0.0f; +} + +// Array with externally managed storage. +// Allocation and resize policy are managed by the owner, +// Very minimal functionality right now, just POD types + +template <typename T, + typename Owner, + typename IndexType, + void (Owner::*realloc)(T*& currentMem, IndexType& currentCapacity, IndexType size, IndexType requiredMinCapacity)> +class OwnedArray +{ +public: + OwnedArray() + : mData(0) + , mCapacity(0) + , mSize(0) + {} + + ~OwnedArray() // owner must call releaseMem before destruction + { + PX_ASSERT(mCapacity==0); + } + + void pushBack(T& element, Owner& owner) + { + // there's a failure case if here if we push an existing element which causes a resize - + // a rare case not worth coding around; if you need it, copy the element then push it. + + PX_ASSERT(&element<mData || &element>=mData+mSize); + if(mSize==mCapacity) + (owner.*realloc)(mData, mCapacity, mSize, PxU16(mSize+1)); + + PX_ASSERT(mData && mSize<mCapacity); + mData[mSize++] = element; + } + + IndexType size() const + { + return mSize; + } + + void replaceWithLast(IndexType index) + { + PX_ASSERT(index<mSize); + mData[index] = mData[--mSize]; + } + + T* begin() const + { + return mData; + } + + T* end() const + { + return mData+mSize; + } + + T& operator [](IndexType index) + { + PX_ASSERT(index<mSize); + return mData[index]; + } + + const T& operator [](IndexType index) const + { + PX_ASSERT(index<mSize); + return mData[index]; + } + + void reserve(IndexType capacity, Owner &owner) + { + if(capacity>=mCapacity) + (owner.*realloc)(mData, mCapacity, mSize, capacity); + } + + void releaseMem(Owner &owner) + { + mSize = 0; + (owner.*realloc)(mData, mCapacity, 0, 0); + } + +private: + T* mData; + IndexType mCapacity; + IndexType mSize; + + // just in case someone tries to use a non-POD in here + union FailIfNonPod + { + T t; + int x; + }; +}; + +/** +Any object deriving from PxBase needs to call this function instead of 'delete object;'. + +We don't want implement 'operator delete' in PxBase because that would impose how +memory of derived classes is allocated. Even though most or all of the time derived classes will +be user allocated, we don't want to put UserAllocatable into the API and derive from that. +*/ +template<typename T> +PX_INLINE void deletePxBase(T* object) +{ + if(object->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + PX_DELETE(object); + else + object->~T(); +} + +#if PX_CHECKED +/** +Mark a specified amount of memory with 0xcd pattern. This is used to check that the meta data +definition for serialized classes is complete in checked builds. +*/ +PX_INLINE void markSerializedMem(void* ptr, PxU32 byteSize) +{ + for (PxU32 i = 0; i < byteSize; ++i) + reinterpret_cast<PxU8*>(ptr)[i] = 0xcd; +} + +/** +Macro to instantiate a type for serialization testing. +Note: Only use PX_NEW_SERIALIZED once in a scope. +*/ +#define PX_NEW_SERIALIZED(v,T) \ + void* _buf = physx::shdfnd::ReflectionAllocator<T>().allocate(sizeof(T),__FILE__,__LINE__); \ + Cm::markSerializedMem(_buf, sizeof(T)); \ + v = PX_PLACEMENT_NEW(_buf, T) + +#else +PX_INLINE void markSerializedMem(void*, PxU32){} + +#define PX_NEW_SERIALIZED(v,T) v = PX_NEW(T) +#endif + +template<typename T, class Alloc> +struct ArrayAccess: public Ps::Array<T, Alloc> +{ + void store(PxSerializationContext& context) const + { + if(this->mData && (this->mSize || this->capacity())) + context.writeData(this->mData, this->capacity()*sizeof(T)); + } + + void load(PxDeserializationContext& context) + { + if(this->mData && (this->mSize || this->capacity())) + this->mData = context.readExtraData<T>(this->capacity()); + } +}; + +template<typename T, typename Alloc> +void exportArray(const Ps::Array<T, Alloc>& a, PxSerializationContext& context) +{ + static_cast<const ArrayAccess<T, Alloc>&>(a).store(context); +} + +template<typename T, typename Alloc> +void importArray(Ps::Array<T, Alloc>& a, PxDeserializationContext& context) +{ + static_cast<ArrayAccess<T, Alloc>&>(a).load(context); +} + +template<typename T, PxU32 N, typename Alloc> +void exportInlineArray(const Ps::InlineArray<T, N, Alloc>& a, PxSerializationContext& context) +{ + if(!a.isInlined()) + Cm::exportArray(a, context); +} + +template<typename T, PxU32 N, typename Alloc> +void importInlineArray(Ps::InlineArray<T, N, Alloc>& a, PxDeserializationContext& context) +{ + if(!a.isInlined()) + Cm::importArray(a, context); +} + +} // namespace Cm + + + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/CmVisualization.cpp b/PhysX_3.4/Source/Common/src/CmVisualization.cpp new file mode 100644 index 00000000..3fdfec85 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmVisualization.cpp @@ -0,0 +1,159 @@ +// 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/PxTransform.h" +#include "CmPhysXCommon.h" +#include "CmRenderOutput.h" +#include "CmVisualization.h" + +using namespace physx; +using namespace Cm; + +void Cm::visualizeJointFrames(RenderOutput& out, + PxReal scale, + const PxTransform& parent, + const PxTransform& child) +{ + if(scale==0.0f) + return; + + out << parent << Cm::DebugBasis(PxVec3(scale, scale, scale) * 1.5f, + PxU32(PxDebugColor::eARGB_DARKRED), PxU32(PxDebugColor::eARGB_DARKGREEN), PxU32(PxDebugColor::eARGB_DARKBLUE)); + out << child << Cm::DebugBasis(PxVec3(scale, scale, scale)); +} + +void Cm::visualizeLinearLimit(RenderOutput& out, + PxReal scale, + const PxTransform& t0, + const PxTransform& /*t1*/, + PxReal value, + bool active) +{ + if(scale==0.0f) + return; + + // debug circle is around z-axis, and we want it around x-axis + PxTransform r(t0.p+value*t0.q.getBasisVector0(), t0.q*PxQuat(PxPi/2,PxVec3(0,1.f,0))); + out << (active ? PxDebugColor::eARGB_RED : PxDebugColor::eARGB_GREY); + out << PxTransform(PxIdentity); + out << Cm::DebugArrow(t0.p,r.p); + + out << r << Cm::DebugCircle(20, scale*0.3f); +} + +void Cm::visualizeAngularLimit(RenderOutput& out, + PxReal scale, + const PxTransform& t, + PxReal lower, + PxReal upper, + bool active) +{ + if(scale==0.0f) + return; + + out << t << (active ? PxDebugColor::eARGB_RED : PxDebugColor::eARGB_GREY); + + out << Cm::RenderOutput::LINES + << PxVec3(0) << PxVec3(0, PxCos(lower), PxSin(lower)) * scale + << PxVec3(0) << PxVec3(0, PxCos(upper), PxSin(upper)) * scale; + + out << Cm::RenderOutput::LINESTRIP; + PxReal angle = lower, step = (upper-lower)/20; + + for(PxU32 i=0; i<=20; i++, angle += step) + out << PxVec3(0, PxCos(angle), PxSin(angle)) * scale; +} + +void Cm::visualizeLimitCone(RenderOutput& out, + PxReal scale, + const PxTransform& t, + PxReal tanQSwingY, + PxReal tanQSwingZ, + bool active) +{ + if(scale==0.0f) + return; + + out << t << (active ? PxDebugColor::eARGB_RED : PxDebugColor::eARGB_GREY); + out << Cm::RenderOutput::LINES; + + PxVec3 prev(0,0,0); + + const int LINES = 32; + + for(PxU32 i=0;i<=32;i++) + { + PxReal angle = 2*PxPi/LINES*i; + PxReal c = PxCos(angle), s = PxSin(angle); + PxVec3 rv(0,-tanQSwingZ*s, tanQSwingY*c); + PxReal rv2 = rv.magnitudeSquared(); + PxQuat q = PxQuat(0,2*rv.y,2*rv.z,1-rv2) * (1/(1+rv2)); + PxVec3 a = q.rotate(PxVec3(1.0f,0,0)) * scale; + + out << prev << a << PxVec3(0) << a; + prev = a; + } +} + +void Cm::visualizeDoubleCone(Cm::RenderOutput& out, + PxReal scale, + const PxTransform& t, + PxReal angle, + bool active) +{ + if(scale==0.0f) + return; + + out << t << (active ? PxDebugColor::eARGB_RED : PxDebugColor::eARGB_GREY); + + const PxReal height = PxSin(angle);//, radius = cos(angle); + + const PxU32 LINES = 32; + + out << Cm::RenderOutput::LINESTRIP; + + const PxReal step = PxPi*2/LINES; + + for(PxU32 i=0; i<=LINES; i++) + out << PxVec3(height, PxCos(step * i), PxSin(step * i)) * scale; + + angle = 0; + out << Cm::RenderOutput::LINESTRIP; + for(PxU32 i=0; i<=LINES; i++, angle += PxPi*2/LINES) + out << PxVec3(-height, PxCos(step * i), PxSin(step * i)) * scale; + + angle = 0; + out << Cm::RenderOutput::LINES; + for(PxU32 i=0;i<LINES;i++, angle += PxPi*2/LINES) + { + out << PxVec3(0) << PxVec3(-height, PxCos(step * i), PxSin(step * i)) * scale; + out << PxVec3(0) << PxVec3(height, PxCos(step * i), PxSin(step * i)) * scale; + } +} + diff --git a/PhysX_3.4/Source/Common/src/CmVisualization.h b/PhysX_3.4/Source/Common/src/CmVisualization.h new file mode 100644 index 00000000..ecedfb17 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/CmVisualization.h @@ -0,0 +1,125 @@ +// 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. + + +#ifndef PX_PHYSICS_COMMON_VISUALIZATION +#define PX_PHYSICS_COMMON_VISUALIZATION + +#include "foundation/PxTransform.h" +#include "CmPhysXCommon.h" +#include "PxConstraintDesc.h" + +namespace physx +{ + +class RenderOutput; + +namespace Cm +{ + PX_PHYSX_COMMON_API void visualizeJointFrames(RenderOutput& out, + PxReal scale, + const PxTransform& parent, + const PxTransform& child); + + PX_PHYSX_COMMON_API void visualizeLinearLimit(RenderOutput& out, + PxReal scale, + const PxTransform& t0, + const PxTransform& t1, + PxReal value, + bool active); + + PX_PHYSX_COMMON_API void visualizeAngularLimit(RenderOutput& out, + PxReal scale, + const PxTransform& t0, + PxReal lower, + PxReal upper, + bool active); + + + PX_PHYSX_COMMON_API void visualizeLimitCone(RenderOutput& out, + PxReal scale, + const PxTransform& t, + PxReal ySwing, + PxReal zSwing, + bool active); + + PX_PHYSX_COMMON_API void visualizeDoubleCone(RenderOutput& out, + PxReal scale, + const PxTransform& t, + PxReal angle, + bool active); + + + struct ConstraintImmediateVisualizer : public PxConstraintVisualizer + { + PxF32 mFrameScale; + PxF32 mLimitScale; + RenderOutput& mCmOutput; + + //Not possible to implement + ConstraintImmediateVisualizer& operator=( const ConstraintImmediateVisualizer& ); + + ConstraintImmediateVisualizer( PxF32 _frameScale, PxF32 _limitScale, RenderOutput& _output ) + : mFrameScale( _frameScale ) + , mLimitScale( _limitScale ) + //, mCmOutput(static_cast<RenderBuffer &>(_output)) + , mCmOutput( _output ) + { + } + + virtual void visualizeJointFrames( const PxTransform& parent, const PxTransform& child ) + { + Cm::visualizeJointFrames(mCmOutput, mFrameScale, parent, child ); + } + + virtual void visualizeLinearLimit( const PxTransform& t0, const PxTransform& t1, PxReal value, bool active ) + { + Cm::visualizeLinearLimit( mCmOutput, mLimitScale, t0, t1, value, active ); + } + + virtual void visualizeAngularLimit( const PxTransform& t0, PxReal lower, PxReal upper, bool active) + { + Cm::visualizeAngularLimit( mCmOutput, mLimitScale, t0, lower, upper, active ); + } + + virtual void visualizeLimitCone( const PxTransform& t, PxReal ySwing, PxReal zSwing, bool active) + { + Cm::visualizeLimitCone( mCmOutput, mLimitScale, t, ySwing, zSwing, active ); + } + + virtual void visualizeDoubleCone( const PxTransform& t, PxReal angle, bool active) + { + Cm::visualizeDoubleCone( mCmOutput, mLimitScale, t, angle, active ); + } + }; +} + +} + +#endif diff --git a/PhysX_3.4/Source/Common/src/windows/CmWindowsDelayLoadHook.cpp b/PhysX_3.4/Source/Common/src/windows/CmWindowsDelayLoadHook.cpp new file mode 100644 index 00000000..42a50c0e --- /dev/null +++ b/PhysX_3.4/Source/Common/src/windows/CmWindowsDelayLoadHook.cpp @@ -0,0 +1,82 @@ +// 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 "windows/PxWindowsDelayLoadHook.h" +#include "windows/PsWindowsInclude.h" +#include "windows/CmWindowsLoadLibrary.h" + +// Prior to Visual Studio 2015 Update 3, these hooks were non-const. +#define DELAYIMP_INSECURE_WRITABLE_HOOKS +#include <delayimp.h> + +static const physx::PxDelayLoadHook* gDelayLoadHook = NULL; + +void physx::PxSetPhysXCommonDelayLoadHook(const physx::PxDelayLoadHook* hook) +{ + gDelayLoadHook = hook; +} + +using namespace physx; + +#pragma comment(lib, "delayimp") + +FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo pdli) +{ + switch (dliNotify) { + case dliStartProcessing : + break; + + case dliNotePreLoadLibrary : + { + return Cm::physXCommonDliNotePreLoadLibrary(pdli->szDll,gDelayLoadHook); + } + break; + + case dliNotePreGetProcAddress : + break; + + case dliFailLoadLib : + break; + + case dliFailGetProc : + break; + + case dliNoteEndProcessing : + break; + + default : + + return NULL; + } + + return NULL; +} + +PfnDliHook __pfnDliNotifyHook2 = delayHook; diff --git a/PhysX_3.4/Source/Common/src/windows/CmWindowsModuleUpdateLoader.cpp b/PhysX_3.4/Source/Common/src/windows/CmWindowsModuleUpdateLoader.cpp new file mode 100644 index 00000000..6ff93bc4 --- /dev/null +++ b/PhysX_3.4/Source/Common/src/windows/CmWindowsModuleUpdateLoader.cpp @@ -0,0 +1,130 @@ +// 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 "PsFoundation.h" + +#ifdef SUPPORT_UPDATE_LOADER_LOGGING +#if PX_X86 +#define NX_USE_SDK_DLLS +#include "PhysXUpdateLoader.h" +#endif +#endif /* SUPPORT_UPDATE_LOADER_LOGGING */ + +#include "windows/CmWindowsModuleUpdateLoader.h" +#include "windows/CmWindowsLoadLibrary.h" + + +namespace physx { namespace Cm { + +#if PX_VC +#pragma warning(disable: 4191) //'operator/operation' : unsafe conversion from 'type of expression' to 'type required' +#endif + + +typedef HMODULE (*GetUpdatedModule_FUNC)(const char*, const char*); + +#ifdef SUPPORT_UPDATE_LOADER_LOGGING +#if PX_X86 +typedef void (*setLogging_FUNC)(PXUL_ErrorCode, pt2LogFunc); + +static void LogMessage(PXUL_ErrorCode messageType, char* message) +{ + switch(messageType) + { + case PXUL_ERROR_MESSAGES: + getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, + "PhysX Update Loader Error: %s.", message); + break; + case PXUL_WARNING_MESSAGES: + getFoundation().error(PX_WARN, "PhysX Update Loader Warning: %s.", message); + break; + case PXUL_INFO_MESSAGES: + getFoundation().error(PX_INFO, "PhysX Update Loader Information: %s.", message); + break; + default: + getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, + "Unknown message type from update loader."); + break; + } +} +#endif +#endif /* SUPPORT_UPDATE_LOADER_LOGGING */ + +CmModuleUpdateLoader::CmModuleUpdateLoader(const char* updateLoaderDllName) + : mGetUpdatedModuleFunc(NULL) +{ + mUpdateLoaderDllHandle = loadLibrary(updateLoaderDllName); + + if (mUpdateLoaderDllHandle != NULL) + { + mGetUpdatedModuleFunc = GetProcAddress(mUpdateLoaderDllHandle, "GetUpdatedModule"); + +#ifdef SUPPORT_UPDATE_LOADER_LOGGING +#if PX_X86 + setLogging_FUNC setLoggingFunc; + setLoggingFunc = (setLogging_FUNC)GetProcAddress(mUpdateLoaderDllHandle, "setLoggingFunction"); + if(setLoggingFunc != NULL) + { + setLoggingFunc(PXUL_ERROR_MESSAGES, LogMessage); + } +#endif +#endif /* SUPPORT_UPDATE_LOADER_LOGGING */ + } +} + +CmModuleUpdateLoader::~CmModuleUpdateLoader() +{ + if (mUpdateLoaderDllHandle != NULL) + { + FreeLibrary(mUpdateLoaderDllHandle); + mUpdateLoaderDllHandle = NULL; + } +} + +HMODULE CmModuleUpdateLoader::LoadModule(const char* moduleName, const char* appGUID) +{ + HMODULE result = NULL; + + if (mGetUpdatedModuleFunc != NULL) + { + // Try to get the module through PhysXUpdateLoader + GetUpdatedModule_FUNC getUpdatedModuleFunc = (GetUpdatedModule_FUNC)mGetUpdatedModuleFunc; + result = getUpdatedModuleFunc(moduleName, appGUID); + } + else + { + // If no PhysXUpdateLoader, just load the DLL directly + result = loadLibrary(moduleName); + } + + return result; +} + +}; // end of namespace +}; // end of namespace |