Line data Source code
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 "SkMutex.h"
11 : #include "SkOnce.h"
12 : #include "SkOpts.h"
13 : #include "SkRefCnt.h"
14 : #include "SkSpecialImage.h"
15 : #include "SkTDynamicHash.h"
16 : #include "SkTInternalLList.h"
17 :
18 : #ifdef SK_BUILD_FOR_IOS
19 : enum { kDefaultCacheSize = 2 * 1024 * 1024 };
20 : #else
21 : enum { kDefaultCacheSize = 128 * 1024 * 1024 };
22 : #endif
23 :
24 : namespace {
25 :
26 : class CacheImpl : public SkImageFilterCache {
27 : public:
28 : typedef SkImageFilterCacheKey Key;
29 0 : CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { }
30 0 : ~CacheImpl() override {
31 0 : SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
32 :
33 0 : while (!iter.done()) {
34 0 : Value* v = &*iter;
35 0 : ++iter;
36 0 : delete v;
37 : }
38 0 : }
39 0 : struct Value {
40 0 : Value(const Key& key, SkSpecialImage* image, const SkIPoint& offset)
41 0 : : fKey(key), fImage(SkRef(image)), fOffset(offset) {}
42 :
43 : Key fKey;
44 : sk_sp<SkSpecialImage> fImage;
45 : SkIPoint fOffset;
46 0 : static const Key& GetKey(const Value& v) {
47 0 : return v.fKey;
48 : }
49 0 : static uint32_t Hash(const Key& key) {
50 0 : return SkOpts::hash(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
51 : }
52 : SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
53 : };
54 :
55 0 : sk_sp<SkSpecialImage> get(const Key& key, SkIPoint* offset) const override {
56 0 : SkAutoMutexAcquire mutex(fMutex);
57 0 : if (Value* v = fLookup.find(key)) {
58 0 : *offset = v->fOffset;
59 0 : if (v != fLRU.head()) {
60 0 : fLRU.remove(v);
61 0 : fLRU.addToHead(v);
62 : }
63 0 : return v->fImage;
64 : }
65 0 : return nullptr;
66 : }
67 :
68 0 : void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset) override {
69 0 : SkAutoMutexAcquire mutex(fMutex);
70 0 : if (Value* v = fLookup.find(key)) {
71 0 : this->removeInternal(v);
72 : }
73 0 : Value* v = new Value(key, image, offset);
74 0 : fLookup.add(v);
75 0 : fLRU.addToHead(v);
76 0 : fCurrentBytes += image->getSize();
77 0 : while (fCurrentBytes > fMaxBytes) {
78 0 : Value* tail = fLRU.tail();
79 0 : SkASSERT(tail);
80 0 : if (tail == v) {
81 0 : break;
82 : }
83 0 : this->removeInternal(tail);
84 : }
85 0 : }
86 :
87 0 : void purge() override {
88 0 : SkAutoMutexAcquire mutex(fMutex);
89 0 : while (fCurrentBytes > 0) {
90 0 : Value* tail = fLRU.tail();
91 0 : SkASSERT(tail);
92 0 : this->removeInternal(tail);
93 : }
94 0 : }
95 :
96 0 : void purgeByKeys(const Key keys[], int count) override {
97 0 : SkAutoMutexAcquire mutex(fMutex);
98 0 : for (int i = 0; i < count; i++) {
99 0 : if (Value* v = fLookup.find(keys[i])) {
100 0 : this->removeInternal(v);
101 : }
102 : }
103 0 : }
104 :
105 0 : SkDEBUGCODE(int count() const override { return fLookup.count(); })
106 : private:
107 0 : void removeInternal(Value* v) {
108 0 : SkASSERT(v->fImage);
109 0 : fCurrentBytes -= v->fImage->getSize();
110 0 : fLRU.remove(v);
111 0 : fLookup.remove(v->fKey);
112 0 : delete v;
113 0 : }
114 : private:
115 : SkTDynamicHash<Value, Key> fLookup;
116 : mutable SkTInternalLList<Value> fLRU;
117 : size_t fMaxBytes;
118 : size_t fCurrentBytes;
119 : mutable SkMutex fMutex;
120 : };
121 :
122 : } // namespace
123 :
124 0 : SkImageFilterCache* SkImageFilterCache::Create(size_t maxBytes) {
125 0 : return new CacheImpl(maxBytes);
126 : }
127 :
128 0 : SkImageFilterCache* SkImageFilterCache::Get() {
129 : static SkOnce once;
130 : static SkImageFilterCache* cache;
131 :
132 0 : once([]{ cache = SkImageFilterCache::Create(kDefaultCacheSize); });
133 0 : return cache;
134 : }
|