1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkImageFilterCache.h" 9 10 #include "SkImageFilter.h" 11 #include "SkMutex.h" 12 #include "SkOnce.h" 13 #include "SkOpts.h" 14 #include "SkRefCnt.h" 15 #include "SkSpecialImage.h" 16 #include "SkTDynamicHash.h" 17 #include "SkTInternalLList.h" 18 19 #ifdef SK_BUILD_FOR_IOS 20 enum { kDefaultCacheSize = 2 * 1024 * 1024 }; 21 #else 22 enum { kDefaultCacheSize = 128 * 1024 * 1024 }; 23 #endif 24 25 namespace { 26 27 class CacheImpl : public SkImageFilterCache { 28 public: 29 typedef SkImageFilterCacheKey Key; 30 CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { } 31 ~CacheImpl() override { 32 SkTDynamicHash<Value, Key>::Iter iter(&fLookup); 33 34 while (!iter.done()) { 35 Value* v = &*iter; 36 ++iter; 37 delete v; 38 } 39 } 40 struct Value { 41 Value(const Key& key, SkSpecialImage* image, const SkIPoint& offset, const SkImageFilter* filter) 42 : fKey(key), fImage(SkRef(image)), fOffset(offset), fFilter(filter) {} 43 44 Key fKey; 45 sk_sp<SkSpecialImage> fImage; 46 SkIPoint fOffset; 47 const SkImageFilter* fFilter; 48 static const Key& GetKey(const Value& v) { 49 return v.fKey; 50 } 51 static uint32_t Hash(const Key& key) { 52 return SkOpts::hash(reinterpret_cast<const uint32_t*>(&key), sizeof(Key)); 53 } 54 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value); 55 }; 56 57 sk_sp<SkSpecialImage> get(const Key& key, SkIPoint* offset) const override { 58 SkAutoMutexAcquire mutex(fMutex); 59 if (Value* v = fLookup.find(key)) { 60 *offset = v->fOffset; 61 if (v != fLRU.head()) { 62 fLRU.remove(v); 63 fLRU.addToHead(v); 64 } 65 return v->fImage; 66 } 67 return nullptr; 68 } 69 70 void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset, const SkImageFilter* filter) override { 71 SkAutoMutexAcquire mutex(fMutex); 72 if (Value* v = fLookup.find(key)) { 73 this->removeInternal(v); 74 } 75 Value* v = new Value(key, image, offset, filter); 76 fLookup.add(v); 77 fLRU.addToHead(v); 78 fCurrentBytes += image->getSize(); 79 while (fCurrentBytes > fMaxBytes) { 80 Value* tail = fLRU.tail(); 81 SkASSERT(tail); 82 if (tail == v) { 83 break; 84 } 85 this->removeInternal(tail); 86 } 87 } 88 89 void purge() override { 90 SkAutoMutexAcquire mutex(fMutex); 91 while (fCurrentBytes > 0) { 92 Value* tail = fLRU.tail(); 93 SkASSERT(tail); 94 this->removeInternal(tail); 95 } 96 } 97 98 void purgeByKeys(const Key keys[], int count) override { 99 SkAutoMutexAcquire mutex(fMutex); 100 // This function is only called in the destructor of SkImageFilter. 101 // Because the destructor will destroy the fCacheKeys anyway, we set the 102 // filter to be null so that removeInternal() won't call the 103 // SkImageFilter::removeKey() function. 104 for (int i = 0; i < count; i++) { 105 if (Value* v = fLookup.find(keys[i])) { 106 v->fFilter = nullptr; 107 this->removeInternal(v); 108 } 109 } 110 } 111 112 SkDEBUGCODE(int count() const override { return fLookup.count(); }) 113 private: 114 void removeInternal(Value* v) { 115 SkASSERT(v->fImage); 116 if (v->fFilter) { 117 v->fFilter->removeKey(v->fKey); 118 } 119 fCurrentBytes -= v->fImage->getSize(); 120 fLRU.remove(v); 121 fLookup.remove(v->fKey); 122 delete v; 123 } 124 private: 125 SkTDynamicHash<Value, Key> fLookup; 126 mutable SkTInternalLList<Value> fLRU; 127 size_t fMaxBytes; 128 size_t fCurrentBytes; 129 mutable SkMutex fMutex; 130 }; 131 132 } // namespace 133 134 SkImageFilterCache* SkImageFilterCache::Create(size_t maxBytes) { 135 return new CacheImpl(maxBytes); 136 } 137 138 SkImageFilterCache* SkImageFilterCache::Get() { 139 static SkOnce once; 140 static SkImageFilterCache* cache; 141 142 once([]{ cache = SkImageFilterCache::Create(kDefaultCacheSize); }); 143 return cache; 144 } 145