MultiPictureDraw is taskgroup aware.
SampleApp is multipicturedraw aware.

BUG=skia:

Review URL: https://codereview.chromium.org/684923002
diff --git a/gyp/core.gypi b/gyp/core.gypi
index 9170fab..39454b6 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -188,6 +188,8 @@
         '<(skia_src_path)/core/SkStrokeRec.cpp',
         '<(skia_src_path)/core/SkStrokerPriv.cpp',
         '<(skia_src_path)/core/SkStrokerPriv.h',
+        '<(skia_src_path)/core/SkTaskGroup.cpp',
+        '<(skia_src_path)/core/SkTaskGroup.h',
         '<(skia_src_path)/core/SkTextBlob.cpp',
         '<(skia_src_path)/core/SkTextFormatParams.h',
         '<(skia_src_path)/core/SkTextMapStateProc.h',
diff --git a/gyp/dm.gypi b/gyp/dm.gypi
index c744715..932f430 100644
--- a/gyp/dm.gypi
+++ b/gyp/dm.gypi
@@ -45,8 +45,6 @@
     '../dm/DMWriteTask.cpp',
     '../gm/gm.cpp',
 
-    '../src/utils/SkTaskGroup.cpp',
-
     '../src/pipe/utils/SamplePipeControllers.cpp',
     '../src/utils/debugger/SkDebugCanvas.cpp',
     '../src/utils/debugger/SkDrawCommand.cpp',
