Home | History | Annotate | Download | only in graphics
      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