Allow resources' unique keys to be changed.

Review URL: https://codereview.chromium.org/938943002
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index 8658744..a2fde2f 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -237,26 +237,50 @@
     fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
 }
 
-void GrResourceCache::willRemoveUniqueKey(const GrGpuResource* resource) {
+void GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
     // Someone has a ref to this resource in order to invalidate it. When the ref count reaches
     // zero we will get a notifyPurgable() and figure out what to do with it.
-    SkASSERT(resource->getUniqueKey().isValid());
-    fUniqueHash.remove(resource->getUniqueKey());
+    if (resource->getUniqueKey().isValid()) {
+        SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
+        fUniqueHash.remove(resource->getUniqueKey());
+    }
+    resource->cacheAccess().removeUniqueKey();
+    this->validate();
 }
 
-bool GrResourceCache::didSetUniqueKey(GrGpuResource* resource) {
+void GrResourceCache::changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
     SkASSERT(resource);
     SkASSERT(this->isInCache(resource));
-    SkASSERT(resource->getUniqueKey().isValid());
 
-    GrGpuResource* res = fUniqueHash.find(resource->getUniqueKey());
-    if (NULL != res) {
-        return false;
+    // Remove the entry for this resource if it already has a unique key.
+    if (resource->getUniqueKey().isValid()) {
+        SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
+        fUniqueHash.remove(resource->getUniqueKey());
+        SkASSERT(NULL == fUniqueHash.find(resource->getUniqueKey()));
     }
 
-    fUniqueHash.add(resource);
+    // If another resource has the new key, remove its key then install the key on this resource.
+    if (newKey.isValid()) {
+        if (GrGpuResource* old = fUniqueHash.find(newKey)) {
+            // If the old resource using the key is purgeable and is unreachable, then remove it.
+            if (!old->resourcePriv().getScratchKey().isValid() && old->isPurgeable()) {
+                // release may call validate() which will assert that resource is in fUniqueHash
+                // if it has a valid key. So in debug reset the key here before we assign it.
+                SkDEBUGCODE(resource->cacheAccess().removeUniqueKey();)
+                old->cacheAccess().release();
+            } else {
+                fUniqueHash.remove(newKey);
+                old->cacheAccess().removeUniqueKey();
+            }
+        }
+        SkASSERT(NULL == fUniqueHash.find(newKey));
+        resource->cacheAccess().setUniqueKey(newKey);
+        fUniqueHash.add(resource);
+    } else {
+        resource->cacheAccess().removeUniqueKey();
+    }
+
     this->validate();
-    return true;
 }
 
 void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {