| Index: src/core/SkImageFilterCache.cpp
|
| diff --git a/src/core/SkImageFilterCache.cpp b/src/core/SkImageFilterCache.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d87cf6b7c33840c85f4dc9a75842a98fd1a7dbd5
|
| --- /dev/null
|
| +++ b/src/core/SkImageFilterCache.cpp
|
| @@ -0,0 +1,131 @@
|
| +/*
|
| + * Copyright 2016 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#include "SkImageFilterCache.h"
|
| +
|
| +#include "SkChecksum.h"
|
| +#include "SkMutex.h"
|
| +#include "SkOncePtr.h"
|
| +#include "SkRefCnt.h"
|
| +#include "SkSpecialImage.h"
|
| +#include "SkTDynamicHash.h"
|
| +#include "SkTInternalLList.h"
|
| +
|
| +#ifdef SK_BUILD_FOR_IOS
|
| + enum { kDefaultCacheSize = 2 * 1024 * 1024 };
|
| +#else
|
| + enum { kDefaultCacheSize = 128 * 1024 * 1024 };
|
| +#endif
|
| +
|
| +namespace {
|
| +
|
| +class CacheImpl : public SkImageFilterCache {
|
| +public:
|
| + typedef SkImageFilterCacheKey Key;
|
| + CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { }
|
| + ~CacheImpl() override {
|
| + SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
|
| +
|
| + while (!iter.done()) {
|
| + Value* v = &*iter;
|
| + ++iter;
|
| + delete v;
|
| + }
|
| + }
|
| + struct Value {
|
| + Value(const Key& key, SkSpecialImage* image, const SkIPoint& offset)
|
| + : fKey(key), fImage(SkRef(image)), fOffset(offset) {}
|
| +
|
| + Key fKey;
|
| + SkAutoTUnref<SkSpecialImage> fImage;
|
| + SkIPoint fOffset;
|
| + static const Key& GetKey(const Value& v) {
|
| + return v.fKey;
|
| + }
|
| + static uint32_t Hash(const Key& key) {
|
| + return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
|
| + }
|
| + SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
|
| + };
|
| +
|
| + SkSpecialImage* get(const Key& key, SkIPoint* offset) const override {
|
| + SkAutoMutexAcquire mutex(fMutex);
|
| + if (Value* v = fLookup.find(key)) {
|
| + *offset = v->fOffset;
|
| + if (v != fLRU.head()) {
|
| + fLRU.remove(v);
|
| + fLRU.addToHead(v);
|
| + }
|
| + return v->fImage;
|
| + }
|
| + return nullptr;
|
| + }
|
| +
|
| + void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset) override {
|
| + SkAutoMutexAcquire mutex(fMutex);
|
| + if (Value* v = fLookup.find(key)) {
|
| + this->removeInternal(v);
|
| + }
|
| + Value* v = new Value(key, image, offset);
|
| + fLookup.add(v);
|
| + fLRU.addToHead(v);
|
| + fCurrentBytes += image->getSize();
|
| + while (fCurrentBytes > fMaxBytes) {
|
| + Value* tail = fLRU.tail();
|
| + SkASSERT(tail);
|
| + if (tail == v) {
|
| + break;
|
| + }
|
| + this->removeInternal(tail);
|
| + }
|
| + }
|
| +
|
| + void purge() override {
|
| + SkAutoMutexAcquire mutex(fMutex);
|
| + while (fCurrentBytes > 0) {
|
| + Value* tail = fLRU.tail();
|
| + SkASSERT(tail);
|
| + this->removeInternal(tail);
|
| + }
|
| + }
|
| +
|
| + void purgeByKeys(const Key keys[], int count) override {
|
| + SkAutoMutexAcquire mutex(fMutex);
|
| + for (int i = 0; i < count; i++) {
|
| + if (Value* v = fLookup.find(keys[i])) {
|
| + this->removeInternal(v);
|
| + }
|
| + }
|
| + }
|
| +
|
| + SkDEBUGCODE(int count() const override { return fLookup.count(); })
|
| +private:
|
| + void removeInternal(Value* v) {
|
| + SkASSERT(v->fImage);
|
| + fCurrentBytes -= v->fImage->getSize();
|
| + fLRU.remove(v);
|
| + fLookup.remove(v->fKey);
|
| + delete v;
|
| + }
|
| +private:
|
| + SkTDynamicHash<Value, Key> fLookup;
|
| + mutable SkTInternalLList<Value> fLRU;
|
| + size_t fMaxBytes;
|
| + size_t fCurrentBytes;
|
| + mutable SkMutex fMutex;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +SkImageFilterCache* SkImageFilterCache::Create(size_t maxBytes) {
|
| + return new CacheImpl(maxBytes);
|
| +}
|
| +
|
| +SK_DECLARE_STATIC_ONCE_PTR(SkImageFilterCache, cache);
|
| +SkImageFilterCache* SkImageFilterCache::Get() {
|
| + return cache.get([]{ return SkImageFilterCache::Create(kDefaultCacheSize); });
|
| +}
|
|
|