Add threaded backend sink to DM. Fix a scheduler bug.

The bug is spotted by the new sink. I'd expect more bugs to be revealed
and fixed using the new sink.

Bug: skia:
Change-Id: I6b0c9267079fbd6149004f0ecd55ddb179702588
Reviewed-on: https://skia-review.googlesource.com/109720
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Yuqian Li <liyuqian@google.com>
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 0dd35ff..2229b9c 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -49,6 +49,7 @@
 #include "SkStream.h"
 #include "SkSwizzler.h"
 #include "SkTaskGroup.h"
+#include "SkThreadedBMPDevice.h"
 #include "SkTLogic.h"
 #include <cmath>
 #include <functional>
@@ -1856,7 +1857,7 @@
     : fColorType(colorType)
     , fColorSpace(std::move(colorSpace)) {}
 
-Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
+void RasterSink::allocPixels(const Src& src, SkBitmap* dst) const {
     const SkISize size = src.size();
     // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
     SkAlphaType alphaType = kPremul_SkAlphaType;
@@ -1865,12 +1866,44 @@
     dst->allocPixelsFlags(SkImageInfo::Make(size.width(), size.height(),
                                             fColorType, alphaType, fColorSpace),
                           SkBitmap::kZeroPixels_AllocFlag);
+}
+
+Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
+    this->allocPixels(src, dst);
     SkCanvas canvas(*dst);
     return src.draw(&canvas);
 }
 
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
+ThreadedSink::ThreadedSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace)
+        : RasterSink(colorType, colorSpace)
+        , fExecutor(SkExecutor::MakeFIFOThreadPool(FLAGS_backendThreads)) {
+}
+
+Error ThreadedSink::draw(const Src& src, SkBitmap* dst, SkWStream* stream, SkString* str) const {
+    this->allocPixels(src, dst);
+
+    std::unique_ptr<SkThreadedBMPDevice> device(new SkThreadedBMPDevice(
+            *dst, FLAGS_backendTiles, FLAGS_backendThreads, fExecutor.get()));
+    std::unique_ptr<SkCanvas> canvas(new SkCanvas(device.get()));
+    Error result = src.draw(canvas.get());
+    canvas->flush();
+    return result;
+
+    // ??? yuqian:  why does the following give me segmentation fault while the above one works?
+    //              The seg fault occurs right in the beginning of ThreadedSink::draw with invalid
+    //              memory address (it would crash without even calling this->allocPixels).
+
+    // SkThreadedBMPDevice device(*dst, tileCnt, FLAGS_cpuThreads, fExecutor.get());
+    // SkCanvas canvas(&device);
+    // Error result = src.draw(&canvas);
+    // canvas.flush();
+    // return result;
+}
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
 // Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(),
 // passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
 // Several examples below.