Add explicit UniqueID classes for GrGpuResource & GrSurfaceProxy

This sets the stage for using the Proxy's/RenderTargetContext's ID above the flush and the RenderTarget's/GrGpuResource's below the flush.

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4650

Change-Id: I9f1e6b00c02a0691d90b58c49e1d8c60684884c1
Reviewed-on: https://skia-review.googlesource.com/4650
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/include/gpu/GrGpuResource.h b/include/gpu/GrGpuResource.h
index 5f5ccbf..4597464 100644
--- a/include/gpu/GrGpuResource.h
+++ b/include/gpu/GrGpuResource.h
@@ -175,12 +175,38 @@
         return fGpuMemorySize;
     }
 
+    class UniqueID {
+    public:
+        static UniqueID InvalidID() {
+            return UniqueID(uint32_t(SK_InvalidUniqueID));
+        }
+
+        UniqueID() {}
+
+        explicit UniqueID(uint32_t id) : fID(id) {}
+
+        uint32_t asUInt() const { return fID; }
+
+        bool operator==(const UniqueID& other) const {
+            return fID == other.fID;
+        }
+        bool operator!=(const UniqueID& other) const {
+            return !(*this == other);
+        }
+
+        void makeInvalid() { fID = SK_InvalidUniqueID; }
+        bool isInvalid() const { return SK_InvalidUniqueID == fID; }
+
+    protected:
+        uint32_t fID;
+    };
+
     /**
      * Gets an id that is unique for this GrGpuResource object. It is static in that it does
      * not change when the content of the GrGpuResource object changes. This will never return
      * 0.
      */
-    uint32_t uniqueID() const { return fUniqueID; }
+    UniqueID uniqueID() const { return fUniqueID; }
 
     /** Returns the current unique key for the resource. It will be invalid if the resource has no
         associated unique key. */
@@ -300,7 +326,7 @@
 
     SkBudgeted                  fBudgeted;
     bool                        fRefsWrappedObjects;
-    const uint32_t              fUniqueID;
+    const UniqueID              fUniqueID;
 
     typedef GrIORef<GrGpuResource> INHERITED;
     friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero.
diff --git a/include/private/GrAuditTrail.h b/include/private/GrAuditTrail.h
index b39f13f..6e8c92d 100644
--- a/include/private/GrAuditTrail.h
+++ b/include/private/GrAuditTrail.h
@@ -9,6 +9,7 @@
 #define GrAuditTrail_DEFINED
 
 #include "GrConfig.h"
+#include "GrGpuResource.h"
 #include "SkRect.h"
 #include "SkString.h"
 #include "SkTArray.h"
@@ -107,13 +108,14 @@
     // We could just return our internal bookkeeping struct if copying the data out becomes
     // a performance issue, but until then its nice to decouple
     struct BatchInfo {
-        SkRect fBounds;
-        uint32_t fRenderTargetUniqueID;
+        SkRect                  fBounds;
+        // TODO: switch over to GrSurfaceProxy::UniqueID
+        GrGpuResource::UniqueID fRenderTargetUniqueID;
         struct Batch {
             int fClientID;
             SkRect fBounds;
         };
-        SkTArray<Batch> fBatches;
+        SkTArray<Batch>                 fBatches;
     };
 
     void getBoundsByClientID(SkTArray<BatchInfo>* outInfo, int clientID);
@@ -139,10 +141,11 @@
     typedef SkTArray<Batch*> Batches;
 
     struct BatchNode {
+        BatchNode(const GrGpuResource::UniqueID& id) : fRenderTargetUniqueID(id) { }
         SkString toJson() const;
-        SkRect fBounds;
-        Batches fChildren;
-        uint32_t fRenderTargetUniqueID;
+        SkRect                         fBounds;
+        Batches                        fChildren;
+        const GrGpuResource::UniqueID  fRenderTargetUniqueID;
     };
     typedef SkTArray<std::unique_ptr<BatchNode>, true> BatchList;
 
diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h
index 1e846c5..dd5ece1 100644
--- a/include/private/GrSurfaceProxy.h
+++ b/include/private/GrSurfaceProxy.h
@@ -99,7 +99,44 @@
     int height() const { return fDesc.fHeight; }
     GrPixelConfig config() const { return fDesc.fConfig; }
 
-    uint32_t uniqueID() const { return fUniqueID; }
+    class UniqueID {
+    public:
+        // wrapped
+        explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
+        // deferred
+        UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
+
+        uint32_t asUInt() const { return fID; }
+
+        bool operator==(const UniqueID& other) const {
+            return fID == other.fID;
+        }
+        bool operator!=(const UniqueID& other) const {
+            return !(*this == other);
+        }
+
+        bool isInvalid() const { return SK_InvalidUniqueID == fID; }
+
+    private:
+        const uint32_t fID;
+    };
+
+    /*
+     * The contract for the uniqueID is:
+     *   for wrapped resources:
+     *      the uniqueID will match that of the wrapped resource
+     *
+     *   for deferred resources:
+     *      the uniqueID will be different from the real resource, when it is allocated
+     *      the proxy's uniqueID will not change across the instantiate call
+     *
+     *    the uniqueIDs of the proxies and the resources draw from the same pool
+     *
+     * What this boils down to is that the uniqueID of a proxy can be used to consistently
+     * track/identify a proxy but should never be used to distinguish between
+     * resources and proxies - beware!
+     */
+    UniqueID uniqueID() const { return fUniqueID; }
 
     GrSurface* instantiate(GrTextureProvider* texProvider);
 
@@ -151,9 +188,9 @@
         : fDesc(desc)
         , fFit(fit)
         , fBudgeted(budgeted)
-        , fUniqueID(GrGpuResource::CreateUniqueID())
         , fGpuMemorySize(kInvalidGpuMemorySize)
         , fLastOpList(nullptr) {
+        // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
     }
 
     // Wrapped version
@@ -162,10 +199,10 @@
     virtual ~GrSurfaceProxy();
 
     // For wrapped resources, 'fDesc' will always be filled in from the wrapped resource.
-    const GrSurfaceDesc fDesc;
-    const SkBackingFit  fFit;      // always exact for wrapped resources
-    const SkBudgeted    fBudgeted; // set from the backing resource for wrapped resources
-    const uint32_t      fUniqueID; // set from the backing resource for wrapped resources
+    const GrSurfaceDesc  fDesc;
+    const SkBackingFit   fFit;      // always exact for wrapped resources
+    const SkBudgeted     fBudgeted; // set from the backing resource for wrapped resources
+    const UniqueID       fUniqueID; // set from the backing resource for wrapped resources
 
     static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
     SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
