port encode_bitmap_for_png() to SkRasterPipeline

This logically shouldn't change anything, but it does a bit:
   - no diffs in 565
   - sRGB and 8888 show minor diffs, only when unpremul is non-trivial
   - f16 shows minor diffs all over, and major ones in shallow gradients

I think the shallow gradient diffs make sense. F16's high-precision is
being quantized down to a much narrower range (something like 10-40
values), so where the lines are drawn between sRGB bits will come down
to all sorts of things, especially rounding.

Change-Id: I156b7c613b73d6d6089221e61d0c529798ac1f9f
Reviewed-on: https://skia-review.googlesource.com/19449
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/tools/picture_utils.cpp b/tools/picture_utils.cpp
index db24553..5e87639 100644
--- a/tools/picture_utils.cpp
+++ b/tools/picture_utils.cpp
@@ -16,6 +16,7 @@
 #include "SkPicture.h"
 #include "SkStream.h"
 #include "SkString.h"
+#include "SkRasterPipeline.h"
 
 #include "sk_tool_utils.h"
 
@@ -74,71 +75,45 @@
 
     sk_sp<SkData> encode_bitmap_for_png(SkBitmap bitmap) {
         const int w = bitmap.width(),
-                h = bitmap.height();
+                  h = bitmap.height();
+
         // PNG wants unpremultiplied 8-bit RGBA pixels (16-bit could work fine too).
         // We leave the gamma of these bytes unspecified, to continue the status quo,
         // which we think generally is to interpret them as sRGB.
 
         SkAutoTMalloc<uint32_t> rgba(w*h);
 
-        auto srgbColorSpace = SkColorSpace::MakeSRGB();
-        if (bitmap. colorType() ==  kN32_SkColorType &&
-            bitmap.colorSpace() == srgbColorSpace.get()) {
-            // These are premul sRGB 8-bit pixels in SkPMColor order.
-            // We want unpremul sRGB 8-bit pixels in RGBA order.  We'll get there via floats.
-            auto px = (const uint32_t*)bitmap.getPixels();
-            if (!px) {
-                return nullptr;
-            }
-            for (int i = 0; i < w*h; i++) {
-                Sk4f fs = Sk4f_fromS32(px[i]);         // Convert up to linear floats.
-#if defined(SK_PMCOLOR_IS_BGRA)
-                fs = SkNx_shuffle<2,1,0,3>(fs);        // Shuffle to RGBA, if not there already.
-#endif
-                float invA = 1.0f / fs[3];
-                fs = fs * Sk4f(invA, invA, invA, 1);   // Unpremultiply.
-                rgba[i] = Sk4f_toS32(fs);              // Pack down to sRGB bytes.
-            }
+        const void* src = bitmap.getPixels();
+        uint32_t*   dst = rgba.get();
 
-        } else if (bitmap.colorType() == kRGBA_F16_SkColorType) {
-            // These are premul linear half-float pixels in RGBA order.
-            // We want unpremul sRGB 8-bit pixels in RGBA order.  We'll get there via floats.
-            auto px = (const uint64_t*)bitmap.getPixels();
-            if (!px) {
-                return nullptr;
-            }
-            for (int i = 0; i < w*h; i++) {
-                // Convert up to linear floats.
-                Sk4f fs(SkHalfToFloat(static_cast<SkHalf>(px[i] >> (0 * 16))),
-                        SkHalfToFloat(static_cast<SkHalf>(px[i] >> (1 * 16))),
-                        SkHalfToFloat(static_cast<SkHalf>(px[i] >> (2 * 16))),
-                        SkHalfToFloat(static_cast<SkHalf>(px[i] >> (3 * 16))));
-                if (fs[3]) {                                    // Unpremultiply.
-                    fs *= Sk4f(1/fs[3], 1/fs[3], 1/fs[3], 1);
-                }
-                fs = Sk4f::Max(0.0f, Sk4f::Min(fs, 1.0f));      // Clamp to [0,1].
-                rgba[i] = Sk4f_toS32(fs);                       // Pack down to sRGB bytes.
-            }
+        SkRasterPipeline_<256> p;
+        switch (bitmap.colorType()) {
+            case  kRGBA_F16_SkColorType: p.append(SkRasterPipeline::load_f16,  &src); break;
+            case kRGBA_8888_SkColorType:
+            case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &src); break;
+            case   kRGB_565_SkColorType: p.append(SkRasterPipeline::load_565,  &src); break;
+            default: SkASSERT(false);  // DM doesn't support any other formats, does it?
+        }
+        if (bitmap.info().gammaCloseToSRGB()) {
+            p.append(SkRasterPipeline::from_srgb);
+        }
+        if (bitmap.colorType() == kBGRA_8888_SkColorType) {
+            p.append(SkRasterPipeline::swap_rb);
+        }
+        p.append(SkRasterPipeline::unpremul);
+        p.append(SkRasterPipeline::clamp_0);
+        p.append(SkRasterPipeline::clamp_1);
+        if (bitmap.info().colorSpace()) {
+            // We leave legacy modes as-is.  They're already sRGB encoded (kind of).
+            p.append(SkRasterPipeline::to_srgb);
+        }
+        p.append(SkRasterPipeline::store_8888, &dst);
 
-        } else {
-            // We "should" gamma correct in here but we don't.
-            // We want Gold to show exactly what our clients are seeing, broken gamma.
-
-            // Convert smaller formats up to premul linear 8-bit (in SkPMColor order).
-            if (bitmap.colorType() != kN32_SkColorType) {
-                SkBitmap n32;
-                if (!sk_tool_utils::copy_to(&n32, kN32_SkColorType, bitmap)) {
-                    return nullptr;
-                }
-                bitmap = n32;
-            }
-
-            // Convert premul linear 8-bit to unpremul linear 8-bit RGBA.
-            if (!bitmap.readPixels(SkImageInfo::Make(w,h, kRGBA_8888_SkColorType,
-                                                     kUnpremul_SkAlphaType),
-                                   rgba, 4*w, 0,0)) {
-                return nullptr;
-            }
+        auto run = p.compile();
+        for (int y = 0; y < h; y++) {
+            run(0,y, w);
+            src = SkTAddOffset<const void>(src, bitmap.rowBytes());
+            dst += w;
         }
 
         return SkData::MakeFromMalloc(rgba.release(), w*h*sizeof(uint32_t));