Add native caching of uniquely keyed GrTextureProxies (take 2)

TBR=bsalomon@google.com

Change-Id: I590dcdc85fb60706c7eb06277694791dc04c9141
Reviewed-on: https://skia-review.googlesource.com/49543
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index f6170c0..c207b44 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -10,6 +10,8 @@
 
 #include "GrCaps.h"
 #include "GrGpuResourceCacheAccess.h"
+#include "GrTexture.h"
+#include "GrTextureProxyCacheAccess.h"
 #include "GrTracing.h"
 #include "SkGr.h"
 #include "SkMessageBus.h"
@@ -578,6 +580,8 @@
 void GrResourceCache::processInvalidUniqueKeys(
     const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
     for (int i = 0; i < msgs.count(); ++i) {
+        this->processInvalidProxyUniqueKey(msgs[i].key());
+
         GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
         if (resource) {
             resource->resourcePriv().removeUniqueKey();
@@ -847,3 +851,63 @@
 }
 
 #endif
+
+void GrResourceCache::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
+    SkASSERT(key.isValid());
+    SkASSERT(proxy);
+
+    // If there is already a GrResource with this key then the caller has violated the normal
+    // usage pattern of uniquely keyed resources (e.g., they have created one w/o first seeing
+    // if it already existed in the cache).
+    SkASSERT(!this->findAndRefUniqueResource(key));
+
+    // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped
+    // resources are a special case: the unique keys give us a weak ref so that we can reuse the
+    // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced,
+    // it will always be released - it is never converted to a scratch resource.
+    if (SkBudgeted::kNo == proxy->isBudgeted() &&
+                    (!proxy->priv().isInstantiated() ||
+                     !proxy->priv().peekSurface()->resourcePriv().refsWrappedObjects())) {
+        return;
+    }
+
+    SkASSERT(!fUniquelyKeyedProxies.find(key));     // multiple proxies can't get the same key
+
+    proxy->cacheAccess().setUniqueKey(this, key);
+    SkASSERT(proxy->getUniqueKey() == key);
+    fUniquelyKeyedProxies.add(proxy);
+}
+
+sk_sp<GrTextureProxy> GrResourceCache::findProxyByUniqueKey(const GrUniqueKey& key,
+                                                            GrSurfaceOrigin origin) {
+
+    sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key));
+    if (result) {
+        SkASSERT(result->origin() == origin);
+        return result;
+    }
+
+    GrGpuResource* resource = findAndRefUniqueResource(key);
+    if (!resource) {
+        return nullptr;
+    }
+
+    sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
+    SkASSERT(texture);
+
+    result = GrSurfaceProxy::MakeWrapped(std::move(texture), origin);
+    SkASSERT(result->getUniqueKey() == key);
+    fUniquelyKeyedProxies.add(result.get());
+    return result;
+}
+
+void GrResourceCache::processInvalidProxyUniqueKey(const GrUniqueKey& key) {
+    // Note: this method is called for the whole variety of GrGpuResources so often 'key'
+    // will not be in 'fUniquelyKeyedProxies'.
+    GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
+    if (proxy) {
+        fUniquelyKeyedProxies.remove(key);
+        proxy->cacheAccess().clearUniqueKey();
+    }
+}
+