blob: adf46846c889fc476ee8a7ef3b5fd99c9ee5e889 [file] [log] [blame]
bsalomon@google.com4da34e32012-06-19 15:40:27 +00001/*
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
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000010#ifdef SK_DEBUG
bsalomon@google.com4da34e32012-06-19 15:40:27 +000011 #define VALIDATE this->validate()
12#else
13 #define VALIDATE
14#endif
15
16GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +000017 SkDEBUGCODE(fAllocationCnt = 0);
joshualittb7133be2015-04-08 09:08:31 -070018 SkDEBUGCODE(fAllocBlockCnt = 0);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000019
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000020 minAllocSize = SkTMax<size_t>(minAllocSize, 1 << 10);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000021 fMinAllocSize = GrSizeAlignUp(minAllocSize + kPerAllocPad, kAlignment),
22 fPreallocSize = GrSizeAlignUp(preallocSize + kPerAllocPad, kAlignment);
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000023 fPreallocSize = SkTMax(fPreallocSize, fMinAllocSize);
joshualitt22c6f5c2016-01-05 08:07:18 -080024 fSize = 0;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000025
26 fHead = CreateBlock(fPreallocSize);
27 fTail = fHead;
halcanary96fcdcc2015-08-27 07:41:13 -070028 fHead->fNext = nullptr;
29 fHead->fPrev = nullptr;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000030 VALIDATE;
31};
32
33GrMemoryPool::~GrMemoryPool() {
34 VALIDATE;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000035 SkASSERT(0 == fAllocationCnt);
36 SkASSERT(fHead == fTail);
37 SkASSERT(0 == fHead->fLiveCount);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000038 DeleteBlock(fHead);
39};
40
41void* GrMemoryPool::allocate(size_t size) {
42 VALIDATE;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000043 size += kPerAllocPad;
robertphillips19c62502016-01-06 07:04:46 -080044 size = GrSizeAlignUp(size, kAlignment);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000045 if (fTail->fFreeSize < size) {
robertphillips@google.comadacc702013-10-14 21:53:24 +000046 size_t blockSize = size;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000047 blockSize = SkTMax<size_t>(blockSize, fMinAllocSize);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000048 BlockHeader* block = CreateBlock(blockSize);
49
50 block->fPrev = fTail;
halcanary96fcdcc2015-08-27 07:41:13 -070051 block->fNext = nullptr;
52 SkASSERT(nullptr == fTail->fNext);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000053 fTail->fNext = block;
54 fTail = block;
joshualittb7133be2015-04-08 09:08:31 -070055 fSize += block->fSize;
56 SkDEBUGCODE(++fAllocBlockCnt);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000057 }
robertphillipsb7f4b8e2016-01-07 10:12:16 -080058 SkASSERT(kAssignedMarker == fTail->fBlockSentinal);
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000059 SkASSERT(fTail->fFreeSize >= size);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000060 intptr_t ptr = fTail->fCurrPtr;
61 // We stash a pointer to the block header, just before the allocated space,
62 // so that we can decrement the live count on delete in constant time.
robertphillips19c62502016-01-06 07:04:46 -080063 AllocHeader* allocData = reinterpret_cast<AllocHeader*>(ptr);
64 SkDEBUGCODE(allocData->fSentinal = kAssignedMarker);
65 allocData->fHeader = fTail;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000066 ptr += kPerAllocPad;
tomhudson@google.comdcba4c22012-07-24 21:36:16 +000067 fTail->fPrevPtr = fTail->fCurrPtr;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000068 fTail->fCurrPtr += size;
69 fTail->fFreeSize -= size;
70 fTail->fLiveCount += 1;
joshualittb7133be2015-04-08 09:08:31 -070071
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +000072 SkDEBUGCODE(++fAllocationCnt);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000073 VALIDATE;
74 return reinterpret_cast<void*>(ptr);
75}
76
77void GrMemoryPool::release(void* p) {
78 VALIDATE;
79 intptr_t ptr = reinterpret_cast<intptr_t>(p) - kPerAllocPad;
robertphillips19c62502016-01-06 07:04:46 -080080 AllocHeader* allocData = reinterpret_cast<AllocHeader*>(ptr);
81 SkASSERT(kAssignedMarker == allocData->fSentinal);
82 SkDEBUGCODE(allocData->fSentinal = kFreedMarker);
83 BlockHeader* block = allocData->fHeader;
robertphillipsb7f4b8e2016-01-07 10:12:16 -080084 SkASSERT(kAssignedMarker == block->fBlockSentinal);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000085 if (1 == block->fLiveCount) {
86 // the head block is special, it is reset rather than deleted
87 if (fHead == block) {
joshualittb7133be2015-04-08 09:08:31 -070088 fHead->fCurrPtr = reinterpret_cast<intptr_t>(fHead) + kHeaderSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000089 fHead->fLiveCount = 0;
90 fHead->fFreeSize = fPreallocSize;
91 } else {
92 BlockHeader* prev = block->fPrev;
93 BlockHeader* next = block->fNext;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000094 SkASSERT(prev);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000095 prev->fNext = next;
96 if (next) {
97 next->fPrev = prev;
98 } else {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000099 SkASSERT(fTail == block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000100 fTail = prev;
101 }
joshualittb7133be2015-04-08 09:08:31 -0700102 fSize -= block->fSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000103 DeleteBlock(block);
joshualittb7133be2015-04-08 09:08:31 -0700104 SkDEBUGCODE(fAllocBlockCnt--);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000105 }
106 } else {
107 --block->fLiveCount;
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000108 // Trivial reclaim: if we're releasing the most recent allocation, reuse it
109 if (block->fPrevPtr == ptr) {
110 block->fFreeSize += (block->fCurrPtr - block->fPrevPtr);
111 block->fCurrPtr = block->fPrevPtr;
112 }
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000113 }
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000114 SkDEBUGCODE(--fAllocationCnt);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000115 VALIDATE;
116}
117
118GrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t size) {
joshualittb7133be2015-04-08 09:08:31 -0700119 size_t paddedSize = size + kHeaderSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000120 BlockHeader* block =
joshualittb7133be2015-04-08 09:08:31 -0700121 reinterpret_cast<BlockHeader*>(sk_malloc_throw(paddedSize));
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000122 // we assume malloc gives us aligned memory
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000123 SkASSERT(!(reinterpret_cast<intptr_t>(block) % kAlignment));
robertphillipsb7f4b8e2016-01-07 10:12:16 -0800124 SkDEBUGCODE(block->fBlockSentinal = kAssignedMarker);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000125 block->fLiveCount = 0;
126 block->fFreeSize = size;
127 block->fCurrPtr = reinterpret_cast<intptr_t>(block) + kHeaderSize;
halcanary96fcdcc2015-08-27 07:41:13 -0700128 block->fPrevPtr = 0; // gcc warns on assigning nullptr to an intptr_t.
joshualittb7133be2015-04-08 09:08:31 -0700129 block->fSize = paddedSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000130 return block;
131}
132
133void GrMemoryPool::DeleteBlock(BlockHeader* block) {
robertphillipsb7f4b8e2016-01-07 10:12:16 -0800134 SkASSERT(kAssignedMarker == block->fBlockSentinal);
135 SkDEBUGCODE(block->fBlockSentinal = kFreedMarker); // FWIW
reed@google.com939ca7c2013-09-26 19:56:51 +0000136 sk_free(block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000137}
138
139void GrMemoryPool::validate() {
humper@google.com0e515772013-01-07 19:54:40 +0000140#ifdef SK_DEBUG
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000141 BlockHeader* block = fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700142 BlockHeader* prev = nullptr;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000143 SkASSERT(block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000144 int allocCount = 0;
145 do {
robertphillipsb7f4b8e2016-01-07 10:12:16 -0800146 SkASSERT(kAssignedMarker == block->fBlockSentinal);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000147 allocCount += block->fLiveCount;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000148 SkASSERT(prev == block->fPrev);
bsalomon49f085d2014-09-05 13:34:00 -0700149 if (prev) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000150 SkASSERT(prev->fNext == block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000151 }
152
153 intptr_t b = reinterpret_cast<intptr_t>(block);
154 size_t ptrOffset = block->fCurrPtr - b;
155 size_t totalSize = ptrOffset + block->fFreeSize;
156 size_t userSize = totalSize - kHeaderSize;
157 intptr_t userStart = b + kHeaderSize;
158
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000159 SkASSERT(!(b % kAlignment));
160 SkASSERT(!(totalSize % kAlignment));
161 SkASSERT(!(userSize % kAlignment));
162 SkASSERT(!(block->fCurrPtr % kAlignment));
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000163 if (fHead != block) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000164 SkASSERT(block->fLiveCount);
165 SkASSERT(userSize >= fMinAllocSize);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000166 } else {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000167 SkASSERT(userSize == fPreallocSize);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000168 }
169 if (!block->fLiveCount) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000170 SkASSERT(ptrOffset == kHeaderSize);
171 SkASSERT(userStart == block->fCurrPtr);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000172 } else {
robertphillips19c62502016-01-06 07:04:46 -0800173 AllocHeader* allocData = reinterpret_cast<AllocHeader*>(userStart);
174 SkASSERT(allocData->fSentinal == kAssignedMarker ||
175 allocData->fSentinal == kFreedMarker);
176 SkASSERT(block == allocData->fHeader);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000177 }
robertphillips19c62502016-01-06 07:04:46 -0800178
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000179 prev = block;
180 } while ((block = block->fNext));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000181 SkASSERT(allocCount == fAllocationCnt);
182 SkASSERT(prev == fTail);
joshualitt22c6f5c2016-01-05 08:07:18 -0800183 SkASSERT(fAllocBlockCnt != 0 || fSize == 0);
humper@google.com0e515772013-01-07 19:54:40 +0000184#endif
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000185}