Simplified stencil buffer caching

https://codereview.appspot.com/6503073/



git-svn-id: http://skia.googlecode.com/svn/trunk@5400 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index f456a81..81974c0 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -762,13 +762,12 @@
      * Stencil buffers add themselves to the cache using
      * addAndLockStencilBuffer. When a SB's RT-attachment count
      * reaches zero the SB unlocks itself using unlockStencilBuffer and is
-     * eligible for purging. findStencilBuffer is called to check the cache for
-     * a SB that matching an RT's criteria. If a match is found that has been
-     * unlocked (its attachment count has reached 0) then it will be relocked.
+     * eligible for purging. findAndLockStencilBuffer is called to check the
+     * cache for a SB that matches an RT's criteria. 
      */
     void addAndLockStencilBuffer(GrStencilBuffer* sb);
     void unlockStencilBuffer(GrStencilBuffer* sb);
-    GrStencilBuffer* findStencilBuffer(int width, int height, int sampleCnt);
+    GrStencilBuffer* findAndLockStencilBuffer(int width, int height, int sampleCnt);
 
     GrPathRenderer* getPathRenderer(const SkPath& path,
                                     GrPathFill fill,
diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h
index d6e8ee0..f3add50 100644
--- a/include/gpu/GrRenderTarget.h
+++ b/include/gpu/GrRenderTarget.h
@@ -168,6 +168,10 @@
         fTexture = NULL;
     }
 
+    // override of GrResource
+    virtual void onAbandon() SK_OVERRIDE;
+    virtual void onRelease() SK_OVERRIDE;
+
 private:
     GrStencilBuffer*  fStencilBuffer;
     GrTexture*        fTexture; // not ref'ed
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 2c724b5..a2158e2 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -216,8 +216,7 @@
                                          const GrCacheData& cacheData,
                                          const GrTextureParams* params) {
     GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheData, false);
-    GrResource* resource = fTextureCache->findAndLock(resourceKey,
-                                                      GrResourceCache::kNested_LockType);
+    GrResource* resource = fTextureCache->findAndLock(resourceKey);
     return static_cast<GrTexture*>(resource);
 }
 
@@ -237,19 +236,25 @@
     fTextureCache->createAndLock(resourceKey, sb);
 }
 
-GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
+GrStencilBuffer* GrContext::findAndLockStencilBuffer(int width, int height,
                                               int sampleCnt) {
     GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(width,
                                                             height,
                                                             sampleCnt);
-    GrResource* resource = fTextureCache->findAndLock(resourceKey,
-                                            GrResourceCache::kSingle_LockType);
+    GrResource* resource = fTextureCache->findAndLock(resourceKey);
     return static_cast<GrStencilBuffer*>(resource);
 }
 
 void GrContext::unlockStencilBuffer(GrStencilBuffer* sb) {
     ASSERT_OWNED_RESOURCE(sb);
-    GrAssert(NULL != sb->getCacheEntry());
+
+    if (NULL == sb->getCacheEntry()) {
+        // This can happen when the GrResourceCache is being deleted. If
+        // a stencil buffer was evicted before its reffing render targets,
+        // the render targets will attempt to unlock the stencil buffer
+        // when they are deleted.
+        return;
+    }
 
     fTextureCache->unlock(sb->getCacheEntry());
 }
