Move allocation of texture from SkGpuDevice to GrLayerCache

In order to atlas the layers the GrLayerCache needs to be given more control over where a given layer's texture is allocated (i.e., it could be a raw scratch texture or in the cache).

R=bsalomon@google.com

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/350183006
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index d59d2e8..cdef414 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -130,7 +130,7 @@
 
     fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
 
-    fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (fGpu)));
+    fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
 
     fLastDrawWasBuffered = kNo_BufferedDraw;
 
diff --git a/src/gpu/GrLayerCache.cpp b/src/gpu/GrLayerCache.cpp
index f6377bf..86258ab 100644
--- a/src/gpu/GrLayerCache.cpp
+++ b/src/gpu/GrLayerCache.cpp
@@ -41,8 +41,8 @@
     int      fLayerID;
 };
 
-GrLayerCache::GrLayerCache(GrGpu* gpu)
-    : fGpu(SkRef(gpu))
+GrLayerCache::GrLayerCache(GrContext* context)
+    : fContext(context)
     , fLayerPool(16) {      // TODO: may need to increase this later
 }
 
@@ -57,7 +57,7 @@
 
     // The layer cache only gets 1 plot
     SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight);
-    fAtlasMgr.reset(SkNEW_ARGS(GrAtlasMgr, (fGpu, kSkia8888_GrPixelConfig,
+    fAtlasMgr.reset(SkNEW_ARGS(GrAtlasMgr, (fContext->getGpu(), kSkia8888_GrPixelConfig,
                                             textureSize, 1, 1, false)));
 }
 
@@ -75,6 +75,10 @@
     return layer;
 }
 
+GrCachedLayer* GrLayerCache::findLayer(const SkPicture* picture, int layerID) {
+    SkASSERT(picture->uniqueID() != SK_InvalidGenID);
+    return fLayerHash.find(PictureLayerKey(picture->uniqueID(), layerID));
+}
 
 GrCachedLayer* GrLayerCache::findLayerOrCreate(const SkPicture* picture, int layerID) {
     SkASSERT(picture->uniqueID() != SK_InvalidGenID);
@@ -82,5 +86,24 @@
     if (NULL == layer) {
         layer = this->createLayer(picture, layerID);
     }
+
     return layer;
 }
+
+bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {
+    SkASSERT(NULL == layer->getTexture());
+
+    // This just uses scratch textures and doesn't cache the texture.
+    // This can yield a lot of re-rendering
+    layer->setTexture(fContext->lockAndRefScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
+    return false;
+}
+
+void GrLayerCache::unlock(GrCachedLayer* layer) {
+    if (NULL == layer || NULL == layer->getTexture()) {
+        return;
+    }
+
+    fContext->unlockScratchTexture(layer->getTexture());
+    layer->setTexture(NULL);
+}
diff --git a/src/gpu/GrLayerCache.h b/src/gpu/GrLayerCache.h
index a957e78..d06b748 100644
--- a/src/gpu/GrLayerCache.h
+++ b/src/gpu/GrLayerCache.h
@@ -9,13 +9,12 @@
 #define GrLayerCache_DEFINED
 
 #include "GrAllocPool.h"
+#include "GrAtlas.h"
 #include "GrTHashTable.h"
 #include "GrPictureUtils.h"
 #include "GrRect.h"
 
-class GrAtlasMgr;
 class GrGpu;
-class GrPlot;
 class SkPicture;
 
 // GrAtlasLocation captures an atlased item's position in the atlas. This
@@ -97,24 +96,36 @@
 // classes.
 class GrLayerCache {
 public:
-    GrLayerCache(GrGpu*);
+    GrLayerCache(GrContext*);
     ~GrLayerCache();
 
+    // As a cache, the GrLayerCache can be ordered to free up all its cached
+    // elements by the GrContext
     void freeAll();
 
-    GrCachedLayer* findLayerOrCreate(const SkPicture* picture, int id);
+    GrCachedLayer* findLayer(const SkPicture* picture, int layerID);
+    GrCachedLayer* findLayerOrCreate(const SkPicture* picture, int layerID);
+    
+    // Inform the cache that layer's cached image is now required. Return true
+    // if it was found in the ResourceCache and doesn't need to be regenerated.
+    // If false is returned the caller should (re)render the layer into the
+    // newly acquired texture.
+    bool lock(GrCachedLayer* layer, const GrTextureDesc& desc);
+
+    // Inform the cache that layer's cached image is not currently required
+    void unlock(GrCachedLayer* layer);
 
 private:
-    SkAutoTUnref<GrGpu>       fGpu;
+    GrContext*                fContext;  // pointer back to owning context
     SkAutoTDelete<GrAtlasMgr> fAtlasMgr; // TODO: could lazily allocate
+    GrAtlas                   fPlotUsage;
 
     class PictureLayerKey;
     GrTHashTable<GrCachedLayer, PictureLayerKey, 7> fLayerHash;
     GrTAllocPool<GrCachedLayer> fLayerPool;
 
     void init();
-    GrCachedLayer* createLayer(const SkPicture* picture, int id);
-
+    GrCachedLayer* createLayer(const SkPicture* picture, int layerID);
 };
 
 #endif
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 861383b..d34170c 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1842,6 +1842,10 @@
 
 bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* canvas, const SkPicture* picture) {
 
+    if (NULL == picture->fPlayback.get()) {
+        return false;
+    }
+
     SkPicture::AccelData::Key key = GPUAccelData::ComputeAccelDataKey();
 
     const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key);
@@ -1938,60 +1942,50 @@
 
     SkPicturePlayback::PlaybackReplacements replacements;
 
+    // Generate the layer and/or ensure it is locked
     for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
         if (pullForward[i]) {
             GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture, i);
 
             const GPUAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
 
-            if (NULL != picture->fPlayback.get()) {
-                SkPicturePlayback::PlaybackReplacements::ReplacementInfo* layerInfo =
+            SkPicturePlayback::PlaybackReplacements::ReplacementInfo* layerInfo =
                                                                         replacements.push();
-                layerInfo->fStart = info.fSaveLayerOpID;
-                layerInfo->fStop = info.fRestoreOpID;
-                layerInfo->fPos = info.fOffset;
+            layerInfo->fStart = info.fSaveLayerOpID;
+            layerInfo->fStop = info.fRestoreOpID;
+            layerInfo->fPos = info.fOffset;
 
-                GrTextureDesc desc;
-                desc.fFlags = kRenderTarget_GrTextureFlagBit;
-                desc.fWidth = info.fSize.fWidth;
-                desc.fHeight = info.fSize.fHeight;
-                desc.fConfig = kSkia8888_GrPixelConfig;
-                // TODO: need to deal with sample count
+            GrTextureDesc desc;
+            desc.fFlags = kRenderTarget_GrTextureFlagBit;
+            desc.fWidth = info.fSize.fWidth;
+            desc.fHeight = info.fSize.fHeight;
+            desc.fConfig = kSkia8888_GrPixelConfig;
+            // TODO: need to deal with sample count
 
-                bool bNeedsRendering = true;
+            bool needsRendering = !fContext->getLayerCache()->lock(layer, desc);
+            if (NULL == layer->getTexture()) {
+                continue;
+            }
 
-                // This just uses scratch textures and doesn't cache the texture.
-                // This can yield a lot of re-rendering
-                if (NULL == layer->getTexture()) {
-                    layer->setTexture(fContext->lockAndRefScratchTexture(desc,
-                                                        GrContext::kApprox_ScratchTexMatch));
-                    if (NULL == layer->getTexture()) {
-                        continue;
-                    }
-                } else {
-                    bNeedsRendering = false;
-                }
+            layerInfo->fBM = SkNEW(SkBitmap);  // fBM is allocated so ReplacementInfo can be POD
+            wrap_texture(layer->getTexture(), desc.fWidth, desc.fHeight, layerInfo->fBM);
 
-                layerInfo->fBM = SkNEW(SkBitmap);
-                wrap_texture(layer->getTexture(), desc.fWidth, desc.fHeight, layerInfo->fBM);
+            SkASSERT(info.fPaint);
+            layerInfo->fPaint = info.fPaint;
 
-                SkASSERT(info.fPaint);
-                layerInfo->fPaint = info.fPaint;
+            if (needsRendering) {
+                SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
+                                                    layer->getTexture()->asRenderTarget()));
 
-                if (bNeedsRendering) {
-                    SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
-                                                        layer->getTexture()->asRenderTarget()));
+                SkCanvas* canvas = surface->getCanvas();
 
