Recycle stencil buffers across render targets.

Review URL: https://codereview.chromium.org/939093002
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index eef965e..27fed3c 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -66,7 +66,7 @@
             !(kNoStencil_GrSurfaceFlag & desc.fFlags)) {
             SkASSERT(tex->asRenderTarget());
             // TODO: defer this and attach dynamically
-            if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget(), budgeted)) {
+            if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) {
                 tex->unref();
                 return NULL;
             }
@@ -84,12 +84,13 @@
     return tex;
 }
 
-bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt, bool budgeted) {
+bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
     SkASSERT(NULL == rt->getStencilBuffer());
-    GrScratchKey sbKey;
-    GrStencilBuffer::ComputeKey(rt->width(), rt->height(), rt->numSamples(), &sbKey);
+    GrUniqueKey sbKey;
+    GrStencilBuffer::ComputeSharedStencilBufferKey(rt->width(), rt->height(), rt->numSamples(),
+                                                   &sbKey);
     SkAutoTUnref<GrStencilBuffer> sb(static_cast<GrStencilBuffer*>(
-        this->getContext()->getResourceCache()->findAndRefScratchResource(sbKey)));
+        this->getContext()->getResourceCache()->findAndRefUniqueResource(sbKey)));
     if (sb) {
         rt->setStencilBuffer(sb);
         bool attached = this->attachStencilBufferToRenderTarget(sb, rt);
@@ -98,7 +99,7 @@
         }
         return attached;
     }