diff --git a/gyp/pathops_skpclip.gyp b/gyp/pathops_skpclip.gyp
index 32a909b..4dadd79 100755
--- a/gyp/pathops_skpclip.gyp
+++ b/gyp/pathops_skpclip.gyp
@@ -24,7 +24,6 @@
       'sources': [
 		'../tests/PathOpsDebug.cpp',
         '../tests/PathOpsSkpClipTest.cpp',
-        '../src/utils/SkTaskGroup.cpp',
       ],
       'conditions': [
         [ 'skia_android_framework == 1', {
diff --git a/gyp/pathops_unittest.gyp b/gyp/pathops_unittest.gyp
index 1aaccfa..c873254 100644
--- a/gyp/pathops_unittest.gyp
+++ b/gyp/pathops_unittest.gyp
@@ -21,7 +21,6 @@
         '../tests/PathOpsDebug.cpp',
         '../tests/PathOpsOpLoopThreadedTest.cpp',
         '../tests/skia_test.cpp',
-        '../src/utils/SkTaskGroup.cpp',
       ],
       'conditions': [
         [ 'skia_android_framework == 1', {
diff --git a/gyp/tools.gyp b/gyp/tools.gyp
index e689ed1..dae1cf5 100644
--- a/gyp/tools.gyp
+++ b/gyp/tools.gyp
@@ -165,7 +165,6 @@
         '../tools/skpdiff/SkImageDiffer.cpp',
         '../tools/skpdiff/SkPMetric.cpp',
         '../tools/skpdiff/skpdiff_util.cpp',
-        '../src/utils/SkTaskGroup.cpp',
       ],
       'include_dirs': [
         '../src/core/', # needed for SkTLList.h
diff --git a/include/core/SkMultiPictureDraw.h b/include/core/SkMultiPictureDraw.h
index d8d9cb7..461d381 100644
--- a/include/core/SkMultiPictureDraw.h
+++ b/include/core/SkMultiPictureDraw.h
@@ -56,13 +56,23 @@
 
 private:
     struct DrawData {
-        SkCanvas*        canvas;  // reffed
-        const SkPicture* picture; // reffed
-        SkMatrix         matrix;
-        SkPaint*         paint;   // owned
+        SkCanvas*        fCanvas;  // reffed
+        const SkPicture* fPicture; // reffed
+        SkMatrix         fMatrix;
+        SkPaint*         fPaint;   // owned
+
+        void init(SkCanvas*, const SkPicture*, const SkMatrix*, const SkPaint*);
+        void draw();
+
+        static void Reset(SkTDArray<DrawData>&);
+
+        static void Run(void* ctx) {
+            static_cast<DrawData*>(ctx)->draw();
+        }
     };
 
-    SkTDArray<DrawData> fDrawData;
+    SkTDArray<DrawData> fThreadSafeDrawData;
+    SkTDArray<DrawData> fGPUDrawData;
 };
 
 #endif
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 2c17379..1b4a55e 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -742,6 +742,8 @@
 DEFINE_string(pdfPath, "", "Path to direcotry of pdf files.");
 #endif
 
+#include "SkTaskGroup.h"
+
 SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* devManager)
     : INHERITED(hwnd)
     , fDevManager(NULL) {
@@ -813,6 +815,7 @@
         fCurrIndex = 0;
     }
 
+    static SkTaskGroup::Enabler enabled(-1);
     gSampleWindow = this;
 
 #ifdef  PIPE_FILE
@@ -1306,7 +1309,7 @@
 
     return canvas;
 }
-
+#include "SkMultiPictureDraw.h"
 void SampleWindow::afterChildren(SkCanvas* orig) {
     if (fSaveToPdf) {
         fSaveToPdf = false;
@@ -1336,7 +1339,39 @@
 
         if (true) {
             this->installDrawFilter(orig);
-            orig->drawPicture(picture);
+            
+            if (true) {
+                SkImageInfo info;
+                size_t rowBytes;
+                void* addr = orig->accessTopLayerPixels(&info, &rowBytes);
+                if (addr) {
+                    SkSurface* surfs[4];
+                    SkMultiPictureDraw md;
+
+                    SkImageInfo n = SkImageInfo::Make(info.width()/2, info.height()/2,
+                                                      info.colorType(), info.alphaType());
+                    int index = 0;
+                    for (int y = 0; y < 2; ++y) {
+                        for (int x = 0; x < 2; ++x) {
+                            char* p = (char*)addr;
+                            p += y * n.height() * rowBytes;
+                            p += x * n.width() * sizeof(SkPMColor);
+                            surfs[index] = SkSurface::NewRasterDirect(n, p, rowBytes);
+                            SkCanvas* c = surfs[index]->getCanvas();
+                            c->translate(SkIntToScalar(-x * n.width()),
+                                         SkIntToScalar(-y * n.height()));
+                            md.add(c, picture, NULL, NULL);
+                            index++;
+                        }
+                    }
+                    md.draw();
+                    for (int i = 0; i < 4; ++i) {
+                        surfs[i]->unref();
+                    }
+                }
+            } else {
+                orig->drawPicture(picture);
+            }
         } else if (true) {
             SkDynamicMemoryWStream ostream;
             picture->serialize(&ostream);
diff --git a/src/core/SkMultiPictureDraw.cpp b/src/core/SkMultiPictureDraw.cpp
index 5fe3c0e..b59b63b 100644
--- a/src/core/SkMultiPictureDraw.cpp
+++ b/src/core/SkMultiPictureDraw.cpp
@@ -13,21 +13,49 @@
 #include "SkCanvas.h"
 #include "SkMultiPictureDraw.h"
 #include "SkPicture.h"
+#include "SkTaskGroup.h"
+
+void SkMultiPictureDraw::DrawData::draw() {
+    fCanvas->drawPicture(fPicture, &fMatrix, fPaint);
+}
+
+void SkMultiPictureDraw::DrawData::init(SkCanvas* canvas, const SkPicture* picture,
+                                        const SkMatrix* matrix, const SkPaint* paint) {
+    fPicture = SkRef(picture);
+    fCanvas = SkRef(canvas);
+    if (matrix) {
+        fMatrix = *matrix;
+    } else {
+        fMatrix.setIdentity();
+    }
+    if (paint) {
+        fPaint = SkNEW_ARGS(SkPaint, (*paint));
+    } else {
+        fPaint = NULL;
+    }
+}
+
+void SkMultiPictureDraw::DrawData::Reset(SkTDArray<DrawData>& data) {
+    for (int i = 0; i < data.count(); ++i) {
+        data[i].fPicture->unref();
+        data[i].fCanvas->unref();
+        SkDELETE(data[i].fPaint);
+    }
+    data.rewind();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
 
 SkMultiPictureDraw::SkMultiPictureDraw(int reserve) {
     if (reserve > 0) {
-        fDrawData.setReserve(reserve);
+        fGPUDrawData.setReserve(reserve);
+        fThreadSafeDrawData.setReserve(reserve);
     }
 }
 
 void SkMultiPictureDraw::reset() {
-    for (int i = 0; i < fDrawData.count(); ++i) {
-        fDrawData[i].picture->unref();
-        fDrawData[i].canvas->unref();
-        SkDELETE(fDrawData[i].paint);
-    }
-
-    fDrawData.rewind();
+    DrawData::Reset(fGPUDrawData);
+    DrawData::Reset(fThreadSafeDrawData);
 }
 
 void SkMultiPictureDraw::add(SkCanvas* canvas, 
@@ -39,47 +67,58 @@
         return;
     }
 
-    DrawData* data = fDrawData.append();
-
-    data->picture = SkRef(picture);
-    data->canvas = SkRef(canvas);
-    if (matrix) {
-        data->matrix = *matrix;
-    } else {
-        data->matrix.setIdentity();
-    }
-    if (paint) {
-        data->paint = SkNEW_ARGS(SkPaint, (*paint));
-    } else {
-        data->paint = NULL;
-    }
+    SkTDArray<DrawData>& array = canvas->getGrContext() ? fGPUDrawData : fThreadSafeDrawData;
+    array.append()->init(canvas, picture, matrix, paint);
 }
 
 #undef SK_IGNORE_GPU_LAYER_HOISTING
 #define SK_IGNORE_GPU_LAYER_HOISTING 1
 
+class AutoMPDReset : SkNoncopyable {
+    SkMultiPictureDraw* fMPD;
+public:
+    AutoMPDReset(SkMultiPictureDraw* mpd) : fMPD(mpd) {}
+    ~AutoMPDReset() { fMPD->reset(); }
+};
+
 void SkMultiPictureDraw::draw() {
+    AutoMPDReset mpdreset(this);
+    // we place the taskgroup after the MPDReset, to ensure that we don't delete the DrawData
+    // objects until after we're finished the tasks (which have pointers to the data).
+
+    SkTaskGroup group;
+    for (int i = 0; i < fThreadSafeDrawData.count(); ++i) {
+        group.add(DrawData::Run, &fThreadSafeDrawData[i]);
+    }
+    // we deliberately don't call wait() here, since the destructor will do that, this allows us
+    // to continue processing gpu-data without having to wait on the cpu tasks.
+
+    const int count = fGPUDrawData.count();
+    if (0 == count) {
+        return;
+    }
 
 #ifndef SK_IGNORE_GPU_LAYER_HOISTING
-    GrContext* context = NULL;
+    GrContext* context = fGPUDrawData[0].fCanvas->getGrContext();
+    SkASSERT(context);
 
-    // Start by collecting all the layers that are going to be atlased and render 
+    // Start by collecting all the layers that are going to be atlased and render
     // them (if necessary). Hoisting the free floating layers is deferred until
     // drawing the canvas that requires them.
     SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled;
 
-    for (int i = 0; i < fDrawData.count(); ++i) {
-        if (fDrawData[i].canvas->getGrContext() &&
-            !fDrawData[i].paint && fDrawData[i].matrix.isIdentity()) {
-            SkASSERT(NULL == context || context == fDrawData[i].canvas->getGrContext());
-            context = fDrawData[i].canvas->getGrContext();
+    for (int i = 0; i < count; ++i) {
+        const DrawData& data = fGPUDrawData[i];
+        // we only expect 1 context for all the canvases
+        SkASSERT(data.canvas->getGrContext() == context);
 
+        if (!data.fPaint && data.fMatrix.isIdentity()) {
             // TODO: this path always tries to optimize pictures. Should we
             // switch to this API approach (vs. SkCanvas::EXPERIMENTAL_optimize)?
-            fDrawData[i].canvas->EXPERIMENTAL_optimize(fDrawData[i].picture);
+            data.fCanvas->EXPERIMENTAL_optimize(data.fPicture);
 
             SkRect clipBounds;
-            if (!fDrawData[i].canvas->getClipBounds(&clipBounds)) {
+            if (!data.fCanvas->getClipBounds(&clipBounds)) {
                 continue;
             }
 
@@ -87,32 +126,33 @@
             // would improve the packing and reduce the number of swaps
             // TODO: another optimization would be to make a first pass to
             // lock any required layer that is already in the atlas
-            GrLayerHoister::FindLayersToAtlas(context, fDrawData[i].picture,
+            GrLayerHoister::FindLayersToAtlas(context, data.fPicture,
                                               clipBounds, 
                                               &atlasedNeedRendering, &atlasedRecycled);
         }
     }
 
-    if (NULL != context) {
-        GrLayerHoister::DrawLayersToAtlas(context, atlasedNeedRendering);
-    }
+    GrLayerHoister::DrawLayersToAtlas(context, atlasedNeedRendering);
 
     SkTDArray<GrHoistedLayer> needRendering, recycled;
 #endif
 
-    for (int i = 0; i < fDrawData.count(); ++i) {
+    for (int i = 0; i < count; ++i) {
+        const DrawData& data = fGPUDrawData[i];
+        SkCanvas* canvas = data.fCanvas;
+        const SkPicture* picture = data.fPicture;
+
 #ifndef SK_IGNORE_GPU_LAYER_HOISTING
-        if (fDrawData[i].canvas->getGrContext() && 
-            !fDrawData[i].paint && fDrawData[i].matrix.isIdentity()) {
+        if (!data.fPaint && data.fMatrix.isIdentity()) {
 
             SkRect clipBounds;
-            if (!fDrawData[i].canvas->getClipBounds(&clipBounds)) {
+            if (!canvas->getClipBounds(&clipBounds)) {
                 continue;
             }
 
             // Find the layers required by this canvas. It will return atlased
             // layers in the 'recycled' list since they have already been drawn.
-            GrLayerHoister::FindLayersToHoist(context, fDrawData[i].picture,
+            GrLayerHoister::FindLayersToHoist(context, picture,
                                               clipBounds, &needRendering, &recycled);
 
             GrLayerHoister::DrawLayers(context, needRendering);
@@ -122,11 +162,10 @@
             GrLayerHoister::ConvertLayersToReplacements(needRendering, &replacements);
             GrLayerHoister::ConvertLayersToReplacements(recycled, &replacements);
 
-            const SkMatrix initialMatrix = fDrawData[i].canvas->getTotalMatrix();
+            const SkMatrix initialMatrix = canvas->getTotalMatrix();
 
             // Render the entire picture using new layers
-            GrRecordReplaceDraw(fDrawData[i].picture, fDrawData[i].canvas, 
-                                &replacements, initialMatrix, NULL);
+            GrRecordReplaceDraw(picture, canvas, &replacements, initialMatrix, NULL);
 
             GrLayerHoister::UnlockLayers(context, needRendering);
             GrLayerHoister::UnlockLayers(context, recycled);
@@ -136,19 +175,13 @@
         } else
 #endif
         {
-            fDrawData[i].canvas->drawPicture(fDrawData[i].picture,
-                                             &fDrawData[i].matrix,
-                                             fDrawData[i].paint);
+            canvas->drawPicture(picture, &data.fMatrix, data.fPaint);
         }
     }
 
 #ifndef SK_IGNORE_GPU_LAYER_HOISTING
-    if (NULL != context) {
-        GrLayerHoister::UnlockLayers(context, atlasedNeedRendering);
-        GrLayerHoister::UnlockLayers(context, atlasedRecycled);
-    }
+    GrLayerHoister::UnlockLayers(context, atlasedNeedRendering);
+    GrLayerHoister::UnlockLayers(context, atlasedRecycled);
 #endif
-
-    this->reset();
 }
 
diff --git a/src/utils/SkTaskGroup.cpp b/src/core/SkTaskGroup.cpp
similarity index 99%
rename from src/utils/SkTaskGroup.cpp
rename to src/core/SkTaskGroup.cpp
index f1ec7f4..dd12538 100644
--- a/src/utils/SkTaskGroup.cpp
+++ b/src/core/SkTaskGroup.cpp
@@ -1,6 +1,7 @@
 #include "SkTaskGroup.h"
 
 #include "SkCondVar.h"
+#include "SkRunnable.h"
 #include "SkTDArray.h"
 #include "SkThread.h"
 #include "SkThreadUtils.h"
diff --git a/src/utils/SkTaskGroup.h b/src/core/SkTaskGroup.h
similarity index 97%
rename from src/utils/SkTaskGroup.h
rename to src/core/SkTaskGroup.h
index c60ceda..75443c3 100644
--- a/src/utils/SkTaskGroup.h
+++ b/src/core/SkTaskGroup.h
@@ -9,7 +9,8 @@
 #define SkTaskGroup_DEFINED
 
 #include "SkTypes.h"
-#include "SkRunnable.h"
+
+struct SkRunnable;
 
 class SkTaskGroup : SkNoncopyable {
 public:
diff --git a/tests/LazyPtrTest.cpp b/tests/LazyPtrTest.cpp
index f719c2e..799f705 100644
--- a/tests/LazyPtrTest.cpp
+++ b/tests/LazyPtrTest.cpp
@@ -1,5 +1,6 @@
 #include "Test.h"
 #include "SkLazyPtr.h"
+#include "SkRunnable.h"
 #include "SkTaskGroup.h"
 
 namespace {
diff --git a/tests/OnceTest.cpp b/tests/OnceTest.cpp
index e2711f0..da901f4 100644
--- a/tests/OnceTest.cpp
+++ b/tests/OnceTest.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkOnce.h"
+#include "SkRunnable.h"
 #include "SkTaskGroup.h"
 #include "Test.h"
 
diff --git a/tests/PathOpsSkpClipTest.cpp b/tests/PathOpsSkpClipTest.cpp
index b8142cd..ad0a95f 100755
--- a/tests/PathOpsSkpClipTest.cpp
+++ b/tests/PathOpsSkpClipTest.cpp
@@ -15,6 +15,7 @@
 #include "SkPathOpsDebug.h"
 #include "SkPicture.h"
 #include "SkRTConf.h"
+#include "SkRunnable.h"
 #include "SkTSort.h"
 #include "SkStream.h"
 #include "SkString.h"
diff --git a/tests/skia_test.cpp b/tests/skia_test.cpp
index 0058215..172328e 100644
--- a/tests/skia_test.cpp
+++ b/tests/skia_test.cpp
@@ -11,6 +11,7 @@
 #include "SkCommonFlags.h"
 #include "SkGraphics.h"
 #include "SkOSFile.h"
+#include "SkRunnable.h"
 #include "SkTArray.h"
 #include "SkTaskGroup.h"
 #include "SkTemplates.h"