experiments to speed up drawing 32bit images into 565

New (legacy style) blitters only coded for shaders (and very restricted blendmodes)

Bug: skia:
See https://buganizer.corp.google.com/issues/64884885

Change-Id: Ie2546093bfe1e670a825dfd9542d252d53732c40
Reviewed-on: https://skia-review.googlesource.com/54103
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Herb Derby <herb@google.com>
diff --git a/src/core/SkBlitter_RGB565.cpp b/src/core/SkBlitter_RGB565.cpp
new file mode 100644
index 0000000..6668f84
--- /dev/null
+++ b/src/core/SkBlitter_RGB565.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCoreBlitters.h"
+#include "SkColorData.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermodePriv.h"
+#include "SkBlitMask.h"
+#include "SkColorData.h"
+
+#include "SkNx.h"
+
+static void D16_S32X_src(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) {
+    SkASSERT(coverage == 0xFF);
+    for (int i = 0; i < count; ++i) {
+        dst[i] = SkPixel32ToPixel16(src[i]);
+    }
+}
+
+static void D16_S32X_src_coverage(uint16_t dst[], const SkPMColor src[], int count,
+                                  uint8_t coverage) {
+    switch (coverage) {
+        case 0: break;
+        case 0xFF:
+            for (int i = 0; i < count; ++i) {
+                dst[i] = SkPixel32ToPixel16(src[i]);
+            }
+            break;
+        default:
+            unsigned scale = coverage + (coverage >> 7);
+            for (int i = 0; i < count; ++i) {
+                dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]);
+            }
+            break;
+    }
+}
+
+static void D16_S32A_srcover(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) {
+    SkASSERT(coverage == 0xFF);
+    for (int i = 0; i < count; ++i) {
+        dst[i] = SkSrcOver32To16(src[i], dst[i]);
+    }
+}
+
+static void D16_S32A_srcover_coverage(uint16_t dst[], const SkPMColor src[], int count,
+                                      uint8_t coverage) {
+    switch (coverage) {
+        case 0: break;
+        case 0xFF:
+            for (int i = 0; i < count; ++i) {
+                dst[i] = SkSrcOver32To16(src[i], dst[i]);
+            }
+            break;
+        default:
+            unsigned scale = coverage + (coverage >> 7);
+            for (int i = 0; i < count; ++i) {
+                dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]);
+            }
+            break;
+    }
+}
+
+bool SkRGB565_Shader_Blitter::Supports(const SkPixmap& device, const SkPaint& paint) {
+    if (device.colorType() != kRGB_565_SkColorType) {
+        return false;
+    }
+    if (device.colorSpace()) {
+        return false;
+    }
+    if (paint.getBlendMode() != SkBlendMode::kSrcOver &&
+        paint.getBlendMode() != SkBlendMode::kSrc) {
+        return false;
+    }
+    if (paint.isLCDRenderText()) {
+        return false;
+    }
+    if (paint.isDither()) {
+        return false;
+    }
+    return true;
+}
+
+SkRGB565_Shader_Blitter::SkRGB565_Shader_Blitter(const SkPixmap& device,
+        const SkPaint& paint, SkShaderBase::Context* shaderContext)
+    : INHERITED(device, paint, shaderContext)
+{
+    SkASSERT(shaderContext);
+    SkASSERT(Supports(device, paint));
+
+    fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
+
+    bool isOpaque = SkToBool(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag);
+
+    if (paint.getBlendMode() == SkBlendMode::kSrc || isOpaque) {
+        fBlend = D16_S32X_src;
+        fBlendCoverage = D16_S32X_src_coverage;
+    } else {    // srcover
+        fBlend = isOpaque ? D16_S32X_src : D16_S32A_srcover;
+        fBlendCoverage = isOpaque ? D16_S32X_src_coverage : D16_S32A_srcover_coverage;
+    }
+}
+
+SkRGB565_Shader_Blitter::~SkRGB565_Shader_Blitter() {
+    sk_free(fBuffer);
+}
+
+void SkRGB565_Shader_Blitter::blitH(int x, int y, int width) {
+    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
+
+    uint16_t* device = fDevice.writable_addr16(x, y);
+
+    SkPMColor*  span = fBuffer;
+    fShaderContext->shadeSpan(x, y, span, width);
+    fBlend(device, span, width, 0xFF);
+}
+
+void SkRGB565_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha coverage[],
+                                        const int16_t runs[]) {
+    SkPMColor* span = fBuffer;
+    uint16_t*  device = fDevice.writable_addr16(x, y);
+    auto*      shaderContext = fShaderContext;
+
+    for (;;) {
+        int count = *runs;
+        if (count <= 0) {
+            break;
+        }
+        int aa = *coverage;
+        if (aa) {
+            shaderContext->shadeSpan(x, y, span, count);
+            fBlendCoverage(device, span, count, aa);
+        }
+        device += count;
+        runs += count;
+        coverage += count;
+        x += count;
+    }
+}