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 "src/core/SkImageFilterCache.h"
9
10 #include "include/private/base/SkMutex.h"
11 #include "include/private/base/SkOnce.h"
12 #include "src/base/SkTInternalLList.h"
13 #include "src/core/SkChecksum.h"
14 #include "src/core/SkImageFilterTypes.h"
15 #include "src/core/SkSpecialImage.h"
16 #include "src/core/SkTDynamicHash.h"
17 #include "src/core/SkTHash.h"
18
19 #include <vector>
20
21 using namespace skia_private;
22
23 #ifdef SK_BUILD_FOR_IOS
24 enum { kDefaultCacheSize = 2 * 1024 * 1024 };
25 #else
26 enum { kDefaultCacheSize = 128 * 1024 * 1024 };
27 #endif
28
29 namespace {
30
31 class CacheImpl : public SkImageFilterCache {
32 public:
33 typedef SkImageFilterCacheKey Key;
CacheImpl(size_t maxBytes)34 CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { }
~CacheImpl()35 ~CacheImpl() override {
36 fLookup.foreach([&](Value* v) { delete v; });
37 }
38 struct Value {
Value__anon0e486af90311::CacheImpl::Value39 Value(const Key& key, const skif::FilterResult& image,
40 const SkImageFilter* filter)
41 : fKey(key), fImage(image), fFilter(filter) {}
42
43 Key fKey;
44 skif::FilterResult fImage;
45 const SkImageFilter* fFilter;
GetKey__anon0e486af90311::CacheImpl::Value46 static const Key& GetKey(const Value& v) {
47 return v.fKey;
48 }
Hash__anon0e486af90311::CacheImpl::Value49 static uint32_t Hash(const Key& key) {
50 return SkChecksum::Hash32(&key, sizeof(Key));
51 }
52 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
53 };
54
get(const Key & key,skif::FilterResult * result) const55 bool get(const Key& key, skif::FilterResult* result) const override {
56 SkASSERT(result);
57
58 SkAutoMutexExclusive mutex(fMutex);
59 if (Value* v = fLookup.find(key)) {
60 if (v != fLRU.head()) {
61 fLRU.remove(v);
62 fLRU.addToHead(v);
63 }
64
65 *result = v->fImage;
66 return true;
67 }
68 return false;
69 }
70
set(const Key & key,const SkImageFilter * filter,const skif::FilterResult & result)71 void set(const Key& key, const SkImageFilter* filter,
72 const skif::FilterResult& result) override {
73 SkAutoMutexExclusive mutex(fMutex);
74 if (Value* v = fLookup.find(key)) {
75 this->removeInternal(v);
76 }
77 Value* v = new Value(key, result, filter);
78 fLookup.add(v);
79 fLRU.addToHead(v);
80 fCurrentBytes += result.image() ? result.image()->getSize() : 0;
81 if (auto* values = fImageFilterValues.find(filter)) {
82 values->push_back(v);
83 } else {
84 fImageFilterValues.set(filter, {v});
85 }
86
87 while (fCurrentBytes > fMaxBytes) {
88 Value* tail = fLRU.tail();
89 SkASSERT(tail);
90 if (tail == v) {
91 break;
92 }
93 this->removeInternal(tail);
94 }
95 }
96
purge()97 void purge() override {
98 SkAutoMutexExclusive mutex(fMutex);
99 while (fCurrentBytes > 0) {
100 Value* tail = fLRU.tail();
101 SkASSERT(tail);
102 this->removeInternal(tail);
103 }
104 }
105
purgeByImageFilter(const SkImageFilter * filter)106 void purgeByImageFilter(const SkImageFilter* filter) override {
107 SkAutoMutexExclusive mutex(fMutex);
108 auto* values = fImageFilterValues.find(filter);
109 if (!values) {
110 return;
111 }
112 for (Value* v : *values) {
113 // We set the filter to be null so that removeInternal() won't delete from values while
114 // we're iterating over it.
115 v->fFilter = nullptr;
116 this->removeInternal(v);
117 }
118 fImageFilterValues.remove(filter);
119 }
120
121 SkDEBUGCODE(int count() const override { return fLookup.count(); })
122 private:
removeInternal(Value * v)123 void removeInternal(Value* v) {
124 if (v->fFilter) {
125 if (auto* values = fImageFilterValues.find(v->fFilter)) {
126 if (values->size() == 1 && (*values)[0] == v) {
127 fImageFilterValues.remove(v->fFilter);
128 } else {
129 for (auto it = values->begin(); it != values->end(); ++it) {
130 if (*it == v) {
131 values->erase(it);
132 break;
133 }
134 }
135 }
136 }
137 }
138 fCurrentBytes -= v->fImage.image() ? v->fImage.image()->getSize() : 0;
139 fLRU.remove(v);
140 fLookup.remove(v->fKey);
141 delete v;
142 }
143 private:
144 SkTDynamicHash<Value, Key> fLookup;
145 mutable SkTInternalLList<Value> fLRU;
146 // Value* always points to an item in fLookup.
147 THashMap<const SkImageFilter*, std::vector<Value*>> fImageFilterValues;
148 size_t fMaxBytes;
149 size_t fCurrentBytes;
150 mutable SkMutex fMutex;
151 };
152
153 } // namespace
154
Create(size_t maxBytes)155 sk_sp<SkImageFilterCache> SkImageFilterCache::Create(size_t maxBytes) {
156 return sk_make_sp<CacheImpl>(maxBytes);
157 }
158
Get(CreateIfNecessary createIfNecessary)159 sk_sp<SkImageFilterCache> SkImageFilterCache::Get(CreateIfNecessary createIfNecessary) {
160 static SkOnce once;
161 static sk_sp<SkImageFilterCache> cache;
162
163 if (createIfNecessary == CreateIfNecessary::kNo) {
164 return cache;
165 }
166
167 once([]{ cache = SkImageFilterCache::Create(kDefaultCacheSize); });
168 return cache;
169 }
170