diff --git a/src/gpu/GrAuditTrail.cpp b/src/gpu/GrAuditTrail.cpp
index ff6debd..93694cb 100644
--- a/src/gpu/GrAuditTrail.cpp
+++ b/src/gpu/GrAuditTrail.cpp
@@ -45,9 +45,8 @@
 
     // We use the batch pointer as a key to find the batchnode we are 'glomming' batches onto
     fIDLookup.set(batch->uniqueID(), auditBatch->fBatchListID);
-    BatchNode* batchNode = new BatchNode;
+    BatchNode* batchNode = new BatchNode(batch->renderTargetUniqueID());
     batchNode->fBounds = batch->bounds();
-    batchNode->fRenderTargetUniqueID = batch->renderTargetUniqueID();
     batchNode->fChildren.push_back(auditBatch);
     fBatchList.emplace_back(batchNode);
 }
@@ -290,7 +289,7 @@
 SkString GrAuditTrail::BatchNode::toJson() const {
     SkString json;
     json.append("{");
-    json.appendf("\"RenderTarget\": \"%u\",", fRenderTargetUniqueID);
+    json.appendf("\"RenderTarget\": \"%u\",", fRenderTargetUniqueID.asUInt());
     skrect_to_json(&json, "Bounds", fBounds);
     JsonifyTArray(&json, "Batches", fChildren, true);
     json.append("}");
diff --git a/src/gpu/GrGpuResource.cpp b/src/gpu/GrGpuResource.cpp
index c1578b5..c3a9556 100644
--- a/src/gpu/GrGpuResource.cpp
+++ b/src/gpu/GrGpuResource.cpp
@@ -70,7 +70,7 @@
 void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
     // Dump resource as "skia/gpu_resources/resource_#".
     SkString dumpName("skia/gpu_resources/resource_");
-    dumpName.appendS32(this->uniqueID());
+    dumpName.appendU32(this->uniqueID().asUInt());
 
     traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", this->gpuMemorySize());
 
diff --git a/src/gpu/GrOpList.cpp b/src/gpu/GrOpList.cpp
index baecbd6..d354e59 100644
--- a/src/gpu/GrOpList.cpp
+++ b/src/gpu/GrOpList.cpp
@@ -62,7 +62,7 @@
 #ifdef SK_DEBUG
 void GrOpList::dump() const {
     SkDebugf("--------------------------------------------------------------\n");
-    SkDebugf("node: %d -> RT: %d\n", fDebugID, fTarget ? fTarget->uniqueID() : -1);
+    SkDebugf("node: %d -> RT: %d\n", fDebugID, fTarget ? fTarget->uniqueID().asUInt() : -1);
     SkDebugf("relies On (%d): ", fDependencies.count());
     for (int i = 0; i < fDependencies.count(); ++i) {
         SkDebugf("%d, ", fDependencies[i]->fDebugID);
diff --git a/src/gpu/GrOpList.h b/src/gpu/GrOpList.h
index 0435568..9c965f8 100644
--- a/src/gpu/GrOpList.h
+++ b/src/gpu/GrOpList.h
@@ -23,6 +23,7 @@
     GrOpList(GrSurfaceProxy* surfaceProxy, GrAuditTrail* auditTrail);
     ~GrOpList() override;
 
+    // These two methods are invoked as flush time
     virtual void prepareBatches(GrBatchFlushState* flushState) = 0;
     virtual bool drawBatches(GrBatchFlushState* flushState) = 0;
 
diff --git a/src/gpu/GrRenderTargetContextPriv.h b/src/gpu/GrRenderTargetContextPriv.h
index 802cba0..8d682ac 100644
--- a/src/gpu/GrRenderTargetContextPriv.h
+++ b/src/gpu/GrRenderTargetContextPriv.h
@@ -82,6 +82,14 @@
 
     int maxWindowRectangles() const;
 
+    /*
+     * This unique ID will not change for a given RenderTargetContext. However, it is _NOT_
+     * guaranteed to match the uniqueID of the underlying GrRenderTarget - beware!
+     */
+    GrSurfaceProxy::UniqueID uniqueID() const {
+        return fRenderTargetContext->fRenderTargetProxy->uniqueID();
+    }
+
     void testingOnly_drawBatch(const GrPaint&,
                                GrDrawBatch* batch,
                                const GrUserStencilSettings* = nullptr,
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index b4e6870..72a29ab 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -178,6 +178,9 @@
     }
 }
 
+// TODO: this is where GrBatch::renderTarget is used (which is fine since it
+// is at flush time). However, we need to store the RenderTargetProxy in the
+// Batches and instantiate them here.
 bool GrRenderTargetOpList::drawBatches(GrBatchFlushState* flushState) {
     if (0 == fRecordedBatches.count()) {
         return false;
@@ -406,6 +409,7 @@
     // Currently this just inserts or updates the last clear batch. However, once in MDB this can
     // remove all the previously recorded batches and change the load op to clear with supplied
     // color.
+    // TODO: this needs to be updated to use GrSurfaceProxy::UniqueID
     if (fLastFullClearBatch &&
         fLastFullClearBatch->renderTargetUniqueID() == renderTarget->uniqueID()) {
         // As currently implemented, fLastFullClearBatch should be the last batch because we would
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index da552c9..831cd32 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -17,7 +17,7 @@
     , fDesc(fTarget->desc())
     , fFit(fit)
     , fBudgeted(fTarget->resourcePriv().isBudgeted())
-    , fUniqueID(fTarget->uniqueID())
+    , fUniqueID(fTarget->uniqueID()) // Note: converting from unique resource ID to a proxy ID!
     , fGpuMemorySize(kInvalidGpuMemorySize)
     , fLastOpList(nullptr) {
 }
diff --git a/src/gpu/batches/GrBatch.h b/src/gpu/batches/GrBatch.h
index bef01b7..ec81ec9 100644
--- a/src/gpu/batches/GrBatch.h
+++ b/src/gpu/batches/GrBatch.h
@@ -9,6 +9,7 @@
 #define GrBatch_DEFINED
 
 #include "../private/SkAtomics.h"
+#include "GrGpuResource.h"
 #include "GrNonAtomicRef.h"
 #include "SkMatrix.h"
 #include "SkRect.h"
@@ -129,7 +130,8 @@
 
     /** Used to block batching across render target changes. Remove this once we store
         GrBatches for different RTs in different targets. */
-    virtual uint32_t renderTargetUniqueID() const = 0;
+    // TODO: this needs to be updated to return GrSurfaceProxy::UniqueID
+    virtual GrGpuResource::UniqueID renderTargetUniqueID() const = 0;
 
     /** Used for spewing information about batches when debugging. */
     virtual SkString dumpInfo() const {
diff --git a/src/gpu/batches/GrClearBatch.h b/src/gpu/batches/GrClearBatch.h
index f11d485..ef38e74 100644
--- a/src/gpu/batches/GrClearBatch.h
+++ b/src/gpu/batches/GrClearBatch.h
@@ -29,7 +29,11 @@
 
     const char* name() const override { return "Clear"; }
 
-    uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->uniqueID(); }
+    // TODO: this needs to be updated to return GrSurfaceProxy::UniqueID
+    GrGpuResource::UniqueID renderTargetUniqueID() const override {
+        return fRenderTarget.get()->uniqueID();
+    }
+    // TODO: store a GrRenderTargetContext instead
     GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); }
 
     SkString dumpInfo() const override {
@@ -38,7 +42,8 @@
             const SkIRect& r = fClip.scissorRect();
             string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom);
         }
-        string.appendf("], Color: 0x%08x, RT: %d", fColor, fRenderTarget.get()->uniqueID());
+        string.appendf("], Color: 0x%08x, RT: %d", fColor,
+                                                   fRenderTarget.get()->uniqueID().asUInt());
         string.append(INHERITED::dumpInfo());
         return string;
     }
diff --git a/src/gpu/batches/GrClearStencilClipBatch.h b/src/gpu/batches/GrClearStencilClipBatch.h
index 42d7c44..f1e5b50 100644
--- a/src/gpu/batches/GrClearStencilClipBatch.h
+++ b/src/gpu/batches/GrClearStencilClipBatch.h
@@ -31,7 +31,10 @@
 
     const char* name() const override { return "ClearStencilClip"; }
 
-    uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->uniqueID(); }
+    // TODO: this needs to be updated to return GrSurfaceProxy::UniqueID
+    GrGpuResource::UniqueID renderTargetUniqueID() const override {
+        return fRenderTarget.get()->uniqueID();
+    }
     GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); }
 
     SkString dumpInfo() const override {
@@ -40,7 +43,8 @@
             const SkIRect& r = fClip.scissorRect();
             string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom);
         }
