blob: 99d17c19138d6b0e8b7d01e0b03bb1f02ae75e40 [file] [log] [blame]
/*
* 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.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_IMAGE_DECODING_STORE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_IMAGE_DECODING_STORE_H_
#include <memory>
#include <utility>
#include "base/macros.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/ptr_util.h"
#include "cc/paint/paint_image_generator.h"
#include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
#include "third_party/blink/renderer/platform/graphics/skia/sk_size_hash.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkTypes.h"
namespace blink {
// Decoder cache entry is identified by:
// 1. Pointer to ImageFrameGenerator.
// 2. Size of the image.
// 3. ImageDecoder::AlphaOption
struct DecoderCacheKey {
const blink::ImageFrameGenerator* gen_;
SkISize size_;
blink::ImageDecoder::AlphaOption alpha_option_;
cc::PaintImage::GeneratorClientId client_id_;
DecoderCacheKey()
: gen_(nullptr),
size_(SkISize::Make(0, 0)),
alpha_option_(static_cast<blink::ImageDecoder::AlphaOption>(0)),
client_id_(cc::PaintImage::kDefaultGeneratorClientId) {}
};
static inline bool operator==(const DecoderCacheKey& a,
const DecoderCacheKey& b) {
return a.gen_ == b.gen_ && a.size_ == b.size_ &&
a.alpha_option_ == b.alpha_option_ && a.client_id_ == b.client_id_;
}
static inline bool operator!=(const DecoderCacheKey& a,
const DecoderCacheKey& b) {
return !(a == b);
}
// Base class for all cache entries.
class CacheEntry : public DoublyLinkedListNode<CacheEntry> {
USING_FAST_MALLOC(CacheEntry);
friend class WTF::DoublyLinkedListNode<CacheEntry>;
public:
enum CacheType {
kTypeDecoder,
};
CacheEntry(const ImageFrameGenerator* generator, int use_count)
: generator_(generator),
use_count_(use_count),
prev_(nullptr),
next_(nullptr) {}
virtual ~CacheEntry() { DCHECK(!use_count_); }
const ImageFrameGenerator* Generator() const { return generator_; }
int UseCount() const { return use_count_; }
void IncrementUseCount() { ++use_count_; }
void DecrementUseCount() {
--use_count_;
DCHECK_GE(use_count_, 0);
}
// FIXME: getSafeSize() returns the size in bytes truncated to a 32-bit
// integer. Find a way to get the size in 64-bits.
virtual size_t MemoryUsageInBytes() const = 0;
virtual CacheType GetType() const = 0;
protected:
const ImageFrameGenerator* generator_;
int use_count_;
private:
CacheEntry* prev_;
CacheEntry* next_;
DISALLOW_COPY_AND_ASSIGN(CacheEntry);
};
class DecoderCacheEntry final : public CacheEntry {
public:
DecoderCacheEntry(const ImageFrameGenerator* generator,
int count,
std::unique_ptr<ImageDecoder> decoder,
cc::PaintImage::GeneratorClientId client_id)
: CacheEntry(generator, count),
cached_decoder_(std::move(decoder)),
size_(SkISize::Make(cached_decoder_->DecodedSize().Width(),
cached_decoder_->DecodedSize().Height())),
alpha_option_(cached_decoder_->GetAlphaOption()),
client_id_(client_id) {}
size_t MemoryUsageInBytes() const override {
return size_.width() * size_.height() * 4;
}
CacheType GetType() const override { return kTypeDecoder; }
static DecoderCacheKey MakeCacheKey(
const ImageFrameGenerator* generator,
const SkISize& size,
ImageDecoder::AlphaOption alpha_option,
cc::PaintImage::GeneratorClientId client_id) {
DecoderCacheKey key;
key.gen_ = generator;
key.size_ = size;
key.alpha_option_ = alpha_option;
key.client_id_ = client_id;
return key;
}
static DecoderCacheKey MakeCacheKey(
const ImageFrameGenerator* generator,
const ImageDecoder* decoder,
cc::PaintImage::GeneratorClientId client_id) {
return MakeCacheKey(generator,
SkISize::Make(decoder->DecodedSize().Width(),
decoder->DecodedSize().Height()),
decoder->GetAlphaOption(), client_id);
}
DecoderCacheKey CacheKey() const {
return MakeCacheKey(generator_, size_, alpha_option_, client_id_);
}
ImageDecoder* CachedDecoder() const { return cached_decoder_.get(); }
private:
std::unique_ptr<ImageDecoder> cached_decoder_;
SkISize size_;
ImageDecoder::AlphaOption alpha_option_;
cc::PaintImage::GeneratorClientId client_id_;
};
} // namespace blink
namespace WTF {
template <>
struct DefaultHash<blink::DecoderCacheKey> {
STATIC_ONLY(DefaultHash);
struct Hash {
STATIC_ONLY(Hash);
static unsigned GetHash(const blink::DecoderCacheKey& p) {
auto first =
HashInts(DefaultHash<blink::ImageFrameGenerator*>::Hash::GetHash(
const_cast<blink::ImageFrameGenerator*>(p.gen_)),
DefaultHash<SkISize>::Hash::GetHash(p.size_));
auto second = HashInts(DefaultHash<uint8_t>::Hash::GetHash(
static_cast<uint8_t>(p.alpha_option_)),
p.client_id_);
return HashInts(first, second);
}
static bool Equal(const blink::DecoderCacheKey& a,
const blink::DecoderCacheKey& b) {
return a.gen_ == b.gen_ && a.size_ == b.size_ &&
a.alpha_option_ == b.alpha_option_ && a.client_id_ == b.client_id_;
}
static const bool safe_to_compare_to_empty_or_deleted = true;
};
};
template <>
struct HashTraits<blink::DecoderCacheKey>
: GenericHashTraits<blink::DecoderCacheKey> {
STATIC_ONLY(HashTraits);
static const bool kEmptyValueIsZero = true;
static blink::DecoderCacheKey EmptyValue() {
return blink::DecoderCacheEntry::MakeCacheKey(
nullptr, SkISize::Make(0, 0),
static_cast<blink::ImageDecoder::AlphaOption>(0),
cc::PaintImage::kDefaultGeneratorClientId);
}
static void ConstructDeletedValue(blink::DecoderCacheKey& slot, bool) {
slot = blink::DecoderCacheEntry::MakeCacheKey(
nullptr, SkISize::Make(-1, -1),
static_cast<blink::ImageDecoder::AlphaOption>(0),
cc::PaintImage::kDefaultGeneratorClientId);
}
static bool IsDeletedValue(const blink::DecoderCacheKey& value) {
return value.size_ == SkISize::Make(-1, -1);
}
};
} // namespace WTF
namespace blink {
// FUNCTION
//
// ImageDecodingStore is a class used to manage cached decoder objects.
//
// EXTERNAL OBJECTS
//
// ImageDecoder
// A decoder object. It is used to decode raw data into bitmap images.
//
// ImageFrameGenerator
// This is a direct user of this cache. Responsible for generating bitmap
// images using an ImageDecoder. It contains encoded image data and is used
// to represent one image file. It is used to index image and decoder
// objects in the cache.
//
// THREAD SAFETY
//
// All public methods can be used on any thread.
class PLATFORM_EXPORT ImageDecodingStore final {
USING_FAST_MALLOC(ImageDecodingStore);
public:
ImageDecodingStore();
~ImageDecodingStore();
static ImageDecodingStore& Instance();
// Accesses a cached decoder object. A decoder is indexed by origin
// (ImageFrameGenerator) and scaled size. Returns true if the cached object
// is found.
bool LockDecoder(const ImageFrameGenerator*,
const SkISize& scaled_size,
ImageDecoder::AlphaOption,
cc::PaintImage::GeneratorClientId client_id,
ImageDecoder**);
void UnlockDecoder(const ImageFrameGenerator*,
cc::PaintImage::GeneratorClientId client_id,
const ImageDecoder*);
void InsertDecoder(const ImageFrameGenerator*,
cc::PaintImage::GeneratorClientId client_id,
std::unique_ptr<ImageDecoder>);
void RemoveDecoder(const ImageFrameGenerator*,
cc::PaintImage::GeneratorClientId client_id,
const ImageDecoder*);
// Remove all cache entries indexed by ImageFrameGenerator.
void RemoveCacheIndexedByGenerator(const ImageFrameGenerator*);
void Clear();
void SetCacheLimitInBytes(size_t);
size_t MemoryUsageInBytes();
int CacheEntries();
int DecoderCacheEntries();
private:
void Prune();
// Called by the memory pressure listener when the memory pressure rises.
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level);
// These helper methods are called while m_mutex is locked.
template <class T, class U, class V>
void InsertCacheInternal(std::unique_ptr<T> cache_entry,
U* cache_map,
V* identifier_map);
// Helper method to remove a cache entry. Ownership is transferred to
// deletionList. Use of Vector<> is handy when removing multiple entries.
template <class T, class U, class V>
void RemoveFromCacheInternal(
const T* cache_entry,
U* cache_map,
V* identifier_map,
Vector<std::unique_ptr<CacheEntry>>* deletion_list);
// Helper method to remove a cache entry. Uses the templated version base on
// the type of cache entry.
void RemoveFromCacheInternal(
const CacheEntry*,
Vector<std::unique_ptr<CacheEntry>>* deletion_list);
// Helper method to remove all cache entries associated with an
// ImageFrameGenerator. Ownership of the cache entries is transferred to
// |deletionList|.
template <class U, class V>
void RemoveCacheIndexedByGeneratorInternal(
U* cache_map,
V* identifier_map,
const ImageFrameGenerator*,
Vector<std::unique_ptr<CacheEntry>>* deletion_list);
// Helper method to remove cache entry pointers from the LRU list.
void RemoveFromCacheListInternal(
const Vector<std::unique_ptr<CacheEntry>>& deletion_list);
// A doubly linked list that maintains usage history of cache entries.
// This is used for eviction of old entries.
// Head of this list is the least recently used cache entry.
// Tail of this list is the most recently used cache entry.
DoublyLinkedList<CacheEntry> ordered_cache_list_ GUARDED_BY(mutex_);
// A lookup table for all decoder cache objects. Owns all decoder cache
// objects.
typedef HashMap<DecoderCacheKey, std::unique_ptr<DecoderCacheEntry>>
DecoderCacheMap;
DecoderCacheMap decoder_cache_map_ GUARDED_BY(mutex_);
// A lookup table to map ImageFrameGenerator to all associated
// decoder cache keys.
typedef HashSet<DecoderCacheKey> DecoderCacheKeySet;
typedef HashMap<const ImageFrameGenerator*, DecoderCacheKeySet>
DecoderCacheKeyMap;
DecoderCacheKeyMap decoder_cache_key_map_ GUARDED_BY(mutex_);
size_t heap_limit_in_bytes_ GUARDED_BY(mutex_);
size_t heap_memory_usage_in_bytes_ GUARDED_BY(mutex_);
// A listener to global memory pressure events.
base::MemoryPressureListener memory_pressure_listener_;
// Also protects:
// - the CacheEntry in |decoder_cache_map_|.
// - calls to underlying skBitmap's LockPixels()/UnlockPixels() as they are
// not threadsafe.
Mutex mutex_;
DISALLOW_COPY_AND_ASSIGN(ImageDecodingStore);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_IMAGE_DECODING_STORE_H_