summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/core/SkImageFilterCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/core/SkImageFilterCache.cpp')
-rw-r--r--gfx/skia/skia/src/core/SkImageFilterCache.cpp164
1 files changed, 164 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/core/SkImageFilterCache.cpp b/gfx/skia/skia/src/core/SkImageFilterCache.cpp
new file mode 100644
index 0000000000..4d998cf86e
--- /dev/null
+++ b/gfx/skia/skia/src/core/SkImageFilterCache.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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 "src/core/SkImageFilterCache.h"
+
+#include <vector>
+
+#include "include/core/SkImageFilter.h"
+#include "include/core/SkRefCnt.h"
+#include "include/private/base/SkMutex.h"
+#include "include/private/base/SkOnce.h"
+#include "src/base/SkTInternalLList.h"
+#include "src/core/SkOpts.h"
+#include "src/core/SkSpecialImage.h"
+#include "src/core/SkTDynamicHash.h"
+#include "src/core/SkTHash.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 {
+ fLookup.foreach([&](Value* v) { delete v; });
+ }
+ struct Value {
+ Value(const Key& key, const skif::FilterResult& image,
+ const SkImageFilter* filter)
+ : fKey(key), fImage(image), fFilter(filter) {}
+
+ Key fKey;
+ skif::FilterResult fImage;
+ const SkImageFilter* fFilter;
+ static const Key& GetKey(const Value& v) {
+ return v.fKey;
+ }
+ static uint32_t Hash(const Key& key) {
+ return SkOpts::hash(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
+ }
+ SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
+ };
+
+ bool get(const Key& key, skif::FilterResult* result) const override {
+ SkASSERT(result);
+
+ SkAutoMutexExclusive mutex(fMutex);
+ if (Value* v = fLookup.find(key)) {
+ if (v != fLRU.head()) {
+ fLRU.remove(v);
+ fLRU.addToHead(v);
+ }
+
+ *result = v->fImage;
+ return true;
+ }
+ return false;
+ }
+
+ void set(const Key& key, const SkImageFilter* filter,
+ const skif::FilterResult& result) override {
+ SkAutoMutexExclusive mutex(fMutex);
+ if (Value* v = fLookup.find(key)) {
+ this->removeInternal(v);
+ }
+ Value* v = new Value(key, result, filter);
+ fLookup.add(v);
+ fLRU.addToHead(v);
+ fCurrentBytes += result.image() ? result.image()->getSize() : 0;
+ if (auto* values = fImageFilterValues.find(filter)) {
+ values->push_back(v);
+ } else {
+ fImageFilterValues.set(filter, {v});
+ }
+
+ while (fCurrentBytes > fMaxBytes) {
+ Value* tail = fLRU.tail();
+ SkASSERT(tail);
+ if (tail == v) {
+ break;
+ }
+ this->removeInternal(tail);
+ }
+ }
+
+ void purge() override {
+ SkAutoMutexExclusive mutex(fMutex);
+ while (fCurrentBytes > 0) {
+ Value* tail = fLRU.tail();
+ SkASSERT(tail);
+ this->removeInternal(tail);
+ }
+ }
+
+ void purgeByImageFilter(const SkImageFilter* filter) override {
+ SkAutoMutexExclusive mutex(fMutex);
+ auto* values = fImageFilterValues.find(filter);
+ if (!values) {
+ return;
+ }
+ for (Value* v : *values) {
+ // We set the filter to be null so that removeInternal() won't delete from values while
+ // we're iterating over it.
+ v->fFilter = nullptr;
+ this->removeInternal(v);
+ }
+ fImageFilterValues.remove(filter);
+ }
+
+ SkDEBUGCODE(int count() const override { return fLookup.count(); })
+private:
+ void removeInternal(Value* v) {
+ if (v->fFilter) {
+ if (auto* values = fImageFilterValues.find(v->fFilter)) {
+ if (values->size() == 1 && (*values)[0] == v) {
+ fImageFilterValues.remove(v->fFilter);
+ } else {
+ for (auto it = values->begin(); it != values->end(); ++it) {
+ if (*it == v) {
+ values->erase(it);
+ break;
+ }
+ }
+ }
+ }
+ }
+ fCurrentBytes -= v->fImage.image() ? v->fImage.image()->getSize() : 0;
+ fLRU.remove(v);
+ fLookup.remove(v->fKey);
+ delete v;
+ }
+private:
+ SkTDynamicHash<Value, Key> fLookup;
+ mutable SkTInternalLList<Value> fLRU;
+ // Value* always points to an item in fLookup.
+ SkTHashMap<const SkImageFilter*, std::vector<Value*>> fImageFilterValues;
+ size_t fMaxBytes;
+ size_t fCurrentBytes;
+ mutable SkMutex fMutex;
+};
+
+} // namespace
+
+SkImageFilterCache* SkImageFilterCache::Create(size_t maxBytes) {
+ return new CacheImpl(maxBytes);
+}
+
+SkImageFilterCache* SkImageFilterCache::Get() {
+ static SkOnce once;
+ static SkImageFilterCache* cache;
+
+ once([]{ cache = SkImageFilterCache::Create(kDefaultCacheSize); });
+ return cache;
+}