| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrMemoryPool.h" | 8 #include "GrMemoryPool.h" |
| 9 | 9 |
| 10 #ifdef SK_DEBUG | 10 #ifdef SK_DEBUG |
| 11 #define VALIDATE this->validate() | 11 #define VALIDATE this->validate() |
| 12 #else | 12 #else |
| 13 #define VALIDATE | 13 #define VALIDATE |
| 14 #endif | 14 #endif |
| 15 | 15 |
| 16 constexpr size_t GrMemoryPool::kSmallestMinAllocSize; |
| 17 |
| 16 GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) { | 18 GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) { |
| 17 SkDEBUGCODE(fAllocationCnt = 0); | 19 SkDEBUGCODE(fAllocationCnt = 0); |
| 18 SkDEBUGCODE(fAllocBlockCnt = 0); | 20 SkDEBUGCODE(fAllocBlockCnt = 0); |
| 19 | 21 |
| 20 minAllocSize = SkTMax<size_t>(minAllocSize, 1 << 10); | 22 minAllocSize = SkTMax<size_t>(GrSizeAlignUp(minAllocSize, kAlignment), kSmal
lestMinAllocSize); |
| 21 fMinAllocSize = GrSizeAlignUp(minAllocSize + kPerAllocPad, kAlignment); | 23 preallocSize = SkTMax<size_t>(GrSizeAlignUp(preallocSize, kAlignment), minAl
locSize); |
| 22 fPreallocSize = GrSizeAlignUp(preallocSize + kPerAllocPad, kAlignment); | 24 |
| 23 fPreallocSize = SkTMax(fPreallocSize, fMinAllocSize); | 25 fMinAllocSize = minAllocSize; |
| 24 fSize = 0; | 26 fSize = 0; |
| 25 | 27 |
| 26 fHead = CreateBlock(fPreallocSize); | 28 fHead = CreateBlock(preallocSize); |
| 27 fTail = fHead; | 29 fTail = fHead; |
| 28 fHead->fNext = nullptr; | 30 fHead->fNext = nullptr; |
| 29 fHead->fPrev = nullptr; | 31 fHead->fPrev = nullptr; |
| 30 VALIDATE; | 32 VALIDATE; |
| 31 }; | 33 }; |
| 32 | 34 |
| 33 GrMemoryPool::~GrMemoryPool() { | 35 GrMemoryPool::~GrMemoryPool() { |
| 34 VALIDATE; | 36 VALIDATE; |
| 35 SkASSERT(0 == fAllocationCnt); | 37 SkASSERT(0 == fAllocationCnt); |
| 36 SkASSERT(fHead == fTail); | 38 SkASSERT(fHead == fTail); |
| 37 SkASSERT(0 == fHead->fLiveCount); | 39 SkASSERT(0 == fHead->fLiveCount); |
| 38 DeleteBlock(fHead); | 40 DeleteBlock(fHead); |
| 39 }; | 41 }; |
| 40 | 42 |
| 41 void* GrMemoryPool::allocate(size_t size) { | 43 void* GrMemoryPool::allocate(size_t size) { |
| 42 VALIDATE; | 44 VALIDATE; |
| 43 size += kPerAllocPad; | 45 size += kPerAllocPad; |
| 44 size = GrSizeAlignUp(size, kAlignment); | 46 size = GrSizeAlignUp(size, kAlignment); |
| 45 if (fTail->fFreeSize < size) { | 47 if (fTail->fFreeSize < size) { |
| 46 size_t blockSize = size; | 48 size_t blockSize = size + kHeaderSize; |
| 47 blockSize = SkTMax<size_t>(blockSize, fMinAllocSize); | 49 blockSize = SkTMax<size_t>(blockSize, fMinAllocSize); |
| 48 BlockHeader* block = CreateBlock(blockSize); | 50 BlockHeader* block = CreateBlock(blockSize); |
| 49 | 51 |
| 50 block->fPrev = fTail; | 52 block->fPrev = fTail; |
| 51 block->fNext = nullptr; | 53 block->fNext = nullptr; |
| 52 SkASSERT(nullptr == fTail->fNext); | 54 SkASSERT(nullptr == fTail->fNext); |
| 53 fTail->fNext = block; | 55 fTail->fNext = block; |
| 54 fTail = block; | 56 fTail = block; |
| 55 fSize += block->fSize; | 57 fSize += block->fSize; |
| 56 SkDEBUGCODE(++fAllocBlockCnt); | 58 SkDEBUGCODE(++fAllocBlockCnt); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 80 AllocHeader* allocData = reinterpret_cast<AllocHeader*>(ptr); | 82 AllocHeader* allocData = reinterpret_cast<AllocHeader*>(ptr); |
| 81 SkASSERT(kAssignedMarker == allocData->fSentinal); | 83 SkASSERT(kAssignedMarker == allocData->fSentinal); |
| 82 SkDEBUGCODE(allocData->fSentinal = kFreedMarker); | 84 SkDEBUGCODE(allocData->fSentinal = kFreedMarker); |
| 83 BlockHeader* block = allocData->fHeader; | 85 BlockHeader* block = allocData->fHeader; |
| 84 SkASSERT(kAssignedMarker == block->fBlockSentinal); | 86 SkASSERT(kAssignedMarker == block->fBlockSentinal); |
| 85 if (1 == block->fLiveCount) { | 87 if (1 == block->fLiveCount) { |
| 86 // the head block is special, it is reset rather than deleted | 88 // the head block is special, it is reset rather than deleted |
| 87 if (fHead == block) { | 89 if (fHead == block) { |
| 88 fHead->fCurrPtr = reinterpret_cast<intptr_t>(fHead) + kHeaderSize; | 90 fHead->fCurrPtr = reinterpret_cast<intptr_t>(fHead) + kHeaderSize; |
| 89 fHead->fLiveCount = 0; | 91 fHead->fLiveCount = 0; |
| 90 fHead->fFreeSize = fPreallocSize; | 92 fHead->fFreeSize = fHead->fSize - kHeaderSize; |
| 91 } else { | 93 } else { |
| 92 BlockHeader* prev = block->fPrev; | 94 BlockHeader* prev = block->fPrev; |
| 93 BlockHeader* next = block->fNext; | 95 BlockHeader* next = block->fNext; |
| 94 SkASSERT(prev); | 96 SkASSERT(prev); |
| 95 prev->fNext = next; | 97 prev->fNext = next; |
| 96 if (next) { | 98 if (next) { |
| 97 next->fPrev = prev; | 99 next->fPrev = prev; |
| 98 } else { | 100 } else { |
| 99 SkASSERT(fTail == block); | 101 SkASSERT(fTail == block); |
| 100 fTail = prev; | 102 fTail = prev; |
| 101 } | 103 } |
| 102 fSize -= block->fSize; | 104 fSize -= block->fSize; |
| 103 DeleteBlock(block); | 105 DeleteBlock(block); |
| 104 SkDEBUGCODE(fAllocBlockCnt--); | 106 SkDEBUGCODE(fAllocBlockCnt--); |
| 105 } | 107 } |
| 106 } else { | 108 } else { |
| 107 --block->fLiveCount; | 109 --block->fLiveCount; |
| 108 // Trivial reclaim: if we're releasing the most recent allocation, reuse
it | 110 // Trivial reclaim: if we're releasing the most recent allocation, reuse
it |
| 109 if (block->fPrevPtr == ptr) { | 111 if (block->fPrevPtr == ptr) { |
| 110 block->fFreeSize += (block->fCurrPtr - block->fPrevPtr); | 112 block->fFreeSize += (block->fCurrPtr - block->fPrevPtr); |
| 111 block->fCurrPtr = block->fPrevPtr; | 113 block->fCurrPtr = block->fPrevPtr; |
| 112 } | 114 } |
| 113 } | 115 } |
| 114 SkDEBUGCODE(--fAllocationCnt); | 116 SkDEBUGCODE(--fAllocationCnt); |
| 115 VALIDATE; | 117 VALIDATE; |
| 116 } | 118 } |
| 117 | 119 |
| 118 GrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t size) { | 120 GrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t blockSize) { |
| 119 size_t paddedSize = size + kHeaderSize; | 121 blockSize = SkTMax<size_t>(blockSize, kHeaderSize); |
| 120 BlockHeader* block = | 122 BlockHeader* block = |
| 121 reinterpret_cast<BlockHeader*>(sk_malloc_throw(paddedSize)); | 123 reinterpret_cast<BlockHeader*>(sk_malloc_throw(blockSize)); |
| 122 // we assume malloc gives us aligned memory | 124 // we assume malloc gives us aligned memory |
| 123 SkASSERT(!(reinterpret_cast<intptr_t>(block) % kAlignment)); | 125 SkASSERT(!(reinterpret_cast<intptr_t>(block) % kAlignment)); |
| 124 SkDEBUGCODE(block->fBlockSentinal = kAssignedMarker); | 126 SkDEBUGCODE(block->fBlockSentinal = kAssignedMarker); |
| 125 block->fLiveCount = 0; | 127 block->fLiveCount = 0; |
| 126 block->fFreeSize = size; | 128 block->fFreeSize = blockSize - kHeaderSize; |
| 127 block->fCurrPtr = reinterpret_cast<intptr_t>(block) + kHeaderSize; | 129 block->fCurrPtr = reinterpret_cast<intptr_t>(block) + kHeaderSize; |
| 128 block->fPrevPtr = 0; // gcc warns on assigning nullptr to an intptr_t. | 130 block->fPrevPtr = 0; // gcc warns on assigning nullptr to an intptr_t. |
| 129 block->fSize = paddedSize; | 131 block->fSize = blockSize; |
| 130 return block; | 132 return block; |
| 131 } | 133 } |
| 132 | 134 |
| 133 void GrMemoryPool::DeleteBlock(BlockHeader* block) { | 135 void GrMemoryPool::DeleteBlock(BlockHeader* block) { |
| 134 SkASSERT(kAssignedMarker == block->fBlockSentinal); | 136 SkASSERT(kAssignedMarker == block->fBlockSentinal); |
| 135 SkDEBUGCODE(block->fBlockSentinal = kFreedMarker); // FWIW | 137 SkDEBUGCODE(block->fBlockSentinal = kFreedMarker); // FWIW |
| 136 sk_free(block); | 138 sk_free(block); |
| 137 } | 139 } |
| 138 | 140 |
| 139 void GrMemoryPool::validate() { | 141 void GrMemoryPool::validate() { |
| 140 #ifdef SK_DEBUG | 142 #ifdef SK_DEBUG |
| 141 BlockHeader* block = fHead; | 143 BlockHeader* block = fHead; |
| 142 BlockHeader* prev = nullptr; | 144 BlockHeader* prev = nullptr; |
| 143 SkASSERT(block); | 145 SkASSERT(block); |
| 144 int allocCount = 0; | 146 int allocCount = 0; |
| 145 do { | 147 do { |
| 146 SkASSERT(kAssignedMarker == block->fBlockSentinal); | 148 SkASSERT(kAssignedMarker == block->fBlockSentinal); |
| 147 allocCount += block->fLiveCount; | 149 allocCount += block->fLiveCount; |
| 148 SkASSERT(prev == block->fPrev); | 150 SkASSERT(prev == block->fPrev); |
| 149 if (prev) { | 151 if (prev) { |
| 150 SkASSERT(prev->fNext == block); | 152 SkASSERT(prev->fNext == block); |
| 151 } | 153 } |
| 152 | 154 |
| 153 intptr_t b = reinterpret_cast<intptr_t>(block); | 155 intptr_t b = reinterpret_cast<intptr_t>(block); |
| 154 size_t ptrOffset = block->fCurrPtr - b; | 156 size_t ptrOffset = block->fCurrPtr - b; |
| 155 size_t totalSize = ptrOffset + block->fFreeSize; | 157 size_t totalSize = ptrOffset + block->fFreeSize; |
| 156 size_t userSize = totalSize - kHeaderSize; | |
| 157 intptr_t userStart = b + kHeaderSize; | 158 intptr_t userStart = b + kHeaderSize; |
| 158 | 159 |
| 159 SkASSERT(!(b % kAlignment)); | 160 SkASSERT(!(b % kAlignment)); |
| 160 SkASSERT(!(totalSize % kAlignment)); | 161 SkASSERT(!(totalSize % kAlignment)); |
| 161 SkASSERT(!(userSize % kAlignment)); | |
| 162 SkASSERT(!(block->fCurrPtr % kAlignment)); | 162 SkASSERT(!(block->fCurrPtr % kAlignment)); |
| 163 if (fHead != block) { | 163 if (fHead != block) { |
| 164 SkASSERT(block->fLiveCount); | 164 SkASSERT(block->fLiveCount); |
| 165 SkASSERT(userSize >= fMinAllocSize); | 165 SkASSERT(totalSize >= fMinAllocSize); |
| 166 } else { | 166 } else { |
| 167 SkASSERT(userSize == fPreallocSize); | 167 SkASSERT(totalSize == block->fSize); |
| 168 } | 168 } |
| 169 if (!block->fLiveCount) { | 169 if (!block->fLiveCount) { |
| 170 SkASSERT(ptrOffset == kHeaderSize); | 170 SkASSERT(ptrOffset == kHeaderSize); |
| 171 SkASSERT(userStart == block->fCurrPtr); | 171 SkASSERT(userStart == block->fCurrPtr); |
| 172 } else { | 172 } else { |
| 173 AllocHeader* allocData = reinterpret_cast<AllocHeader*>(userStart); | 173 AllocHeader* allocData = reinterpret_cast<AllocHeader*>(userStart); |
| 174 SkASSERT(allocData->fSentinal == kAssignedMarker || | 174 SkASSERT(allocData->fSentinal == kAssignedMarker || |
| 175 allocData->fSentinal == kFreedMarker); | 175 allocData->fSentinal == kFreedMarker); |
| 176 SkASSERT(block == allocData->fHeader); | 176 SkASSERT(block == allocData->fHeader); |
| 177 } | 177 } |
| 178 | 178 |
| 179 prev = block; | 179 prev = block; |
| 180 } while ((block = block->fNext)); | 180 } while ((block = block->fNext)); |
| 181 SkASSERT(allocCount == fAllocationCnt); | 181 SkASSERT(allocCount == fAllocationCnt); |
| 182 SkASSERT(prev == fTail); | 182 SkASSERT(prev == fTail); |
| 183 SkASSERT(fAllocBlockCnt != 0 || fSize == 0); | 183 SkASSERT(fAllocBlockCnt != 0 || fSize == 0); |
| 184 #endif | 184 #endif |
| 185 } | 185 } |
| OLD | NEW |