blob: e59ed83d275866c58d81dafd1d7c12cd5534ab53 [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);
joshualittb7133be2015-04-08 09:08:31 -070024 fSize = fPreallocSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000025
26 fHead = CreateBlock(fPreallocSize);
27 fTail = fHead;
28 fHead->fNext = NULL;
29 fHead->fPrev = NULL;
30 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;
43 size = GrSizeAlignUp(size, kAlignment);
44 size += kPerAllocPad;
45 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;
51 block->fNext = NULL;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000052 SkASSERT(NULL == 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 }
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000058 SkASSERT(fTail->fFreeSize >= size);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000059 intptr_t ptr = fTail->fCurrPtr;
60 // We stash a pointer to the block header, just before the allocated space,
61 // so that we can decrement the live count on delete in constant time.
62 *reinterpret_cast<BlockHeader**>(ptr) = fTail;
63 ptr += kPerAllocPad;
tomhudson@google.comdcba4c22012-07-24 21:36:16 +000064 fTail->fPrevPtr = fTail->fCurrPtr;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000065 fTail->fCurrPtr += size;
66 fTail->fFreeSize -= size;
67 fTail->fLiveCount += 1;
joshualittb7133be2015-04-08 09:08:31 -070068
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +000069 SkDEBUGCODE(++fAllocationCnt);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000070 VALIDATE;
71 return reinterpret_cast<void*>(ptr);
72}
73
74void GrMemoryPool::release(void* p) {
75 VALIDATE;
76 intptr_t ptr = reinterpret_cast<intptr_t>(p) - kPerAllocPad;
77 BlockHeader* block = *reinterpret_cast<BlockHeader**>(ptr);
78 if (1 == block->fLiveCount) {
79 // the head block is special, it is reset rather than deleted
80 if (fHead == block) {
joshualittb7133be2015-04-08 09:08:31 -070081 fHead->fCurrPtr = reinterpret_cast<intptr_t>(fHead) + kHeaderSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000082 fHead->fLiveCount = 0;
83 fHead->fFreeSize = fPreallocSize;
84 } else {
85 BlockHeader* prev = block->fPrev;
86 BlockHeader* next = block->fNext;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000087 SkASSERT(prev);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000088 prev->fNext = next;
89 if (next) {
90 next->fPrev = prev;
91 } else {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000092 SkASSERT(fTail == block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000093 fTail = prev;
94 }
joshualittb7133be2015-04-08 09:08:31 -070095 fSize -= block->fSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +000096 DeleteBlock(block);
joshualittb7133be2015-04-08 09:08:31 -070097 SkDEBUGCODE(fAllocBlockCnt--);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000098 }
99 } else {
100 --block->fLiveCount;
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000101 // Trivial reclaim: if we're releasing the most recent allocation, reuse it
102 if (block->fPrevPtr == ptr) {
103 block->fFreeSize += (block->fCurrPtr - block->fPrevPtr);
104 block->fCurrPtr = block->fPrevPtr;
105 }
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000106 }
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000107 SkDEBUGCODE(--fAllocationCnt);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000108 VALIDATE;
109}
110
111GrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t size) {
joshualittb7133be2015-04-08 09:08:31 -0700112 size_t paddedSize = size + kHeaderSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000113 BlockHeader* block =
joshualittb7133be2015-04-08 09:08:31 -0700114 reinterpret_cast<BlockHeader*>(sk_malloc_throw(paddedSize));
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000115 // we assume malloc gives us aligned memory
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000116 SkASSERT(!(reinterpret_cast<intptr_t>(block) % kAlignment));
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000117 block->fLiveCount = 0;
118 block->fFreeSize = size;
119 block->fCurrPtr = reinterpret_cast<intptr_t>(block) + kHeaderSize;
bsalomon@google.comd9e01812012-08-29 19:35:44 +0000120 block->fPrevPtr = 0; // gcc warns on assigning NULL to an intptr_t.
joshualittb7133be2015-04-08 09:08:31 -0700121 block->fSize = paddedSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000122 return block;
123}
124
125void GrMemoryPool::DeleteBlock(BlockHeader* block) {
reed@google.com939ca7c2013-09-26 19:56:51 +0000126 sk_free(block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000127}
128
129void GrMemoryPool::validate() {
humper@google.com0e515772013-01-07 19:54:40 +0000130#ifdef SK_DEBUG
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000131 BlockHeader* block = fHead;
132 BlockHeader* prev = NULL;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000133 SkASSERT(block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000134 int allocCount = 0;
135 do {
136 allocCount += block->fLiveCount;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000137 SkASSERT(prev == block->fPrev);
bsalomon49f085d2014-09-05 13:34:00 -0700138 if (prev) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000139 SkASSERT(prev->fNext == block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000140 }
141
142 intptr_t b = reinterpret_cast<intptr_t>(block);
143 size_t ptrOffset = block->fCurrPtr - b;
144 size_t totalSize = ptrOffset + block->fFreeSize;
145 size_t userSize = totalSize - kHeaderSize;
146 intptr_t userStart = b + kHeaderSize;
147
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000148 SkASSERT(!(b % kAlignment));
149 SkASSERT(!(totalSize % kAlignment));
150 SkASSERT(!(userSize % kAlignment));
151 SkASSERT(!(block->fCurrPtr % kAlignment));
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000152 if (fHead != block) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000153 SkASSERT(block->fLiveCount);
154 SkASSERT(userSize >= fMinAllocSize);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000155 } else {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000156 SkASSERT(userSize == fPreallocSize);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000157 }
158 if (!block->fLiveCount) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000159 SkASSERT(ptrOffset == kHeaderSize);
160 SkASSERT(userStart == block->fCurrPtr);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000161 } else {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000162 SkASSERT(block == *reinterpret_cast<BlockHeader**>(userStart));
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000163 }
164 prev = block;
165 } while ((block = block->fNext));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000166 SkASSERT(allocCount == fAllocationCnt);
167 SkASSERT(prev == fTail);
joshualittb7133be2015-04-08 09:08:31 -0700168 SkASSERT(fAllocBlockCnt != 0 || fSize == fPreallocSize);
humper@google.com0e515772013-01-07 19:54:40 +0000169#endif
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000170}