Change Atlas recycling to track current flush count and recycle if Atlas not used in current flush.

BUG=
R=bsalomon@google.com, robertphillips@google.com

Author: jvanverth@google.com

Review URL: https://chromiumcodereview.appspot.com/23120004

git-svn-id: http://skia.googlecode.com/svn/trunk@10777 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrAtlas.cpp b/src/gpu/GrAtlas.cpp
index f2daca1..5207061 100644
--- a/src/gpu/GrAtlas.cpp
+++ b/src/gpu/GrAtlas.cpp
@@ -50,10 +50,10 @@
 static int g_UploadCount = 0;
 #endif
 
-GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
+GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) :
+                 fDrawToken(NULL, 0) {
     fAtlasMgr = mgr;    // just a pointer, not an owner
     fNext = NULL;
-    fUsed = false;
 
     fTexture = mgr->getTexture(format); // we're not an owner, just a pointer
     fPlot.set(plotX, plotY);
@@ -87,7 +87,7 @@
     GrAtlas* atlas = *startAtlas;
     bool removed = false;
     while (NULL != atlas) {
-        if (!atlas->used()) {
+        if (atlas->drawToken().isIssued()) {
             *atlasRef = atlas->fNext;
             atlasMgr->deleteAtlas(atlas);
             atlas = *atlasRef;
@@ -189,7 +189,7 @@
         case kA888_GrMaskFormat:
             return kSkia8888_GrPixelConfig;
         default:
-            GrAssert(!"unknown maskformat");
+            SkASSERT(!"unknown maskformat");
     }
     return kUnknown_GrPixelConfig;
 }
@@ -217,8 +217,8 @@
         return NULL;
     }
 
-    GrAssert(0 == kA8_GrMaskFormat);
-    GrAssert(1 == kA565_GrMaskFormat);
+    SkASSERT(0 == kA8_GrMaskFormat);
+    SkASSERT(1 == kA565_GrMaskFormat);
     if (NULL == fTexture[format]) {
         // TODO: Update this to use the cache rather than directly creating a texture.
         GrTextureDesc desc;
@@ -247,6 +247,6 @@
 }
 
 void GrAtlasMgr::freePlot(GrMaskFormat format, int x, int y) {
-    GrAssert(fPlotMgr->isBusy(x, y));
+    SkASSERT(fPlotMgr->isBusy(x, y));
     fPlotMgr->freePlot(x, y);
 }
diff --git a/src/gpu/GrAtlas.h b/src/gpu/GrAtlas.h
index b6f25c2..7831a8d 100644
--- a/src/gpu/GrAtlas.h
+++ b/src/gpu/GrAtlas.h
@@ -13,6 +13,7 @@
 
 #include "GrPoint.h"
 #include "GrTexture.h"
+#include "GrDrawTarget.h"
 
 class GrGpu;
 class GrRectanizer;
@@ -36,32 +37,25 @@
         }
     }
 
-    static void MarkAllUnused(GrAtlas* atlas) {
-        while (NULL != atlas) {
-            atlas->fUsed = false;
-            atlas = atlas->fNext;
-        }
-    }
-
     static bool RemoveUnusedAtlases(GrAtlasMgr* atlasMgr, GrAtlas** startAtlas);
 
-    bool used() const { return fUsed; }
-    void setUsed(bool used) { fUsed = used; }
+    GrDrawTarget::DrawToken drawToken() const { return fDrawToken; }
+    void setDrawToken(GrDrawTarget::DrawToken draw) { fDrawToken = draw; }
 
 private:
     GrAtlas(GrAtlasMgr*, int plotX, int plotY, GrMaskFormat format);
     ~GrAtlas(); // does not try to delete the fNext field
 
-    GrAtlas*        fNext;
-
     // for recycling
-    bool            fUsed;
+    GrDrawTarget::DrawToken fDrawToken;
 
-    GrTexture*      fTexture;
-    GrRectanizer*   fRects;
-    GrAtlasMgr*     fAtlasMgr;
-    GrIPoint16      fPlot;
-    GrMaskFormat    fMaskFormat;
+    GrAtlas*                fNext;
+
+    GrTexture*              fTexture;
+    GrRectanizer*           fRects;
+    GrAtlasMgr*             fAtlasMgr;
+    GrIPoint16              fPlot;
+    GrMaskFormat            fMaskFormat;
 
     friend class GrAtlasMgr;
 };
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 0c2b568..9501d96 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -621,6 +621,23 @@
         GrDrawTarget*    fTarget;
     };
 
