Files
XCEngine/engine/third_party/physx/source/common/src/CmPreallocatingPool.h

415 lines
10 KiB
C++

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef CM_PREALLOCATING_POOL_H
#define CM_PREALLOCATING_POOL_H
#include "foundation/PxUserAllocated.h"
#include "foundation/PxSort.h"
#include "foundation/PxArray.h"
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(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 ("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)
PxSort(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;
PxArray<PreallocatingRegion> mPools;
bool mNeedsSorting;
const char* mTypeName;
};
template<class T>
class PreallocatingPool : public PxUserAllocated
{
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());
PxPrefetch(t, sizeof(T));
return t;
}
PX_INLINE T* construct()
{
T* t = reinterpret_cast<T*>(mPool.allocateMemory());
return t ? PX_PLACEMENT_NEW(t, T()) : NULL;
}
template<class A1>
PX_INLINE T* construct(A1& a)
{
T* t = reinterpret_cast<T*>(mPool.allocateMemory());
return t ? PX_PLACEMENT_NEW(t, T(a)) : NULL;
}
template<class A1, class A2>
PX_INLINE T* construct(A1& a, A2& b)
{
T* t = reinterpret_cast<T*>(mPool.allocateMemory());
return t ? PX_PLACEMENT_NEW(t, T(a,b)) : NULL;
}
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 ? PX_PLACEMENT_NEW(t, T(a,b,c)) : NULL;
}
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 ? PX_PLACEMENT_NEW(t, T(a,b,c,d)) : NULL;
}
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 ? PX_PLACEMENT_NEW(t, T(a,b,c,d,e)) : NULL;
}
////
PX_INLINE T* construct(T* t)
{
PX_ASSERT(t);
return PX_PLACEMENT_NEW(t, T());
}
template<class A1>
PX_INLINE T* construct(T* t, A1& a)
{
PX_ASSERT(t);
return PX_PLACEMENT_NEW(t, T(a));
}
template<class A1, class A2>
PX_INLINE T* construct(T* t, A1& a, A2& b)
{
PX_ASSERT(t);
return PX_PLACEMENT_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 PX_PLACEMENT_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 PX_PLACEMENT_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 PX_PLACEMENT_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>
{
PxArray<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