2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "platform/graphics/ImageDecodingStore.h"
29 #include "platform/TraceEvent.h"
30 #include "wtf/Threading.h"
36 static const size_t defaultMaxTotalSizeOfHeapEntries
= 32 * 1024 * 1024;
40 ImageDecodingStore::ImageDecodingStore()
41 : m_heapLimitInBytes(defaultMaxTotalSizeOfHeapEntries
)
42 , m_heapMemoryUsageInBytes(0)
46 ImageDecodingStore::~ImageDecodingStore()
49 setCacheLimitInBytes(0);
50 ASSERT(!m_decoderCacheMap
.size());
51 ASSERT(!m_orderedCacheList
.size());
52 ASSERT(!m_decoderCacheKeyMap
.size());
56 ImageDecodingStore
& ImageDecodingStore::instance()
58 AtomicallyInitializedStaticReference(ImageDecodingStore
, store
, ImageDecodingStore::create().leakPtr());
62 bool ImageDecodingStore::lockDecoder(const ImageFrameGenerator
* generator
, const SkISize
& scaledSize
, ImageDecoder
** decoder
)
66 MutexLocker
lock(m_mutex
);
67 DecoderCacheMap::iterator iter
= m_decoderCacheMap
.find(DecoderCacheEntry::makeCacheKey(generator
, scaledSize
));
68 if (iter
== m_decoderCacheMap
.end())
71 DecoderCacheEntry
* cacheEntry
= iter
->value
.get();
73 // There can only be one user of a decoder at a time.
74 ASSERT(!cacheEntry
->useCount());
75 cacheEntry
->incrementUseCount();
76 *decoder
= cacheEntry
->cachedDecoder();
80 void ImageDecodingStore::unlockDecoder(const ImageFrameGenerator
* generator
, const ImageDecoder
* decoder
)
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());
86 CacheEntry
* cacheEntry
= iter
->value
.get();
87 cacheEntry
->decrementUseCount();
89 // Put the entry to the end of list.
90 m_orderedCacheList
.remove(cacheEntry
);
91 m_orderedCacheList
.append(cacheEntry
);
94 void ImageDecodingStore::insertDecoder(const ImageFrameGenerator
* generator
, PassOwnPtr
<ImageDecoder
> decoder
)
96 // Prune old cache entries to give space for the new one.
99 OwnPtr
<DecoderCacheEntry
> newCacheEntry
= DecoderCacheEntry::create(generator
, decoder
);
101 MutexLocker
lock(m_mutex
);
102 ASSERT(!m_decoderCacheMap
.contains(newCacheEntry
->cacheKey()));
103 insertCacheInternal(newCacheEntry
.release(), &m_decoderCacheMap
, &m_decoderCacheKeyMap
);
106 void ImageDecodingStore::removeDecoder(const ImageFrameGenerator
* generator
, const ImageDecoder
* decoder
)
108 Vector
<OwnPtr
<CacheEntry
>> cacheEntriesToDelete
;
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());
114 CacheEntry
* cacheEntry
= iter
->value
.get();
115 ASSERT(cacheEntry
->useCount());
116 cacheEntry
->decrementUseCount();
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
);
123 // Remove from LRU list.
124 removeFromCacheListInternal(cacheEntriesToDelete
);
128 void ImageDecodingStore::removeCacheIndexedByGenerator(const ImageFrameGenerator
* generator
)
130 Vector
<OwnPtr
<CacheEntry
>> cacheEntriesToDelete
;
132 MutexLocker
lock(m_mutex
);
134 // Remove image cache objects and decoder cache objects associated
135 // with a ImageFrameGenerator.
136 removeCacheIndexedByGeneratorInternal(&m_decoderCacheMap
, &m_decoderCacheKeyMap
, generator
, &cacheEntriesToDelete
);
138 // Remove from LRU list as well.
139 removeFromCacheListInternal(cacheEntriesToDelete
);
143 void ImageDecodingStore::clear()
145 size_t cacheLimitInBytes
;
147 MutexLocker
lock(m_mutex
);
148 cacheLimitInBytes
= m_heapLimitInBytes
;
149 m_heapLimitInBytes
= 0;
155 MutexLocker
lock(m_mutex
);
156 m_heapLimitInBytes
= cacheLimitInBytes
;
160 void ImageDecodingStore::setCacheLimitInBytes(size_t cacheLimit
)
163 MutexLocker
lock(m_mutex
);
164 m_heapLimitInBytes
= cacheLimit
;
169 size_t ImageDecodingStore::memoryUsageInBytes()
171 MutexLocker
lock(m_mutex
);
172 return m_heapMemoryUsageInBytes
;
175 int ImageDecodingStore::cacheEntries()
177 MutexLocker
lock(m_mutex
);
178 return m_decoderCacheMap
.size();
181 void ImageDecodingStore::prune()
183 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStore::prune");
185 Vector
<OwnPtr
<CacheEntry
>> cacheEntriesToDelete
;
187 MutexLocker
lock(m_mutex
);
189 // Head of the list is the least recently used entry.
190 const CacheEntry
* cacheEntry
= m_orderedCacheList
.head();
192 // Walk the list of cache entries starting from the least recently used
193 // and then keep them for deletion later.
195 const bool isPruneNeeded
= m_heapMemoryUsageInBytes
> m_heapLimitInBytes
|| !m_heapLimitInBytes
;
199 // Cache is not used; Remove it.
200 if (!cacheEntry
->useCount())
201 removeFromCacheInternal(cacheEntry
, &cacheEntriesToDelete
);
202 cacheEntry
= cacheEntry
->next();
205 // Remove from cache list as well.
206 removeFromCacheListInternal(cacheEntriesToDelete
);
210 template<class T
, class U
, class V
>
211 void ImageDecodingStore::insertCacheInternal(PassOwnPtr
<T
> cacheEntry
, U
* cacheMap
, V
* identifierMap
)
213 const size_t cacheEntryBytes
= cacheEntry
->memoryUsageInBytes();
214 m_heapMemoryUsageInBytes
+= cacheEntryBytes
;
216 // m_orderedCacheList is used to support LRU operations to reorder cache
218 m_orderedCacheList
.append(cacheEntry
.get());
220 typename
U::KeyType key
= cacheEntry
->cacheKey();
221 typename
V::AddResult result
= identifierMap
->add(cacheEntry
->generator(), typename
V::MappedType());
222 result
.storedValue
->value
.add(key
);
223 cacheMap
->add(key
, cacheEntry
);
225 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreHeapMemoryUsageBytes", m_heapMemoryUsageInBytes
);
226 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreNumOfDecoders", m_decoderCacheMap
.size());
229 template<class T
, class U
, class V
>
230 void ImageDecodingStore::removeFromCacheInternal(const T
* cacheEntry
, U
* cacheMap
, V
* identifierMap
, Vector
<OwnPtr
<CacheEntry
>>* deletionList
)
232 const size_t cacheEntryBytes
= cacheEntry
->memoryUsageInBytes();
233 ASSERT(m_heapMemoryUsageInBytes
>= cacheEntryBytes
);
234 m_heapMemoryUsageInBytes
-= cacheEntryBytes
;
236 // Remove entry from identifier map.
237 typename
V::iterator iter
= identifierMap
->find(cacheEntry
->generator());
238 ASSERT(iter
!= identifierMap
->end());
239 iter
->value
.remove(cacheEntry
->cacheKey());
240 if (!iter
->value
.size())
241 identifierMap
->remove(iter
);
243 // Remove entry from cache map.
244 deletionList
->append(cacheMap
->take(cacheEntry
->cacheKey()));
246 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreHeapMemoryUsageBytes", m_heapMemoryUsageInBytes
);
247 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreNumOfDecoders", m_decoderCacheMap
.size());
250 void ImageDecodingStore::removeFromCacheInternal(const CacheEntry
* cacheEntry
, Vector
<OwnPtr
<CacheEntry
>>* deletionList
)
252 if (cacheEntry
->type() == CacheEntry::TypeDecoder
) {
253 removeFromCacheInternal(static_cast<const DecoderCacheEntry
*>(cacheEntry
), &m_decoderCacheMap
, &m_decoderCacheKeyMap
, deletionList
);
259 template<class U
, class V
>
260 void ImageDecodingStore::removeCacheIndexedByGeneratorInternal(U
* cacheMap
, V
* identifierMap
, const ImageFrameGenerator
* generator
, Vector
<OwnPtr
<CacheEntry
>>* deletionList
)
262 typename
V::iterator iter
= identifierMap
->find(generator
);
263 if (iter
== identifierMap
->end())
266 // Get all cache identifiers associated with generator.
267 Vector
<typename
U::KeyType
> cacheIdentifierList
;
268 copyToVector(iter
->value
, cacheIdentifierList
);
270 // For each cache identifier find the corresponding CacheEntry and remove it.
271 for (size_t i
= 0; i
< cacheIdentifierList
.size(); ++i
) {
272 ASSERT(cacheMap
->contains(cacheIdentifierList
[i
]));
273 const typename
U::MappedType::PtrType cacheEntry
= cacheMap
->get(cacheIdentifierList
[i
]);
274 ASSERT(!cacheEntry
->useCount());
275 removeFromCacheInternal(cacheEntry
, cacheMap
, identifierMap
, deletionList
);
279 void ImageDecodingStore::removeFromCacheListInternal(const Vector
<OwnPtr
<CacheEntry
>>& deletionList
)
281 for (size_t i
= 0; i
< deletionList
.size(); ++i
)
282 m_orderedCacheList
.remove(deletionList
[i
].get());