Move SkMessageBus::Get out of header, and retry crrev.com/106563002.
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 15 Jan 2014 23:09:01 +0000 (23:09 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 15 Jan 2014 23:09:01 +0000 (23:09 +0000)
BUG=
R=bsalomon@google.com, kkinnunen@nvidia.com

Author: mtklein@google.com

Review URL: https://codereview.chromium.org/140053002

git-svn-id: http://skia.googlecode.com/svn/trunk@13104 2bbb7eff-a529-9590-31e7-b0007b416f81

src/core/SkMessageBus.h
src/gpu/GrResourceCache.cpp
tests/MessageBusTest.cpp
tests/ResourceCacheTest.cpp

index 0a40831..ddeac57 100644 (file)
@@ -44,6 +44,18 @@ private:
     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.
+#define DECLARE_SKMESSAGEBUS_MESSAGE(Message)             \
+    template <>                                           \
+    SkMessageBus<Message>* SkMessageBus<Message>::Get() { \
+        static SkMessageBus<Message>* bus = NULL;         \
+        SK_DECLARE_STATIC_ONCE(once);                     \
+        SkOnce(&once, &New, &bus);                        \
+        SkASSERT(bus != NULL);                            \
+        return bus;                                       \
+    }
+
 //   ----------------------- Implementation of SkMessageBus::Inbox -----------------------
 
 template<typename Message>
@@ -93,17 +105,6 @@ template <typename Message>
 }
 
 template <typename Message>
-/*static*/ SkMessageBus<Message>* SkMessageBus<Message>::Get() {
-    // The first time this method is called, create the singleton bus for this message type.
-    static SkMessageBus<Message>* bus = NULL;
-    SK_DECLARE_STATIC_ONCE(once);
-    SkOnce(&once, &New, &bus);
-
-    SkASSERT(bus != NULL);
-    return bus;
-}
-
-template <typename Message>
 /*static*/ void SkMessageBus<Message>::Post(const Message& m) {
     SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
     SkAutoMutexAcquire lock(bus->fInboxesMutex);
index 5cf3f82..1ba60e8 100644 (file)
@@ -11,6 +11,7 @@
 #include "GrResourceCache.h"
 #include "GrResource.h"
 
+DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage);
 
 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() {
     static int32_t gNextType = 0;
@@ -312,8 +313,7 @@ void GrResourceCache::purgeInvalidated() {
         //
         // This is complicated and confusing.  May try this in the future.  For
         // now, these resources are just LRU'd as if we never got the message.
-        GrResourceEntry* entry = fCache.find(invalidated[i].key, GrTFindUnreffedFunctor());
-        if (entry) {
+        while (GrResourceEntry* entry = fCache.find(invalidated[i].key, GrTFindUnreffedFunctor())) {
             this->deleteResource(entry);
         }
     }
index 0e40d12..f7a02b2 100644 (file)
@@ -8,14 +8,11 @@
 #include "SkMessageBus.h"
 #include "Test.h"
 
-namespace {
-
 struct TestMessage {
     int x;
     float y;
 };
-
-}  // namespace
+DECLARE_SKMESSAGEBUS_MESSAGE(TestMessage)
 
 DEF_TEST(MessageBus, r) {
     // Register two inboxes to receive all TestMessages.
index 845094b..c912ae0 100644 (file)
@@ -8,6 +8,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrContextFactory.h"
+#include "GrResourceCache.h"
 #include "SkGpuDevice.h"
 #include "Test.h"
 
@@ -57,6 +58,79 @@ static void test_cache(skiatest::Reporter* reporter,
     context->setTextureCacheLimits(oldMaxNum, oldMaxBytes);
 }
 
+class TestResource : public GrResource {
+public:
+    SK_DECLARE_INST_COUNT(TestResource);
+    explicit TestResource(GrGpu* gpu)
+        : INHERITED(gpu, false)
+        , fCache(NULL)
+        , fToDelete(NULL) {
+        ++fAlive;
+    }
+
+    ~TestResource() {
+        --fAlive;
+        if (NULL != fToDelete) {
+            // Breaks our little 2-element cycle below.
+            fToDelete->setDeleteWhenDestroyed(NULL, NULL);
+            fCache->deleteResource(fToDelete->getCacheEntry());
+        }
+        this->release();
+    }
+
+    size_t sizeInBytes() const SK_OVERRIDE { return 100; }
+
+    static int alive() { return fAlive; }
+
+    void setDeleteWhenDestroyed(GrResourceCache* cache, TestResource* resource) {
+        fCache = cache;
+        fToDelete = resource;
+    }
+
+private:
+    GrResourceCache* fCache;
+    TestResource* fToDelete;
+    static int fAlive;
+
+    typedef GrResource INHERITED;
+};
+int TestResource::fAlive = 0;
+
+static void test_purge_invalidated(skiatest::Reporter* reporter, GrContext* context) {
+    GrCacheID::Domain domain = GrCacheID::GenerateDomain();
+    GrCacheID::Key keyData;
+    keyData.fData64[0] = 5;
+    keyData.fData64[1] = 18;
+    GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
+    GrResourceKey key(GrCacheID(domain, keyData), t, 0);
+
+    GrResourceCache cache(5, 30000);
+
+    // Add two resources with the same key that delete each other from the cache when destroyed.
+    TestResource* a = new TestResource(context->getGpu());
+    TestResource* b = new TestResource(context->getGpu());
+    cache.addResource(key, a);
+    cache.addResource(key, b);
+    // Circle back.
+    a->setDeleteWhenDestroyed(&cache, b);
+    b->setDeleteWhenDestroyed(&cache, a);
+    a->unref();
+    b->unref();
+
+    // Add a third independent resource also with the same key.
+    GrResource* r = new TestResource(context->getGpu());
+    cache.addResource(key, r);
+    r->unref();
+
+    // Invalidate all three, all three should be purged and destroyed.
+    REPORTER_ASSERT(reporter, 3 == TestResource::alive());
+    const GrResourceInvalidatedMessage msg = { key };
+    SkMessageBus<GrResourceInvalidatedMessage>::Post(msg);
+    cache.purgeAsNeeded();
+    REPORTER_ASSERT(reporter, 0 == TestResource::alive());
+}
+
+////////////////////////////////////////////////////////////////////////////////
 DEF_GPUTEST(ResourceCache, reporter, factory) {
     for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
         GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
@@ -79,6 +153,7 @@ DEF_GPUTEST(ResourceCache, reporter, factory) {
         SkCanvas canvas(device.get());
 
         test_cache(reporter, context, &canvas);
+        test_purge_invalidated(reporter, context);
     }
 }