-        string.appendf("], IC: %d, RT: %d", fInsideStencilMask, fRenderTarget.get()->uniqueID());
+        string.appendf("], IC: %d, RT: %d", fInsideStencilMask,
+                                            fRenderTarget.get()->uniqueID().asUInt());
         string.append(INHERITED::dumpInfo());
         return string;
     }
diff --git a/src/gpu/batches/GrCopySurfaceBatch.h b/src/gpu/batches/GrCopySurfaceBatch.h
index c987d0d..a014ccb 100644
--- a/src/gpu/batches/GrCopySurfaceBatch.h
+++ b/src/gpu/batches/GrCopySurfaceBatch.h
@@ -32,10 +32,14 @@
 
     const char* name() const override { return "CopySurface"; }
 
-    uint32_t renderTargetUniqueID() const override {
+    // TODO: this needs to be updated to return GrSurfaceProxy::UniqueID
+    GrGpuResource::UniqueID renderTargetUniqueID() const override {
+        // TODO: When we have CopyContexts it seems that this should return the ID
+        // of the SurfaceProxy underlying the CopyContext.
         GrRenderTarget* rt = fDst.get()->asRenderTarget();
-        return rt ? rt->uniqueID() : 0;
+        return rt ? rt->uniqueID() : GrGpuResource::UniqueID::InvalidID();
     }
+    // TODO: this seems odd - figure it out and add a comment!
     GrRenderTarget* renderTarget() const override { return nullptr; }
 
     SkString dumpInfo() const override {
diff --git a/src/gpu/batches/GrDiscardBatch.h b/src/gpu/batches/GrDiscardBatch.h
index 8a3be0e..54f41b9 100644
--- a/src/gpu/batches/GrDiscardBatch.h
+++ b/src/gpu/batches/GrDiscardBatch.h
@@ -26,12 +26,15 @@
 
     const char* name() const override { return "Discard"; }
 
-    uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->uniqueID(); }
+    // TODO: this needs to be updated to return GrSurfaceProxy::UniqueID
+    GrGpuResource::UniqueID renderTargetUniqueID() const override {
+        return fRenderTarget.get()->uniqueID();
+    }
     GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); }
 
     SkString dumpInfo() const override {
         SkString string;
-        string.printf("RT: %d", fRenderTarget.get()->uniqueID());
+        string.printf("RT: %d", fRenderTarget.get()->uniqueID().asUInt());
         string.append(INHERITED::dumpInfo());
         return string;
     }
diff --git a/src/gpu/batches/GrDrawBatch.h b/src/gpu/batches/GrDrawBatch.h
index e675f5f..a5c153e 100644
--- a/src/gpu/batches/GrDrawBatch.h
+++ b/src/gpu/batches/GrDrawBatch.h
@@ -74,11 +74,14 @@
     // TODO no GrPrimitiveProcessors yet read fragment position
     bool willReadFragmentPosition() const { return false; }
 