-    if (this->createStencilBufferForRenderTarget(rt, budgeted, rt->width(), rt->height())) {
+    if (this->createStencilBufferForRenderTarget(rt, rt->width(), rt->height())) {
         // Right now we're clearing the stencil buffer here after it is
         // attached to an RT for the first time. When we start matching
         // stencil buffers with smaller color targets this will no longer
@@ -108,6 +109,7 @@
         // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
         // FBO status.
         this->clearStencil(rt);
+        rt->getStencilBuffer()->resourcePriv().setUniqueKey(sbKey);
         return true;
     } else {
         return false;
@@ -122,8 +124,7 @@
     }
     // TODO: defer this and attach dynamically
     GrRenderTarget* tgt = tex->asRenderTarget();
-    if (tgt &&
-        !this->attachStencilBufferToRenderTarget(tgt, true /*budgeted*/)) {
+    if (tgt && !this->attachStencilBufferToRenderTarget(tgt)) {
         tex->unref();
         return NULL;
     } else {
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 2d5eaba..a0950e0 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -481,8 +481,7 @@
     // width and height may be larger than rt (if underlying API allows it).
     // Should attach the SB to the RT. Returns false if compatible sb could
     // not be created.
-    virtual bool createStencilBufferForRenderTarget(GrRenderTarget*, bool budgeted,
-                                                    int width, int height) = 0;
+    virtual bool createStencilBufferForRenderTarget(GrRenderTarget*, int width, int height) = 0;
 
     // attaches an existing SB to an existing RT.
     virtual bool attachStencilBufferToRenderTarget(GrStencilBuffer*, GrRenderTarget*) = 0;
@@ -491,7 +490,7 @@
     virtual void clearStencil(GrRenderTarget* target) = 0;
 
     // Given a rt, find or create a stencil buffer and attach it
-    bool attachStencilBufferToRenderTarget(GrRenderTarget* target, bool budgeted);
+    bool attachStencilBufferToRenderTarget(GrRenderTarget* target);
 
     virtual void didAddGpuTraceMarker() = 0;
     virtual void didRemoveGpuTraceMarker() = 0;
diff --git a/src/gpu/GrStencilBuffer.cpp b/src/gpu/GrStencilBuffer.cpp
index be463a0..3f2b28f 100644
--- a/src/gpu/GrStencilBuffer.cpp
+++ b/src/gpu/GrStencilBuffer.cpp
@@ -9,11 +9,11 @@
 #include "GrStencilBuffer.h"
 #include "GrResourceKey.h"
 
-void GrStencilBuffer::ComputeKey(int width, int height, int sampleCnt, GrScratchKey* key) {
-    static const GrScratchKey::ResourceType kType = GrScratchKey::GenerateResourceType();
-    GrScratchKey::Builder builder(key, kType, 2);
-    SkASSERT(width <= SK_MaxU16);
-    SkASSERT(height <= SK_MaxU16);
-    builder[0] = width | (height << 16);
-    builder[1] = sampleCnt;
+void GrStencilBuffer::ComputeSharedStencilBufferKey(int width, int height, int sampleCnt,
+                                                    GrUniqueKey* key) {
+    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+    GrUniqueKey::Builder builder(key, kDomain, 3);
+    builder[0] = width;
+    builder[1] = height;
+    builder[2] = sampleCnt;
 }
diff --git a/src/gpu/GrStencilBuffer.h b/src/gpu/GrStencilBuffer.h
index 43d2114..3788e61 100644
--- a/src/gpu/GrStencilBuffer.h
+++ b/src/gpu/GrStencilBuffer.h
@@ -47,7 +47,10 @@
                !fLastClipStackRect.contains(clipSpaceRect);
     }
 
-    static void ComputeKey(int width, int height, int sampleCnt, GrScratchKey* key);
+    // We create a unique stencil buffer at each width, height and sampleCnt and share it for
+    // all render targets that require a stencil with those params.
+    static void ComputeSharedStencilBufferKey(int width, int height, int sampleCnt,
+                                              GrUniqueKey* key);
 
 protected:
     GrStencilBuffer(GrGpu* gpu, LifeCycle lifeCycle, int width, int height, int bits, int sampleCnt)
@@ -57,11 +60,6 @@
         , fBits(bits)
         , fSampleCnt(sampleCnt)
         , fLastClipStackGenID(SkClipStack::kInvalidGenID) {
-        if (kCached_LifeCycle == lifeCycle) {
-            GrScratchKey key;
-            ComputeKey(width, height, sampleCnt, &key);
-            this->setScratchKey(key);
-        }
         fLastClipStackRect.setEmpty();
     }
 
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index 8df59ff..0e1c069 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -229,8 +229,7 @@
 
     void onResolveRenderTarget(GrRenderTarget* target) SK_OVERRIDE { return; }
 
-    bool createStencilBufferForRenderTarget(GrRenderTarget*, bool budgeted,
-                                            int width, int height) SK_OVERRIDE {
+    bool createStencilBufferForRenderTarget(GrRenderTarget*, int width, int height) SK_OVERRIDE {
         return false;
     }
 
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 5a861d4..ef4423b 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -442,8 +442,6 @@
     GrRenderTarget* tgt = SkNEW_ARGS(GrGLRenderTarget, (this, desc, idDesc));
     if (wrapDesc.fStencilBits) {
         GrGLStencilBuffer::IDDesc sbDesc;
-        sbDesc.fRenderbufferID = 0;
-        sbDesc.fLifeCycle = GrGpuResource::kWrapped_LifeCycle;
         GrGLStencilBuffer::Format format;
         format.fInternalFormat = GrGLStencilBuffer::kUnknownInternalFormat;
         format.fPacked = false;
@@ -1128,8 +1126,7 @@
 }
 }
 
-bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, bool budgeted, int width,
-                                                 int height) {
+bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width, int height) {
     // All internally created RTs are also textures. We don't create
     // SBs for a client's standalone RT (that is a RT that isn't also a texture).
     SkASSERT(rt->asTexture());
@@ -1138,9 +1135,6 @@
 
     int samples = rt->numSamples();
     GrGLStencilBuffer::IDDesc sbDesc;
-    sbDesc.fRenderbufferID = 0;
-    sbDesc.fLifeCycle = budgeted ? GrGpuResource::kCached_LifeCycle
-                                 : GrGpuResource::kUncached_LifeCycle;
 
     int stencilFmtCnt = this->glCaps().stencilFormats().count();
     for (int i = 0; i < stencilFmtCnt; ++i) {
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 18f0f74..7cbca01 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -122,8 +122,7 @@
     GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) SK_OVERRIDE;
     GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&) SK_OVERRIDE;
     GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) SK_OVERRIDE;
-    bool createStencilBufferForRenderTarget(GrRenderTarget* rt, bool budgeted,
-                                            int width, int height) SK_OVERRIDE;
+    bool createStencilBufferForRenderTarget(GrRenderTarget* rt, int width, int height) SK_OVERRIDE;
     bool attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTarget* rt) SK_OVERRIDE;
 
     void onClear(GrRenderTarget*, const SkIRect* rect, GrColor color,
diff --git a/src/gpu/gl/GrGLStencilBuffer.h b/src/gpu/gl/GrGLStencilBuffer.h
index 305ece8..75e98a0 100644
--- a/src/gpu/gl/GrGLStencilBuffer.h
+++ b/src/gpu/gl/GrGLStencilBuffer.h
@@ -24,6 +24,7 @@
     };
 
     struct IDDesc {
+        IDDesc() : fRenderbufferID(0), fLifeCycle(kCached_LifeCycle) {}
         GrGLuint fRenderbufferID;
         GrGpuResource::LifeCycle fLifeCycle;
     };