Index: src/gpu/GrMemoryPool.h |
diff --git a/src/gpu/GrMemoryPool.h b/src/gpu/GrMemoryPool.h |
index 43826d354a134f8d7bcbf667e395cb2095194fd0..e483aab6f2177ce333e7ad41c25de788e095bb75 100644 |
--- a/src/gpu/GrMemoryPool.h |
+++ b/src/gpu/GrMemoryPool.h |
@@ -13,16 +13,23 @@ |
/** |
* Allocates memory in blocks and parcels out space in the blocks for allocation |
* requests. It is optimized for allocate / release speed over memory |
- * effeciency. The interface is designed to be used to implement operator new |
+ * efficiency. The interface is designed to be used to implement operator new |
* and delete overrides. All allocations are expected to be released before the |
* pool's destructor is called. Allocations will be 8-byte aligned. |
*/ |
class GrMemoryPool { |
public: |
/** |
- * Prealloc size is the amount of space to make available at pool creation |
- * time and keep around until pool destruction. The min alloc size is the |
- * smallest allowed size of additional allocations. |
+ * Prealloc size is the amount of space to allocate at pool creation |
+ * time and keep around until pool destruction. The min alloc size is |
+ * the smallest allowed size of additional allocations. Both sizes are |
+ * adjusted to ensure that: |
+ * 1. they are are 8-byte aligned |
herb_g
2016/11/29 18:31:14
Generally , 8-byte alignment is not enough. You sh
|
+ * 2. minAllocSize >= kSmallestMinAllocSize |
+ * 3. preallocSize >= minAllocSize |
+ * |
+ * Both sizes is what the pool will end up allocating from the system, and |
+ * portions of the allocated memory is used for internal bookkeeping. |
*/ |
GrMemoryPool(size_t preallocSize, size_t minAllocSize); |
@@ -48,6 +55,16 @@ public: |
*/ |
size_t size() const { return fSize; } |
+ /** |
+ * Returns the preallocated size of the GrMemoryPool |
+ */ |
+ size_t preallocSize() const { return fHead->fSize; } |
+ |
+ /** |
+ * Minimum value of minAllocSize constructor argument. |
+ */ |
+ constexpr static size_t kSmallestMinAllocSize = 1 << 10; |
+ |
private: |
struct BlockHeader; |
@@ -81,14 +98,7 @@ private: |
BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides |
}; |
- enum { |
- // We assume this alignment is good enough for everybody. |
- kAlignment = 8, |
- kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment), |
- kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment), |
- }; |
size_t fSize; |
- size_t fPreallocSize; |
size_t fMinAllocSize; |
BlockHeader* fHead; |
BlockHeader* fTail; |
@@ -96,6 +106,79 @@ private: |
int fAllocationCnt; |
int fAllocBlockCnt; |
#endif |
+ |
+protected: |
+ enum { |
+ // We assume this alignment is good enough for everybody. |
+ kAlignment = 8, |
+ kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment), |
+ kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment), |
+ }; |
+}; |
+ |
+/** |
+ * Variant of GrMemoryPool that can only allocate objects of a single type. It is |
+ * not as flexible as GrMemoryPool, but it has more convenient allocate() method, |
+ * and more importantly, it guarantees number of objects that are preallocated at |
+ * construction or when adding a new memory block. I.e. |
+ * |
+ * GrMemoryPool pool(3 * sizeof(T), 1000 * sizeof(T)); |
+ * pool.allocate(sizeof(T)); |
+ * pool.allocate(sizeof(T)); |
+ * pool.allocate(sizeof(T)); |
+ * |
+ * will preallocate 3 * sizeof(T) bytes and use some of those bytes for internal |
+ * structures. Because of that, last allocate() call will end up allocating a new |
+ * block of 1000 * sizeof(T) bytes. In contrast, |
+ * |
+ * GrObjectMemoryPool<T> pool(3, 1000); |
+ * pool.allocate(); |
+ * pool.allocate(); |
+ * pool.allocate(); |
+ * |
+ * guarantees to preallocate enough memory for 3 objects of sizeof(T), so last |
+ * allocate() will use preallocated memory and won't cause allocation of a new block. |
+ * |
+ * Same thing is true for the second (minAlloc) ctor argument: this class guarantees |
+ * that a newly added block will have enough space for 1000 objects of sizeof(T), while |
+ * GrMemoryPool does not. |
+ */ |
+template <class T> |
+class GrObjectMemoryPool: public GrMemoryPool { |
+public: |
+ /** |
+ * Preallocates memory for preallocCount objects, and sets new block size to be |
+ * enough to hold minAllocCount objects. |
+ */ |
+ GrObjectMemoryPool(size_t preallocCount, size_t minAllocCount) |
+ : GrMemoryPool(CountToSize(preallocCount), |
+ CountToSize(SkTMax(minAllocCount, kSmallestMinAllocCount))) { |
+ } |
+ |
+ /** |
+ * Allocates memory for an object, but doesn't construct or otherwise initialize it. |
+ * The memory must be freed with release(). |
+ */ |
+ T* allocate() { return static_cast<T*>(GrMemoryPool::allocate(sizeof(T))); } |
herb_g
2016/11/29 18:31:14
I think this is a very dangerous API. It is not RA
|
+ |
+private: |
+ constexpr static size_t kTotalObjectSize = |
+ kPerAllocPad + GR_CT_ALIGN_UP(sizeof(T), kAlignment); |
+ |
+ constexpr static size_t CountToSize(size_t count) { |
+ return kHeaderSize + count * kTotalObjectSize; |
+ } |
+ |
+public: |
+ /** |
+ * Minimum value of minAllocCount constructor argument. |
+ */ |
+ constexpr static size_t kSmallestMinAllocCount = |
+ (GrMemoryPool::kSmallestMinAllocSize - kHeaderSize + kTotalObjectSize - 1) / |
+ kTotalObjectSize; |
}; |
+template <class T> |
+constexpr size_t GrObjectMemoryPool<T>::kSmallestMinAllocCount; |
+ |
#endif |