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