Refactor layer hoisting code

This CL consolidates the layer hoisting functionality in GrLayerHoister in preparation for retiring SkDpuDevice::EXPERIMENTAL_drawPicture in favor of SkMultiPictureDraw::draw.

R=bsalomon@google.com

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/580173002
diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp
index a29d91a..aa9576b 100644
--- a/src/gpu/GrLayerHoister.cpp
+++ b/src/gpu/GrLayerHoister.cpp
@@ -9,12 +9,16 @@
 #include "GrLayerHoister.h"
 #include "SkCanvas.h"
 #include "SkRecordDraw.h"
+#include "GrRecordReplaceDraw.h"
+#include "SkGrPixelRef.h"
 #include "SkSurface.h"
 
 // Return true if any layers are suitable for hoisting
 bool GrLayerHoister::FindLayersToHoist(const GrAccelData *gpuData,
                                        const SkRect& query,
-                                       bool pullForward[]) {
+                                       SkTDArray<GrCachedLayer*>* atlased,
+                                       SkTDArray<GrCachedLayer*>* nonAtlased,
+                                       GrLayerCache* layerCache) {
     bool anyHoisted = false;
 
     // Layer hoisting pre-renders the entire layer since it will be cached and potentially
@@ -23,6 +27,8 @@
     // is used to limit which clips are pre-rendered.
     static const int kSaveLayerMaxSize = 256;
 
+    SkAutoTArray<bool> pullForward(gpuData->numSaveLayers());
+
     // Pre-render all the layers that intersect the query rect
     for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
         pullForward[i] = false;
@@ -51,12 +57,87 @@
         anyHoisted = true;
     }
 
+    if (!anyHoisted) {
+        return false;
+    }
+
+    atlased->setReserve(atlased->reserved() + gpuData->numSaveLayers());
+
+    // Generate the layer and/or ensure it is locked
+    for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
+        if (pullForward[i]) {
+            const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
+
+            GrCachedLayer* layer = layerCache->findLayerOrCreate(info.fPictureID,
+                                                                 info.fSaveLayerOpID,
+                                                                 info.fRestoreOpID,
+                                                                 info.fOffset,
+                                                                 info.fOriginXform,
+                                                                 info.fPaint);
+
+            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 needsRendering = layerCache->lock(layer, desc,
+                                                   info.fHasNestedLayers || info.fIsNested);
+            if (NULL == layer->texture()) {
+                continue;
+            }
+
+            if (needsRendering) {
+                if (layer->isAtlased()) {
+                    *atlased->append() = layer;
+                } else {
+                    *nonAtlased->append() = layer;
+                }
+            }
+        }
+    }
+
     return anyHoisted;
 }
 
