121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com/* 321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com * Copyright 2012 Google Inc. 421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com * 521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com * Use of this source code is governed by a BSD-style license that can be 621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com * found in the LICENSE file. 721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com */ 821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com#include "SkBitmapHeap.h" 1021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com#include "SkBitmap.h" 1121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com#include "SkTSearch.h" 1221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 1321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.comSkBitmapHeapEntry::SkBitmapHeapEntry() 1421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com : fSlot(-1) 1521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com , fRefCount(0) 163e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com , fBytesAllocated(0) { 1721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 1821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 1921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.comSkBitmapHeapEntry::~SkBitmapHeapEntry() { 2021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com SkASSERT(0 == fRefCount); 2121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 2221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 2321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.comvoid SkBitmapHeapEntry::addReferences(int count) { 2421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (0 == fRefCount) { 2521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // If there are no current owners then the heap manager 2621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // will be the only one able to modify it, so it does not 2721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // need to be an atomic operation. 2821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com fRefCount = count; 2921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } else { 3021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com sk_atomic_add(&fRefCount, count); 3121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 3221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 3321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 3421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com/////////////////////////////////////////////////////////////////////////////// 3521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 36672588b684d484dce6ae251e9e163e4a46924322reed@google.comstatic bool operator<(const SkIPoint& a, const SkIPoint& b) { 37672588b684d484dce6ae251e9e163e4a46924322reed@google.com return *(const int64_t*)&a < *(const int64_t*)&b; 38672588b684d484dce6ae251e9e163e4a46924322reed@google.com} 39672588b684d484dce6ae251e9e163e4a46924322reed@google.com 40672588b684d484dce6ae251e9e163e4a46924322reed@google.comstatic bool operator>(const SkIPoint& a, const SkIPoint& b) { 41672588b684d484dce6ae251e9e163e4a46924322reed@google.com return *(const int64_t*)&a > *(const int64_t*)&b; 42672588b684d484dce6ae251e9e163e4a46924322reed@google.com} 43672588b684d484dce6ae251e9e163e4a46924322reed@google.com 4420f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.combool SkBitmapHeap::LookupEntry::Less(const SkBitmapHeap::LookupEntry& a, 4520f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com const SkBitmapHeap::LookupEntry& b) { 4620f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com if (a.fGenerationId < b.fGenerationId) { 4720f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com return true; 4820f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com } else if (a.fGenerationId > b.fGenerationId) { 4920f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com return false; 50672588b684d484dce6ae251e9e163e4a46924322reed@google.com } else if (a.fPixelOrigin < b.fPixelOrigin) { 5120f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com return true; 52672588b684d484dce6ae251e9e163e4a46924322reed@google.com } else if (a.fPixelOrigin > b.fPixelOrigin) { 5320f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com return false; 5420f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com } else if (a.fWidth < b.fWidth) { 5520f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com return true; 5620f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com } else if (a.fWidth > b.fWidth) { 5720f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com return false; 5820f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com } else if (a.fHeight < b.fHeight) { 5920f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com return true; 603e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com } 6120f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com return false; 623e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com} 633e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com 643e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com/////////////////////////////////////////////////////////////////////////////// 653e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com 6621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.comSkBitmapHeap::SkBitmapHeap(int32_t preferredSize, int32_t ownerCount) 6721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com : INHERITED() 682880df2609eba09b555ca37be04b6ad89290c765Tom Hudson , fExternalStorage(nullptr) 692880df2609eba09b555ca37be04b6ad89290c765Tom Hudson , fMostRecentlyUsed(nullptr) 702880df2609eba09b555ca37be04b6ad89290c765Tom Hudson , fLeastRecentlyUsed(nullptr) 7121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com , fPreferredCount(preferredSize) 7221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com , fOwnerCount(ownerCount) 737ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com , fBytesAllocated(0) 747ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com , fDeferAddingOwners(false) { 7521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 7621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 7721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.comSkBitmapHeap::SkBitmapHeap(ExternalStorage* storage, int32_t preferredSize) 7821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com : INHERITED() 7921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com , fExternalStorage(storage) 802880df2609eba09b555ca37be04b6ad89290c765Tom Hudson , fMostRecentlyUsed(nullptr) 812880df2609eba09b555ca37be04b6ad89290c765Tom Hudson , fLeastRecentlyUsed(nullptr) 8221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com , fPreferredCount(preferredSize) 8321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com , fOwnerCount(IGNORE_OWNERS) 847ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com , fBytesAllocated(0) 857ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com , fDeferAddingOwners(false) { 8610dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com SkSafeRef(storage); 8721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 8821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 8921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.comSkBitmapHeap::~SkBitmapHeap() { 9010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com SkDEBUGCODE( 9110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com for (int i = 0; i < fStorage.count(); i++) { 9210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com bool unused = false; 9310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com for (int j = 0; j < fUnusedSlots.count(); j++) { 9410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com if (fUnusedSlots[j] == fStorage[i]->fSlot) { 9510dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com unused = true; 9610dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com break; 9710dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 9810dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 9910dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com if (!unused) { 10010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fBytesAllocated -= fStorage[i]->fBytesAllocated; 10110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 10210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 10310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fBytesAllocated -= (fStorage.count() * sizeof(SkBitmapHeapEntry)); 10410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com ) 10510dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com SkASSERT(0 == fBytesAllocated); 10621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com fStorage.deleteAll(); 10721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com SkSafeUnref(fExternalStorage); 108c51db02181982fbcb8888e2a89132363a7d9371cscroggo fLookupTable.deleteAll(); 10921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 11021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 1113e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.comvoid SkBitmapHeap::removeFromLRU(SkBitmapHeap::LookupEntry* entry) { 1123e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com if (fMostRecentlyUsed == entry) { 1133e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com fMostRecentlyUsed = entry->fLessRecentlyUsed; 1142880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (nullptr == fMostRecentlyUsed) { 1153e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com SkASSERT(fLeastRecentlyUsed == entry); 1162880df2609eba09b555ca37be04b6ad89290c765Tom Hudson fLeastRecentlyUsed = nullptr; 1173e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com } else { 1182880df2609eba09b555ca37be04b6ad89290c765Tom Hudson fMostRecentlyUsed->fMoreRecentlyUsed = nullptr; 1193e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com } 1203e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com } else { 1213e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com // Remove entry from its prior place, and make sure to cover the hole. 1223e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com if (fLeastRecentlyUsed == entry) { 1232880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkASSERT(entry->fMoreRecentlyUsed != nullptr); 1243e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com fLeastRecentlyUsed = entry->fMoreRecentlyUsed; 1253e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com } 1263e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com // Since we have already considered the case where entry is the most recently used, it must 1273e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com // have a more recently used at this point. 1282880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkASSERT(entry->fMoreRecentlyUsed != nullptr); 12921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com entry->fMoreRecentlyUsed->fLessRecentlyUsed = entry->fLessRecentlyUsed; 1303e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com 1312880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (entry->fLessRecentlyUsed != nullptr) { 1323e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com SkASSERT(fLeastRecentlyUsed != entry); 1333e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com entry->fLessRecentlyUsed->fMoreRecentlyUsed = entry->fMoreRecentlyUsed; 1343e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com } 13521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 1362880df2609eba09b555ca37be04b6ad89290c765Tom Hudson entry->fMoreRecentlyUsed = nullptr; 1373e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com} 1383e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com 1393e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.comvoid SkBitmapHeap::appendToLRU(SkBitmapHeap::LookupEntry* entry) { 1402880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (fMostRecentlyUsed != nullptr) { 1412880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkASSERT(nullptr == fMostRecentlyUsed->fMoreRecentlyUsed); 14221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com fMostRecentlyUsed->fMoreRecentlyUsed = entry; 14321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com entry->fLessRecentlyUsed = fMostRecentlyUsed; 14421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 14521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com fMostRecentlyUsed = entry; 1462880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (nullptr == fLeastRecentlyUsed) { 14721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com fLeastRecentlyUsed = entry; 14821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 14921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 15021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 15121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com// iterate through our LRU cache and try to find an entry to evict 1523e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.comSkBitmapHeap::LookupEntry* SkBitmapHeap::findEntryToReplace(const SkBitmap& replacement) { 15321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com SkASSERT(fPreferredCount != UNLIMITED_SIZE); 15421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com SkASSERT(fStorage.count() >= fPreferredCount); 15521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 1563e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com SkBitmapHeap::LookupEntry* iter = fLeastRecentlyUsed; 1572880df2609eba09b555ca37be04b6ad89290c765Tom Hudson while (iter != nullptr) { 1583e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com SkBitmapHeapEntry* heapEntry = fStorage[iter->fStorageSlot]; 1593e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com if (heapEntry->fRefCount > 0) { 16021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // If the least recently used bitmap has not been unreferenced 16121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // by its owner, then according to our LRU specifications a more 1627ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com // recently used one can not have used all its references yet either. 1632880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return nullptr; 16421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 1653e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com if (replacement.getGenerationID() == iter->fGenerationId) { 16621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // Do not replace a bitmap with a new one using the same 16721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // pixel ref. Instead look for a different one that will 16821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // potentially free up more space. 16921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com iter = iter->fMoreRecentlyUsed; 17021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } else { 17121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com return iter; 17221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 17321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 1742880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return nullptr; 17521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 17621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 17710dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.comsize_t SkBitmapHeap::freeMemoryIfPossible(size_t bytesToFree) { 17810dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com if (UNLIMITED_SIZE == fPreferredCount) { 17910dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com return 0; 18010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 1813e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com LookupEntry* iter = fLeastRecentlyUsed; 18210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com size_t origBytesAllocated = fBytesAllocated; 18310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // Purge starting from LRU until a non-evictable bitmap is found or until 18410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // everything is evicted. 1852880df2609eba09b555ca37be04b6ad89290c765Tom Hudson while (iter != nullptr) { 1863e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com SkBitmapHeapEntry* heapEntry = fStorage[iter->fStorageSlot]; 1873e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com if (heapEntry->fRefCount > 0) { 1883e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com break; 1893e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com } 1903e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com LookupEntry* next = iter->fMoreRecentlyUsed; 1913e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com this->removeEntryFromLookupTable(iter); 19210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // Free the pixel memory. removeEntryFromLookupTable already reduced 19310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // fBytesAllocated properly. 1943e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com heapEntry->fBitmap.reset(); 19510dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // Add to list of unused slots which can be reused in the future. 1963e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com fUnusedSlots.push(heapEntry->fSlot); 19710dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com iter = next; 19810dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com if (origBytesAllocated - fBytesAllocated >= bytesToFree) { 19910dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com break; 20010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 20110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 20210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com 20310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com if (fLeastRecentlyUsed != iter) { 20410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // There was at least one eviction. 20510dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fLeastRecentlyUsed = iter; 2062880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (nullptr == fLeastRecentlyUsed) { 20710dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // Everything was evicted 2082880df2609eba09b555ca37be04b6ad89290c765Tom Hudson fMostRecentlyUsed = nullptr; 20910dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fBytesAllocated -= (fStorage.count() * sizeof(SkBitmapHeapEntry)); 21010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fStorage.deleteAll(); 21110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fUnusedSlots.reset(); 21210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com SkASSERT(0 == fBytesAllocated); 21310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } else { 2142880df2609eba09b555ca37be04b6ad89290c765Tom Hudson fLeastRecentlyUsed->fLessRecentlyUsed = nullptr; 21510dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 21610dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 217fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 21810dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com return origBytesAllocated - fBytesAllocated; 21910dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com} 22010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com 22110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.comint SkBitmapHeap::findInLookupTable(const LookupEntry& indexEntry, SkBitmapHeapEntry** entry) { 22220f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com int index = SkTSearch<const LookupEntry, LookupEntry::Less>( 22320f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com (const LookupEntry**)fLookupTable.begin(), 22410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fLookupTable.count(), 22520f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com &indexEntry, sizeof(void*)); 22621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 22721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (index < 0) { 22821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // insert ourselves into the bitmapIndex 22921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com index = ~index; 2302880df2609eba09b555ca37be04b6ad89290c765Tom Hudson *fLookupTable.insert(index) = new LookupEntry(indexEntry); 2312880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else if (entry != nullptr) { 23221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // populate the entry if needed 2333e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com *entry = fStorage[fLookupTable[index]->fStorageSlot]; 23421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 23521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 23621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com return index; 23721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 23821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 23921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.combool SkBitmapHeap::copyBitmap(const SkBitmap& originalBitmap, SkBitmap& copiedBitmap) { 24021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com SkASSERT(!fExternalStorage); 24121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 24221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // If the bitmap is mutable, we need to do a deep copy, since the 24321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // caller may modify it afterwards. 24421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (originalBitmap.isImmutable()) { 24521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com copiedBitmap = originalBitmap; 24621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com// TODO if we have the pixel ref in the heap we could pass it here to avoid a potential deep copy 2472880df2609eba09b555ca37be04b6ad89290c765Tom Hudson// else if (sharedPixelRef != nullptr) { 24821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com// copiedBitmap = orig; 24921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com// copiedBitmap.setPixelRef(sharedPixelRef, originalBitmap.pixelRefOffset()); 25021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } else if (originalBitmap.empty()) { 25121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com copiedBitmap.reset(); 2526285f4f7662853336b788d6ee3e177c396f7fb01commit-bot@chromium.org } else if (!originalBitmap.deepCopyTo(&copiedBitmap)) { 25321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com return false; 25421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 25521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com copiedBitmap.setImmutable(); 25621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com return true; 25721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 25821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 2593e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.comint SkBitmapHeap::removeEntryFromLookupTable(LookupEntry* entry) { 26010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // remove the bitmap index for the deleted entry 26110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com SkDEBUGCODE(int count = fLookupTable.count();) 2622880df2609eba09b555ca37be04b6ad89290c765Tom Hudson int index = this->findInLookupTable(*entry, nullptr); 26310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // Verify that findInLookupTable found an existing entry rather than adding 26410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // a new entry to the lookup table. 26510dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com SkASSERT(count == fLookupTable.count()); 2663e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com fBytesAllocated -= fStorage[entry->fStorageSlot]->fBytesAllocated; 2672880df2609eba09b555ca37be04b6ad89290c765Tom Hudson delete fLookupTable[index]; 26810dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fLookupTable.remove(index); 26910dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com return index; 27010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com} 27110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com 27221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.comint32_t SkBitmapHeap::insert(const SkBitmap& originalBitmap) { 2732880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkBitmapHeapEntry* entry = nullptr; 27410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com int searchIndex = this->findInLookupTable(LookupEntry(originalBitmap), &entry); 27521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 27621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (entry) { 2773e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com // Already had a copy of the bitmap in the heap. 27821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (fOwnerCount != IGNORE_OWNERS) { 2797ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com if (fDeferAddingOwners) { 2807ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com *fDeferredEntries.append() = entry->fSlot; 2817ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com } else { 2827ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com entry->addReferences(fOwnerCount); 2837ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com } 28421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 28521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (fPreferredCount != UNLIMITED_SIZE) { 2863e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com LookupEntry* lookupEntry = fLookupTable[searchIndex]; 2873e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com if (lookupEntry != fMostRecentlyUsed) { 2883e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com this->removeFromLRU(lookupEntry); 2893e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com this->appendToLRU(lookupEntry); 2903e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com } 29121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 29221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com return entry->fSlot; 29321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 29421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 29521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // decide if we need to evict an existing heap entry or create a new one 29621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (fPreferredCount != UNLIMITED_SIZE && fStorage.count() >= fPreferredCount) { 29721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // iterate through our LRU cache and try to find an entry to evict 2983e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com LookupEntry* lookupEntry = this->findEntryToReplace(originalBitmap); 2992880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (lookupEntry != nullptr) { 3003e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com // we found an entry to evict 3013e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com entry = fStorage[lookupEntry->fStorageSlot]; 3023e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com // Remove it from the LRU. The new entry will be added to the LRU later. 3033e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com this->removeFromLRU(lookupEntry); 3043e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com int index = this->removeEntryFromLookupTable(lookupEntry); 30521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 30621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // update the current search index now that we have removed one 30721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (index < searchIndex) { 30821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com searchIndex--; 30921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 31021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 31121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 31221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 31321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // if we didn't have an entry yet we need to create one 31421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (!entry) { 31510dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com if (fPreferredCount != UNLIMITED_SIZE && fUnusedSlots.count() > 0) { 31610dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com int slot; 31710dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fUnusedSlots.pop(&slot); 31810dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com entry = fStorage[slot]; 31910dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } else { 3202880df2609eba09b555ca37be04b6ad89290c765Tom Hudson entry = new SkBitmapHeapEntry; 32110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fStorage.append(1, &entry); 32210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com entry->fSlot = fStorage.count() - 1; 32310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fBytesAllocated += sizeof(SkBitmapHeapEntry); 32410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 32521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 32621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 32721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // create a copy of the bitmap 32821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com bool copySucceeded; 32921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (fExternalStorage) { 33021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com copySucceeded = fExternalStorage->insert(originalBitmap, entry->fSlot); 33121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } else { 33221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com copySucceeded = copyBitmap(originalBitmap, entry->fBitmap); 33321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 33421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 33521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // if the copy failed then we must abort 33621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (!copySucceeded) { 33721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // delete the index 3382880df2609eba09b555ca37be04b6ad89290c765Tom Hudson delete fLookupTable[searchIndex]; 33921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com fLookupTable.remove(searchIndex); 34010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // If entry is the last slot in storage, it is safe to delete it. 34110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com if (fStorage.count() - 1 == entry->fSlot) { 34210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com // free the slot 34310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fStorage.remove(entry->fSlot); 34410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com fBytesAllocated -= sizeof(SkBitmapHeapEntry); 3452880df2609eba09b555ca37be04b6ad89290c765Tom Hudson delete entry; 3463e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com } else { 3473e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com fUnusedSlots.push(entry->fSlot); 34810dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com } 34921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com return INVALID_SLOT; 35021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 35121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 35221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // update the index with the appropriate slot in the heap 3533e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com fLookupTable[searchIndex]->fStorageSlot = entry->fSlot; 35421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 3553e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com // compute the space taken by this entry 35621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // TODO if there is a shared pixel ref don't count it 35721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // If the SkBitmap does not share an SkPixelRef with an SkBitmap already 35821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // in the SharedHeap, also include the size of its pixels. 359ce65f385a0d31a93a31ffd57478de4b8c4e833b3junov@chromium.org entry->fBytesAllocated = originalBitmap.getSize(); 36021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 36121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com // add the bytes from this entry to the total count 36221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com fBytesAllocated += entry->fBytesAllocated; 36321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com 36421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (fOwnerCount != IGNORE_OWNERS) { 365013c5d9107a4abd50e879ca66cf60b0c3a8256d4scroggo@google.com if (fDeferAddingOwners) { 366013c5d9107a4abd50e879ca66cf60b0c3a8256d4scroggo@google.com *fDeferredEntries.append() = entry->fSlot; 367013c5d9107a4abd50e879ca66cf60b0c3a8256d4scroggo@google.com } else { 368013c5d9107a4abd50e879ca66cf60b0c3a8256d4scroggo@google.com entry->addReferences(fOwnerCount); 369013c5d9107a4abd50e879ca66cf60b0c3a8256d4scroggo@google.com } 37021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 37121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com if (fPreferredCount != UNLIMITED_SIZE) { 3723e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com this->appendToLRU(fLookupTable[searchIndex]); 37321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com } 37421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com return entry->fSlot; 37521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com} 3767ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com 3777ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.comvoid SkBitmapHeap::deferAddingOwners() { 3787ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com fDeferAddingOwners = true; 3797ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com} 3807ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com 3817ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.comvoid SkBitmapHeap::endAddingOwnersDeferral(bool add) { 3827ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com if (add) { 3837ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com for (int i = 0; i < fDeferredEntries.count(); i++) { 3847ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com SkASSERT(fOwnerCount != IGNORE_OWNERS); 3857ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com SkBitmapHeapEntry* heapEntry = this->getEntry(fDeferredEntries[i]); 3862880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkASSERT(heapEntry != nullptr); 3877ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com heapEntry->addReferences(fOwnerCount); 3887ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com } 3897ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com } 3907ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com fDeferAddingOwners = false; 3917ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com fDeferredEntries.reset(); 3927ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com} 393