| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2013 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #include "SkLruImageCache.h" | |
| 9 | |
| 10 static intptr_t NextGenerationID() { | |
| 11 static intptr_t gNextID; | |
| 12 do { | |
| 13 gNextID++; | |
| 14 } while (SkImageCache::UNINITIALIZED_ID == gNextID); | |
| 15 return gNextID; | |
| 16 } | |
| 17 | |
| 18 class CachedPixels : public SkNoncopyable { | |
| 19 | |
| 20 public: | |
| 21 CachedPixels(size_t length) | |
| 22 : fLength(length) | |
| 23 , fID(NextGenerationID()) | |
| 24 , fLocked(false) { | |
| 25 fAddr = sk_malloc_throw(length); | |
| 26 } | |
| 27 | |
| 28 ~CachedPixels() { | |
| 29 sk_free(fAddr); | |
| 30 } | |
| 31 | |
| 32 void* getData() { return fAddr; } | |
| 33 | |
| 34 intptr_t getID() const { return fID; } | |
| 35 | |
| 36 size_t getLength() const { return fLength; } | |
| 37 | |
| 38 void lock() { SkASSERT(!fLocked); fLocked = true; } | |
| 39 | |
| 40 void unlock() { SkASSERT(fLocked); fLocked = false; } | |
| 41 | |
| 42 bool isLocked() const { return fLocked; } | |
| 43 | |
| 44 private: | |
| 45 void* fAddr; | |
| 46 size_t fLength; | |
| 47 const intptr_t fID; | |
| 48 bool fLocked; | |
| 49 SK_DECLARE_INTERNAL_LLIST_INTERFACE(CachedPixels); | |
| 50 }; | |
| 51 | |
| 52 ////////////////////////////////////////////////////////////////////////////////
//// | |
| 53 | |
| 54 SkLruImageCache::SkLruImageCache(size_t budget) | |
| 55 : fRamBudget(budget) | |
| 56 , fRamUsed(0) {} | |
| 57 | |
| 58 SkLruImageCache::~SkLruImageCache() { | |
| 59 // Don't worry about updating pointers. All will be deleted. | |
| 60 Iter iter; | |
| 61 CachedPixels* pixels = iter.init(fLRU, Iter::kTail_IterStart); | |
| 62 while (pixels != NULL) { | |
| 63 CachedPixels* prev = iter.prev(); | |
| 64 SkASSERT(!pixels->isLocked()); | |
| 65 #ifdef SK_DEBUG | |
| 66 fRamUsed -= pixels->getLength(); | |
| 67 #endif | |
| 68 SkDELETE(pixels); | |
| 69 pixels = prev; | |
| 70 } | |
| 71 #ifdef SK_DEBUG | |
| 72 SkASSERT(fRamUsed == 0); | |
| 73 #endif | |
| 74 } | |
| 75 | |
| 76 #ifdef SK_DEBUG | |
| 77 SkImageCache::MemoryStatus SkLruImageCache::getMemoryStatus(intptr_t ID) const { | |
| 78 if (SkImageCache::UNINITIALIZED_ID == ID) { | |
| 79 return SkImageCache::kFreed_MemoryStatus; | |
| 80 } | |
| 81 SkAutoMutexAcquire ac(&fMutex); | |
| 82 CachedPixels* pixels = this->findByID(ID); | |
| 83 if (NULL == pixels) { | |
| 84 return SkImageCache::kFreed_MemoryStatus; | |
| 85 } | |
| 86 if (pixels->isLocked()) { | |
| 87 return SkImageCache::kPinned_MemoryStatus; | |
| 88 } | |
| 89 return SkImageCache::kUnpinned_MemoryStatus; | |
| 90 } | |
| 91 | |
| 92 void SkLruImageCache::purgeAllUnpinnedCaches() { | |
| 93 SkAutoMutexAcquire ac(&fMutex); | |
| 94 this->purgeTilAtOrBelow(0); | |
| 95 } | |
| 96 #endif | |
| 97 | |
| 98 size_t SkLruImageCache::setImageCacheLimit(size_t newLimit) { | |
| 99 size_t oldLimit = fRamBudget; | |
| 100 SkAutoMutexAcquire ac(&fMutex); | |
| 101 fRamBudget = newLimit; | |
| 102 this->purgeIfNeeded(); | |
| 103 return oldLimit; | |
| 104 } | |
| 105 | |
| 106 void* SkLruImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) { | |
| 107 SkAutoMutexAcquire ac(&fMutex); | |
| 108 CachedPixels* pixels = SkNEW_ARGS(CachedPixels, (bytes)); | |
| 109 if (ID != NULL) { | |
| 110 *ID = pixels->getID(); | |
| 111 } | |
| 112 pixels->lock(); | |
| 113 fRamUsed += bytes; | |
| 114 fLRU.addToHead(pixels); | |
| 115 this->purgeIfNeeded(); | |
| 116 return pixels->getData(); | |
| 117 } | |
| 118 | |
| 119 void* SkLruImageCache::pinCache(intptr_t ID, SkImageCache::DataStatus* status) { | |
| 120 SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); | |
| 121 SkAutoMutexAcquire ac(&fMutex); | |
| 122 CachedPixels* pixels = this->findByID(ID); | |
| 123 if (NULL == pixels) { | |
| 124 return NULL; | |
| 125 } | |
| 126 if (pixels != fLRU.head()) { | |
| 127 fLRU.remove(pixels); | |
| 128 fLRU.addToHead(pixels); | |
| 129 } | |
| 130 SkASSERT(status != NULL); | |
| 131 // This cache will never return pinned memory whose data has been overwritte
n. | |
| 132 *status = SkImageCache::kRetained_DataStatus; | |
| 133 pixels->lock(); | |
| 134 return pixels->getData(); | |
| 135 } | |
| 136 | |
| 137 void SkLruImageCache::releaseCache(intptr_t ID) { | |
| 138 SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); | |
| 139 SkAutoMutexAcquire ac(&fMutex); | |
| 140 CachedPixels* pixels = this->findByID(ID); | |
| 141 SkASSERT(pixels != NULL); | |
| 142 pixels->unlock(); | |
| 143 this->purgeIfNeeded(); | |
| 144 } | |
| 145 | |
| 146 void SkLruImageCache::throwAwayCache(intptr_t ID) { | |
| 147 SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); | |
| 148 SkAutoMutexAcquire ac(&fMutex); | |
| 149 CachedPixels* pixels = this->findByID(ID); | |
| 150 if (pixels != NULL) { | |
| 151 if (pixels->isLocked()) { | |
| 152 pixels->unlock(); | |
| 153 } | |
| 154 this->removePixels(pixels); | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 void SkLruImageCache::removePixels(CachedPixels* pixels) { | |
| 159 // Mutex is already locked. | |
| 160 SkASSERT(!pixels->isLocked()); | |
| 161 const size_t size = pixels->getLength(); | |
| 162 SkASSERT(size <= fRamUsed); | |
| 163 fLRU.remove(pixels); | |
| 164 SkDELETE(pixels); | |
| 165 fRamUsed -= size; | |
| 166 } | |
| 167 | |
| 168 CachedPixels* SkLruImageCache::findByID(intptr_t ID) const { | |
| 169 // Mutex is already locked. | |
| 170 Iter iter; | |
| 171 // Start from the head, most recently used. | |
| 172 CachedPixels* pixels = iter.init(fLRU, Iter::kHead_IterStart); | |
| 173 while (pixels != NULL) { | |
| 174 if (pixels->getID() == ID) { | |
| 175 return pixels; | |
| 176 } | |
| 177 pixels = iter.next(); | |
| 178 } | |
| 179 return NULL; | |
| 180 } | |
| 181 | |
| 182 void SkLruImageCache::purgeIfNeeded() { | |
| 183 // Mutex is already locked. | |
| 184 if (fRamBudget > 0) { | |
| 185 this->purgeTilAtOrBelow(fRamBudget); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 void SkLruImageCache::purgeTilAtOrBelow(size_t limit) { | |
| 190 // Mutex is already locked. | |
| 191 if (fRamUsed > limit) { | |
| 192 Iter iter; | |
| 193 // Start from the tail, least recently used. | |
| 194 CachedPixels* pixels = iter.init(fLRU, Iter::kTail_IterStart); | |
| 195 while (pixels != NULL && fRamUsed > limit) { | |
| 196 CachedPixels* prev = iter.prev(); | |
| 197 if (!pixels->isLocked()) { | |
| 198 this->removePixels(pixels); | |
| 199 } | |
| 200 pixels = prev; | |
| 201 } | |
| 202 } | |
| 203 } | |
| OLD | NEW |