+static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* result) {
+    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
+    result->setInfo(info);
+    result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
+}
+
+static void convert_layers_to_replacements(const SkTDArray<GrCachedLayer*>& layers,
+                                           GrReplacements* replacements) {
+    // TODO: just replace GrReplacements::ReplacementInfo with GrCachedLayer?
+    for (int i = 0; i < layers.count(); ++i) {
+        GrReplacements::ReplacementInfo* layerInfo = replacements->push();
+        layerInfo->fStart = layers[i]->start();
+        layerInfo->fStop = layers[i]->stop();
+        layerInfo->fPos = layers[i]->offset();;
+
+        SkBitmap bm;
+        wrap_texture(layers[i]->texture(),
+                     !layers[i]->isAtlased() ? layers[i]->rect().width()
+                                             : layers[i]->texture()->width(),
+                     !layers[i]->isAtlased() ? layers[i]->rect().height()
+                                             : layers[i]->texture()->height(),
+                     &bm);
+        layerInfo->fImage = SkImage::NewTexture(bm);
+
+        layerInfo->fPaint = layers[i]->paint() ? SkNEW_ARGS(SkPaint, (*layers[i]->paint())) : NULL;
+
+        layerInfo->fSrcRect = SkIRect::MakeXYWH(layers[i]->rect().fLeft,
+                                                layers[i]->rect().fTop,
+                                                layers[i]->rect().width(),
+                                                layers[i]->rect().height());
+    }
+}
+
 void GrLayerHoister::DrawLayers(const SkPicture* picture,
                                 const SkTDArray<GrCachedLayer*>& atlased,
-                                const SkTDArray<GrCachedLayer*>& nonAtlased) {
+                                const SkTDArray<GrCachedLayer*>& nonAtlased,
+                                GrReplacements* replacements) {
     // Render the atlased layers that require it
     if (atlased.count() > 0) {
         // All the atlased layers are rendered into the same GrTexture
@@ -146,6 +227,9 @@
 
         layerCanvas->flush();
     }
+
+    convert_layers_to_replacements(atlased, replacements);
+    convert_layers_to_replacements(nonAtlased, replacements);
 }
 
 void GrLayerHoister::UnlockLayers(GrLayerCache* layerCache, const SkPicture* picture) {
diff --git a/src/gpu/GrLayerHoister.h b/src/gpu/GrLayerHoister.h
index 4116aef..a3b97e3 100644
--- a/src/gpu/GrLayerHoister.h
+++ b/src/gpu/GrLayerHoister.h
@@ -13,6 +13,7 @@
 
 class GrAccelData;
 struct GrCachedLayer;
+class GrReplacements;
 struct SkRect;
 
 // This class collects the layer hoisting functionality in one place.
@@ -23,25 +24,30 @@
 class GrLayerHoister {
 public:
     /** Find the layers in 'gpuData' that need hoisting.
-        @param gpuData  Acceleration structure containing layer information for a picture
-        @param query    The rectangle that is about to be drawn.
-        @param pullForward A gpuData->numSaveLayers -sized Boolean array indicating 
-                           which layers are to be hoisted
+        @param gpuData    Acceleration structure containing layer information for a picture
+        @param query      The rectangle that is about to be drawn.
+        @param atlased    Out parameter storing the layers that should be hoisted to the atlas
+        @param nonAtlased Out parameter storing the layers that should be hoisted stand alone
+        @param layerCache The source of new layers
         Return true if any layers are suitable for hoisting; false otherwise
     */
     static bool FindLayersToHoist(const GrAccelData *gpuData,
                                   const SkRect& query,
-                                  bool pullForward[]);
+                                  SkTDArray<GrCachedLayer*>* altased,
+                                  SkTDArray<GrCachedLayer*>* nonAtlased,
+                                  GrLayerCache* layerCache);
 
     /** Draw the specified layers of 'picture' into either the atlas or free
         floating textures.
-        @param picture  The picture containing the layers
-        @param atlased  The layers to be drawn into the atlas
-        @param nonAtlased The layers to be drawn into their own textures
+        @param picture      The picture containing the layers
+        @param atlased      The layers to be drawn into the atlas
+        @param nonAtlased   The layers to be drawn into their own textures
+        @oaram replacements The replacement structure to fill in with the rendered layer info
     */
     static void DrawLayers(const SkPicture* picture,
                            const SkTDArray<GrCachedLayer*>& atlased,
-                           const SkTDArray<GrCachedLayer*>& nonAtlased);
+                           const SkTDArray<GrCachedLayer*>& nonAtlased,
+                           GrReplacements* replacements);
 
     /** Unlock all the layers associated with picture in the layer cache.
         @param layerCache holder of the locked layers
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 25ab122..02dca83 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1836,39 +1836,6 @@
     fContext->getLayerCache()->trackPicture(picture);
 }
 
-static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* result) {
-    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
-    result->setInfo(info);
-    result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
-}
-
-static void convert_layers_to_replacements(const SkTDArray<GrCachedLayer*>& layers,
-                                           GrReplacements* replacements) {
-    // TODO: just replace GrReplacements::ReplacementInfo with GrCachedLayer?
-    for (int i = 0; i < layers.count(); ++i) {
-        GrReplacements::ReplacementInfo* layerInfo = replacements->push();
-        layerInfo->fStart = layers[i]->start();
-        layerInfo->fStop = layers[i]->stop();
-        layerInfo->fPos = layers[i]->offset();;
-
-        SkBitmap bm;
-        wrap_texture(layers[i]->texture(),
-                     !layers[i]->isAtlased() ? layers[i]->rect().width()
-                                             : layers[i]->texture()->width(),
-                     !layers[i]->isAtlased() ? layers[i]->rect().height()
-                                             : layers[i]->texture()->height(),
-                     &bm);
-        layerInfo->fImage = SkImage::NewTexture(bm);
-
-        layerInfo->fPaint = layers[i]->paint() ? SkNEW_ARGS(SkPaint, (*layers[i]->paint())) : NULL;
-
-        layerInfo->fSrcRect = SkIRect::MakeXYWH(layers[i]->rect().fLeft,
-                                                layers[i]->rect().fTop,
-                                                layers[i]->rect().width(),
-                                                layers[i]->rect().height());
-    }
-}
-
 bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* picture,
                                            const SkMatrix* matrix, const SkPaint* paint) {
     // todo: should handle these natively
@@ -1886,66 +1853,25 @@
     }
 
     const GrAccelData *gpuData = static_cast<const GrAccelData*>(data);
-
     if (0 == gpuData->numSaveLayers()) {
         return false;
     }
 
-    SkAutoTArray<bool> pullForward(gpuData->numSaveLayers());
-
     SkRect clipBounds;
     if (!mainCanvas->getClipBounds(&clipBounds)) {
         return true;
     }
 
-    if (!GrLayerHoister::FindLayersToHoist(gpuData, clipBounds, pullForward.get())) {
+    SkTDArray<GrCachedLayer*> atlased, nonAtlased;
+
+    if (!GrLayerHoister::FindLayersToHoist(gpuData, clipBounds, &atlased, &nonAtlased,
+                                           fContext->getLayerCache())) {
         return false;
     }
 
-    SkTDArray<GrCachedLayer*> atlased, nonAtlased;
-    atlased.setReserve(gpuData->numSaveLayers());
-
-    // Generate the layer and/or ensure it is locked
-    for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
-        if (pullForward[i]) {
-            const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
-
-            GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(),
-                                                                                info.fSaveLayerOpID, 
-                                                                                info.fRestoreOpID,
-                                                                                info.fOffset,
-                                                                                info.fOriginXform,
-                                                                                info.fPaint);
-
-            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 needsRendering = fContext->getLayerCache()->lock(layer, desc,
-                                                    info.fHasNestedLayers || info.fIsNested);
-            if (NULL == layer->texture()) {
-                continue;
-            }
-
-            if (needsRendering) {
-                if (layer->isAtlased()) {
-                    *atlased.append() = layer;
-                } else {
-                    *nonAtlased.append() = layer;
-                }
-            }
-        }
-    }
-
-    GrLayerHoister::DrawLayers(picture, atlased, nonAtlased);
-
     GrReplacements replacements;
 
-    convert_layers_to_replacements(atlased, &replacements);
-    convert_layers_to_replacements(nonAtlased, &replacements);
+    GrLayerHoister::DrawLayers(picture, atlased, nonAtlased, &replacements);
 
     // Render the entire picture using new layers
     GrRecordReplaceDraw(*picture->fRecord, mainCanvas, picture->fBBH.get(), &replacements, NULL);