Made clip mask cache use Scratch Texture system

http://codereview.appspot.com/6210044/



git-svn-id: http://skia.googlecode.com/svn/trunk@3920 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index b26d2b3..bb661c9 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -853,6 +853,7 @@
                         GrContext::kApprox_ScratchTexMatch) {
         if (NULL != fContext) {
             fContext->unlockTexture(fEntry);
+            fEntry.reset();
         }
         fContext = context;
         if (NULL != fContext) {
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 2e9a4b9..43b2743 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -338,7 +338,6 @@
 
 void GrClipMaskManager::drawTexture(GrGpu* gpu,
                                     GrTexture* target,
-                                    const GrRect& rect,
                                     GrTexture* texture) {
     GrDrawState* drawState = gpu->drawState();
     GrAssert(NULL != drawState);
@@ -354,6 +353,9 @@
                                  GrSamplerState::kNearest_Filter,
                                  sampleM);
 
+    GrRect rect = GrRect::MakeWH(SkIntToScalar(target->width()), 
+                                 SkIntToScalar(target->height()));
+
     gpu->drawSimpleRect(rect, NULL, 1 << 0);
 
     drawState->setTexture(0, NULL);
@@ -372,10 +374,13 @@
     gpu->clear(NULL, color);
 }
 
+}
+
 // get a texture to act as a temporary buffer for AA clip boolean operations
 // TODO: given the expense of createTexture we may want to just cache this too
-void get_temp(GrGpu *gpu, const GrRect& bounds, GrTexture** temp) {
-    if (NULL != *temp) {
+void GrClipMaskManager::getTemp(const GrRect& bounds, 
+                                GrAutoScratchTexture* temp) {
+    if (NULL != temp->texture()) {
         // we've already allocated the temp texture
         return;
     }
@@ -388,39 +393,27 @@
         0           // samples
     };
 
-    *temp = gpu->createTexture(desc, NULL, 0);
+    temp->set(fAACache.getContext(), desc);
 }
 
+
+void GrClipMaskManager::setupCache(const GrClip& clipIn,
+                                   const GrRect& bounds) {
+    // Since we are setting up the cache we know the last lookup was a miss
+    // Free up the currently cached mask so it can be reused
+    fAACache.reset();
+
+    const GrTextureDesc desc = {
+        kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit,
+        SkScalarCeilToInt(bounds.width()),
+        SkScalarCeilToInt(bounds.height()),
+        kAlpha_8_GrPixelConfig,
+        0           // samples
+    };
+
+    fAACache.acquireMask(clipIn, desc, bounds);
 }
 
-void GrClipMaskManager::getAccum(GrGpu* gpu,
-                                 const GrRect& bounds,
-                                 GrTexture** accum) {
-    GrAssert(NULL == *accum);
-
-    // since we are getting an accumulator we know our cache is shot. See
-    // if we can reuse the texture stored in the cache
-    if (fAACache.getLastMaskWidth() >= bounds.width() &&
-        fAACache.getLastMaskHeight() >= bounds.height()) {
-        // we can just reuse the existing texture
-        *accum = fAACache.detachLastMask();
-        fAACache.reset();
-    } else {
-        const GrTextureDesc desc = {
-            kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit,
-            SkScalarCeilToInt(bounds.width()),
-            SkScalarCeilToInt(bounds.height()),
-            kAlpha_8_GrPixelConfig,
-            0           // samples
-        };
-
-        *accum = gpu->createTexture(desc, NULL, 0);
-    }
-
-    GrAssert(1 == (*accum)->getRefCnt());
-}
-
-
 ////////////////////////////////////////////////////////////////////////////////
 // Shared preamble between gpu and SW-only AA clip mask creation paths.
 // Handles caching, determination of clip mask bound & allocation (if needed)
@@ -429,8 +422,7 @@
 bool GrClipMaskManager::clipMaskPreamble(GrGpu* gpu,
                                          const GrClip& clipIn,
                                          GrTexture** result,
-                                         GrRect *resultBounds,
-                                         GrTexture** maskStorage) {
+                                         GrRect *resultBounds) {
     GrDrawState* origDrawState = gpu->drawState();
     GrAssert(origDrawState->isClipState());
 
@@ -441,7 +433,6 @@
     rtRect.setLTRB(0, 0,
                     GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
 
-
     // unlike the stencil path the alpha path is not bound to the size of the
     // render target - determine the minimum size required for the mask
     GrRect bounds;
@@ -477,7 +468,8 @@
         return true;
     }
 
-    this->getAccum(gpu, bounds, maskStorage);
+    this->setupCache(clipIn, bounds);
+
     *resultBounds = bounds;
     return false;
 }
@@ -489,19 +481,17 @@
                                             GrTexture** result,
                                             GrRect *resultBounds) {
 
-    GrTexture* accum = NULL;
-    if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds, &accum)) {
+    if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) {
         return true;
     }
 
