1 /* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "platform/graphics/ImageDecodingStore.h" 28 29 #include "platform/TraceEvent.h" 30 #include "wtf/Threading.h" 31 32 namespace blink { 33 34 namespace { 35 36 static const size_t defaultMaxTotalSizeOfHeapEntries = 32 * 1024 * 1024; 37 38 } // namespace 39 40 ImageDecodingStore::ImageDecodingStore() 41 : m_heapLimitInBytes(defaultMaxTotalSizeOfHeapEntries) 42 , m_heapMemoryUsageInBytes(0) 43 { 44 } 45 46 ImageDecodingStore::~ImageDecodingStore() 47 { 48 #if ENABLE(ASSERT) 49 setCacheLimitInBytes(0); 50 ASSERT(!m_decoderCacheMap.size()); 51 ASSERT(!m_orderedCacheList.size()); 52 ASSERT(!m_decoderCacheKeyMap.size()); 53 #endif 54 } 55 56 ImageDecodingStore* ImageDecodingStore::instance() 57 { 58 AtomicallyInitializedStatic(ImageDecodingStore*, store = ImageDecodingStore::create().leakPtr()); 59 return store; 60 } 61 62 bool ImageDecodingStore::lockDecoder(const ImageFrameGenerator* generator, const SkISize& scaledSize, ImageDecoder** decoder) 63 { 64 ASSERT(decoder); 65 66 MutexLocker lock(m_mutex); 67 DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::makeCacheKey(generator, scaledSize)); 68 if (iter == m_decoderCacheMap.end()) 69 return false; 70 71 DecoderCacheEntry* cacheEntry = iter->value.get(); 72 73 // There can only be one user of a decoder at a time. 74 ASSERT(!cacheEntry->useCount()); 75 cacheEntry->incrementUseCount(); 76 *decoder = cacheEntry->cachedDecoder(); 77 return true; 78 } 79 80 void ImageDecodingStore::unlockDecoder(const ImageFrameGenerator* generator, const ImageDecoder* decoder) 81 { 82 MutexLocker lock(m_mutex); 83 DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::makeCacheKey(generator, decoder)); 84 ASSERT_WITH_SECURITY_IMPLICATION(iter != m_decoderCacheMap.end()); 85 86 CacheEntry* cacheEntry = iter->value.get(); 87 cacheEntry->decrementUseCount(); 88 89 // Put the entry to the end of list. 90 m_orderedCacheList.remove(cacheEntry); 91 m_orderedCacheList.append(cacheEntry); 92 } 93 94 void ImageDecodingStore::insertDecoder(const ImageFrameGenerator* generator, PassOwnPtr<ImageDecoder> decoder) 95 { 96 // Prune old cache entries to give space for the new one. 97 prune(); 98 99 OwnPtr<DecoderCacheEntry> newCacheEntry = DecoderCacheEntry::create(generator, decoder); 100 101 MutexLocker lock(m_mutex); 102 ASSERT(!m_decoderCacheMap.contains(newCacheEntry->cacheKey())); 103 insertCacheInternal(newCacheEntry.release(), &m_decoderCacheMap, &m_decoderCacheKeyMap); 104 } 105 106 void ImageDecodingStore::removeDecoder(const ImageFrameGenerator* generator, const ImageDecoder* decoder) 107 { 108 Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete; 109 { 110 MutexLocker lock(m_mutex); 111 DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::makeCacheKey(generator, decoder)); 112 ASSERT_WITH_SECURITY_IMPLICATION(iter != m_decoderCacheMap.end()); 113 114 CacheEntry* cacheEntry = iter->value.get(); 115 ASSERT(cacheEntry->useCount()); 116 cacheEntry->decrementUseCount(); 117 118 // Delete only one decoder cache entry. Ownership of the cache entry 119 // is transfered to cacheEntriesToDelete such that object can be deleted 120 // outside of the lock. 121 removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete); 122 123 // Remove from LRU list. 124 removeFromCacheListInternal(cacheEntriesToDelete); 125 } 126 } 127 128 void ImageDecodingStore::removeCacheIndexedByGenerator(const ImageFrameGenerator* generator) 129 { 130 Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete; 131 { 132 MutexLocker lock(m_mutex); 133 134 // Remove image cache objects and decoder cache objects associated 135 // with a ImageFrameGenerator. 136 removeCacheIndexedByGeneratorInternal(&m_decoderCacheMap, &m_decoderCacheKeyMap, generator, &cacheEntriesToDelete); 137 138 // Remove from LRU list as well. 139 removeFromCacheListInternal(cacheEntriesToDelete); 140 } 141 } 142 143 void ImageDecodingStore::clear() 144 { 145 size_t cacheLimitInBytes; 146 { 147 MutexLocker lock(m_mutex); 148 cacheLimitInBytes = m_heapLimitInBytes; 149 m_heapLimitInBytes = 0; 150 } 151 152 prune(); 153 154 { 155 MutexLocker lock(m_mutex); 156 m_heapLimitInBytes = cacheLimitInBytes; 157 } 158 } 159 160 void ImageDecodingStore::setCacheLimitInBytes(size_t cacheLimit) 161 { 162 { 163 MutexLocker lock(m_mutex); 164 m_heapLimitInBytes = cacheLimit; 165 } 166 prune(); 167 } 168 169 size_t ImageDecodingStore::memoryUsageInBytes() 170 { 171 MutexLocker lock(m_mutex); 172 return m_heapMemoryUsageInBytes; 173 } 174 175 int ImageDecodingStore::cacheEntries() 176 { 177 MutexLocker lock(m_mutex); 178 return m_decoderCacheMap.size(); 179 } 180 181 int ImageDecodingStore::decoderCacheEntries() 182 { 183 MutexLocker lock(m_mutex); 184 return m_decoderCacheMap.size(); 185 } 186 187 void ImageDecodingStore::prune() 188 { 189 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStore::prune"); 190 191 Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete; 192 { 193 MutexLocker lock(m_mutex); 194 195 // Head of the list is the least recently used entry. 196 const CacheEntry* cacheEntry = m_orderedCacheList.head(); 197 198 // Walk the list of cache entries starting from the least recently used 199 // and then keep them for deletion later. 200 while (cacheEntry) { 201 const bool isPruneNeeded = m_heapMemoryUsageInBytes > m_heapLimitInBytes || !m_heapLimitInBytes; 202 if (!isPruneNeeded) 203 break; 204 205 // Cache is not used; Remove it. 206 if (!cacheEntry->useCount()) 207 removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete); 208 cacheEntry = cacheEntry->next(); 209 } 210 211 // Remove from cache list as well. 212 removeFromCacheListInternal(cacheEntriesToDelete); 213 } 214 } 215 216 template<class T, class U, class V> 217 void ImageDecodingStore::insertCacheInternal(PassOwnPtr<T> cacheEntry, U* cacheMap, V* identifierMap) 218 { 219 const size_t cacheEntryBytes = cacheEntry->memoryUsageInBytes(); 220 m_heapMemoryUsageInBytes += cacheEntryBytes; 221 222 // m_orderedCacheList is used to support LRU operations to reorder cache 223 // entries quickly. 224 m_orderedCacheList.append(cacheEntry.get()); 225 226 typename U::KeyType key = cacheEntry->cacheKey(); 227 typename V::AddResult result = identifierMap->add(cacheEntry->generator(), typename V::MappedType()); 228 result.storedValue->value.add(key); 229 cacheMap->add(key, cacheEntry); 230 231 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreHeapMemoryUsageBytes", m_heapMemoryUsageInBytes); 232 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreNumOfDecoders", m_decoderCacheMap.size()); 233 } 234 235 template<class T, class U, class V> 236 void ImageDecodingStore::removeFromCacheInternal(const T* cacheEntry, U* cacheMap, V* identifierMap, Vector<OwnPtr<CacheEntry> >* deletionList) 237 { 238 const size_t cacheEntryBytes = cacheEntry->memoryUsageInBytes(); 239 ASSERT(m_heapMemoryUsageInBytes >= cacheEntryBytes); 240 m_heapMemoryUsageInBytes -= cacheEntryBytes; 241 242 // Remove entry from identifier map. 243 typename V::iterator iter = identifierMap->find(cacheEntry->generator()); 244 ASSERT(iter != identifierMap->end()); 245 iter->value.remove(cacheEntry->cacheKey()); 246 if (!iter->value.size()) 247 identifierMap->remove(iter); 248 249 // Remove entry from cache map. 250 deletionList->append(cacheMap->take(cacheEntry->cacheKey())); 251 252 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreHeapMemoryUsageBytes", m_heapMemoryUsageInBytes); 253 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreNumOfDecoders", m_decoderCacheMap.size()); 254 } 255 256 void ImageDecodingStore::removeFromCacheInternal(const CacheEntry* cacheEntry, Vector<OwnPtr<CacheEntry> >* deletionList) 257 { 258 if (cacheEntry->type() == CacheEntry::TypeDecoder) { 259 removeFromCacheInternal(static_cast<const DecoderCacheEntry*>(cacheEntry), &m_decoderCacheMap, &m_decoderCacheKeyMap, deletionList); 260 } else { 261 ASSERT(false); 262 } 263 } 264 265 template<class U, class V> 266 void ImageDecodingStore::removeCacheIndexedByGeneratorInternal(U* cacheMap, V* identifierMap, const ImageFrameGenerator* generator, Vector<OwnPtr<CacheEntry> >* deletionList) 267 { 268 typename V::iterator iter = identifierMap->find(generator); 269 if (iter == identifierMap->end()) 270 return; 271 272 // Get all cache identifiers associated with generator. 273 Vector<typename U::KeyType> cacheIdentifierList; 274 copyToVector(iter->value, cacheIdentifierList); 275 276 // For each cache identifier find the corresponding CacheEntry and remove it. 277 for (size_t i = 0; i < cacheIdentifierList.size(); ++i) { 278 ASSERT(cacheMap->contains(cacheIdentifierList[i])); 279 const typename U::MappedType::PtrType cacheEntry = cacheMap->get(cacheIdentifierList[i]); 280 ASSERT(!cacheEntry->useCount()); 281 removeFromCacheInternal(cacheEntry, cacheMap, identifierMap, deletionList); 282 } 283 } 284 285 void ImageDecodingStore::removeFromCacheListInternal(const Vector<OwnPtr<CacheEntry> >& deletionList) 286 { 287 for (size_t i = 0; i < deletionList.size(); ++i) 288 m_orderedCacheList.remove(deletionList[i].get()); 289 } 290 291 } // namespace blink 292