GrMemoryPool.cpp revision 4da34e36cb7a07c3a28ae2a135b1837c26fc7aea
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#include "GrMemoryPool.h" 9 10#if GR_DEBUG 11 #define VALIDATE this->validate() 12#else 13 #define VALIDATE 14#endif 15 16GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) { 17 GR_DEBUGCODE(fAllocationCnt = 0); 18 19 minAllocSize = GrMax<size_t>(minAllocSize, 1 << 10); 20 fMinAllocSize = GrSizeAlignUp(minAllocSize + kPerAllocPad, kAlignment), 21 fPreallocSize = GrSizeAlignUp(preallocSize + kPerAllocPad, kAlignment); 22 fPreallocSize = GrMax(fPreallocSize, fMinAllocSize); 23 24 fHead = CreateBlock(fPreallocSize); 25 fTail = fHead; 26 fHead->fNext = NULL; 27 fHead->fPrev = NULL; 28 VALIDATE; 29}; 30 31GrMemoryPool::~GrMemoryPool() { 32 VALIDATE; 33 GrAssert(0 == fAllocationCnt); 34 GrAssert(fHead == fTail); 35 GrAssert(0 == fHead->fLiveCount); 36 DeleteBlock(fHead); 37}; 38 39void* GrMemoryPool::allocate(size_t size) { 40 VALIDATE; 41 size = GrSizeAlignUp(size, kAlignment); 42 size += kPerAllocPad; 43 if (fTail->fFreeSize < size) { 44 int blockSize = size; 45 blockSize = GrMax<size_t>(blockSize, fMinAllocSize); 46 BlockHeader* block = CreateBlock(blockSize); 47 48 block->fPrev = fTail; 49 block->fNext = NULL; 50 GrAssert(NULL == fTail->fNext); 51 fTail->fNext = block; 52 fTail = block; 53 } 54 GrAssert(fTail->fFreeSize >= size); 55 intptr_t ptr = fTail->fCurrPtr; 56 // We stash a pointer to the block header, just before the allocated space, 57 // so that we can decrement the live count on delete in constant time. 58 *reinterpret_cast<BlockHeader**>(ptr) = fTail; 59 ptr += kPerAllocPad; 60 fTail->fCurrPtr += size; 61 fTail->fFreeSize -= size; 62 fTail->fLiveCount += 1; 63 GR_DEBUGCODE(++fAllocationCnt); 64 VALIDATE; 65 return reinterpret_cast<void*>(ptr); 66} 67 68void GrMemoryPool::release(void* p) { 69 VALIDATE; 70 intptr_t ptr = reinterpret_cast<intptr_t>(p) - kPerAllocPad; 71 BlockHeader* block = *reinterpret_cast<BlockHeader**>(ptr); 72 if (1 == block->fLiveCount) { 73 // the head block is special, it is reset rather than deleted 74 if (fHead == block) { 75 fHead->fCurrPtr = reinterpret_cast<intptr_t>(fHead) + 76 kHeaderSize; 77 fHead->fLiveCount = 0; 78 fHead->fFreeSize = fPreallocSize; 79 } else { 80 BlockHeader* prev = block->fPrev; 81 BlockHeader* next = block->fNext; 82 GrAssert(prev); 83 prev->fNext = next; 84 if (next) { 85 next->fPrev = prev; 86 } else { 87 GrAssert(fTail == block); 88 fTail = prev; 89 } 90 DeleteBlock(block); 91 } 92 } else { 93 --block->fLiveCount; 94 } 95 GR_DEBUGCODE(--fAllocationCnt); 96 VALIDATE; 97} 98 99GrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t size) { 100 BlockHeader* block = 101 reinterpret_cast<BlockHeader*>(GrMalloc(size + kHeaderSize)); 102 // we assume malloc gives us aligned memory 103 GrAssert(!(reinterpret_cast<intptr_t>(block) % kAlignment)); 104 block->fLiveCount = 0; 105 block->fFreeSize = size; 106 block->fCurrPtr = reinterpret_cast<intptr_t>(block) + kHeaderSize; 107 return block; 108} 109 110void GrMemoryPool::DeleteBlock(BlockHeader* block) { 111 GrFree(block); 112} 113 114void GrMemoryPool::validate() { 115 BlockHeader* block = fHead; 116 BlockHeader* prev = NULL; 117 GrAssert(block); 118 int allocCount = 0; 119 do { 120 allocCount += block->fLiveCount; 121 GrAssert(prev == block->fPrev); 122 if (NULL != prev) { 123 GrAssert(prev->fNext == block); 124 } 125 126 intptr_t b = reinterpret_cast<intptr_t>(block); 127 size_t ptrOffset = block->fCurrPtr - b; 128 size_t totalSize = ptrOffset + block->fFreeSize; 129 size_t userSize = totalSize - kHeaderSize; 130 intptr_t userStart = b + kHeaderSize; 131 132 GrAssert(!(b % kAlignment)); 133 GrAssert(!(totalSize % kAlignment)); 134 GrAssert(!(userSize % kAlignment)); 135 GrAssert(!(block->fCurrPtr % kAlignment)); 136 if (fHead != block) { 137 GrAssert(block->fLiveCount); 138 GrAssert(userSize >= fMinAllocSize); 139 } else { 140 GrAssert(userSize == fPreallocSize); 141 } 142 if (!block->fLiveCount) { 143 GrAssert(ptrOffset == kHeaderSize); 144 GrAssert(userStart == block->fCurrPtr); 145 } else { 146 GrAssert(block == *reinterpret_cast<BlockHeader**>(userStart)); 147 } 148 prev = block; 149 } while ((block = block->fNext)); 150 GrAssert(allocCount == fAllocationCnt); 151 GrAssert(prev == fTail); 152} 153 154