+    GrTexture* accum = fAACache.getLastMask();
     if (NULL == accum) {
         fClipMaskInAlpha = false;
+        fAACache.reset();
         return false;
     }
 
-    GrRect newRTBounds;
-    newRTBounds.setLTRB(0, 0, resultBounds->width(), resultBounds->height());
-    
     GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
     GrDrawState* drawState = gpu->drawState();
 
@@ -528,7 +518,7 @@
 
     clear(gpu, accum, clearToInside ? 0xffffffff : 0x00000000);
 
-    GrTexture* temp = NULL;
+    GrAutoScratchTexture temp;
 
     // walk through each clip element and perform its set op
     for (int c = start; c < count; ++c) {
@@ -555,18 +545,18 @@
                 continue;
             }
 
-            get_temp(gpu, *resultBounds, &temp);
-            if (NULL == temp) {
+            getTemp(*resultBounds, &temp);
+            if (NULL == temp.texture()) {
                 fClipMaskInAlpha = false;
-                SkSafeUnref(accum);
+                fAACache.reset();
                 return false;
             }
 
             // clear the temp target & draw into it
-            clear(gpu, temp, 0x00000000);
+            clear(gpu, temp.texture(), 0x00000000);
 
             setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
-            this->drawClipShape(gpu, temp, clipIn, c);
+            this->drawClipShape(gpu, temp.texture(), clipIn, c);
 
             // TODO: rather than adding these two translations here
             // compute the bounding box needed to render the texture
@@ -582,7 +572,7 @@
             // Now draw into the accumulator using the real operation
             // and the temp buffer as a texture
             setup_boolean_blendcoeffs(drawState, op);
-            this->drawTexture(gpu, accum, newRTBounds, temp);
+            this->drawTexture(gpu, accum, temp.texture());
 
             if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
                 GrMatrix m;
@@ -600,10 +590,7 @@
         }
     }
 
-    fAACache.set(clipIn, accum, *resultBounds);
     *result = accum;
-    SkSafeUnref(accum);     // fAACache still has a ref to accum
-    SkSafeUnref(temp);
 
     return true;
 }
@@ -784,13 +771,14 @@
                                                GrTexture** result,
                                                GrRect *resultBounds) {
 
-    GrTexture* accum = NULL;
-    if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds, &accum)) {
+    if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) {
         return true;
     }
 
+    GrTexture* accum = fAACache.getLastMask();
     if (NULL == accum) {
         fClipMaskInAlpha = false;
+        fAACache.reset();
         return false;
     }
 
@@ -819,9 +807,7 @@
     // TODO: need to get pixels out of SkRasterClip & into the texture!
 #endif
 
-    fAACache.set(clipIn, accum, *resultBounds);
     *result = accum;
-    SkSafeUnref(accum);     // fAACache still has a ref to accum
 
     return true;
 }
