RavEngine
Loading...
Searching...
No Matches
CmPool.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
27// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
28
29#ifndef CM_POOL_H
30#define CM_POOL_H
31
32#include "foundation/PxSort.h"
33#include "foundation/PxMutex.h"
34#include "foundation/PxBasicTemplates.h"
35#include "foundation/PxBitMap.h"
36
37namespace physx
38{
39namespace Cm
40{
41
47template <class T, class ArgumentType>
48class PoolList : public PxAllocatorTraits<T>::Type
49{
50 typedef typename PxAllocatorTraits<T>::Type Alloc;
51 PX_NOCOPY(PoolList)
52public:
53 PX_INLINE PoolList(const Alloc& alloc, ArgumentType* argument, PxU32 eltsPerSlab)
54 : Alloc(alloc),
55 mEltsPerSlab(eltsPerSlab),
56 mSlabCount(0),
57 mFreeList(0),
58 mFreeCount(0),
59 mSlabs(NULL),
60 mArgument(argument)
61 {
62 PX_ASSERT(mEltsPerSlab>0);
63 PX_ASSERT((mEltsPerSlab & (mEltsPerSlab-1)) == 0);
64 mLog2EltsPerSlab = 0;
65
66 for(mLog2EltsPerSlab=0; mEltsPerSlab!=PxU32(1<<mLog2EltsPerSlab); mLog2EltsPerSlab++)
67 ;
68 }
69
71 {
72 destroy();
73 }
74
75 PX_INLINE void destroy()
76 {
77 // Run all destructors
78 for(PxU32 i=0;i<mSlabCount;i++)
79 {
80 PX_ASSERT(mSlabs);
81 T* slab = mSlabs[i];
82 for(PxU32 j=0;j<mEltsPerSlab;j++)
83 {
84 slab[j].~T();
85 }
86 }
87
88 //Deallocate
89 for(PxU32 i=0;i<mSlabCount;i++)
90 {
91 Alloc::deallocate(mSlabs[i]);
92 mSlabs[i] = NULL;
93 }
94 mSlabCount = 0;
95
96 if(mFreeList)
97 Alloc::deallocate(mFreeList);
98 mFreeList = NULL;
99 if(mSlabs)
100 {
101 Alloc::deallocate(mSlabs);
102 mSlabs = NULL;
103 }
104 }
105
106 PxU32 preallocate(const PxU32 nbRequired, T** elements)
107 {
108 //(1) Allocate and pull out an array of X elements
109
110 PxU32 nbToAllocate = nbRequired > mFreeCount ? nbRequired - mFreeCount : 0;
111
112 PxU32 nbElements = nbRequired - nbToAllocate;
113
114 PxMemCopy(elements, mFreeList + (mFreeCount - nbElements), sizeof(T*) * nbElements);
115 //PxU32 originalFreeCount = mFreeCount;
116 mFreeCount -= nbElements;
117
118 if (nbToAllocate)
119 {
120 PX_ASSERT(mFreeCount == 0);
121
122 PxU32 nbSlabs = (nbToAllocate + mEltsPerSlab - 1) / mEltsPerSlab; //The number of slabs we need to allocate...
123 //allocate our slabs...
124
125 PxU32 freeCount = mFreeCount;
126
127 for (PxU32 i = 0; i < nbSlabs; ++i)
128 {
129
130 //KS - would be great to allocate this using a single allocation but it will make releasing slabs fail later :(
131 T * mAddr = reinterpret_cast<T*>(Alloc::allocate(mEltsPerSlab * sizeof(T), __FILE__, __LINE__));
132 if (!mAddr)
133 return nbElements; //Allocation failed so only return the set of elements we could allocate from the free list
134
135 PxU32 newSlabCount = mSlabCount+1;
136
137 // Make sure the usage bitmap is up-to-size
138 if (mUseBitmap.size() < newSlabCount*mEltsPerSlab)
139 {
140 mUseBitmap.resize(2 * newSlabCount*mEltsPerSlab); //set last element as not used
141 if (mFreeList)
142 Alloc::deallocate(mFreeList);
143 mFreeList = reinterpret_cast<T**>(Alloc::allocate(2 * newSlabCount * mEltsPerSlab * sizeof(T*), __FILE__, __LINE__));
144
145 T** slabs = reinterpret_cast<T**>(Alloc::allocate(2* newSlabCount *sizeof(T*), __FILE__, __LINE__));
146 if (mSlabs)
147 {
148 PxMemCopy(slabs, mSlabs, sizeof(T*)*mSlabCount);
149
150 Alloc::deallocate(mSlabs);
151 }
152
153 mSlabs = slabs;
154 }
155
156 mSlabs[mSlabCount++] = mAddr;
157
158 PxU32 baseIndex = (mSlabCount-1) * mEltsPerSlab;
159
160 //Now add all these to the mFreeList and elements...
161 PxI32 idx = PxI32(mEltsPerSlab - 1);
162
163 for (; idx >= PxI32(nbToAllocate); --idx)
164 {
165 mFreeList[freeCount++] = PX_PLACEMENT_NEW(mAddr + idx, T(mArgument, baseIndex + idx));
166 }
167
168 PxU32 origElements = nbElements;
169 T** writeIdx = elements + nbElements;
170 for (; idx >= 0; --idx)
171 {
172 writeIdx[idx] = PX_PLACEMENT_NEW(mAddr + idx, T(mArgument, baseIndex + idx));
173 nbElements++;
174 }
175
176 nbToAllocate -= (nbElements - origElements);
177 }
178
179 mFreeCount = freeCount;
180 }
181
182 PX_ASSERT(nbElements == nbRequired);
183
184 for (PxU32 a = 0; a < nbElements; ++a)
185 {
186 mUseBitmap.set(elements[a]->getIndex());
187 }
188
189 return nbRequired;
190 }
191
192 // TODO: would be nice to add templated construct/destroy methods like ObjectPool
193
194 PX_INLINE T* get()
195 {
196 if(mFreeCount == 0 && !extend())
197 return 0;
198 T* element = mFreeList[--mFreeCount];
199 mUseBitmap.set(element->getIndex());
200 return element;
201 }
202
203 PX_INLINE void put(T* element)
204 {
205 PxU32 i = element->getIndex();
206 mUseBitmap.reset(i);
207 mFreeList[mFreeCount++] = element;
208 }
209
210 /*
211 WARNING: Unlike findByIndexFast below, this method is NOT safe to use if another thread
212 is concurrently updating the pool (e.g. through put/get/extend/getIterator), since the
213 safety boundedTest uses mSlabCount and mUseBitmap.
214 */
215 PX_FORCE_INLINE T* findByIndex(PxU32 index) const
216 {
217 if(index>=mSlabCount*mEltsPerSlab || !(mUseBitmap.boundedTest(index)))
218 return 0;
219 return mSlabs[index>>mLog2EltsPerSlab] + (index&(mEltsPerSlab-1));
220 }
221
222 /*
223 This call is safe to do while other threads update the pool.
224 */
225 PX_FORCE_INLINE T* findByIndexFast(PxU32 index) const
226 {
227 return mSlabs[index>>mLog2EltsPerSlab] + (index&(mEltsPerSlab-1));
228 }
229
230 bool extend()
231 {
232 T * mAddr = reinterpret_cast<T*>(Alloc::allocate(mEltsPerSlab * sizeof(T), __FILE__, __LINE__));
233 if(!mAddr)
234 return false;
235
236 PxU32 newSlabCount = mSlabCount+1;
237
238 // Make sure the usage bitmap is up-to-size
239 if(mUseBitmap.size() < newSlabCount*mEltsPerSlab)
240 {
241 mUseBitmap.resize(2* newSlabCount*mEltsPerSlab); //set last element as not used
242 if(mFreeList)
243 Alloc::deallocate(mFreeList);
244 mFreeList = reinterpret_cast<T**>(Alloc::allocate(2* newSlabCount * mEltsPerSlab * sizeof(T*), __FILE__, __LINE__));
245
246 T** slabs = reinterpret_cast<T**>(Alloc::allocate(2 * newSlabCount * sizeof(T*), __FILE__, __LINE__));
247 if (mSlabs)
248 {
249 PxMemCopy(slabs, mSlabs, sizeof(T*)*mSlabCount);
250
251 Alloc::deallocate(mSlabs);
252 }
253
254 mSlabs = slabs;
255 }
256
257 mSlabs[mSlabCount++] = mAddr;
258
259 // Add to free list in descending order so that lowest indices get allocated first -
260 // the FW context code currently *relies* on this behavior to grab the zero-index volume
261 // which can't be allocated to the user. TODO: fix this
262
263 PxU32 baseIndex = (mSlabCount-1) * mEltsPerSlab;
264 PxU32 freeCount = mFreeCount;
265 for(PxI32 i=PxI32(mEltsPerSlab-1);i>=0;i--)
266 mFreeList[freeCount++] = PX_PLACEMENT_NEW(mAddr+i, T(mArgument, baseIndex+ i));
267
268 mFreeCount = freeCount;
269
270 return true;
271 }
272
273 PX_INLINE PxU32 getMaxUsedIndex() const
274 {
275 return mUseBitmap.findLast();
276 }
277
278 PX_INLINE PxBitMap::Iterator getIterator() const
279 {
280 return PxBitMap::Iterator(mUseBitmap);
281 }
282
283private:
284 const PxU32 mEltsPerSlab;
285 PxU32 mSlabCount;
286 PxU32 mLog2EltsPerSlab;
287 T** mFreeList;
288 PxU32 mFreeCount;
289 T** mSlabs;
290 ArgumentType* mArgument;
291 PxBitMap mUseBitmap;
292};
293
294
295}
296}
297
298#endif
Definition CmPool.h:49
Definition PxBitMap.h:278
Definition PxBitMap.h:52
PxU32 findLast() const
returns 0 if no bits set (!!!)
Definition PxBitMap.h:228
Definition PxAllocator.h:188
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
#define PX_INLINE
Definition PxPreprocessor.h:320
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
PX_FORCE_INLINE void * PxMemCopy(void *dest, const void *src, PxU32 count)
Copies the bytes of one memory block to another. The memory blocks must not overlap.
Definition PxMemory.h:83
Definition PxAllocator.h:221