Add support for tagging GrUniqueKeys with a debug string
authorBrian Salomon <bsalomon@google.com>
Fri, 6 Jan 2017 17:04:19 +0000 (12:04 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Fri, 6 Jan 2017 17:54:03 +0000 (17:54 +0000)
Change-Id: Ie7d56214fdee7a19a1e8ca3869e5e4d5e72cedf8
Reviewed-on: https://skia-review.googlesource.com/6632
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
include/gpu/GrResourceKey.h
src/gpu/GrResourceCache.h
tests/ResourceCacheTest.cpp
tools/gpu/GrTest.cpp

index 0ead35e..8ba1140 100644 (file)
@@ -9,10 +9,11 @@
 #ifndef GrResourceKey_DEFINED
 #define GrResourceKey_DEFINED
 
+#include "../private/SkOnce.h"
 #include "../private/SkTemplates.h"
 #include "GrTypes.h"
 #include "SkData.h"
-#include "../private/SkOnce.h"
+#include "SkString.h"
 
 uint32_t GrResourceKeyHash(const uint32_t* data, size_t size);
 
@@ -239,6 +240,7 @@ public:
     GrUniqueKey& operator=(const GrUniqueKey& that) {
         this->INHERITED::operator=(that);
         this->setCustomData(sk_ref_sp(that.getCustomData()));
+        SkDEBUGCODE(fTag = that.fTag;)
         return *this;
     }
 
@@ -254,21 +256,28 @@ public:
         return fData.get();
     }
 
+    SkDEBUGCODE(const char* tag() const { return fTag.c_str(); })
+
     class Builder : public INHERITED::Builder {
     public:
-        Builder(GrUniqueKey* key, Domain domain, int data32Count)
-            : INHERITED::Builder(key, domain, data32Count) {}
+        Builder(GrUniqueKey* key, Domain type, int data32Count, const char* tag = nullptr)
+                : INHERITED::Builder(key, type, data32Count) {
+            SkDEBUGCODE(key->fTag = tag;)
+            (void) tag;  // suppress unused named param warning.
+        }
 
         /** Used to build a key that wraps another key and adds additional data. */
-        Builder(GrUniqueKey* key, const GrUniqueKey& innerKey, Domain domain,
-                int extraData32Cnt)
-            : INHERITED::Builder(key, domain, Data32CntForInnerKey(innerKey) + extraData32Cnt) {
+        Builder(GrUniqueKey* key, const GrUniqueKey& innerKey, Domain domain, int extraData32Cnt,
+                const char* tag = nullptr)
+                : INHERITED::Builder(key, domain, Data32CntForInnerKey(innerKey) + extraData32Cnt) {
             SkASSERT(&innerKey != key);
             // add the inner key to the end of the key so that op[] can be indexed normally.
             uint32_t* innerKeyData = &this->operator[](extraData32Cnt);
             const uint32_t* srcData = innerKey.data();
             (*innerKeyData++) = innerKey.domain();
             memcpy(innerKeyData, srcData, innerKey.dataSize());
+            SkDEBUGCODE(key->fTag = tag;)
+            (void) tag;  // suppress unused named param warning.
         }
 
     private:
@@ -280,6 +289,7 @@ public:
 
 private:
     sk_sp<SkData> fData;
+    SkDEBUGCODE(SkString fTag;)
 };
 
 /**
index ae9a4e7..5f08a51 100644 (file)
@@ -211,6 +211,10 @@ public:
     void dumpStatsKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* value) const;
 #endif
 
+#ifdef SK_DEBUG
+    int countUniqueKeysWithTag(const char* tag) const;
+#endif
+
     // This function is for unit testing and is only defined in test tools.
     void changeTimestamp(uint32_t newTimestamp);
 
index 06304cf..1782093 100644 (file)
@@ -415,9 +415,10 @@ static void test_no_key(skiatest::Reporter* reporter) {
 }
 
 // Each integer passed as a template param creates a new domain.
-template <int> static void make_unique_key(GrUniqueKey* key, int data) {
+template <int>
+static void make_unique_key(GrUniqueKey* key, int data, const char* tag = nullptr) {
     static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain();
-    GrUniqueKey::Builder builder(key, d, 1);
+    GrUniqueKey::Builder builder(key, d, 1, tag);
     builder[0] = data;
 }
 
@@ -1324,6 +1325,42 @@ static void test_abandoned(skiatest::Reporter* reporter) {
     resource->resourcePriv().removeUniqueKey();
 }
 
+static void test_tags(skiatest::Reporter* reporter) {
+#ifdef SK_DEBUG
+    // We will insert 1 resource with tag "tag1", 2 with "tag2", and so on, up through kLastTagIdx.
+    static constexpr int kLastTagIdx = 10;
+    static constexpr int kNumResources = kLastTagIdx * (kLastTagIdx + 1) / 2;
+
+    Mock mock(kNumResources, kNumResources * TestResource::kDefaultSize);
+    GrContext* context = mock.context();
+    GrResourceCache* cache = mock.cache();
+
+    SkString tagStr;
+    int tagIdx = 0;
+    int currTagCnt = 0;
+
+    for (int i = 0; i < kNumResources; ++i, ++currTagCnt) {
+        sk_sp<GrGpuResource> resource(new TestResource(context->getGpu()));
+        GrUniqueKey key;
+        if (currTagCnt == tagIdx) {
+            tagIdx += 1;
+            currTagCnt = 0;
+            tagStr.printf("tag%d", tagIdx);
+        }
+        make_unique_key<1>(&key, i, tagStr.c_str());
+        resource->resourcePriv().setUniqueKey(key);
+    }
+    SkASSERT(kLastTagIdx == tagIdx);
+    SkASSERT(currTagCnt == kLastTagIdx);
+
+    // Test i = 0 to exercise unused tag string.
+    for (int i = 0; i <= kLastTagIdx; ++i) {
+        tagStr.printf("tag%d", i);
+        REPORTER_ASSERT(reporter, cache->countUniqueKeysWithTag(tagStr.c_str()) == i);
+    }
+#endif
+}
+
 DEF_GPUTEST(ResourceCacheMisc, reporter, factory) {
     // The below tests create their own mock contexts.
     test_no_key(reporter);
@@ -1342,6 +1379,7 @@ DEF_GPUTEST(ResourceCacheMisc, reporter, factory) {
     test_large_resource_count(reporter);
     test_custom_data(reporter);
     test_abandoned(reporter);
+    test_tags(reporter);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
index 61703b5..95ee6b8 100644 (file)
@@ -221,6 +221,20 @@ void GrResourceCache::dumpStatsKeyValuePairs(SkTArray<SkString>* keys,
 
 void GrResourceCache::changeTimestamp(uint32_t newTimestamp) { fTimestamp = newTimestamp; }
 
+#ifdef SK_DEBUG
+int GrResourceCache::countUniqueKeysWithTag(const char* tag) const {
+    int count = 0;
+    UniqueHash::ConstIter iter(&fUniqueHash);
+    while (!iter.done()) {
+        if (0 == strcmp(tag, (*iter).getUniqueKey().tag())) {
+            ++count;
+        }
+        ++iter;
+    }
+    return count;
+}
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #define ASSERT_SINGLE_OWNER \