-    uint32_t renderTargetUniqueID() const final {
+    // TODO: this needs to be updated to return GrSurfaceProxy::UniqueID
+    // This is a bit more exciting than the other call sites since it uses the pipeline
+    GrGpuResource::UniqueID renderTargetUniqueID() const final {
         SkASSERT(fPipelineInstalled);
         return this->pipeline()->getRenderTarget()->uniqueID();
     }
 
+    // TODO: store a GrRenderTargetContext instead
     GrRenderTarget* renderTarget() const final {
         SkASSERT(fPipelineInstalled);
         return this->pipeline()->getRenderTarget();
@@ -86,7 +89,7 @@
 
     SkString dumpInfo() const override {
         SkString string;
-        string.appendf("RT: %d\n", this->renderTargetUniqueID());
+        string.appendf("RT: %d\n", this->renderTargetUniqueID().asUInt());
         string.append("ColorStages:\n");
         for (int i = 0; i < this->pipeline()->numColorFragmentProcessors(); i++) {
             string.appendf("\t\t%s\n\t\t%s\n",
diff --git a/src/gpu/batches/GrStencilPathBatch.h b/src/gpu/batches/GrStencilPathBatch.h
index 73bec19..3a6f82d 100644
--- a/src/gpu/batches/GrStencilPathBatch.h
+++ b/src/gpu/batches/GrStencilPathBatch.h
@@ -33,7 +33,10 @@
 
     const char* name() const override { return "StencilPath"; }
 
-    uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->uniqueID(); }
+    // TODO: this needs to be updated to return GrSurfaceProxy::UniqueID
+    GrGpuResource::UniqueID renderTargetUniqueID() const override {
+        return fRenderTarget.get()->uniqueID();
+    }
     GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); }
 
     SkString dumpInfo() const override {
diff --git a/src/gpu/effects/GrSingleTextureEffect.h b/src/gpu/effects/GrSingleTextureEffect.h
index 7d110bf..12b3a8f 100644
--- a/src/gpu/effects/GrSingleTextureEffect.h
+++ b/src/gpu/effects/GrSingleTextureEffect.h
@@ -26,7 +26,7 @@
 
     SkString dumpInfo() const override {
         SkString str;
-        str.appendf("Texture: %d", fTextureAccess.getTexture()->uniqueID());
+        str.appendf("Texture: %d", fTextureAccess.getTexture()->uniqueID().asUInt());
         return str;
     }
 
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 9ccd073..0e777e9 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -551,7 +551,7 @@
 
     if (resetBits & kTextureBinding_GrGLBackendState) {
         for (int s = 0; s < fHWBoundTextureUniqueIDs.count(); ++s) {
-            fHWBoundTextureUniqueIDs[s] = SK_InvalidUniqueID;
+            fHWBoundTextureUniqueIDs[s].makeInvalid();
         }
         for (int b = 0; b < fHWBufferTextures.count(); ++b) {
             SkASSERT(this->caps()->shaderCaps()->texelBufferSupport());
@@ -582,7 +582,7 @@
     }
 
     if (resetBits & kRenderTarget_GrGLBackendState) {
-        fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+        fHWBoundRenderTargetUniqueID.makeInvalid();
         fHWSRGBFramebuffer = kUnknown_TriState;
     }
 
@@ -1511,7 +1511,7 @@
     }
 
     // below here we may bind the FBO
-    fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+    fHWBoundRenderTargetUniqueID.makeInvalid();
     if (idDesc->fRTFBOID != idDesc->fTexFBOID) {
         SkASSERT(desc.fSampleCnt > 0);
         GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID));
@@ -1783,7 +1783,7 @@
         GrGLuint fb = 0;
         GL_CALL(GenFramebuffers(1, &fb));
         GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb));
-        fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+        fHWBoundRenderTargetUniqueID.makeInvalid();
         GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
                                      GR_GL_COLOR_ATTACHMENT0,
                                      GR_GL_TEXTURE_2D,
@@ -2151,7 +2151,7 @@
 void GrGLGpu::notifyBufferReleased(const GrGLBuffer* buffer) {
     if (buffer->hasAttachedToTexture()) {
         // Detach this buffer from any textures to ensure the underlying memory is freed.
-        uint32_t uniqueID = buffer->uniqueID();
+        GrGpuResource::UniqueID uniqueID = buffer->uniqueID();
         for (int i = fHWMaxUsedBufferTextureUnit; i >= 0; --i) {
             auto& buffTex = fHWBufferTextures[i];
             if (uniqueID != buffTex.fAttachedBufferUniqueID) {
@@ -2324,7 +2324,7 @@
             }
             GrGLIRect vp;
             this->bindSurfaceFBOForPixelOps(temp.get(), GR_GL_FRAMEBUFFER, &vp, kDst_TempFBOTarget);
-            fHWBoundRenderTargetUniqueID = 0;
+            fHWBoundRenderTargetUniqueID.makeInvalid();
             return true;
         }
         return false;
@@ -2543,7 +2543,7 @@
     } else {
         // Use a temporary FBO.
         this->bindSurfaceFBOForPixelOps(surface, GR_GL_FRAMEBUFFER, &glvp, kSrc_TempFBOTarget);
-        fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+        fHWBoundRenderTargetUniqueID.makeInvalid();
     }
 
     // the read rect is viewport-relative
@@ -2661,7 +2661,7 @@
 void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bounds, bool disableSRGB) {
     SkASSERT(target);
 
-    uint32_t rtID = target->uniqueID();
+    GrGpuResource::UniqueID rtID = target->uniqueID();
     if (fHWBoundRenderTargetUniqueID != rtID) {
         fStats.incRenderTargetBinds();
         GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, target->renderFBOID()));
@@ -2902,7 +2902,7 @@
             GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->textureFBOID()));
             // make sure we go through flushRenderTarget() since we've modified
             // the bound DRAW FBO ID.
-            fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+            fHWBoundRenderTargetUniqueID.makeInvalid();
             const GrGLIRect& vp = rt->getViewport();
             const SkIRect dirtyRect = rt->getResolveRect();
 
@@ -3198,7 +3198,7 @@
         this->onResolveRenderTarget(texRT);
     }
 
-    uint32_t textureID = texture->uniqueID();
+    GrGpuResource::UniqueID textureID = texture->uniqueID();
     GrGLenum target = texture->target();
     if (fHWBoundTextureUniqueIDs[unitIdx] != textureID) {
         this->setTextureUnit(unitIdx);
@@ -3474,7 +3474,7 @@
     }
     // clear out the this field so that if a program does use this unit it will rebind the correct
     // texture.
-    fHWBoundTextureUniqueIDs[lastUnitIdx] = SK_InvalidUniqueID;
+    fHWBoundTextureUniqueIDs[lastUnitIdx].makeInvalid();
 }
 
 // Determines whether glBlitFramebuffer could be used between src and dst by onCopySurface.
@@ -4188,7 +4188,7 @@
     GrGLIRect dstVP;
     this->bindSurfaceFBOForPixelOps(dst, GR_GL_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget);
     this->flushViewport(dstVP);
-    fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+    fHWBoundRenderTargetUniqueID.makeInvalid();
 
     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
 
@@ -4265,7 +4265,7 @@
     GrGLTexture* dstTex = static_cast<GrGLTexture *>(dst->asTexture());
     SkASSERT(dstTex);
     // We modified the bound FBO
