| Index: src/core/SkImageFilter.cpp
|
| diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
|
| index 6c4561b0646958e92d110989374af3d5fd5e45a3..ffb1f836d890ef1b1cad7a520d7857e1b75411c5 100644
|
| --- a/src/core/SkImageFilter.cpp
|
| +++ b/src/core/SkImageFilter.cpp
|
| @@ -14,10 +14,8 @@
|
| #include "SkMatrixImageFilter.h"
|
| #include "SkMutex.h"
|
| #include "SkOncePtr.h"
|
| -#include "SkPixelRef.h"
|
| #include "SkReadBuffer.h"
|
| #include "SkRect.h"
|
| -#include "SkResourceCache.h"
|
| #include "SkTDynamicHash.h"
|
| #include "SkTInternalLList.h"
|
| #include "SkValidationUtils.h"
|
| @@ -27,6 +25,12 @@
|
| #include "GrDrawContext.h"
|
| #include "SkGrPixelRef.h"
|
| #include "SkGr.h"
|
| +#endif
|
| +
|
| +#ifdef SK_BUILD_FOR_IOS
|
| + enum { kDefaultCacheSize = 2 * 1024 * 1024 };
|
| +#else
|
| + enum { kDefaultCacheSize = 128 * 1024 * 1024 };
|
| #endif
|
|
|
| #ifndef SK_IGNORE_TO_STRING
|
| @@ -473,122 +477,102 @@
|
|
|
| namespace {
|
|
|
| -class ImageFilterRec : public SkResourceCache::Rec {
|
| +class CacheImpl : public SkImageFilter::Cache {
|
| public:
|
| - struct Keys {
|
| - Keys(SkImageFilter::Cache::Key ifcKey) : fIFCKey(ifcKey) {
|
| - static bool unique_namespace;
|
| - fRCKey.init(&unique_namespace,
|
| - 0 /*shared ids allow fine-grained purging, which we can't use here*/,
|
| - sizeof(fIFCKey));
|
| - }
|
| - // The SkImageFilter::Cache::Key must immediately follow the SkResourceCache::Key.
|
| - SkResourceCache::Key fRCKey;
|
| - const SkImageFilter::Cache::Key fIFCKey;
|
| + CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) {
|
| + }
|
| + virtual ~CacheImpl() {
|
| + SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
|
| +
|
| + while (!iter.done()) {
|
| + Value* v = &*iter;
|
| + ++iter;
|
| + delete v;
|
| + }
|
| + }
|
| + struct Value {
|
| + Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
|
| + : fKey(key), fBitmap(bitmap), fOffset(offset) {}
|
| + Key fKey;
|
| + SkBitmap fBitmap;
|
| + 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);
|
| };
|
| -
|
| - ImageFilterRec(SkImageFilter::Cache::Key ifcKey, const SkBitmap& bm, const SkIPoint& offset)
|
| - : fKeys(ifcKey)
|
| - , fBitmap(bm)
|
| - , fOffset(offset) {}
|
| -
|
| - const Key& getKey() const override { return fKeys.fRCKey; }
|
| - size_t bytesUsed() const override { return sizeof(*this) + fBitmap.getSize(); }
|
| - const char* getCategory() const override { return "SkImageFilter::Cache"; }
|
| -
|
| - SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
|
| - if (auto pr = fBitmap.pixelRef()) {
|
| - return pr->diagnostic_only_getDiscardable();
|
| - }
|
| - return nullptr;
|
| - }
|
| -
|
| - const SkBitmap& bitmap() const { return fBitmap; }
|
| - const SkIPoint& offset() const { return fOffset; }
|
| + bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const override {
|
| + SkAutoMutexAcquire mutex(fMutex);
|
| + if (Value* v = fLookup.find(key)) {
|
| + *result = v->fBitmap;
|
| + *offset = v->fOffset;
|
| + if (v != fLRU.head()) {
|
| + fLRU.remove(v);
|
| + fLRU.addToHead(v);
|
| + }
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| + void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) override {
|
| + SkAutoMutexAcquire mutex(fMutex);
|
| + if (Value* v = fLookup.find(key)) {
|
| + removeInternal(v);
|
| + }
|
| + Value* v = new Value(key, result, offset);
|
| + fLookup.add(v);
|
| + fLRU.addToHead(v);
|
| + fCurrentBytes += result.getSize();
|
| + while (fCurrentBytes > fMaxBytes) {
|
| + Value* tail = fLRU.tail();
|
| + SkASSERT(tail);
|
| + if (tail == v) {
|
| + break;
|
| + }
|
| + removeInternal(tail);
|
| + }
|
| + }
|
| +
|
| + void purge() override {
|
| + SkAutoMutexAcquire mutex(fMutex);
|
| + while (fCurrentBytes > 0) {
|
| + Value* tail = fLRU.tail();
|
| + SkASSERT(tail);
|
| + this->removeInternal(tail);
|
| + }
|
| + }
|
|
|
| private:
|
| - const Keys fKeys;
|
| - const SkBitmap fBitmap;
|
| - const SkIPoint fOffset;
|
| + void removeInternal(Value* v) {
|
| + fCurrentBytes -= v->fBitmap.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;
|
| };
|
|
|
| -struct GetVisitor {
|
| - SkBitmap* fResult;
|
| - SkIPoint* fOffset;
|
| -
|
| - static bool Visit(const SkResourceCache::Rec& rec, void* context) {
|
| - auto r = (const ImageFilterRec&)rec;
|
| - auto c = (GetVisitor*)context;
|
| - *c->fResult = r.bitmap();
|
| - *c->fOffset = r.offset();
|
| - return true;
|
| - }
|
| -};
|
| -
|
| -// Thread-safe SkImageFilter::Cache that uses the global SkResourceCache.
|
| -class GlobalCache : public SkImageFilter::Cache {
|
| -public:
|
| - GlobalCache() {}
|
| -
|
| - void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) override {
|
| - const SkBitmap* bm = &result;
|
| - SkBitmap copy;
|
| - // Image filters allocate their own result bitmaps.
|
| - // If we're putting a bitmap into the SkResourceCache backed by discardable memory,
|
| - // we'd better make sure those bitmaps are discardable too (and vice versa).
|
| - // The expected case in Chrome is: rcIsDiscardable == true, bmIsDiscardable == false.
|
| - auto allocator = SkResourceCache::GetAllocator();
|
| -#if 0
|
| - bool rcIsDiscardable = allocator,
|
| - bmIsDiscardable = bm->pixelRef() && bm->pixelRef()->diagnostic_only_getDiscardable();
|
| - if (rcIsDiscardable != bmIsDiscardable) {
|
| -#else
|
| - {
|
| -#endif
|
| - bm->copyTo(©, allocator);
|
| - bm = ©
|
| - }
|
| - SkResourceCache::Add(new ImageFilterRec(key, *bm, offset));
|
| - }
|
| -
|
| - bool get(const Key& ifcKey, SkBitmap* result, SkIPoint* offset) const override {
|
| - const ImageFilterRec::Keys keys(ifcKey);
|
| - GetVisitor visitor { result, offset };
|
| - return SkResourceCache::Find(keys.fRCKey, GetVisitor::Visit, &visitor);
|
| - }
|
| -};
|
| -
|
| -// Non-thread-safe siloed SkImageFilter::Cache, meant to be small and ephemeral.
|
| -class LocalCache : public SkImageFilter::Cache {
|
| -public:
|
| - LocalCache(size_t maxBytes) : fRC(maxBytes) {
|
| - SkASSERT(fRC.allocator() == nullptr);
|
| - }
|
| -
|
| - void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) override {
|
| - SkASSERT(result.pixelRef() == nullptr ||
|
| - result.pixelRef()->diagnostic_only_getDiscardable() == nullptr);
|
| - fRC.add(new ImageFilterRec(key, result, offset));
|
| - }
|
| -
|
| - bool get(const Key& ifcKey, SkBitmap* result, SkIPoint* offset) const override {
|
| - const ImageFilterRec::Keys keys(ifcKey);
|
| - GetVisitor visitor { result, offset };
|
| - return fRC.find(keys.fRCKey, GetVisitor::Visit, &visitor);
|
| - }
|
| -private:
|
| - mutable SkResourceCache fRC; // SkResourceCache::find() is not const (updates LRU).
|
| -};
|
| -
|
| } // namespace
|
|
|
| SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
|
| - return new LocalCache(maxBytes);
|
| + return new CacheImpl(maxBytes);
|
| }
|
|
|
| SK_DECLARE_STATIC_ONCE_PTR(SkImageFilter::Cache, cache);
|
| SkImageFilter::Cache* SkImageFilter::Cache::Get() {
|
| - return cache.get([]{ return new GlobalCache; });
|
| + return cache.get([]{ return SkImageFilter::Cache::Create(kDefaultCacheSize); });
|
| +}
|
| +
|
| +void SkImageFilter::PurgeCache() {
|
| + Cache::Get()->purge();
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|