1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef GrMemoryPool_DEFINED 9 #define GrMemoryPool_DEFINED 10 11 #include "include/gpu/GrTypes.h" 12 13 #include "include/core/SkRefCnt.h" 14 15 #ifdef SK_DEBUG 16 #include "include/private/SkTHash.h" 17 #endif 18 19 /** 20 * Allocates memory in blocks and parcels out space in the blocks for allocation 21 * requests. It is optimized for allocate / release speed over memory 22 * efficiency. The interface is designed to be used to implement operator new 23 * and delete overrides. All allocations are expected to be released before the 24 * pool's destructor is called. Allocations will be 8-byte aligned. 25 */ 26 class GrMemoryPool { 27 public: 28 /** 29 * Prealloc size is the amount of space to allocate at pool creation 30 * time and keep around until pool destruction. The min alloc size is 31 * the smallest allowed size of additional allocations. Both sizes are 32 * adjusted to ensure that: 33 * 1. they are are 8-byte aligned 34 * 2. minAllocSize >= kSmallestMinAllocSize 35 * 3. preallocSize >= minAllocSize 36 * 37 * Both sizes is what the pool will end up allocating from the system, and 38 * portions of the allocated memory is used for internal bookkeeping. 39 */ 40 GrMemoryPool(size_t preallocSize, size_t minAllocSize); 41 42 ~GrMemoryPool(); 43 44 /** 45 * Allocates memory. The memory must be freed with release(). 46 */ 47 void* allocate(size_t size); 48 49 /** 50 * p must have been returned by allocate() 51 */ 52 void release(void* p); 53 54 /** 55 * Returns true if there are no unreleased allocations. 56 */ isEmpty()57 bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; } 58 59 /** 60 * Returns the total allocated size of the GrMemoryPool minus any preallocated amount 61 */ size()62 size_t size() const { return fSize; } 63 64 /** 65 * Returns the preallocated size of the GrMemoryPool 66 */ preallocSize()67 size_t preallocSize() const { return fHead->fSize; } 68 69 /** 70 * Minimum value of minAllocSize constructor argument. 71 */ 72 constexpr static size_t kSmallestMinAllocSize = 1 << 10; 73 74 private: 75 struct BlockHeader; 76 77 static BlockHeader* CreateBlock(size_t size); 78 79 static void DeleteBlock(BlockHeader* block); 80 81 void validate(); 82 83 struct BlockHeader { 84 #ifdef SK_DEBUG 85 uint32_t fBlockSentinal; ///< known value to check for bad back pointers to blocks 86 #endif 87 BlockHeader* fNext; ///< doubly-linked list of blocks. 88 BlockHeader* fPrev; 89 int fLiveCount; ///< number of outstanding allocations in the 90 ///< block. 91 intptr_t fCurrPtr; ///< ptr to the start of blocks free space. 92 intptr_t fPrevPtr; ///< ptr to the last allocation made 93 size_t fFreeSize; ///< amount of free space left in the block. 94 size_t fSize; ///< total allocated size of the block 95 }; 96 97 static const uint32_t kAssignedMarker = 0xCDCDCDCD; 98 static const uint32_t kFreedMarker = 0xEFEFEFEF; 99 100 struct AllocHeader { 101 #ifdef SK_DEBUG 102 uint32_t fSentinal; ///< known value to check for memory stomping (e.g., (CD)*) 103 int32_t fID; ///< ID that can be used to track down leaks by clients. 104 #endif 105 BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides 106 }; 107 108 size_t fSize; 109 size_t fMinAllocSize; 110 BlockHeader* fHead; 111 BlockHeader* fTail; 112 #ifdef SK_DEBUG 113 int fAllocationCnt; 114 int fAllocBlockCnt; 115 SkTHashSet<int32_t> fAllocatedIDs; 116 #endif 117 118 protected: 119 enum { 120 // We assume this alignment is good enough for everybody. 121 kAlignment = 8, 122 kHeaderSize = GrSizeAlignUp(sizeof(BlockHeader), kAlignment), 123 kPerAllocPad = GrSizeAlignUp(sizeof(AllocHeader), kAlignment), 124 }; 125 }; 126 127 class GrOp; 128 129 // DDL TODO: for the DLL use case this could probably be the non-intrinsic-based style of 130 // ref counting 131 class GrOpMemoryPool : public SkRefCnt { 132 public: GrOpMemoryPool(size_t preallocSize,size_t minAllocSize)133 GrOpMemoryPool(size_t preallocSize, size_t minAllocSize) 134 : fMemoryPool(preallocSize, minAllocSize) { 135 } 136 137 template <typename Op, typename... OpArgs> allocate(OpArgs &&...opArgs)138 std::unique_ptr<Op> allocate(OpArgs&&... opArgs) { 139 char* mem = (char*) fMemoryPool.allocate(sizeof(Op)); 140 return std::unique_ptr<Op>(new (mem) Op(std::forward<OpArgs>(opArgs)...)); 141 } 142 allocate(size_t size)143 void* allocate(size_t size) { 144 return fMemoryPool.allocate(size); 145 } 146 147 void release(std::unique_ptr<GrOp> op); 148 isEmpty()149 bool isEmpty() const { return fMemoryPool.isEmpty(); } 150 151 private: 152 GrMemoryPool fMemoryPool; 153 }; 154 155 #endif 156