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 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_IMAGE_DECODING_STORE_H_ 27 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_IMAGE_DECODING_STORE_H_ 28 29 #include <memory> 30 #include <utility> 31 32 #include "base/macros.h" 33 #include "base/memory/memory_pressure_listener.h" 34 #include "base/memory/ptr_util.h" 35 #include "cc/paint/paint_image_generator.h" 36 #include "third_party/blink/renderer/platform/graphics/image_frame_generator.h" 37 #include "third_party/blink/renderer/platform/graphics/skia/sk_size_hash.h" 38 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h" 39 #include "third_party/blink/renderer/platform/platform_export.h" 40 #include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h" 41 #include "third_party/blink/renderer/platform/wtf/hash_set.h" 42 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h" 43 #include "third_party/blink/renderer/platform/wtf/vector.h" 44 #include "third_party/skia/include/core/SkSize.h" 45 #include "third_party/skia/include/core/SkTypes.h" 46 47 namespace blink { 48 49 // Decoder cache entry is identified by: 50 // 1. Pointer to ImageFrameGenerator. 51 // 2. Size of the image. 52 // 3. ImageDecoder::AlphaOption 53 struct DecoderCacheKey { 54 const blink::ImageFrameGenerator* gen_; 55 SkISize size_; 56 blink::ImageDecoder::AlphaOption alpha_option_; 57 cc::PaintImage::GeneratorClientId client_id_; 58 DecoderCacheKeyDecoderCacheKey59 DecoderCacheKey() 60 : gen_(nullptr), 61 size_(SkISize::Make(0, 0)), 62 alpha_option_(static_cast<blink::ImageDecoder::AlphaOption>(0)), 63 client_id_(cc::PaintImage::kDefaultGeneratorClientId) {} 64 }; 65 66 static inline bool operator==(const DecoderCacheKey& a, 67 const DecoderCacheKey& b) { 68 return a.gen_ == b.gen_ && a.size_ == b.size_ && 69 a.alpha_option_ == b.alpha_option_ && a.client_id_ == b.client_id_; 70 } 71 72 static inline bool operator!=(const DecoderCacheKey& a, 73 const DecoderCacheKey& b) { 74 return !(a == b); 75 } 76 77 // Base class for all cache entries. 78 class CacheEntry : public DoublyLinkedListNode<CacheEntry> { 79 USING_FAST_MALLOC(CacheEntry); 80 friend class WTF::DoublyLinkedListNode<CacheEntry>; 81 82 public: 83 enum CacheType { 84 kTypeDecoder, 85 }; 86 CacheEntry(const ImageFrameGenerator * generator,int use_count)87 CacheEntry(const ImageFrameGenerator* generator, int use_count) 88 : generator_(generator), 89 use_count_(use_count), 90 prev_(nullptr), 91 next_(nullptr) {} 92 ~CacheEntry()93 virtual ~CacheEntry() { DCHECK(!use_count_); } 94 Generator()95 const ImageFrameGenerator* Generator() const { return generator_; } UseCount()96 int UseCount() const { return use_count_; } IncrementUseCount()97 void IncrementUseCount() { ++use_count_; } DecrementUseCount()98 void DecrementUseCount() { 99 --use_count_; 100 DCHECK_GE(use_count_, 0); 101 } 102 103 // FIXME: getSafeSize() returns the size in bytes truncated to a 32-bit 104 // integer. Find a way to get the size in 64-bits. 105 virtual size_t MemoryUsageInBytes() const = 0; 106 virtual CacheType GetType() const = 0; 107 108 protected: 109 const ImageFrameGenerator* generator_; 110 int use_count_; 111 112 private: 113 CacheEntry* prev_; 114 CacheEntry* next_; 115 116 DISALLOW_COPY_AND_ASSIGN(CacheEntry); 117 }; 118 119 class DecoderCacheEntry final : public CacheEntry { 120 public: DecoderCacheEntry(const ImageFrameGenerator * generator,int count,std::unique_ptr<ImageDecoder> decoder,cc::PaintImage::GeneratorClientId client_id)121 DecoderCacheEntry(const ImageFrameGenerator* generator, 122 int count, 123 std::unique_ptr<ImageDecoder> decoder, 124 cc::PaintImage::GeneratorClientId client_id) 125 : CacheEntry(generator, count), 126 cached_decoder_(std::move(decoder)), 127 size_(SkISize::Make(cached_decoder_->DecodedSize().Width(), 128 cached_decoder_->DecodedSize().Height())), 129 alpha_option_(cached_decoder_->GetAlphaOption()), 130 client_id_(client_id) {} 131 MemoryUsageInBytes()132 size_t MemoryUsageInBytes() const override { 133 return size_.width() * size_.height() * 4; 134 } GetType()135 CacheType GetType() const override { return kTypeDecoder; } 136 MakeCacheKey(const ImageFrameGenerator * generator,const SkISize & size,ImageDecoder::AlphaOption alpha_option,cc::PaintImage::GeneratorClientId client_id)137 static DecoderCacheKey MakeCacheKey( 138 const ImageFrameGenerator* generator, 139 const SkISize& size, 140 ImageDecoder::AlphaOption alpha_option, 141 cc::PaintImage::GeneratorClientId client_id) { 142 DecoderCacheKey key; 143 key.gen_ = generator; 144 key.size_ = size; 145 key.alpha_option_ = alpha_option; 146 key.client_id_ = client_id; 147 return key; 148 } MakeCacheKey(const ImageFrameGenerator * generator,const ImageDecoder * decoder,cc::PaintImage::GeneratorClientId client_id)149 static DecoderCacheKey MakeCacheKey( 150 const ImageFrameGenerator* generator, 151 const ImageDecoder* decoder, 152 cc::PaintImage::GeneratorClientId client_id) { 153 return MakeCacheKey(generator, 154 SkISize::Make(decoder->DecodedSize().Width(), 155 decoder->DecodedSize().Height()), 156 decoder->GetAlphaOption(), client_id); 157 } CacheKey()158 DecoderCacheKey CacheKey() const { 159 return MakeCacheKey(generator_, size_, alpha_option_, client_id_); 160 } CachedDecoder()161 ImageDecoder* CachedDecoder() const { return cached_decoder_.get(); } 162 163 private: 164 std::unique_ptr<ImageDecoder> cached_decoder_; 165 SkISize size_; 166 ImageDecoder::AlphaOption alpha_option_; 167 cc::PaintImage::GeneratorClientId client_id_; 168 }; 169 170 } // namespace blink 171 172 namespace WTF { 173 174 template <> 175 struct DefaultHash<blink::DecoderCacheKey> { 176 STATIC_ONLY(DefaultHash); 177 struct Hash { 178 STATIC_ONLY(Hash); 179 static unsigned GetHash(const blink::DecoderCacheKey& p) { 180 auto first = 181 HashInts(DefaultHash<blink::ImageFrameGenerator*>::Hash::GetHash( 182 const_cast<blink::ImageFrameGenerator*>(p.gen_)), 183 DefaultHash<SkISize>::Hash::GetHash(p.size_)); 184 auto second = HashInts(DefaultHash<uint8_t>::Hash::GetHash( 185 static_cast<uint8_t>(p.alpha_option_)), 186 p.client_id_); 187 return HashInts(first, second); 188 } 189 static bool Equal(const blink::DecoderCacheKey& a, 190 const blink::DecoderCacheKey& b) { 191 return a.gen_ == b.gen_ && a.size_ == b.size_ && 192 a.alpha_option_ == b.alpha_option_ && a.client_id_ == b.client_id_; 193 } 194 static const bool safe_to_compare_to_empty_or_deleted = true; 195 }; 196 }; 197 198 template <> 199 struct HashTraits<blink::DecoderCacheKey> 200 : GenericHashTraits<blink::DecoderCacheKey> { 201 STATIC_ONLY(HashTraits); 202 static const bool kEmptyValueIsZero = true; 203 static blink::DecoderCacheKey EmptyValue() { 204 return blink::DecoderCacheEntry::MakeCacheKey( 205 nullptr, SkISize::Make(0, 0), 206 static_cast<blink::ImageDecoder::AlphaOption>(0), 207 cc::PaintImage::kDefaultGeneratorClientId); 208 } 209 static void ConstructDeletedValue(blink::DecoderCacheKey& slot, bool) { 210 slot = blink::DecoderCacheEntry::MakeCacheKey( 211 nullptr, SkISize::Make(-1, -1), 212 static_cast<blink::ImageDecoder::AlphaOption>(0), 213 cc::PaintImage::kDefaultGeneratorClientId); 214 } 215 static bool IsDeletedValue(const blink::DecoderCacheKey& value) { 216 return value.size_ == SkISize::Make(-1, -1); 217 } 218 }; 219 220 } // namespace WTF 221 222 namespace blink { 223 224 // FUNCTION 225 // 226 // ImageDecodingStore is a class used to manage cached decoder objects. 227 // 228 // EXTERNAL OBJECTS 229 // 230 // ImageDecoder 231 // A decoder object. It is used to decode raw data into bitmap images. 232 // 233 // ImageFrameGenerator 234 // This is a direct user of this cache. Responsible for generating bitmap 235 // images using an ImageDecoder. It contains encoded image data and is used 236 // to represent one image file. It is used to index image and decoder 237 // objects in the cache. 238 // 239 // THREAD SAFETY 240 // 241 // All public methods can be used on any thread. 242 243 class PLATFORM_EXPORT ImageDecodingStore final { 244 USING_FAST_MALLOC(ImageDecodingStore); 245 246 public: 247 ImageDecodingStore(); 248 ~ImageDecodingStore(); 249 250 static ImageDecodingStore& Instance(); 251 252 // Accesses a cached decoder object. A decoder is indexed by origin 253 // (ImageFrameGenerator) and scaled size. Returns true if the cached object 254 // is found. 255 bool LockDecoder(const ImageFrameGenerator*, 256 const SkISize& scaled_size, 257 ImageDecoder::AlphaOption, 258 cc::PaintImage::GeneratorClientId client_id, 259 ImageDecoder**); 260 void UnlockDecoder(const ImageFrameGenerator*, 261 cc::PaintImage::GeneratorClientId client_id, 262 const ImageDecoder*); 263 void InsertDecoder(const ImageFrameGenerator*, 264 cc::PaintImage::GeneratorClientId client_id, 265 std::unique_ptr<ImageDecoder>); 266 void RemoveDecoder(const ImageFrameGenerator*, 267 cc::PaintImage::GeneratorClientId client_id, 268 const ImageDecoder*); 269 270 // Remove all cache entries indexed by ImageFrameGenerator. 271 void RemoveCacheIndexedByGenerator(const ImageFrameGenerator*); 272 273 void Clear(); 274 void SetCacheLimitInBytes(size_t); 275 size_t MemoryUsageInBytes(); 276 int CacheEntries(); 277 int DecoderCacheEntries(); 278 279 private: 280 void Prune(); 281 282 // Called by the memory pressure listener when the memory pressure rises. 283 void OnMemoryPressure( 284 base::MemoryPressureListener::MemoryPressureLevel level); 285 286 // These helper methods are called while m_mutex is locked. 287 template <class T, class U, class V> 288 void InsertCacheInternal(std::unique_ptr<T> cache_entry, 289 U* cache_map, 290 V* identifier_map); 291 292 // Helper method to remove a cache entry. Ownership is transferred to 293 // deletionList. Use of Vector<> is handy when removing multiple entries. 294 template <class T, class U, class V> 295 void RemoveFromCacheInternal( 296 const T* cache_entry, 297 U* cache_map, 298 V* identifier_map, 299 Vector<std::unique_ptr<CacheEntry>>* deletion_list); 300 301 // Helper method to remove a cache entry. Uses the templated version base on 302 // the type of cache entry. 303 void RemoveFromCacheInternal( 304 const CacheEntry*, 305 Vector<std::unique_ptr<CacheEntry>>* deletion_list); 306 307 // Helper method to remove all cache entries associated with an 308 // ImageFrameGenerator. Ownership of the cache entries is transferred to 309 // |deletionList|. 310 template <class U, class V> 311 void RemoveCacheIndexedByGeneratorInternal( 312 U* cache_map, 313 V* identifier_map, 314 const ImageFrameGenerator*, 315 Vector<std::unique_ptr<CacheEntry>>* deletion_list); 316 317 // Helper method to remove cache entry pointers from the LRU list. 318 void RemoveFromCacheListInternal( 319 const Vector<std::unique_ptr<CacheEntry>>& deletion_list); 320 321 // A doubly linked list that maintains usage history of cache entries. 322 // This is used for eviction of old entries. 323 // Head of this list is the least recently used cache entry. 324 // Tail of this list is the most recently used cache entry. 325 DoublyLinkedList<CacheEntry> ordered_cache_list_ GUARDED_BY(mutex_); 326 327 // A lookup table for all decoder cache objects. Owns all decoder cache 328 // objects. 329 typedef HashMap<DecoderCacheKey, std::unique_ptr<DecoderCacheEntry>> 330 DecoderCacheMap; 331 DecoderCacheMap decoder_cache_map_ GUARDED_BY(mutex_); 332 333 // A lookup table to map ImageFrameGenerator to all associated 334 // decoder cache keys. 335 typedef HashSet<DecoderCacheKey> DecoderCacheKeySet; 336 typedef HashMap<const ImageFrameGenerator*, DecoderCacheKeySet> 337 DecoderCacheKeyMap; 338 DecoderCacheKeyMap decoder_cache_key_map_ GUARDED_BY(mutex_); 339 340 size_t heap_limit_in_bytes_ GUARDED_BY(mutex_); 341 size_t heap_memory_usage_in_bytes_ GUARDED_BY(mutex_); 342 343 // A listener to global memory pressure events. 344 base::MemoryPressureListener memory_pressure_listener_; 345 346 // Also protects: 347 // - the CacheEntry in |decoder_cache_map_|. 348 // - calls to underlying skBitmap's LockPixels()/UnlockPixels() as they are 349 // not threadsafe. 350 Mutex mutex_; 351 352 DISALLOW_COPY_AND_ASSIGN(ImageDecodingStore); 353 }; 354 355 } // namespace blink 356 357 #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_IMAGE_DECODING_STORE_H_ 358