xref: /aosp_15_r20/external/skia/src/core/SkImageFilterCache.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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