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(); |
-} |