AutoScratchTexture can now release its texture and it will return to the texture cache when freed

http://codereview.appspot.com/6262043/



git-svn-id: http://skia.googlecode.com/svn/trunk@4301 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 122baf1..46e80e0 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -100,10 +100,10 @@
         }
         GrTexture* texture() const;
         void reset() { fEntry = NULL; }
+        GrResourceEntry* cacheEntry() { return fEntry; }
     private:
         explicit TextureCacheEntry(GrResourceEntry* entry) { fEntry = entry; }
         void set(GrResourceEntry* entry) { fEntry = entry; }
-        GrResourceEntry* cacheEntry() { return fEntry; }
         GrResourceEntry* fEntry;
         friend class GrContext;
     };
@@ -174,7 +174,7 @@
      * Returns a texture matching the desc. It's contents are unknown. Subsequent
      * requests with the same descriptor are not guaranteed to return the same
      * texture. The same texture is guaranteed not be returned again until it is
-     * unlocked. Must call be balanced with an unlockTexture() call.
+     * unlocked. Call must be balanced with an unlockTexture() call.
      *
      * Textures created by createAndLockTexture() hide the complications of
      * tiling non-power-of-two textures on APIs that don't support this (e.g. 
@@ -192,6 +192,11 @@
     void unlockTexture(TextureCacheEntry entry);
 
     /**
+     * Free any data associated with the provided entry in the texture cache
+     */
+    void freeEntry(TextureCacheEntry entry);
+
+    /**
      * Creates a texture that is outside the cache. Does not count against
      * cache's budget.
      */
@@ -772,6 +777,14 @@
     static int PaintStageVertexLayoutBits(
                                     const GrPaint& paint,
                                     const bool hasTexCoords[GrPaint::kTotalStages]);
+
+    // Needed so GrTexture's returnToCache helper function can call
+    // addExistingTextureToCache
+    friend class GrTexture;
+
+    // Add an existing texture to the texture cache. This is intended solely
+    // for use with textures released from an GrAutoScratchTexture.
+    void addExistingTextureToCache(GrTexture* texture);
 };
 
 /**
@@ -837,12 +850,39 @@
     }
 
     void reset() {
-        if (NULL != fContext) {
+        if (NULL != fContext && NULL != fEntry.cacheEntry()) {
             fContext->unlockTexture(fEntry);
             fEntry.reset();
         }
     }
 
+    /*
+     * When detaching a texture we do not unlock it in the texture cache but
+     * we do set the returnToCache flag. In this way the texture remains 
+     * "locked" in the texture cache until it is freed and recycled in 
+     * GrTexture::internal_dispose. In reality, the texture has been removed 
+     * from the cache (because this is in AutoScratchTexture) and by not 
+     * calling unlockTexture we simply don't re-add it. It will be reattached 
+     * in GrTexture::internal_dispose.
+     *
+     * Note that the caller is assumed to accept and manage the ref to the
+     * returned texture.
+     */
+    GrTexture* detach() {
+        GrTexture* temp = this->texture();
+
+        GrAssert(1 == temp->getRefCnt());
+
+        // freeEntry will remove the texture cache's ref
+        temp->ref();
+        fContext->freeEntry(fEntry);
+        fEntry.reset();
+
+        temp->setFlag((GrTextureFlags) GrTexture::kReturnToCache_FlagBit);
+        GrAssert(1 == temp->getRefCnt());
+        return temp;
+    }
+
     GrTexture* set(GrContext* context,
                    const GrTextureDesc& desc,
                    GrContext::ScratchTexMatch match =
diff --git a/include/gpu/GrTexture.h b/include/gpu/GrTexture.h
index 79b39ec..783a147 100644
--- a/include/gpu/GrTexture.h
+++ b/include/gpu/GrTexture.h
@@ -33,6 +33,29 @@
 
     // from GrResource
     /**
+     * Informational texture flags
+     */
+    enum FlagBits {
+        kFirstBit = (kLastPublic_GrTextureFlagBit << 1),
+
+        /**
+         * This texture should be returned to the texture cache when
+         * it is no longer reffed
+         */
+        kReturnToCache_FlagBit        = kFirstBit,
+    };
+
+    void setFlag(GrTextureFlags flags) {
+        fDesc.fFlags = fDesc.fFlags | flags;
+    }
+    void resetFlag(GrTextureFlags flags) {
+        fDesc.fFlags = fDesc.fFlags & ~flags;
+    }
+    bool isSetFlag(GrTextureFlags flags) const { 
+        return 0 != (fDesc.fFlags & flags); 
+    }
+
+    /**
      *  Approximate number of bytes used by the texture
      */
     virtual size_t sizeInBytes() const SK_OVERRIDE {
@@ -162,11 +185,8 @@
     }
 
     // GrResource overrides
-    virtual void onRelease() {
-        this->releaseRenderTarget();
-    }
-
-    virtual void onAbandon();
+    virtual void onRelease() SK_OVERRIDE;
+    virtual void onAbandon() SK_OVERRIDE;
 
     void validateDesc() const;
 
@@ -176,6 +196,8 @@
     int                 fShiftFixedX;
     int                 fShiftFixedY;
 
+    virtual void internal_dispose() const SK_OVERRIDE;
+
     typedef GrSurface INHERITED;
 };
 
diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h
index 95527c1..8a3d738 100644
--- a/include/gpu/GrTypes.h
+++ b/include/gpu/GrTypes.h
@@ -454,6 +454,9 @@
      * Hint that the CPU may modify this texture after creation.
      */
     kDynamicUpdate_GrTextureFlagBit = 0x4,
+
+    kDummy_GrTextureFlagBit,
+    kLastPublic_GrTextureFlagBit = kDummy_GrTextureFlagBit-1,
 };
 
 GR_MAKE_BITFIELD_OPS(GrTextureFlags)