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