-    fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+    fHWBoundRenderTargetUniqueID.makeInvalid();
     GrGLIRect srcGLRect;
     srcGLRect.setRelativeTo(srcVP,
                             srcRect.fLeft,
@@ -4310,7 +4310,7 @@
     this->bindSurfaceFBOForPixelOps(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget);
     this->bindSurfaceFBOForPixelOps(src, GR_GL_READ_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget);
     // We modified the bound FBO
-    fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+    fHWBoundRenderTargetUniqueID.makeInvalid();
     GrGLIRect srcGLRect;
     GrGLIRect dstGLRect;
     srcGLRect.setRelativeTo(srcVP,
@@ -4414,7 +4414,7 @@
         GL_CALL(GenFramebuffers(1, &fTempDstFBOID));
     }
     GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fTempDstFBOID));
-    fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+    fHWBoundRenderTargetUniqueID.makeInvalid();
 
     // Bind the texture, to get things configured for filtering.
     // We'll be changing our base level further below:
@@ -4570,7 +4570,7 @@
     GL_CALL(ActiveTexture(GR_GL_TEXTURE0));
     GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
     GL_CALL(BindTexture(info->fTarget, info->fID));
-    fHWBoundTextureUniqueIDs[0] = 0;
+    fHWBoundTextureUniqueIDs[0].makeInvalid();
     GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST));
     GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST));
     GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE));
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 32ce979..d0ca40b 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -125,7 +125,7 @@
             const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) override;
 
     void invalidateBoundRenderTarget() {
-        fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+        fHWBoundRenderTargetUniqueID.makeInvalid();
     }
 
     GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
@@ -517,28 +517,28 @@
         GrGLAttribArrayState* bindInternalVertexArray(GrGLGpu*, const GrBuffer* ibuff = nullptr);
 
     private:
-        GrGLuint                fBoundVertexArrayID;
-        bool                    fBoundVertexArrayIDIsValid;
+        GrGLuint             fBoundVertexArrayID;
+        bool                 fBoundVertexArrayIDIsValid;
 
         // We return a non-const pointer to this from bindArrayAndBuffersToDraw when vertex array 0
         // is bound. However, this class is internal to GrGLGpu and this object never leaks out of
         // GrGLGpu.
-        GrGLAttribArrayState    fDefaultVertexArrayAttribState;
+        GrGLAttribArrayState fDefaultVertexArrayAttribState;
 
         // This is used when we're using a core profile.
-        GrGLVertexArray*        fCoreProfileVertexArray;
-    } fHWVertexArrayState;
+        GrGLVertexArray*     fCoreProfileVertexArray;
+    }                                       fHWVertexArrayState;
 
     struct {
-        GrGLenum   fGLTarget;
-        uint32_t   fBoundBufferUniqueID;
-        bool       fBufferZeroKnownBound;
+        GrGLenum                fGLTarget;
+        GrGpuResource::UniqueID fBoundBufferUniqueID;
+        bool                    fBufferZeroKnownBound;
 
         void invalidate() {
-            fBoundBufferUniqueID = SK_InvalidUniqueID;
+            fBoundBufferUniqueID.makeInvalid();
             fBufferZeroKnownBound = false;
         }
-    } fHWBufferState[kGrBufferTypeCount];
+    }                                       fHWBufferState[kGrBufferTypeCount];
 
     struct {
         GrBlendEquation fEquation;
@@ -555,38 +555,38 @@
             fConstColorValid = false;
             fEnabled = kUnknown_TriState;
         }
-    } fHWBlendState;
+    }                                       fHWBlendState;
 
     TriState fMSAAEnabled;
 
-    GrStencilSettings           fHWStencilSettings;
-    TriState                    fHWStencilTestEnabled;
+    GrStencilSettings                       fHWStencilSettings;
+    TriState                                fHWStencilTestEnabled;
 
 
-    GrDrawFace                  fHWDrawFace;
-    TriState                    fHWWriteToColor;
-    uint32_t                    fHWBoundRenderTargetUniqueID;
-    TriState                    fHWSRGBFramebuffer;
-    SkTArray<uint32_t, true>    fHWBoundTextureUniqueIDs;
+    GrDrawFace                              fHWDrawFace;
+    TriState                                fHWWriteToColor;
+    GrGpuResource::UniqueID                 fHWBoundRenderTargetUniqueID;
+    TriState                                fHWSRGBFramebuffer;
+    SkTArray<GrGpuResource::UniqueID, true> fHWBoundTextureUniqueIDs;
 
     struct BufferTexture {
         BufferTexture() : fTextureID(0), fKnownBound(false),
                           fAttachedBufferUniqueID(SK_InvalidUniqueID),
                           fSwizzle(GrSwizzle::RGBA()) {}
 
-        GrGLuint        fTextureID;
-        bool            fKnownBound;
-        GrPixelConfig   fTexelConfig;
-        uint32_t        fAttachedBufferUniqueID;
-        GrSwizzle       fSwizzle;
+        GrGLuint                fTextureID;
+        bool                    fKnownBound;
+        GrPixelConfig           fTexelConfig;
+        GrGpuResource::UniqueID fAttachedBufferUniqueID;
+        GrSwizzle               fSwizzle;
     };
 
-    SkTArray<BufferTexture, true>   fHWBufferTextures;
-    int                             fHWMaxUsedBufferTextureUnit;
+    SkTArray<BufferTexture, true>           fHWBufferTextures;
+    int                                     fHWMaxUsedBufferTextureUnit;
 
     // EXT_raster_multisample.
-    TriState                    fHWRasterMultisampleEnabled;
-    int                         fHWNumRasterSamples;
+    TriState                                fHWRasterMultisampleEnabled;
+    int                                     fHWNumRasterSamples;
     ///@}
 
     /** IDs for copy surface program. */
@@ -595,23 +595,23 @@
         GrGLint     fTextureUniform;
         GrGLint     fTexCoordXformUniform;
         GrGLint     fPosXformUniform;
