| Index: src/core/SkBitmapHeap.cpp
|
| diff --git a/src/core/SkBitmapHeap.cpp b/src/core/SkBitmapHeap.cpp
|
| deleted file mode 100644
|
| index 071647e13e180bd99dd87fb4fbadab6cb7d26900..0000000000000000000000000000000000000000
|
| --- a/src/core/SkBitmapHeap.cpp
|
| +++ /dev/null
|
| @@ -1,391 +0,0 @@
|
| -/*
|
| - * Copyright 2012 Google Inc.
|
| - *
|
| - * Use of this source code is governed by a BSD-style license that can be
|
| - * found in the LICENSE file.
|
| - */
|
| -
|
| -#include "SkBitmapHeap.h"
|
| -#include "SkBitmap.h"
|
| -#include "SkTSearch.h"
|
| -
|
| -SkBitmapHeapEntry::SkBitmapHeapEntry()
|
| - : fSlot(-1)
|
| - , fRefCount(0)
|
| - , fBytesAllocated(0) {
|
| -}
|
| -
|
| -SkBitmapHeapEntry::~SkBitmapHeapEntry() {
|
| - SkASSERT(0 == fRefCount);
|
| -}
|
| -
|
| -void SkBitmapHeapEntry::addReferences(int count) {
|
| - if (0 == fRefCount) {
|
| - // If there are no current owners then the heap manager
|
| - // will be the only one able to modify it, so it does not
|
| - // need to be an atomic operation.
|
| - fRefCount = count;
|
| - } else {
|
| - sk_atomic_add(&fRefCount, count);
|
| - }
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -static bool operator<(const SkIPoint& a, const SkIPoint& b) {
|
| - return *(const int64_t*)&a < *(const int64_t*)&b;
|
| -}
|
| -
|
| -static bool operator>(const SkIPoint& a, const SkIPoint& b) {
|
| - return *(const int64_t*)&a > *(const int64_t*)&b;
|
| -}
|
| -
|
| -bool SkBitmapHeap::LookupEntry::Less(const SkBitmapHeap::LookupEntry& a,
|
| - const SkBitmapHeap::LookupEntry& b) {
|
| - if (a.fGenerationId < b.fGenerationId) {
|
| - return true;
|
| - } else if (a.fGenerationId > b.fGenerationId) {
|
| - return false;
|
| - } else if (a.fPixelOrigin < b.fPixelOrigin) {
|
| - return true;
|
| - } else if (a.fPixelOrigin > b.fPixelOrigin) {
|
| - return false;
|
| - } else if (a.fWidth < b.fWidth) {
|
| - return true;
|
| - } else if (a.fWidth > b.fWidth) {
|
| - return false;
|
| - } else if (a.fHeight < b.fHeight) {
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -SkBitmapHeap::SkBitmapHeap(int32_t preferredSize, int32_t ownerCount)
|
| - : INHERITED()
|
| - , fExternalStorage(nullptr)
|
| - , fMostRecentlyUsed(nullptr)
|
| - , fLeastRecentlyUsed(nullptr)
|
| - , fPreferredCount(preferredSize)
|
| - , fOwnerCount(ownerCount)
|
| - , fBytesAllocated(0)
|
| - , fDeferAddingOwners(false) {
|
| -}
|
| -
|
| -SkBitmapHeap::SkBitmapHeap(ExternalStorage* storage, int32_t preferredSize)
|
| - : INHERITED()
|
| - , fExternalStorage(storage)
|
| - , fMostRecentlyUsed(nullptr)
|
| - , fLeastRecentlyUsed(nullptr)
|
| - , fPreferredCount(preferredSize)
|
| - , fOwnerCount(IGNORE_OWNERS)
|
| - , fBytesAllocated(0)
|
| - , fDeferAddingOwners(false) {
|
| - SkSafeRef(storage);
|
| -}
|
| -
|
| -SkBitmapHeap::~SkBitmapHeap() {
|
| - SkDEBUGCODE(
|
| - for (int i = 0; i < fStorage.count(); i++) {
|
| - bool unused = false;
|
| - for (int j = 0; j < fUnusedSlots.count(); j++) {
|
| - if (fUnusedSlots[j] == fStorage[i]->fSlot) {
|
| - unused = true;
|
| - break;
|
| - }
|
| - }
|
| - if (!unused) {
|
| - fBytesAllocated -= fStorage[i]->fBytesAllocated;
|
| - }
|
| - }
|
| - fBytesAllocated -= (fStorage.count() * sizeof(SkBitmapHeapEntry));
|
| - )
|
| - SkASSERT(0 == fBytesAllocated);
|
| - fStorage.deleteAll();
|
| - SkSafeUnref(fExternalStorage);
|
| - fLookupTable.deleteAll();
|
| -}
|
| -
|
| -void SkBitmapHeap::removeFromLRU(SkBitmapHeap::LookupEntry* entry) {
|
| - if (fMostRecentlyUsed == entry) {
|
| - fMostRecentlyUsed = entry->fLessRecentlyUsed;
|
| - if (nullptr == fMostRecentlyUsed) {
|
| - SkASSERT(fLeastRecentlyUsed == entry);
|
| - fLeastRecentlyUsed = nullptr;
|
| - } else {
|
| - fMostRecentlyUsed->fMoreRecentlyUsed = nullptr;
|
| - }
|
| - } else {
|
| - // Remove entry from its prior place, and make sure to cover the hole.
|
| - if (fLeastRecentlyUsed == entry) {
|
| - SkASSERT(entry->fMoreRecentlyUsed != nullptr);
|
| - fLeastRecentlyUsed = entry->fMoreRecentlyUsed;
|
| - }
|
| - // Since we have already considered the case where entry is the most recently used, it must
|
| - // have a more recently used at this point.
|
| - SkASSERT(entry->fMoreRecentlyUsed != nullptr);
|
| - entry->fMoreRecentlyUsed->fLessRecentlyUsed = entry->fLessRecentlyUsed;
|
| -
|
| - if (entry->fLessRecentlyUsed != nullptr) {
|
| - SkASSERT(fLeastRecentlyUsed != entry);
|
| - entry->fLessRecentlyUsed->fMoreRecentlyUsed = entry->fMoreRecentlyUsed;
|
| - }
|
| - }
|
| - entry->fMoreRecentlyUsed = nullptr;
|
| -}
|
| -
|
| -void SkBitmapHeap::appendToLRU(SkBitmapHeap::LookupEntry* entry) {
|
| - if (fMostRecentlyUsed != nullptr) {
|
| - SkASSERT(nullptr == fMostRecentlyUsed->fMoreRecentlyUsed);
|
| - fMostRecentlyUsed->fMoreRecentlyUsed = entry;
|
| - entry->fLessRecentlyUsed = fMostRecentlyUsed;
|
| - }
|
| - fMostRecentlyUsed = entry;
|
| - if (nullptr == fLeastRecentlyUsed) {
|
| - fLeastRecentlyUsed = entry;
|
| - }
|
| -}
|
| -
|
| -// iterate through our LRU cache and try to find an entry to evict
|
| -SkBitmapHeap::LookupEntry* SkBitmapHeap::findEntryToReplace(const SkBitmap& replacement) {
|
| - SkASSERT(fPreferredCount != UNLIMITED_SIZE);
|
| - SkASSERT(fStorage.count() >= fPreferredCount);
|
| -
|
| - SkBitmapHeap::LookupEntry* iter = fLeastRecentlyUsed;
|
| - while (iter != nullptr) {
|
| - SkBitmapHeapEntry* heapEntry = fStorage[iter->fStorageSlot];
|
| - if (heapEntry->fRefCount > 0) {
|
| - // If the least recently used bitmap has not been unreferenced
|
| - // by its owner, then according to our LRU specifications a more
|
| - // recently used one can not have used all its references yet either.
|
| - return nullptr;
|
| - }
|
| - if (replacement.getGenerationID() == iter->fGenerationId) {
|
| - // Do not replace a bitmap with a new one using the same
|
| - // pixel ref. Instead look for a different one that will
|
| - // potentially free up more space.
|
| - iter = iter->fMoreRecentlyUsed;
|
| - } else {
|
| - return iter;
|
| - }
|
| - }
|
| - return nullptr;
|
| -}
|
| -
|
| -size_t SkBitmapHeap::freeMemoryIfPossible(size_t bytesToFree) {
|
| - if (UNLIMITED_SIZE == fPreferredCount) {
|
| - return 0;
|
| - }
|
| - LookupEntry* iter = fLeastRecentlyUsed;
|
| - size_t origBytesAllocated = fBytesAllocated;
|
| - // Purge starting from LRU until a non-evictable bitmap is found or until
|
| - // everything is evicted.
|
| - while (iter != nullptr) {
|
| - SkBitmapHeapEntry* heapEntry = fStorage[iter->fStorageSlot];
|
| - if (heapEntry->fRefCount > 0) {
|
| - break;
|
| - }
|
| - LookupEntry* next = iter->fMoreRecentlyUsed;
|
| - this->removeEntryFromLookupTable(iter);
|
| - // Free the pixel memory. removeEntryFromLookupTable already reduced
|
| - // fBytesAllocated properly.
|
| - heapEntry->fBitmap.reset();
|
| - // Add to list of unused slots which can be reused in the future.
|
| - fUnusedSlots.push(heapEntry->fSlot);
|
| - iter = next;
|
| - if (origBytesAllocated - fBytesAllocated >= bytesToFree) {
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (fLeastRecentlyUsed != iter) {
|
| - // There was at least one eviction.
|
| - fLeastRecentlyUsed = iter;
|
| - if (nullptr == fLeastRecentlyUsed) {
|
| - // Everything was evicted
|
| - fMostRecentlyUsed = nullptr;
|
| - fBytesAllocated -= (fStorage.count() * sizeof(SkBitmapHeapEntry));
|
| - fStorage.deleteAll();
|
| - fUnusedSlots.reset();
|
| - SkASSERT(0 == fBytesAllocated);
|
| - } else {
|
| - fLeastRecentlyUsed->fLessRecentlyUsed = nullptr;
|
| - }
|
| - }
|
| -
|
| - return origBytesAllocated - fBytesAllocated;
|
| -}
|
| -
|
| -int SkBitmapHeap::findInLookupTable(const LookupEntry& indexEntry, SkBitmapHeapEntry** entry) {
|
| - int index = SkTSearch<const LookupEntry, LookupEntry::Less>(
|
| - (const LookupEntry**)fLookupTable.begin(),
|
| - fLookupTable.count(),
|
| - &indexEntry, sizeof(void*));
|
| -
|
| - if (index < 0) {
|
| - // insert ourselves into the bitmapIndex
|
| - index = ~index;
|
| - *fLookupTable.insert(index) = new LookupEntry(indexEntry);
|
| - } else if (entry != nullptr) {
|
| - // populate the entry if needed
|
| - *entry = fStorage[fLookupTable[index]->fStorageSlot];
|
| - }
|
| -
|
| - return index;
|
| -}
|
| -
|
| -bool SkBitmapHeap::copyBitmap(const SkBitmap& originalBitmap, SkBitmap& copiedBitmap) {
|
| - SkASSERT(!fExternalStorage);
|
| -
|
| - // If the bitmap is mutable, we need to do a deep copy, since the
|
| - // caller may modify it afterwards.
|
| - if (originalBitmap.isImmutable()) {
|
| - copiedBitmap = originalBitmap;
|
| -// TODO if we have the pixel ref in the heap we could pass it here to avoid a potential deep copy
|
| -// else if (sharedPixelRef != nullptr) {
|
| -// copiedBitmap = orig;
|
| -// copiedBitmap.setPixelRef(sharedPixelRef, originalBitmap.pixelRefOffset());
|
| - } else if (originalBitmap.empty()) {
|
| - copiedBitmap.reset();
|
| - } else if (!originalBitmap.deepCopyTo(&copiedBitmap)) {
|
| - return false;
|
| - }
|
| - copiedBitmap.setImmutable();
|
| - return true;
|
| -}
|
| -
|
| -int SkBitmapHeap::removeEntryFromLookupTable(LookupEntry* entry) {
|
| - // remove the bitmap index for the deleted entry
|
| - SkDEBUGCODE(int count = fLookupTable.count();)
|
| - int index = this->findInLookupTable(*entry, nullptr);
|
| - // Verify that findInLookupTable found an existing entry rather than adding
|
| - // a new entry to the lookup table.
|
| - SkASSERT(count == fLookupTable.count());
|
| - fBytesAllocated -= fStorage[entry->fStorageSlot]->fBytesAllocated;
|
| - delete fLookupTable[index];
|
| - fLookupTable.remove(index);
|
| - return index;
|
| -}
|
| -
|
| -int32_t SkBitmapHeap::insert(const SkBitmap& originalBitmap) {
|
| - SkBitmapHeapEntry* entry = nullptr;
|
| - int searchIndex = this->findInLookupTable(LookupEntry(originalBitmap), &entry);
|
| -
|
| - if (entry) {
|
| - // Already had a copy of the bitmap in the heap.
|
| - if (fOwnerCount != IGNORE_OWNERS) {
|
| - if (fDeferAddingOwners) {
|
| - *fDeferredEntries.append() = entry->fSlot;
|
| - } else {
|
| - entry->addReferences(fOwnerCount);
|
| - }
|
| - }
|
| - if (fPreferredCount != UNLIMITED_SIZE) {
|
| - LookupEntry* lookupEntry = fLookupTable[searchIndex];
|
| - if (lookupEntry != fMostRecentlyUsed) {
|
| - this->removeFromLRU(lookupEntry);
|
| - this->appendToLRU(lookupEntry);
|
| - }
|
| - }
|
| - return entry->fSlot;
|
| - }
|
| -
|
| - // decide if we need to evict an existing heap entry or create a new one
|
| - if (fPreferredCount != UNLIMITED_SIZE && fStorage.count() >= fPreferredCount) {
|
| - // iterate through our LRU cache and try to find an entry to evict
|
| - LookupEntry* lookupEntry = this->findEntryToReplace(originalBitmap);
|
| - if (lookupEntry != nullptr) {
|
| - // we found an entry to evict
|
| - entry = fStorage[lookupEntry->fStorageSlot];
|
| - // Remove it from the LRU. The new entry will be added to the LRU later.
|
| - this->removeFromLRU(lookupEntry);
|
| - int index = this->removeEntryFromLookupTable(lookupEntry);
|
| -
|
| - // update the current search index now that we have removed one
|
| - if (index < searchIndex) {
|
| - searchIndex--;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // if we didn't have an entry yet we need to create one
|
| - if (!entry) {
|
| - if (fPreferredCount != UNLIMITED_SIZE && fUnusedSlots.count() > 0) {
|
| - int slot;
|
| - fUnusedSlots.pop(&slot);
|
| - entry = fStorage[slot];
|
| - } else {
|
| - entry = new SkBitmapHeapEntry;
|
| - fStorage.append(1, &entry);
|
| - entry->fSlot = fStorage.count() - 1;
|
| - fBytesAllocated += sizeof(SkBitmapHeapEntry);
|
| - }
|
| - }
|
| -
|
| - // create a copy of the bitmap
|
| - bool copySucceeded;
|
| - if (fExternalStorage) {
|
| - copySucceeded = fExternalStorage->insert(originalBitmap, entry->fSlot);
|
| - } else {
|
| - copySucceeded = copyBitmap(originalBitmap, entry->fBitmap);
|
| - }
|
| -
|
| - // if the copy failed then we must abort
|
| - if (!copySucceeded) {
|
| - // delete the index
|
| - delete fLookupTable[searchIndex];
|
| - fLookupTable.remove(searchIndex);
|
| - // If entry is the last slot in storage, it is safe to delete it.
|
| - if (fStorage.count() - 1 == entry->fSlot) {
|
| - // free the slot
|
| - fStorage.remove(entry->fSlot);
|
| - fBytesAllocated -= sizeof(SkBitmapHeapEntry);
|
| - delete entry;
|
| - } else {
|
| - fUnusedSlots.push(entry->fSlot);
|
| - }
|
| - return INVALID_SLOT;
|
| - }
|
| -
|
| - // update the index with the appropriate slot in the heap
|
| - fLookupTable[searchIndex]->fStorageSlot = entry->fSlot;
|
| -
|
| - // compute the space taken by this entry
|
| - // TODO if there is a shared pixel ref don't count it
|
| - // If the SkBitmap does not share an SkPixelRef with an SkBitmap already
|
| - // in the SharedHeap, also include the size of its pixels.
|
| - entry->fBytesAllocated = originalBitmap.getSize();
|
| -
|
| - // add the bytes from this entry to the total count
|
| - fBytesAllocated += entry->fBytesAllocated;
|
| -
|
| - if (fOwnerCount != IGNORE_OWNERS) {
|
| - if (fDeferAddingOwners) {
|
| - *fDeferredEntries.append() = entry->fSlot;
|
| - } else {
|
| - entry->addReferences(fOwnerCount);
|
| - }
|
| - }
|
| - if (fPreferredCount != UNLIMITED_SIZE) {
|
| - this->appendToLRU(fLookupTable[searchIndex]);
|
| - }
|
| - return entry->fSlot;
|
| -}
|
| -
|
| -void SkBitmapHeap::deferAddingOwners() {
|
| - fDeferAddingOwners = true;
|
| -}
|
| -
|
| -void SkBitmapHeap::endAddingOwnersDeferral(bool add) {
|
| - if (add) {
|
| - for (int i = 0; i < fDeferredEntries.count(); i++) {
|
| - SkASSERT(fOwnerCount != IGNORE_OWNERS);
|
| - SkBitmapHeapEntry* heapEntry = this->getEntry(fDeferredEntries[i]);
|
| - SkASSERT(heapEntry != nullptr);
|
| - heapEntry->addReferences(fOwnerCount);
|
| - }
|
| - }
|
| - fDeferAddingOwners = false;
|
| - fDeferredEntries.reset();
|
| -}
|
|
|