14da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com/* 24da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com * Copyright 2012 Google Inc. 34da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com * 44da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com * Use of this source code is governed by a BSD-style license that can be 54da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com * found in the LICENSE file. 64da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com */ 74da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 84da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com#include "GrMemoryPool.h" 94da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 10515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG 114da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com #define VALIDATE this->validate() 124da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com#else 134da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com #define VALIDATE 144da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com#endif 154da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 164da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.comGrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) { 171acc3d7cc28c5631b5300578ab13439bdefd4e33commit-bot@chromium.org SkDEBUGCODE(fAllocationCnt = 0); 184da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 19972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org minAllocSize = SkTMax<size_t>(minAllocSize, 1 << 10); 204da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fMinAllocSize = GrSizeAlignUp(minAllocSize + kPerAllocPad, kAlignment), 214da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fPreallocSize = GrSizeAlignUp(preallocSize + kPerAllocPad, kAlignment); 22972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org fPreallocSize = SkTMax(fPreallocSize, fMinAllocSize); 234da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 244da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fHead = CreateBlock(fPreallocSize); 254da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fTail = fHead; 264da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fHead->fNext = NULL; 274da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fHead->fPrev = NULL; 284da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com VALIDATE; 294da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com}; 304da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 314da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.comGrMemoryPool::~GrMemoryPool() { 324da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com VALIDATE; 33f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(0 == fAllocationCnt); 34f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(fHead == fTail); 35f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(0 == fHead->fLiveCount); 364da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com DeleteBlock(fHead); 374da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com}; 384da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 394da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.comvoid* GrMemoryPool::allocate(size_t size) { 404da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com VALIDATE; 414da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com size = GrSizeAlignUp(size, kAlignment); 424da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com size += kPerAllocPad; 434da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com if (fTail->fFreeSize < size) { 44adacc7067ad617cdc7bbef39192ca80f4b4d27f9robertphillips@google.com size_t blockSize = size; 45972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org blockSize = SkTMax<size_t>(blockSize, fMinAllocSize); 464da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com BlockHeader* block = CreateBlock(blockSize); 474da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 484da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com block->fPrev = fTail; 494da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com block->fNext = NULL; 50f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(NULL == fTail->fNext); 514da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fTail->fNext = block; 524da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fTail = block; 534da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } 54f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(fTail->fFreeSize >= size); 554da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com intptr_t ptr = fTail->fCurrPtr; 564da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com // We stash a pointer to the block header, just before the allocated space, 574da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com // so that we can decrement the live count on delete in constant time. 584da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com *reinterpret_cast<BlockHeader**>(ptr) = fTail; 594da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com ptr += kPerAllocPad; 60dcba4c2cc30cc64f08def991376c6dab65cfb51ctomhudson@google.com fTail->fPrevPtr = fTail->fCurrPtr; 614da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fTail->fCurrPtr += size; 624da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fTail->fFreeSize -= size; 634da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fTail->fLiveCount += 1; 641acc3d7cc28c5631b5300578ab13439bdefd4e33commit-bot@chromium.org SkDEBUGCODE(++fAllocationCnt); 654da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com VALIDATE; 664da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com return reinterpret_cast<void*>(ptr); 674da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com} 684da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 694da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.comvoid GrMemoryPool::release(void* p) { 704da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com VALIDATE; 714da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com intptr_t ptr = reinterpret_cast<intptr_t>(p) - kPerAllocPad; 724da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com BlockHeader* block = *reinterpret_cast<BlockHeader**>(ptr); 734da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com if (1 == block->fLiveCount) { 744da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com // the head block is special, it is reset rather than deleted 754da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com if (fHead == block) { 764da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fHead->fCurrPtr = reinterpret_cast<intptr_t>(fHead) + 774da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com kHeaderSize; 784da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fHead->fLiveCount = 0; 794da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fHead->fFreeSize = fPreallocSize; 804da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } else { 814da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com BlockHeader* prev = block->fPrev; 824da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com BlockHeader* next = block->fNext; 83f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(prev); 844da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com prev->fNext = next; 854da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com if (next) { 864da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com next->fPrev = prev; 874da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } else { 88f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(fTail == block); 894da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com fTail = prev; 904da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } 914da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com DeleteBlock(block); 924da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } 934da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } else { 944da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com --block->fLiveCount; 95dcba4c2cc30cc64f08def991376c6dab65cfb51ctomhudson@google.com // Trivial reclaim: if we're releasing the most recent allocation, reuse it 96dcba4c2cc30cc64f08def991376c6dab65cfb51ctomhudson@google.com if (block->fPrevPtr == ptr) { 97dcba4c2cc30cc64f08def991376c6dab65cfb51ctomhudson@google.com block->fFreeSize += (block->fCurrPtr - block->fPrevPtr); 98dcba4c2cc30cc64f08def991376c6dab65cfb51ctomhudson@google.com block->fCurrPtr = block->fPrevPtr; 99dcba4c2cc30cc64f08def991376c6dab65cfb51ctomhudson@google.com } 1004da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } 1011acc3d7cc28c5631b5300578ab13439bdefd4e33commit-bot@chromium.org SkDEBUGCODE(--fAllocationCnt); 1024da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com VALIDATE; 1034da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com} 1044da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 1054da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.comGrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t size) { 1064da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com BlockHeader* block = 107939ca7ce860c5e80a4fdccc0dba5f7bfa29fef22reed@google.com reinterpret_cast<BlockHeader*>(sk_malloc_throw(size + kHeaderSize)); 1084da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com // we assume malloc gives us aligned memory 109f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!(reinterpret_cast<intptr_t>(block) % kAlignment)); 1104da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com block->fLiveCount = 0; 1114da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com block->fFreeSize = size; 1124da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com block->fCurrPtr = reinterpret_cast<intptr_t>(block) + kHeaderSize; 113d9e0181405c9853ffd20502555200205a5ab09b1bsalomon@google.com block->fPrevPtr = 0; // gcc warns on assigning NULL to an intptr_t. 1144da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com return block; 1154da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com} 1164da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 1174da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.comvoid GrMemoryPool::DeleteBlock(BlockHeader* block) { 118939ca7ce860c5e80a4fdccc0dba5f7bfa29fef22reed@google.com sk_free(block); 1194da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com} 1204da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 1214da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.comvoid GrMemoryPool::validate() { 1220e51577a14f903ffeafa117a75954baeb173ffb9humper@google.com#ifdef SK_DEBUG 1234da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com BlockHeader* block = fHead; 1244da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com BlockHeader* prev = NULL; 125f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(block); 1264da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com int allocCount = 0; 1274da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com do { 1284da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com allocCount += block->fLiveCount; 129f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(prev == block->fPrev); 1304da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com if (NULL != prev) { 131f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(prev->fNext == block); 1324da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } 1334da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 1344da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com intptr_t b = reinterpret_cast<intptr_t>(block); 1354da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com size_t ptrOffset = block->fCurrPtr - b; 1364da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com size_t totalSize = ptrOffset + block->fFreeSize; 1374da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com size_t userSize = totalSize - kHeaderSize; 1384da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com intptr_t userStart = b + kHeaderSize; 1394da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com 140f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!(b % kAlignment)); 141f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!(totalSize % kAlignment)); 142f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!(userSize % kAlignment)); 143f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!(block->fCurrPtr % kAlignment)); 1444da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com if (fHead != block) { 145f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(block->fLiveCount); 146f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(userSize >= fMinAllocSize); 1474da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } else { 148f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(userSize == fPreallocSize); 1494da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } 1504da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com if (!block->fLiveCount) { 151f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(ptrOffset == kHeaderSize); 152f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(userStart == block->fCurrPtr); 1534da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } else { 154f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(block == *reinterpret_cast<BlockHeader**>(userStart)); 1554da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } 1564da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com prev = block; 1574da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } while ((block = block->fNext)); 158f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(allocCount == fAllocationCnt); 159f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(prev == fTail); 1600e51577a14f903ffeafa117a75954baeb173ffb9humper@google.com#endif 1614da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com} 162