-    }                           fCopyPrograms[3];
-    sk_sp<GrGLBuffer>           fCopyProgramArrayBuffer;
+    }                                       fCopyPrograms[3];
+    sk_sp<GrGLBuffer>                       fCopyProgramArrayBuffer;
 
     /** IDs for texture mipmap program. (4 filter configurations) */
     struct {
         GrGLuint    fProgram;
         GrGLint     fTextureUniform;
         GrGLint     fTexCoordXformUniform;
-    }                           fMipmapPrograms[4];
-    sk_sp<GrGLBuffer>           fMipmapProgramArrayBuffer;
+    }                                       fMipmapPrograms[4];
+    sk_sp<GrGLBuffer>                       fMipmapProgramArrayBuffer;
 
     struct {
-        GrGLuint fProgram;
-        GrGLint  fColorUniform;
-        GrGLint  fRectUniform;
-    }                           fWireRectProgram;
-    sk_sp<GrGLBuffer>           fWireRectArrayBuffer;
+        GrGLuint    fProgram;
+        GrGLint     fColorUniform;
+        GrGLint     fRectUniform;
+    }                                       fWireRectProgram;
+    sk_sp<GrGLBuffer>                       fWireRectArrayBuffer;
 
     static int TextureTargetToCopyProgramIdx(GrGLenum target) {
         switch (target) {
@@ -634,15 +634,15 @@
     }
 
     struct {
-        GrGLuint                    fProgram;
-        GrGLint                     fPosXformUniform;
-        sk_sp<GrGLBuffer>           fArrayBuffer;
-    } fPLSSetupProgram;
+        GrGLuint          fProgram;
+        GrGLint           fPosXformUniform;
+        sk_sp<GrGLBuffer> fArrayBuffer;
+    }                                       fPLSSetupProgram;
 
-    bool fHWPLSEnabled;
-    bool fPLSHasBeenUsed;
+    bool                                    fHWPLSEnabled;
+    bool                                    fPLSHasBeenUsed;
 
-    float fHWMinSampleShading;
+    float                                   fHWMinSampleShading;
 
     typedef GrGpu INHERITED;
     friend class GrGLPathRendering; // For accessing setTextureUnit.
diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp
index 5af5e67..45efba2 100644
--- a/src/gpu/gl/GrGLRenderTarget.cpp
+++ b/src/gpu/gl/GrGLRenderTarget.cpp
@@ -188,7 +188,7 @@
         // Due to this resource having both a texture and a renderbuffer component, dump as
         // skia/gpu_resources/resource_#/renderbuffer
         SkString dumpName("skia/gpu_resources/resource_");
-        dumpName.appendS32(this->uniqueID());
+        dumpName.appendU32(this->uniqueID().asUInt());
         dumpName.append("/renderbuffer");
 
         traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", size);
diff --git a/src/gpu/gl/GrGLTextureRenderTarget.cpp b/src/gpu/gl/GrGLTextureRenderTarget.cpp
index 9c350f8..0abeb8e 100644
--- a/src/gpu/gl/GrGLTextureRenderTarget.cpp
+++ b/src/gpu/gl/GrGLTextureRenderTarget.cpp
@@ -18,7 +18,7 @@
   // texture and a
   // renderbuffer component, dump as skia/gpu_resources/resource_#/texture
   SkString dumpName("skia/gpu_resources/resource_");
-  dumpName.appendS32(this->uniqueID());
+  dumpName.appendU32(this->uniqueID().asUInt());
   dumpName.append("/texture");
 
   // Use the texture's gpuMemorySize, not our own, which includes the
diff --git a/src/gpu/gl/GrGLVertexArray.cpp b/src/gpu/gl/GrGLVertexArray.cpp
index 04299d7..e03101a 100644
--- a/src/gpu/gl/GrGLVertexArray.cpp
+++ b/src/gpu/gl/GrGLVertexArray.cpp
@@ -129,5 +129,5 @@
 
 void GrGLVertexArray::invalidateCachedState() {
     fAttribArrays.invalidate();
-    fIndexBufferUniqueID = SK_InvalidUniqueID;
+    fIndexBufferUniqueID.makeInvalid();
 }
diff --git a/src/gpu/gl/GrGLVertexArray.h b/src/gpu/gl/GrGLVertexArray.h
index 6398926..4c77d2b 100644
--- a/src/gpu/gl/GrGLVertexArray.h
+++ b/src/gpu/gl/GrGLVertexArray.h
@@ -8,6 +8,7 @@
 #ifndef GrGLVertexArray_DEFINED
 #define GrGLVertexArray_DEFINED
 
+#include "GrGpuResource.h"
 #include "GrTypesPriv.h"
 #include "gl/GrGLDefines.h"
 #include "gl/GrGLTypes.h"
@@ -68,17 +69,17 @@
      * Tracks the state of glVertexAttribArray for an attribute index.
      */
     struct AttribArrayState {
-            void invalidate() {
-                fEnableIsValid = false;
-                fVertexBufferUniqueID = SK_InvalidUniqueID;
-            }
+        void invalidate() {
+            fEnableIsValid = false;
+            fVertexBufferUniqueID.makeInvalid();
+        }
 
-            bool                  fEnableIsValid;
-            bool                  fEnabled;
-            uint32_t              fVertexBufferUniqueID;
-            GrVertexAttribType    fType;
-            GrGLsizei             fStride;
-            GrGLvoid*             fOffset;
+        bool                            fEnableIsValid;
+        bool                            fEnabled;
+        GrGpuResource::UniqueID         fVertexBufferUniqueID;
+        GrVertexAttribType              fType;
+        GrGLsizei                       fStride;
+        GrGLvoid*                       fOffset;
     };
 
     SkSTArray<16, AttribArrayState, true> fAttribArrayStates;
@@ -110,9 +111,9 @@
     void invalidateCachedState();
 
 private:
-    GrGLuint                fID;
-    GrGLAttribArrayState    fAttribArrays;
-    uint32_t                fIndexBufferUniqueID;
+    GrGLuint                  fID;
+    GrGLAttribArrayState      fAttribArrays;
+    GrGpuResource::UniqueID   fIndexBufferUniqueID;
 };
 
 #endif
diff --git a/src/gpu/instanced/GLInstancedRendering.cpp b/src/gpu/instanced/GLInstancedRendering.cpp
index dabfe4e..7503204 100644
--- a/src/gpu/instanced/GLInstancedRendering.cpp
+++ b/src/gpu/instanced/GLInstancedRendering.cpp
@@ -104,7 +104,7 @@
         GL_CALL(VertexAttribIPointer((int)Attrib::kVertexAttrs, 1, GR_GL_INT, sizeof(ShapeVertex),
                                      (void*) offsetof(ShapeVertex, fAttrs)));
 
-        SkASSERT(SK_InvalidUniqueID == fInstanceAttribsBufferUniqueId);
+        SkASSERT(fInstanceAttribsBufferUniqueId.isInvalid());
     }
 
     // Create and map instance and draw-indirect buffers.
