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
28namespace {
29
30class CacheImpl : public SkImageFilterCache {
31public:
32 typedef SkImageFilterCacheKey Key;
33 CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { }
34 ~CacheImpl() override {
35 fLookup.foreach([&](Value* v) { delete v; });
36 }
37 struct Value {
38 Value(const Key& key, const skif::FilterResult<For::kOutput>& image,
39 const SkImageFilter* filter)
40 : fKey(key), fImage(image), fFilter(filter) {}
41
42 Key fKey;
43 skif::FilterResult<For::kOutput> fImage;
44 const SkImageFilter* fFilter;
45 static const Key& GetKey(const Value& v) {
46 return v.fKey;
47 }
48 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
54 bool get(const Key& key, skif::FilterResult<For::kOutput>* 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
70 void set(const Key& key, const SkImageFilter* filter,
71 const skif::FilterResult<For::kOutput>& 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
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
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(); })
121private:
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 }
142private:
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
154SkImageFilterCache* SkImageFilterCache::Create(size_t maxBytes) {
155 return new CacheImpl(maxBytes);
156}
157
158SkImageFilterCache* SkImageFilterCache::Get() {
159 static SkOnce once;
160 static SkImageFilterCache* cache;
161
162 once([]{ cache = SkImageFilterCache::Create(kDefaultCacheSize); });
163 return cache;
164}
165