-                    SkCanvas* canvas = surface->getCanvas();
+                canvas->setMatrix(info.fCTM);
+                canvas->clear(SK_ColorTRANSPARENT);
 
-                    canvas->setMatrix(info.fCTM);
-                    canvas->clear(SK_ColorTRANSPARENT);
-
-                    picture->fPlayback->setDrawLimits(info.fSaveLayerOpID, info.fRestoreOpID);
-                    picture->fPlayback->draw(*canvas, NULL);
-                    picture->fPlayback->setDrawLimits(0, 0);
-                    canvas->flush();
-                }
+                picture->fPlayback->setDrawLimits(info.fSaveLayerOpID, info.fRestoreOpID);
+                picture->fPlayback->draw(*canvas, NULL);
+                picture->fPlayback->setDrawLimits(0, 0);
+                canvas->flush();
             }
         }
     }
@@ -2001,13 +1995,10 @@
     picture->fPlayback->draw(*canvas, NULL);
     picture->fPlayback->setReplacements(NULL);
 
+    // unlock the layers
     for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
-        GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture, i);
-
-        if (NULL != layer->getTexture()) {
-            fContext->unlockScratchTexture(layer->getTexture());
-            layer->setTexture(NULL);
-        }
+        GrCachedLayer* layer = fContext->getLayerCache()->findLayer(picture, i);
+        fContext->getLayerCache()->unlock(layer);
     }
 
     return true;