@@ -318,7 +318,7 @@
     fVertexArrayID = 0;
     fInstanceBuffer.reset();
     fDrawIndirectBuffer.reset();
-    fInstanceAttribsBufferUniqueId = SK_InvalidUniqueID;
+    fInstanceAttribsBufferUniqueId.makeInvalid();
 }
 
 }
diff --git a/src/gpu/instanced/GLInstancedRendering.h b/src/gpu/instanced/GLInstancedRendering.h
index 9ac2bfe..c9f0d8f 100644
--- a/src/gpu/instanced/GLInstancedRendering.h
+++ b/src/gpu/instanced/GLInstancedRendering.h
@@ -51,7 +51,7 @@
     sk_sp<GrBuffer>                       fInstanceBuffer;
     sk_sp<GrBuffer>                       fDrawIndirectBuffer;
     SkAutoSTMalloc<1024, GLDrawCmdInfo>   fGLDrawCmdsInfo;
-    uint32_t                              fInstanceAttribsBufferUniqueId;
+    GrGpuResource::UniqueID               fInstanceAttribsBufferUniqueId;
     int                                   fInstanceAttribsBaseInstance;
 
     class GLBatch;
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.h b/src/gpu/text/GrStencilAndCoverTextContext.h
index 3cf4374..f4773ff 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.h
+++ b/src/gpu/text/GrStencilAndCoverTextContext.h
@@ -97,18 +97,18 @@
         GrPathRange* createGlyphs(GrContext*) const;
         void appendGlyph(const SkGlyph&, const SkPoint&, FallbackBlobBuilder*);
 
-        GrStyle                    fStyle;
-        SkPaint                    fFont;
-        SkScalar                   fTextRatio;
-        float                      fTextInverseRatio;
-        bool                       fUsingRawGlyphPaths;
-        GrUniqueKey                fGlyphPathsKey;
-        int                        fTotalGlyphCount;
-        sk_sp<InstanceData>        fInstanceData;
-        int                        fFallbackGlyphCount;
-        sk_sp<SkTextBlob>          fFallbackTextBlob;
-        mutable SkGlyphCache*      fDetachedGlyphCache;
-        mutable uint32_t           fLastDrawnGlyphsID;
+        GrStyle                         fStyle;
+        SkPaint                         fFont;
+        SkScalar                        fTextRatio;
+        float                           fTextInverseRatio;
+        bool                            fUsingRawGlyphPaths;
+        GrUniqueKey                     fGlyphPathsKey;
+        int                             fTotalGlyphCount;
+        sk_sp<InstanceData>             fInstanceData;
+        int                             fFallbackGlyphCount;
+        sk_sp<SkTextBlob>               fFallbackTextBlob;
+        mutable SkGlyphCache*           fDetachedGlyphCache;
+        mutable GrGpuResource::UniqueID fLastDrawnGlyphsID;
     };
 
     // Text blobs/caches.
diff --git a/tests/ClearTest.cpp b/tests/ClearTest.cpp
index d83fb92..d43e65f 100644
--- a/tests/ClearTest.cpp
+++ b/tests/ClearTest.cpp
@@ -37,8 +37,15 @@
     return true;
 }
 
