GrMemoryPool.cpp revision 972f9cd7a063d0544f8c919fd12b9a3adbd12b24
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