Purge clip masks when they are no longer findable.
This improves memory usage when the content contains frequently changing clips implemented as masks.
BUG=chromium:676459
Change-Id: I06ea5f9fe1cff9564ea136bad9fe97f6ecd77ad9
Reviewed-on: https://skia-review.googlesource.com/6629
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkMessageBus.h b/src/core/SkMessageBus.h
deleted file mode 100644
index 79f5c02..0000000
--- a/src/core/SkMessageBus.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkMessageBus_DEFINED
-#define SkMessageBus_DEFINED
-
-#include "SkMutex.h"
-#include "SkOnce.h"
-#include "SkTArray.h"
-#include "SkTDArray.h"
-#include "SkTypes.h"
-
-template <typename Message>
-class SkMessageBus : SkNoncopyable {
-public:
- // Post a message to be received by all Inboxes for this Message type. Threadsafe.
- static void Post(const Message& m);
-
- class Inbox {
- public:
- Inbox();
- ~Inbox();
-
- // Overwrite out with all the messages we've received since the last call. Threadsafe.
- void poll(SkTArray<Message>* out);
-
- private:
- SkTArray<Message> fMessages;
- SkMutex fMessagesMutex;
-
- friend class SkMessageBus;
- void receive(const Message& m); // SkMessageBus is a friend only to call this.
- };
-
-private:
- SkMessageBus();
- static SkMessageBus* Get();
-
- SkTDArray<Inbox*> fInboxes;
- SkMutex fInboxesMutex;
-};
-
-// This must go in a single .cpp file, not some .h, or we risk creating more than one global
-// SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile.
-#define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \
- template <> \
- SkMessageBus<Message>* SkMessageBus<Message>::Get() { \
- static SkOnce once; \
- static SkMessageBus<Message>* bus; \
- once([] { bus = new SkMessageBus<Message>(); }); \
- return bus; \
- }
-
-// ----------------------- Implementation of SkMessageBus::Inbox -----------------------
-
-template<typename Message>
-SkMessageBus<Message>::Inbox::Inbox() {
- // Register ourselves with the corresponding message bus.
- SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
- SkAutoMutexAcquire lock(bus->fInboxesMutex);
- bus->fInboxes.push(this);
-}
-
-template<typename Message>
-SkMessageBus<Message>::Inbox::~Inbox() {
- // Remove ourselves from the corresponding message bus.
- SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
- SkAutoMutexAcquire lock(bus->fInboxesMutex);
- // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
- for (int i = 0; i < bus->fInboxes.count(); i++) {
- if (this == bus->fInboxes[i]) {
- bus->fInboxes.removeShuffle(i);
- break;
- }
- }
-}
-
-template<typename Message>
-void SkMessageBus<Message>::Inbox::receive(const Message& m) {
- SkAutoMutexAcquire lock(fMessagesMutex);
- fMessages.push_back(m);
-}
-
-template<typename Message>
-void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) {
- SkASSERT(messages);
- messages->reset();
- SkAutoMutexAcquire lock(fMessagesMutex);
- fMessages.swap(messages);
-}
-
-// ----------------------- Implementation of SkMessageBus -----------------------
-
-template <typename Message>
-SkMessageBus<Message>::SkMessageBus() {}
-
-template <typename Message>
-/*static*/ void SkMessageBus<Message>::Post(const Message& m) {
- SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
- SkAutoMutexAcquire lock(bus->fInboxesMutex);
- for (int i = 0; i < bus->fInboxes.count(); i++) {
- bus->fInboxes[i]->receive(m);
- }
-}
-
-#endif // SkMessageBus_DEFINED
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index a7bcce4..7b50d52 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -27,6 +27,7 @@
typedef GrReducedClip::ElementList ElementList;
static const int kMaxAnalyticElements = 4;
+const char GrClipStackClip::kMaskTestTag[] = "clip_mask";
bool GrClipStackClip::quickContains(const SkRect& rect) const {
if (!fStack || fStack->isWideOpen()) {
@@ -341,9 +342,9 @@
if (UseSWOnlyPath(context, hasUserStencilSettings, renderTargetContext, reducedClip)) {
// The clip geometry is complex enough that it will be more efficient to create it
// entirely in software
- result = CreateSoftwareClipMask(context, reducedClip);
+ result = this->createSoftwareClipMask(context, reducedClip);
} else {
- result = CreateAlphaClipMask(context, reducedClip);
+ result = this->createAlphaClipMask(context, reducedClip);
}
if (result) {
@@ -384,9 +385,9 @@
////////////////////////////////////////////////////////////////////////////////
// Create a 8-bit clip mask in alpha
-static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) {
+static void create_clip_mask_key(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) {
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
- GrUniqueKey::Builder builder(key, kDomain, 3);
+ GrUniqueKey::Builder builder(key, kDomain, 3, GrClipStackClip::kMaskTestTag);
builder[0] = clipGenID;
// SkToS16 because image filters outset layers to a size indicated by the filter, which can
// sometimes result in negative coordinates from clip space.
@@ -394,11 +395,25 @@
builder[2] = SkToS16(bounds.fTop) | (SkToS16(bounds.fBottom) << 16);
}
-sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
- const GrReducedClip& reducedClip) {
+static void add_invalidate_on_pop_message(const SkClipStack& stack, int32_t clipGenID,
+ const GrUniqueKey& clipMaskKey) {
+ SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
+ while (const Element* element = iter.prev()) {
+ if (element->getGenID() == clipGenID) {
+ std::unique_ptr<GrUniqueKeyInvalidatedMessage> msg(
+ new GrUniqueKeyInvalidatedMessage(clipMaskKey));
+ element->addResourceInvalidationMessage(std::move(msg));
+ return;
+ }
+ }
+ SkDEBUGFAIL("Gen ID was not found in stack.");
+}
+
+sk_sp<GrTexture> GrClipStackClip::createAlphaClipMask(GrContext* context,
+ const GrReducedClip& reducedClip) const {
GrResourceProvider* resourceProvider = context->resourceProvider();
GrUniqueKey key;
- GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
+ create_clip_mask_key(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
return sk_sp<GrTexture>(texture);
}
@@ -423,13 +438,14 @@
}
texture->resourcePriv().setUniqueKey(key);
+ add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key);
return texture;
}
-sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrContext* context,
- const GrReducedClip& reducedClip) {
+sk_sp<GrTexture> GrClipStackClip::createSoftwareClipMask(GrContext* context,
+ const GrReducedClip& reducedClip) const {
GrUniqueKey key;
- GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
+ create_clip_mask_key(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
if (GrTexture* texture = context->textureProvider()->findAndRefTextureByUniqueKey(key)) {
return sk_sp<GrTexture>(texture);
}
@@ -493,6 +509,6 @@
}
tex->resourcePriv().setUniqueKey(key);
-
+ add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key);
return sk_ref_sp(tex);
}
diff --git a/src/gpu/GrClipStackClip.h b/src/gpu/GrClipStackClip.h
index f5b8411..1c4d40b 100644
--- a/src/gpu/GrClipStackClip.h
+++ b/src/gpu/GrClipStackClip.h
@@ -40,6 +40,9 @@
bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const override;
+ sk_sp<GrTexture> testingOnly_createClipMask(GrContext*) const;
+ static const char kMaskTestTag[];
+
private:
static bool PathNeedsSWRenderer(GrContext* context,
bool hasUserStencilSettings,
@@ -51,18 +54,15 @@
// Creates an alpha mask of the clip. The mask is a rasterization of elements through the
// rect specified by clipSpaceIBounds.
- static sk_sp<GrTexture> CreateAlphaClipMask(GrContext*, const GrReducedClip&);
+ sk_sp<GrTexture> createAlphaClipMask(GrContext*, const GrReducedClip&) const;
// Similar to createAlphaClipMask but it rasterizes in SW and uploads to the result texture.
- static sk_sp<GrTexture> CreateSoftwareClipMask(GrContext*, const GrReducedClip&);
+ sk_sp<GrTexture> createSoftwareClipMask(GrContext*, const GrReducedClip&) const;
- static bool UseSWOnlyPath(GrContext*,
- bool hasUserStencilSettings,
- const GrRenderTargetContext*,
- const GrReducedClip&);
-
- static GrTexture* CreateCachedMask(int width, int height, const GrUniqueKey& key,
- bool renderTarget);
+ static bool UseSWOnlyPath(GrContext*,
+ bool hasUserStencilSettings,
+ const GrRenderTargetContext*,
+ const GrReducedClip&);
SkIPoint fOrigin;
sk_sp<const SkClipStack> fStack;