@@ -841,7 +827,8 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-void GrClipMaskManager::freeResources() {
+void GrClipMaskManager::releaseResources() {
     // in case path renderer has any GrResources, start from scratch
     GrSafeSetNull(fPathRendererChain);
+    fAACache.releaseResources();
 }
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 5ab189d..c87bb7c 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -16,6 +16,7 @@
 #include "SkRefCnt.h"
 #include "GrTexture.h"
 #include "SkDeque.h"
+#include "GrContext.h"
 
 class GrGpu;
 class GrPathRenderer;
@@ -44,7 +45,8 @@
 class GrClipMaskCache : public GrNoncopyable {
 public:
     GrClipMaskCache() 
-    : fStack(sizeof(GrClipStackFrame)) {
+    : fContext(NULL)
+    , fStack(sizeof(GrClipStackFrame)) {
         // We need an initial frame to capture the clip state prior to 
         // any pushes
         new (fStack.push_back()) GrClipStackFrame();
@@ -68,9 +70,9 @@
 
         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
 
-        if (back->fLastMask &&
-            back->fLastMask->width() >= width &&
-            back->fLastMask->height() >= height &&
+        if (back->fLastMask.texture() &&
+            back->fLastMask.texture()->width() >= width &&
+            back->fLastMask.texture()->height() >= height &&
             clip == back->fLastClip) {
             return true;
         }
@@ -78,21 +80,6 @@
         return false;
     }
 
-    void set(const GrClip& clip, GrTexture* mask, const GrRect& bound) {
-
-        if (fStack.empty()) {
-            GrAssert(false);
-            return;
-        }
-
-        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
-
-        back->fLastClip = clip;
-        SkSafeRef(mask);
-        back->fLastMask.reset(mask);
-        back->fLastBound = bound;
-    }
-
     void reset() {
         if (fStack.empty()) {
             GrAssert(false);
@@ -147,7 +134,7 @@
 
         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
 
-        return back->fLastMask.get();
+        return back->fLastMask.texture();
     }
 
     const GrTexture* getLastMask() const {
@@ -159,19 +146,21 @@
 
         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
 
-        return back->fLastMask.get();
+        return back->fLastMask.texture();
     }
 
-    GrTexture* detachLastMask() {
+    void acquireMask(const GrClip& clip,
+                     const GrTextureDesc& desc,
+                     const GrRect& bound) {
 
         if (fStack.empty()) {
             GrAssert(false);
-            return NULL;
+            return;
         }
 
         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
 
-        return back->fLastMask.detach();
+        back->acquireMask(fContext, clip, desc, bound);
     }
 
     int getLastMaskWidth() const {
@@ -183,11 +172,11 @@
 
         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
 
-        if (NULL == back->fLastMask.get()) {
+        if (NULL == back->fLastMask.texture()) {
             return -1;
         }
 
-        return back->fLastMask.get()->width();
+        return back->fLastMask.texture()->width();
     }
 
     int getLastMaskHeight() const {
@@ -199,11 +188,11 @@
 
         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
 
-        if (NULL == back->fLastMask.get()) {
+        if (NULL == back->fLastMask.texture()) {
             return -1;
         }
 
-        return back->fLastMask.get()->height();
+        return back->fLastMask.texture()->height();
     }
 
     void getLastBound(GrRect* bound) const {
@@ -219,6 +208,24 @@
         *bound = back->fLastBound;
     }
 
+    void setContext(GrContext* context) {
+        fContext = context;
+    }
+
+    GrContext* getContext() {
+        return fContext;
+    }
+
+    void releaseResources() {
+
+        SkDeque::F2BIter iter(fStack);
+        for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
+                frame != NULL;
+                frame = (GrClipStackFrame*) iter.next()) {
+            frame->reset();
+        }
+    }
+
 protected:
 private:
     struct GrClipStackFrame {
@@ -227,22 +234,39 @@
             reset();
         }
 
+        void acquireMask(GrContext* context,
+                         const GrClip& clip, 
+                         const GrTextureDesc& desc,
+                         const GrRect& bound) {
+
+            fLastClip = clip;
+
+            fLastMask.set(context, desc);
+
+            fLastBound = bound;
+        }
+
         void reset () {
             fLastClip.setEmpty();
-            fLastMask.reset(NULL);
+
+            const GrTextureDesc desc = { kNone_GrTextureFlags, 0, 0, 
+                                         kUnknown_GrPixelConfig, 0 };
+
+            fLastMask.set(NULL, desc);
             fLastBound.setEmpty();
         }
 
         GrClip                  fLastClip;
         // The mask's width & height values are used in setupDrawStateAAClip to 
         // correctly scale the uvs for geometry drawn with this mask
-        SkAutoTUnref<GrTexture> fLastMask;
+        GrAutoScratchTexture    fLastMask;
         // fLastBound stores the bounding box of the clip mask in canvas 
         // space. The left and top fields are used to offset the uvs for 
         // geometry drawn with this mask (in setupDrawStateAAClip)
         GrRect                  fLastBound;
     };
 
+    GrContext*   fContext;
     SkDeque      fStack;
 
     typedef GrNoncopyable INHERITED;
@@ -268,7 +292,7 @@
                         const GrClip& clip, 
                         ScissoringSettings* scissorSettings);
 
-    void freeResources();
+    void releaseResources();
 
     bool isClipInStencil() const { return fClipMaskInStencil; }
     bool isClipInAlpha() const { return fClipMaskInAlpha; }
@@ -277,6 +301,10 @@
         fClipMaskInStencil = false;
     }
 
+    void setContext(GrContext* context) {
+        fAACache.setContext(context);
+    }
+
 protected:
 private:
     bool fClipMaskInStencil;        // is the clip mask in the stencil buffer?
@@ -302,8 +330,7 @@
     bool clipMaskPreamble(GrGpu* gpu,
                           const GrClip& clipIn,
                           GrTexture** result,
-                          GrRect *resultBounds,
-                          GrTexture** maskStorage);
+                          GrRect *resultBounds);
 
     bool drawPath(GrGpu* gpu,
                   const SkPath& path,
@@ -317,10 +344,12 @@
 
     void drawTexture(GrGpu* gpu,
                      GrTexture* target,
-                     const GrRect& rect,
                      GrTexture* texture);
 
-    void getAccum(GrGpu* gpu, const GrRect& bounds, GrTexture** accum);
+    void getTemp(const GrRect& bounds, GrAutoScratchTexture* temp);
+
+    void setupCache(const GrClip& clip, 
+                    const GrRect& bounds);
 
     // determines the path renderer used to draw a clip path element.
     GrPathRenderer* getClipPathRenderer(GrGpu* gpu,
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index a5c7284..4839e4f 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -66,6 +66,8 @@
 
 void GrGpu::abandonResources() {
 
+    fClipMaskManager.releaseResources();
+
     while (NULL != fResourceHead) {
         fResourceHead->abandon();
     }
@@ -79,12 +81,12 @@
     fVertexPool = NULL;
     delete fIndexPool;
     fIndexPool = NULL;
-
-    fClipMaskManager.freeResources();
 }
 
 void GrGpu::releaseResources() {
 
+    fClipMaskManager.releaseResources();
+
     while (NULL != fResourceHead) {
         fResourceHead->release();
     }
@@ -98,8 +100,6 @@
     fVertexPool = NULL;
     delete fIndexPool;
     fIndexPool = NULL;
-
-    fClipMaskManager.freeResources();
 }
 
 void GrGpu::insertResource(GrResource* resource) {
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index de14935..aeb51f8 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -87,6 +87,7 @@
     void setContext(GrContext* context) {
         GrAssert(NULL == fContext); 
         fContext = context;
+        fClipMaskManager.setContext(context);
     }
     GrContext* getContext() { return fContext; }
     const GrContext* getContext() const { return fContext; }
diff --git a/tests/ClipCacheTest.cpp b/tests/ClipCacheTest.cpp
index 93c6aeb..1fc5d45 100644
--- a/tests/ClipCacheTest.cpp
+++ b/tests/ClipCacheTest.cpp
@@ -61,6 +61,8 @@
 
     GrClipMaskCache cache;
 
+    cache.setContext(context);
+
     GrClip emptyClip;
     emptyClip.setEmpty();
 
@@ -77,25 +79,32 @@
     GrClip clip1;
     clip1.setFromRect(bound1);
 
-    SkAutoTUnref<GrTexture> texture(createTexture(context));
-    REPORTER_ASSERT(reporter, texture.get());
+    const GrTextureDesc desc = {
+        kRenderTarget_GrTextureFlagBit,
+        X_SIZE,
+        Y_SIZE,
+        kSkia8888_PM_GrPixelConfig,
+        0
+    };
 
-    if (NULL == texture.get()) {
+    cache.acquireMask(clip1, desc, bound1);
+
+    GrTexture* texture1 = cache.getLastMask();
+    REPORTER_ASSERT(reporter, texture1);
+    if (NULL == texture1) {
         return;
     }
 
-    cache.set(clip1, texture.get(), bound1);
-
     // check that the set took
-    check_state(reporter, cache, clip1, texture.get(), bound1);
-    REPORTER_ASSERT(reporter, 2 == texture.get()->getRefCnt());
+    check_state(reporter, cache, clip1, texture1, bound1);
+    REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt());
 
     // push the state
     cache.push();
 
     // verify that the pushed state is initially empty
     check_state(reporter, cache, emptyClip, NULL, emptyBound);
-    REPORTER_ASSERT(reporter, 2 == texture.get()->getRefCnt());
+    REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt());
 
     // modify the new state
     GrRect bound2;
@@ -105,11 +114,18 @@
     clip2.setEmpty();
     clip2.setFromRect(bound2);
 
-    cache.set(clip2, texture.get(), bound2);
+    cache.acquireMask(clip2, desc, bound2);
+
+    GrTexture* texture2 = cache.getLastMask();
+    REPORTER_ASSERT(reporter, texture2);
+    if (NULL == texture2) {
+        return;
+    }
 
     // check that the changes took
-    check_state(reporter, cache, clip2, texture.get(), bound2);
-    REPORTER_ASSERT(reporter, 3 == texture.get()->getRefCnt());
+    check_state(reporter, cache, clip2, texture2, bound2);
+    REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt());
+    REPORTER_ASSERT(reporter, 1 == texture2->getRefCnt());
 
     // check to make sure canReuse works
     REPORTER_ASSERT(reporter, cache.canReuse(clip2, 10, 10));
@@ -119,15 +135,17 @@
     cache.pop();
 
     // verify that the old state is restored
-    check_state(reporter, cache, clip1, texture.get(), bound1);
-    REPORTER_ASSERT(reporter, 2 == texture.get()->getRefCnt());
+    check_state(reporter, cache, clip1, texture1, bound1);
+    REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt());
+    REPORTER_ASSERT(reporter, 1 == texture2->getRefCnt());
 
     // manually clear the state
     cache.reset();
 
     // verify it is now empty
     check_state(reporter, cache, emptyClip, NULL, emptyBound);
-    REPORTER_ASSERT(reporter, 1 == texture.get()->getRefCnt());
+    REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt());
+    REPORTER_ASSERT(reporter, 1 == texture2->getRefCnt());
 
     // pop again - so there is no state
     cache.pop();
@@ -137,7 +155,8 @@
     // only do in release since it generates asserts in debug
     check_state(reporter, cache, emptyClip, NULL, emptyBound);
 #endif
-    REPORTER_ASSERT(reporter, 1 == texture.get()->getRefCnt());
+    REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt());
+    REPORTER_ASSERT(reporter, 1 == texture2->getRefCnt());
 }
 
 ////////////////////////////////////////////////////////////////////////////////