+    ///////////////////////////////////////////////////////////////////////////
+    // Draw execution tracking (for font atlases and other resources)
+    class DrawToken {
+    public:
+        DrawToken(GrDrawTarget* drawTarget, uint32_t drawID) :
+                  fDrawTarget(drawTarget), fDrawID(drawID) {}
+        
+        bool isIssued() { return NULL != fDrawTarget && fDrawTarget->isIssued(fDrawID); }
+        
+    private:
+        GrDrawTarget*  fDrawTarget;
+        uint32_t       fDrawID;   // this may wrap, but we're doing direct comparison
+                                  // so that should be okay
+    };
+    
+    virtual DrawToken getCurrentDrawToken() { return DrawToken(this, 0); }
+        
 protected:
 
     enum GeometrySrcType {
@@ -839,6 +856,9 @@
     // but couldn't be made. Otherwise, returns true.
     bool setupDstReadIfNecessary(DrawInfo* info);
 
+    // Check to see if this set of draw commands has been sent out
+    virtual bool       isIssued(uint32_t drawID) { return true; }
+    
     enum {
         kPreallocGeoSrcStateStackCnt = 4,
     };
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 3ec9596..9e0d213 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -27,7 +27,8 @@
     , fClipProxyState(kUnknown_ClipProxyState)
     , fVertexPool(*vertexPool)
     , fIndexPool(*indexPool)
-    , fFlushing(false) {
+    , fFlushing(false)
+    , fDrawID(0) {
 
     fDstGpu->ref();
     fCaps.reset(SkRef(fDstGpu->caps()));
@@ -536,6 +537,7 @@
     fDstGpu->setDrawState(prevDrawState);
     prevDrawState->unref();
     this->reset();
+    ++fDrawID;
 }
 
 bool GrInOrderDrawBuffer::onCopySurface(GrSurface* dst,
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index 6512dcc..ba5e790 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -66,6 +66,9 @@
      */
     void flush();
 
+    // tracking for draws
+    virtual DrawToken getCurrentDrawToken() { return DrawToken(this, fDrawID); }
+
     // overrides from GrDrawTarget
     virtual bool geometryHints(int* vertexCount,
                                int* indexCount) const SK_OVERRIDE;
@@ -75,7 +78,6 @@
 
     virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) SK_OVERRIDE;
 
-
 protected:
     virtual void clipWillBeSet(const GrClipData* newClip) SK_OVERRIDE;
 
@@ -222,7 +224,10 @@
     };
     SkSTArray<kGeoPoolStatePreAllocCnt, GeometryPoolState> fGeoPoolStateStack;
 
+    virtual bool       isIssued(uint32_t drawID) { return drawID != fDrawID; }
+    
     bool                            fFlushing;
+    uint32_t                        fDrawID;
 
     typedef GrDrawTarget INHERITED;
 };
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index 8f0f1cf..f4a3df6 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -148,14 +148,15 @@
         }
     }
 
+    GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
     if (NULL == glyph->fAtlas) {
-        if (fStrike->getGlyphAtlas(glyph, scaler)) {
+        if (fStrike->getGlyphAtlas(glyph, scaler, drawToken)) {
             goto HAS_ATLAS;
         }
 
         // try to clear out an unused atlas before we flush
         fContext->getFontCache()->freeAtlasExceptFor(fStrike);
-        if (fStrike->getGlyphAtlas(glyph, scaler)) {
+        if (fStrike->getGlyphAtlas(glyph, scaler, drawToken)) {
             goto HAS_ATLAS;
         }
 
@@ -165,7 +166,8 @@
 
         // try to purge
         fContext->getFontCache()->purgeExceptFor(fStrike);
-        if (fStrike->getGlyphAtlas(glyph, scaler)) {
+        // need to use new flush count here
+        if (fStrike->getGlyphAtlas(glyph, scaler, drawToken)) {
             goto HAS_ATLAS;
         }
 
diff --git a/src/gpu/GrTextStrike.cpp b/src/gpu/GrTextStrike.cpp
index 9373351..1fe83c9 100644
--- a/src/gpu/GrTextStrike.cpp
+++ b/src/gpu/GrTextStrike.cpp
@@ -86,9 +86,6 @@
             fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
             this->detachStrikeFromList(strikeToPurge);
             delete strikeToPurge;
-        } else {
-            // for the remaining strikes, we just mark them unused
-            GrAtlas::MarkAllUnused(strikeToPurge->fAtlas);
         }
     }
 #if FONT_CACHE_STATS
@@ -185,7 +182,7 @@
 static void free_glyph(GrGlyph*& glyph) { glyph->free(); }
 
 static void invalidate_glyph(GrGlyph*& glyph) {
-    if (glyph->fAtlas && !glyph->fAtlas->used()) {
+    if (glyph->fAtlas && glyph->fAtlas->drawToken().isIssued()) {
         glyph->fAtlas = NULL;
     }
 }
@@ -217,11 +214,10 @@
 bool GrTextStrike::removeUnusedAtlases() {
     fCache.getArray().visitAll(invalidate_glyph);
     return GrAtlas::RemoveUnusedAtlases(fAtlasMgr, &fAtlas);
-
-    return false;
 }
 
-bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
+bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler,
+                                 GrDrawTarget::DrawToken currentDrawToken) {
 #if 0   // testing hack to force us to flush our cache often
     static int gCounter;
     if ((++gCounter % 10) == 0) return false;
@@ -231,7 +227,7 @@
     GrAssert(scaler);
     GrAssert(fCache.contains(glyph));
     if (glyph->fAtlas) {
-        glyph->fAtlas->setUsed(true);
+        glyph->fAtlas->setDrawToken(currentDrawToken);
         return true;
     }
 
@@ -256,6 +252,6 @@
     }
 
     glyph->fAtlas = atlas;
-    atlas->setUsed(true);
+    atlas->setDrawToken(currentDrawToken);
     return true;
 }
diff --git a/src/gpu/GrTextStrike.h b/src/gpu/GrTextStrike.h
index e359e26..64c4b90 100644
--- a/src/gpu/GrTextStrike.h
+++ b/src/gpu/GrTextStrike.h
@@ -16,6 +16,7 @@
 #include "GrTHashCache.h"
 #include "GrPoint.h"
 #include "GrGlyph.h"
+#include "GrDrawTarget.h"
 
 class GrAtlasMgr;
 class GrFontCache;
@@ -37,7 +38,7 @@
     GrMaskFormat getMaskFormat() const { return fMaskFormat; }
 
     inline GrGlyph* getGlyph(GrGlyph::PackedID, GrFontScaler*);
-    bool getGlyphAtlas(GrGlyph*, GrFontScaler*);
+    bool getGlyphAtlas(GrGlyph*, GrFontScaler*, GrDrawTarget::DrawToken currentDrawToken);
 
     // testing
     int countGlyphs() const { return fCache.getArray().count(); }