+// TODO: this test does this thorough purging of the rendertargets b.c. right now
+// the clear optimizations rely on the rendertarget's uniqueID. It can be
+// relaxed when we switch that over to using rendertargetcontext ids (although
+// we probably will want to have more clear values then too)
 static bool reset_rtc(sk_sp<GrRenderTargetContext>* rtc, GrContext* context, int w, int h) {
-    SkDEBUGCODE(uint32_t oldID = 0;)
+#ifdef SK_DEBUG
+    GrGpuResource::UniqueID oldID = GrGpuResource::UniqueID::InvalidID();
+#endif
+
     if (*rtc) {
         SkDEBUGCODE(oldID = (*rtc)->accessRenderTarget()->uniqueID();)
         rtc->reset(nullptr);
diff --git a/tests/ProxyTest.cpp b/tests/ProxyTest.cpp
index 618941e..8d59cae 100644
--- a/tests/ProxyTest.cpp
+++ b/tests/ProxyTest.cpp
@@ -21,14 +21,16 @@
                           GrSurfaceOrigin origin,
                           int width, int height, 
                           GrPixelConfig config,
-                          uint32_t uniqueID,
+                          const GrGpuResource::UniqueID& uniqueID,
                           SkBudgeted budgeted) {
     REPORTER_ASSERT(reporter, proxy->origin() == origin);
     REPORTER_ASSERT(reporter, proxy->width() == width);
     REPORTER_ASSERT(reporter, proxy->height() == height);
     REPORTER_ASSERT(reporter, proxy->config() == config);
-    if (SK_InvalidUniqueID != uniqueID) {
-        REPORTER_ASSERT(reporter, proxy->uniqueID() == uniqueID);    
+    if (!uniqueID.isInvalid()) {
+        REPORTER_ASSERT(reporter, proxy->uniqueID().asUInt() == uniqueID.asUInt());
+    } else {
+        REPORTER_ASSERT(reporter, !proxy->uniqueID().isInvalid());
     }
     REPORTER_ASSERT(reporter, proxy->isBudgeted() == budgeted);
 }
@@ -39,20 +41,31 @@
                                GrRenderTargetProxy* rtProxy,
                                int numSamples,
                                SkBackingFit fit,
-                               int expectedMaxWindowRects) {
+                               int expectedMaxWindowRects,
+                               bool wasWrapped) {
     REPORTER_ASSERT(reporter, rtProxy->maxWindowRectangles(caps) == expectedMaxWindowRects);
     REPORTER_ASSERT(reporter, rtProxy->numStencilSamples() == numSamples);
 
+    GrSurfaceProxy::UniqueID idBefore = rtProxy->uniqueID();
     GrRenderTarget* rt = rtProxy->instantiate(provider);
     REPORTER_ASSERT(reporter, rt);
 
+    REPORTER_ASSERT(reporter, rtProxy->uniqueID() == idBefore);
+    if (wasWrapped) {
+        // Wrapped resources share their uniqueID with the wrapping RenderTargetProxy
+        REPORTER_ASSERT(reporter, rtProxy->uniqueID().asUInt() == rt->uniqueID().asUInt());
+    } else {
+        // Deferred resources should always have a different ID from their instantiated rendertarget
+        REPORTER_ASSERT(reporter, rtProxy->uniqueID().asUInt() != rt->uniqueID().asUInt());
+    }
+
     REPORTER_ASSERT(reporter, rt->origin() == rtProxy->origin());
     if (SkBackingFit::kExact == fit) {
         REPORTER_ASSERT(reporter, rt->width() == rtProxy->width());
         REPORTER_ASSERT(reporter, rt->height() == rtProxy->height());
     } else {
         REPORTER_ASSERT(reporter, rt->width() >= rtProxy->width());
-        REPORTER_ASSERT(reporter, rt->height() >= rtProxy->height());    
+        REPORTER_ASSERT(reporter, rt->height() >= rtProxy->height());
     }
     REPORTER_ASSERT(reporter, rt->config() == rtProxy->config());
 
@@ -68,10 +81,21 @@
 static void check_texture(skiatest::Reporter* reporter,
                           GrTextureProvider* provider,
                           GrTextureProxy* texProxy,
-                          SkBackingFit fit) {
+                          SkBackingFit fit,
+                          bool wasWrapped) {
+    GrSurfaceProxy::UniqueID idBefore = texProxy->uniqueID();
     GrTexture* tex = texProxy->instantiate(provider);
     REPORTER_ASSERT(reporter, tex);
 
+    REPORTER_ASSERT(reporter, texProxy->uniqueID() == idBefore);
+    if (wasWrapped) {
+        // Wrapped resources share their uniqueID with the wrapping TextureProxy
+        REPORTER_ASSERT(reporter, texProxy->uniqueID().asUInt() == tex->uniqueID().asUInt());
+    } else {
+        // Deferred resources should always have a different ID from their instantiated texture
+        REPORTER_ASSERT(reporter, texProxy->uniqueID().asUInt() != tex->uniqueID().asUInt());
+    }
+
     REPORTER_ASSERT(reporter, tex->origin() == texProxy->origin());
     if (SkBackingFit::kExact == fit) {
         REPORTER_ASSERT(reporter, tex->width() == texProxy->width());
@@ -88,6 +112,8 @@
     GrTextureProvider* provider = ctxInfo.grContext()->textureProvider();
     const GrCaps& caps = *ctxInfo.grContext()->caps();
 
+    const GrGpuResource::UniqueID kInvalidResourceID = GrGpuResource::UniqueID::InvalidID();
+
     for (auto origin : { kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin }) {
         for (auto widthHeight : { 100, 128 }) {
             for (auto config : { kAlpha_8_GrPixelConfig, kRGBA_8888_GrPixelConfig }) {
@@ -112,10 +138,10 @@
                                                                                 fit, budgeted));
                                 check_surface(reporter, sProxy.get(), origin,
                                               widthHeight, widthHeight, config,
-                                              SK_InvalidUniqueID, budgeted);
+                                              kInvalidResourceID, budgeted);
                                 check_rendertarget(reporter, caps, provider,
-                                                   sProxy->asRenderTargetProxy(), 
-                                                   numSamples, fit, caps.maxWindowRectangles());
+                                                   sProxy->asRenderTargetProxy(), numSamples,
+                                                   fit, caps.maxWindowRectangles(), false);
                             }
 
                             desc.fFlags = kNone_GrSurfaceFlags;
@@ -127,8 +153,8 @@
                                                                                       budgeted));
                             check_surface(reporter, sProxy.get(), origin,
                                           widthHeight, widthHeight, config,
-                                          SK_InvalidUniqueID, budgeted);
-                            check_texture(reporter, provider, sProxy->asTextureProxy(), fit);
+                                          kInvalidResourceID, budgeted);
+                            check_texture(reporter, provider, sProxy->asTextureProxy(), fit, false);
                         }
                     }
                 }
@@ -175,7 +201,7 @@
                                       kWidthHeight, kWidthHeight, config,
                                       defaultFBO->uniqueID(), SkBudgeted::kNo);
                         check_rendertarget(reporter, caps, provider, sProxy->asRenderTargetProxy(),
-                                           numSamples, SkBackingFit::kExact, 0);
+                                           numSamples, SkBackingFit::kExact, 0, true);
                     }
 
                     sk_sp<GrTexture> tex;
@@ -192,7 +218,7 @@
                                       rt->uniqueID(), budgeted);
                         check_rendertarget(reporter, caps, provider, sProxy->asRenderTargetProxy(),
                                            numSamples, SkBackingFit::kExact,
-                                           caps.maxWindowRectangles());
+                                           caps.maxWindowRectangles(), true);
                     }
 
                     if (!tex) {
@@ -205,7 +231,7 @@
                     check_surface(reporter, sProxy.get(), origin,
                                   kWidthHeight, kWidthHeight, config, tex->uniqueID(), budgeted);
                     check_texture(reporter, provider, sProxy->asTextureProxy(),
-                                  SkBackingFit::kExact);
+                                  SkBackingFit::kExact, true);
                 }
             }
         }
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index b755a7e..2ac8d29 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -310,7 +310,7 @@
                 ERRORF(reporter, "Not texture backed.");
                 return static_cast<intptr_t>(0);
             }
-            return static_cast<intptr_t>(texture->uniqueID());
+            return static_cast<intptr_t>(texture->uniqueID().asUInt());
         };
 
         auto surfaceBackingStore = [reporter](SkSurface* surface) {
@@ -321,7 +321,7 @@
                 ERRORF(reporter, "Not render target backed.");
                 return static_cast<intptr_t>(0);
             }
-            return static_cast<intptr_t>(rt->uniqueID());
+            return static_cast<intptr_t>(rt->uniqueID().asUInt());
         };
 
         test_unique_image_snap(reporter, surface.get(), false, imageBackingStore,
diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp
index bc699fc..eaf72c3 100644
--- a/tools/debugger/SkDebugCanvas.cpp
+++ b/tools/debugger/SkDebugCanvas.cpp
@@ -349,7 +349,8 @@
         // get the render target of the top device so we can ignore batches drawn offscreen
         SkBaseDevice* bd = canvas->getDevice_just_for_deprecated_compatibility_testing();
         SkGpuDevice* gbd = reinterpret_cast<SkGpuDevice*>(bd);
-        uint32_t rtID = gbd->accessRenderTargetContext()->accessRenderTarget()->uniqueID();
+        GrGpuResource::UniqueID rtID = 
+                            gbd->accessRenderTargetContext()->accessRenderTarget()->uniqueID();
 
         // get the bounding boxes to draw
         SkTArray<GrAuditTrail::BatchInfo> childrenBounds;