@@ -415,8 +420,7 @@
 
     do {
         GrResourceKey key = GrTexture::ComputeKey(fGpu, NULL, desc, cacheData, true);
-        resource = fTextureCache->findAndLock(key,
-                                              GrResourceCache::kNested_LockType);
+        resource = fTextureCache->findAndLock(key);
         // if we miss, relax the fit of the flags...
         // then try doubling width... then height.
         if (NULL != resource || kExact_ScratchTexMatch == match) {
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 148d572..fae9d99 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -144,9 +144,9 @@
 bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
     GrAssert(NULL == rt->getStencilBuffer());
     GrStencilBuffer* sb =
-        this->getContext()->findStencilBuffer(rt->width(),
-                                              rt->height(),
-                                              rt->numSamples());
+        this->getContext()->findAndLockStencilBuffer(rt->width(),
+                                                     rt->height(),
+                                                     rt->numSamples());
     if (NULL != sb) {
         rt->setStencilBuffer(sb);
         bool attached = this->attachStencilBufferToRenderTarget(sb, rt);
@@ -157,9 +157,6 @@
     }
     if (this->createStencilBufferForRenderTarget(rt,
                                                  rt->width(), rt->height())) {
-        rt->getStencilBuffer()->ref();
-        rt->getStencilBuffer()->transferToCacheAndLock();
-
         // 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
diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp
index 816a633..6235808 100644
--- a/src/gpu/GrRenderTarget.cpp
+++ b/src/gpu/GrRenderTarget.cpp
@@ -96,12 +96,24 @@
 
 void GrRenderTarget::setStencilBuffer(GrStencilBuffer* stencilBuffer) {
     if (NULL != fStencilBuffer) {
-        fStencilBuffer->wasDetachedFromRenderTarget(this);
+        GrContext* context = this->getContext();
+        if (NULL != context) {
+            context->unlockStencilBuffer(fStencilBuffer);
+        }
         fStencilBuffer->unref();
     }
+
     fStencilBuffer = stencilBuffer;
+
     if (NULL != fStencilBuffer) {
-        fStencilBuffer->wasAttachedToRenderTarget(this);
         fStencilBuffer->ref();
     }
 }
+
+void GrRenderTarget::onRelease() {
+    this->setStencilBuffer(NULL);
+}
+
+void GrRenderTarget::onAbandon() {
+    this->setStencilBuffer(NULL);
+}
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index f4919b1..4561aea 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -195,7 +195,7 @@
     return entry->fResource;
 }
 
-GrResource* GrResourceCache::findAndLock(const GrResourceKey& key, LockType type) {
+GrResource* GrResourceCache::findAndLock(const GrResourceKey& key) {
     GrAutoResourceCacheValidate atcv(this);
 
     GrResourceEntry* entry = fCache.find(key);
@@ -206,9 +206,7 @@
     this->internalDetach(entry, false);
     this->attachToHead(entry, false);
 
-    if (kNested_LockType == type || !entry->isLocked()) {
-        this->lock(entry);
-    }
+    this->lock(entry);
 
     return entry->fResource;
 }
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h
index bfa528d..59320b0 100644
--- a/src/gpu/GrResourceCache.h
+++ b/src/gpu/GrResourceCache.h
@@ -232,14 +232,6 @@
     size_t getCachedResourceBytes() const { return fEntryBytes; }
 
     /**
-     * Controls whether locks should be nestable or not.
-     */
-    enum LockType {
-        kNested_LockType,
-        kSingle_LockType,
-    };
-
-    /**
      *  Search for an entry with the same Key. If found, return it.
      *  If not found, return null.
      */
@@ -249,7 +241,7 @@
      *  Search for an entry with the same Key. If found, "lock" it and return it.
      *  If not found, return null.
      */
-    GrResource* findAndLock(const GrResourceKey&, LockType style);
+    GrResource* findAndLock(const GrResourceKey&);
 
     /**
      *  Create a new cache entry, based on the provided key and resource, and
diff --git a/src/gpu/GrStencilBuffer.cpp b/src/gpu/GrStencilBuffer.cpp
index 7bd6f32..2b7dfed 100644
--- a/src/gpu/GrStencilBuffer.cpp
+++ b/src/gpu/GrStencilBuffer.cpp
@@ -14,49 +14,10 @@
 
 GR_DEFINE_RESOURCE_CACHE_TYPE(GrStencilBuffer)
 
-void GrStencilBuffer::wasDetachedFromRenderTarget(const GrRenderTarget* rt) {
-    GrAssert(fRTAttachmentCnt > 0);
-    if (0 == --fRTAttachmentCnt) {
-        this->unlockInCache();
-        // At this point we could be deleted!
-    }
-}
-
 void GrStencilBuffer::transferToCacheAndLock() {
     GrAssert(NULL == this->getCacheEntry());
-    GrAssert(!fHoldingLock);
 
     this->getGpu()->getContext()->addAndLockStencilBuffer(this);
-    fHoldingLock = true;
-}
-
-void GrStencilBuffer::onRelease() {
-    // When the GrGpu rips through its list of resources and releases
-    // them it may release an SB before it releases its attached RTs.
-    // In that case when GrStencilBuffer sees its last detach it no
-    // long has a gpu ptr (gets nulled in GrResource::release()) and can't
-    // access the cache to unlock itself. So if we're being released and still
-    // have attachments go ahead and unlock now.
-    if (fRTAttachmentCnt) {
-        this->unlockInCache();
-        // we shouldn't be deleted here because some RT still has a ref on us.
-    }
-}
-
-void GrStencilBuffer::onAbandon() {
-    // we can use the same behavior as release.
-    this->onRelease();
-}
-
-void GrStencilBuffer::unlockInCache() {
-    if (fHoldingLock && this->isInCache()) {
-        GrGpu* gpu = this->getGpu();
-        if (NULL != gpu) {
-            GrAssert(NULL != gpu->getContext());
-            gpu->getContext()->unlockStencilBuffer(this);
-        }
-        fHoldingLock = false;
-    }
 }
 
 namespace {
diff --git a/src/gpu/GrStencilBuffer.h b/src/gpu/GrStencilBuffer.h
index f83590a..27c0a0c 100644
--- a/src/gpu/GrStencilBuffer.h
+++ b/src/gpu/GrStencilBuffer.h
@@ -23,9 +23,7 @@
     GR_DECLARE_RESOURCE_CACHE_TYPE()
 
     virtual ~GrStencilBuffer() {
-        // currently each rt that has attached this sb keeps a ref
         // TODO: allow SB to be purged and detach itself from rts
-        GrAssert(0 == fRTAttachmentCnt);
     }
 
     int width() const { return fWidth; }
@@ -65,12 +63,6 @@
     // a ref to the the cache which will unref when purged.
     void transferToCacheAndLock();
 
-    void wasAttachedToRenderTarget(const GrRenderTarget* rt) {
-        ++fRTAttachmentCnt;
-    }
-
-    void wasDetachedFromRenderTarget(const GrRenderTarget* rt);
-
     static GrResourceKey ComputeKey(int width, int height, int sampleCnt);
 
 protected:
@@ -83,22 +75,11 @@
         , fLastClipStack()
         , fLastClipData()
         , fLastClipWidth(-1)
-        , fLastClipHeight(-1)
-        , fHoldingLock(false)
-        , fRTAttachmentCnt(0) {
+        , fLastClipHeight(-1) {
     }
 
-    // GrResource overrides
-
-    // subclass override must call INHERITED::onRelease
-    virtual void onRelease();
-    // subclass override must call INHERITED::onAbandon
-    virtual void onAbandon();
-
 private:
 
-    void unlockInCache();
-
     int fWidth;
     int fHeight;
     int fBits;
@@ -109,9 +90,6 @@
     int         fLastClipWidth;
     int         fLastClipHeight;
 
-    bool             fHoldingLock;
-    int              fRTAttachmentCnt;
-
     typedef GrResource INHERITED;
 };
 
diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp
index 16d7f1b..3e72757 100644
--- a/src/gpu/gl/GrGLRenderTarget.cpp
+++ b/src/gpu/gl/GrGLRenderTarget.cpp
@@ -92,7 +92,7 @@
     fMSColorRenderbufferID  = 0;
     GrSafeUnref(fTexIDObj);
     fTexIDObj = NULL;
-    this->setStencilBuffer(NULL);
+    INHERITED::onRelease();
 }
 
 void GrGLRenderTarget::onAbandon() {
@@ -103,6 +103,6 @@
         fTexIDObj->abandon();
         fTexIDObj = NULL;
     }
-    this->setStencilBuffer(NULL);
+    INHERITED::onAbandon();
 }
 
diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h
index 64d95fa..493e90e 100644
--- a/src/gpu/gl/GrGLRenderTarget.h
+++ b/src/gpu/gl/GrGLRenderTarget.h
@@ -80,8 +80,8 @@
 
 protected:
     // override of GrResource
-    virtual void onAbandon();
-    virtual void onRelease();
+    virtual void onAbandon() SK_OVERRIDE;
+    virtual void onRelease() SK_OVERRIDE;
 
 private:
     GrGLuint      fRTFBOID;
diff --git a/src/gpu/gl/GrGLStencilBuffer.cpp b/src/gpu/gl/GrGLStencilBuffer.cpp
index 69c0959..a9612f5 100644
--- a/src/gpu/gl/GrGLStencilBuffer.cpp
+++ b/src/gpu/gl/GrGLStencilBuffer.cpp
@@ -28,12 +28,10 @@
         GR_GL_CALL(gl, DeleteRenderbuffers(1, &fRenderbufferID));
         fRenderbufferID = 0;
     }
-    INHERITED::onRelease();
 }
 
 void GrGLStencilBuffer::onAbandon() {
     fRenderbufferID = 0;
-    INHERITED::onAbandon();
 }
 
 
diff --git a/src/gpu/gl/GrGLStencilBuffer.h b/src/gpu/gl/GrGLStencilBuffer.h
index 65eb0d9..2d175f6 100644
--- a/src/gpu/gl/GrGLStencilBuffer.h
+++ b/src/gpu/gl/GrGLStencilBuffer.h
@@ -34,7 +34,7 @@
 
     virtual ~GrGLStencilBuffer();
 
-    virtual size_t sizeInBytes() const;
+    virtual size_t sizeInBytes() const SK_OVERRIDE;
 
     GrGLuint renderbufferID() const {
         return fRenderbufferID;
@@ -43,9 +43,9 @@
     const Format& format() const { return fFormat; }
 
 protected:
-    virtual void onRelease();
-
-    virtual void onAbandon();
+    // overrides of GrResource
+    virtual void onRelease() SK_OVERRIDE;
+    virtual void onAbandon() SK_OVERRIDE;
 
 private:
     Format fFormat;
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 2af77fa..33c79b4 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -1110,8 +1110,10 @@
                              samples, format));
             if (this->attachStencilBufferToRenderTarget(sb, rt)) {
                 fLastSuccessfulStencilFmtIdx = sIdx;
+                // This code transfers the creation ref to the
+                // cache and then adds a ref for the render target
+                sb->transferToCacheAndLock();
                 rt->setStencilBuffer(sb);
-                sb->unref();
                 return true;
            }
            sb->abandon(); // otherwise we lose sbID