mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
291 lines
10 KiB
C++
291 lines
10 KiB
C++
/*
|
|
* Copyright (C) 2012 Google Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "sky/engine/platform/graphics/ImageDecodingStore.h"
|
|
|
|
#include "sky/engine/platform/TraceEvent.h"
|
|
#include "sky/engine/wtf/Threading.h"
|
|
|
|
namespace blink {
|
|
|
|
namespace {
|
|
|
|
static const size_t defaultMaxTotalSizeOfHeapEntries = 32 * 1024 * 1024;
|
|
|
|
} // namespace
|
|
|
|
ImageDecodingStore::ImageDecodingStore()
|
|
: m_heapLimitInBytes(defaultMaxTotalSizeOfHeapEntries)
|
|
, m_heapMemoryUsageInBytes(0)
|
|
{
|
|
}
|
|
|
|
ImageDecodingStore::~ImageDecodingStore()
|
|
{
|
|
#if ENABLE(ASSERT)
|
|
setCacheLimitInBytes(0);
|
|
ASSERT(!m_decoderCacheMap.size());
|
|
ASSERT(!m_orderedCacheList.size());
|
|
ASSERT(!m_decoderCacheKeyMap.size());
|
|
#endif
|
|
}
|
|
|
|
ImageDecodingStore* ImageDecodingStore::instance()
|
|
{
|
|
AtomicallyInitializedStatic(ImageDecodingStore*, store = ImageDecodingStore::create().leakPtr());
|
|
return store;
|
|
}
|
|
|
|
bool ImageDecodingStore::lockDecoder(const ImageFrameGenerator* generator, const SkISize& scaledSize, ImageDecoder** decoder)
|
|
{
|
|
ASSERT(decoder);
|
|
|
|
MutexLocker lock(m_mutex);
|
|
DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::makeCacheKey(generator, scaledSize));
|
|
if (iter == m_decoderCacheMap.end())
|
|
return false;
|
|
|
|
DecoderCacheEntry* cacheEntry = iter->value.get();
|
|
|
|
// There can only be one user of a decoder at a time.
|
|
ASSERT(!cacheEntry->useCount());
|
|
cacheEntry->incrementUseCount();
|
|
*decoder = cacheEntry->cachedDecoder();
|
|
return true;
|
|
}
|
|
|
|
void ImageDecodingStore::unlockDecoder(const ImageFrameGenerator* generator, const ImageDecoder* decoder)
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::makeCacheKey(generator, decoder));
|
|
ASSERT_WITH_SECURITY_IMPLICATION(iter != m_decoderCacheMap.end());
|
|
|
|
CacheEntry* cacheEntry = iter->value.get();
|
|
cacheEntry->decrementUseCount();
|
|
|
|
// Put the entry to the end of list.
|
|
m_orderedCacheList.remove(cacheEntry);
|
|
m_orderedCacheList.append(cacheEntry);
|
|
}
|
|
|
|
void ImageDecodingStore::insertDecoder(const ImageFrameGenerator* generator, PassOwnPtr<ImageDecoder> decoder)
|
|
{
|
|
// Prune old cache entries to give space for the new one.
|
|
prune();
|
|
|
|
OwnPtr<DecoderCacheEntry> newCacheEntry = DecoderCacheEntry::create(generator, decoder);
|
|
|
|
MutexLocker lock(m_mutex);
|
|
ASSERT(!m_decoderCacheMap.contains(newCacheEntry->cacheKey()));
|
|
insertCacheInternal(newCacheEntry.release(), &m_decoderCacheMap, &m_decoderCacheKeyMap);
|
|
}
|
|
|
|
void ImageDecodingStore::removeDecoder(const ImageFrameGenerator* generator, const ImageDecoder* decoder)
|
|
{
|
|
Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::makeCacheKey(generator, decoder));
|
|
ASSERT_WITH_SECURITY_IMPLICATION(iter != m_decoderCacheMap.end());
|
|
|
|
CacheEntry* cacheEntry = iter->value.get();
|
|
ASSERT(cacheEntry->useCount());
|
|
cacheEntry->decrementUseCount();
|
|
|
|
// Delete only one decoder cache entry. Ownership of the cache entry
|
|
// is transfered to cacheEntriesToDelete such that object can be deleted
|
|
// outside of the lock.
|
|
removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete);
|
|
|
|
// Remove from LRU list.
|
|
removeFromCacheListInternal(cacheEntriesToDelete);
|
|
}
|
|
}
|
|
|
|
void ImageDecodingStore::removeCacheIndexedByGenerator(const ImageFrameGenerator* generator)
|
|
{
|
|
Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
|
|
// Remove image cache objects and decoder cache objects associated
|
|
// with a ImageFrameGenerator.
|
|
removeCacheIndexedByGeneratorInternal(&m_decoderCacheMap, &m_decoderCacheKeyMap, generator, &cacheEntriesToDelete);
|
|
|
|
// Remove from LRU list as well.
|
|
removeFromCacheListInternal(cacheEntriesToDelete);
|
|
}
|
|
}
|
|
|
|
void ImageDecodingStore::clear()
|
|
{
|
|
size_t cacheLimitInBytes;
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
cacheLimitInBytes = m_heapLimitInBytes;
|
|
m_heapLimitInBytes = 0;
|
|
}
|
|
|
|
prune();
|
|
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
m_heapLimitInBytes = cacheLimitInBytes;
|
|
}
|
|
}
|
|
|
|
void ImageDecodingStore::setCacheLimitInBytes(size_t cacheLimit)
|
|
{
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
m_heapLimitInBytes = cacheLimit;
|
|
}
|
|
prune();
|
|
}
|
|
|
|
size_t ImageDecodingStore::memoryUsageInBytes()
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
return m_heapMemoryUsageInBytes;
|
|
}
|
|
|
|
int ImageDecodingStore::cacheEntries()
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
return m_decoderCacheMap.size();
|
|
}
|
|
|
|
int ImageDecodingStore::decoderCacheEntries()
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
return m_decoderCacheMap.size();
|
|
}
|
|
|
|
void ImageDecodingStore::prune()
|
|
{
|
|
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStore::prune");
|
|
|
|
Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
|
|
{
|
|
MutexLocker lock(m_mutex);
|
|
|
|
// Head of the list is the least recently used entry.
|
|
const CacheEntry* cacheEntry = m_orderedCacheList.head();
|
|
|
|
// Walk the list of cache entries starting from the least recently used
|
|
// and then keep them for deletion later.
|
|
while (cacheEntry) {
|
|
const bool isPruneNeeded = m_heapMemoryUsageInBytes > m_heapLimitInBytes || !m_heapLimitInBytes;
|
|
if (!isPruneNeeded)
|
|
break;
|
|
|
|
// Cache is not used; Remove it.
|
|
if (!cacheEntry->useCount())
|
|
removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete);
|
|
cacheEntry = cacheEntry->next();
|
|
}
|
|
|
|
// Remove from cache list as well.
|
|
removeFromCacheListInternal(cacheEntriesToDelete);
|
|
}
|
|
}
|
|
|
|
template<class T, class U, class V>
|
|
void ImageDecodingStore::insertCacheInternal(PassOwnPtr<T> cacheEntry, U* cacheMap, V* identifierMap)
|
|
{
|
|
const size_t cacheEntryBytes = cacheEntry->memoryUsageInBytes();
|
|
m_heapMemoryUsageInBytes += cacheEntryBytes;
|
|
|
|
// m_orderedCacheList is used to support LRU operations to reorder cache
|
|
// entries quickly.
|
|
m_orderedCacheList.append(cacheEntry.get());
|
|
|
|
typename U::KeyType key = cacheEntry->cacheKey();
|
|
typename V::AddResult result = identifierMap->add(cacheEntry->generator(), typename V::MappedType());
|
|
result.storedValue->value.add(key);
|
|
cacheMap->add(key, cacheEntry);
|
|
|
|
TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreHeapMemoryUsageBytes", m_heapMemoryUsageInBytes);
|
|
TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreNumOfDecoders", m_decoderCacheMap.size());
|
|
}
|
|
|
|
template<class T, class U, class V>
|
|
void ImageDecodingStore::removeFromCacheInternal(const T* cacheEntry, U* cacheMap, V* identifierMap, Vector<OwnPtr<CacheEntry> >* deletionList)
|
|
{
|
|
const size_t cacheEntryBytes = cacheEntry->memoryUsageInBytes();
|
|
ASSERT(m_heapMemoryUsageInBytes >= cacheEntryBytes);
|
|
m_heapMemoryUsageInBytes -= cacheEntryBytes;
|
|
|
|
// Remove entry from identifier map.
|
|
typename V::iterator iter = identifierMap->find(cacheEntry->generator());
|
|
ASSERT(iter != identifierMap->end());
|
|
iter->value.remove(cacheEntry->cacheKey());
|
|
if (!iter->value.size())
|
|
identifierMap->remove(iter);
|
|
|
|
// Remove entry from cache map.
|
|
deletionList->append(cacheMap->take(cacheEntry->cacheKey()));
|
|
|
|
TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreHeapMemoryUsageBytes", m_heapMemoryUsageInBytes);
|
|
TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreNumOfDecoders", m_decoderCacheMap.size());
|
|
}
|
|
|
|
void ImageDecodingStore::removeFromCacheInternal(const CacheEntry* cacheEntry, Vector<OwnPtr<CacheEntry> >* deletionList)
|
|
{
|
|
if (cacheEntry->type() == CacheEntry::TypeDecoder) {
|
|
removeFromCacheInternal(static_cast<const DecoderCacheEntry*>(cacheEntry), &m_decoderCacheMap, &m_decoderCacheKeyMap, deletionList);
|
|
} else {
|
|
ASSERT(false);
|
|
}
|
|
}
|
|
|
|
template<class U, class V>
|
|
void ImageDecodingStore::removeCacheIndexedByGeneratorInternal(U* cacheMap, V* identifierMap, const ImageFrameGenerator* generator, Vector<OwnPtr<CacheEntry> >* deletionList)
|
|
{
|
|
typename V::iterator iter = identifierMap->find(generator);
|
|
if (iter == identifierMap->end())
|
|
return;
|
|
|
|
// Get all cache identifiers associated with generator.
|
|
Vector<typename U::KeyType> cacheIdentifierList;
|
|
copyToVector(iter->value, cacheIdentifierList);
|
|
|
|
// For each cache identifier find the corresponding CacheEntry and remove it.
|
|
for (size_t i = 0; i < cacheIdentifierList.size(); ++i) {
|
|
ASSERT(cacheMap->contains(cacheIdentifierList[i]));
|
|
const typename U::MappedType::PtrType cacheEntry = cacheMap->get(cacheIdentifierList[i]);
|
|
ASSERT(!cacheEntry->useCount());
|
|
removeFromCacheInternal(cacheEntry, cacheMap, identifierMap, deletionList);
|
|
}
|
|
}
|
|
|
|
void ImageDecodingStore::removeFromCacheListInternal(const Vector<OwnPtr<CacheEntry> >& deletionList)
|
|
{
|
|
for (size_t i = 0; i < deletionList.size(); ++i)
|
|
m_orderedCacheList.remove(deletionList[i].get());
|
|
}
|
|
|
|
} // namespace blink
|