4444 and gray 8

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=5147
CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot

Change-Id: Id08804803b2bbeab4fa88538491e99e53d5c2efe
Reviewed-on: https://skia-review.googlesource.com/5147
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp
index ab4d76d..5521236 100644
--- a/src/image/SkImageShader.cpp
+++ b/src/image/SkImageShader.cpp
@@ -288,12 +288,10 @@
 
     // TODO: all formats
     switch (info.colorType()) {
-        case kRGBA_8888_SkColorType:
-        case kBGRA_8888_SkColorType:
-        case   kRGB_565_SkColorType:
-        case  kRGBA_F16_SkColorType:
-            break;
-        default: return false;
+        case kAlpha_8_SkColorType:
+        case kIndex_8_SkColorType:
+            return false;
+        default: break;
     }
 
     // When the matrix is just an integer translate, bilerp == nearest neighbor.
@@ -348,6 +346,15 @@
         bool srgb = info.gammaCloseToSRGB() && dst != nullptr;
 
         switch (info.colorType()) {
+            case kGray_8_SkColorType:
+                p->append(srgb ? SkRasterPipeline::accum_g8_srgb
+                               : SkRasterPipeline::accum_g8, ctx);
+                break;
+
+            case kARGB_4444_SkColorType:
+                p->append(srgb ? SkRasterPipeline::accum_4444_srgb
+                               : SkRasterPipeline::accum_4444, ctx);
+                break;
             case kRGB_565_SkColorType:
                 p->append(srgb ? SkRasterPipeline::accum_565_srgb
                                : SkRasterPipeline::accum_565, ctx);
diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h
index ba8883a..c6fbe69 100644
--- a/src/opts/SkRasterPipeline_opts.h
+++ b/src/opts/SkRasterPipeline_opts.h
@@ -184,6 +184,15 @@
     v.store(dst);
 }
 
+SI void from_4444(const SkNh& _4444, SkNf* r, SkNf* g, SkNf* b, SkNf* a) {
+    auto _32_bit = SkNx_cast<int>(_4444);
+
+    *r = SkNx_cast<float>(_32_bit & (0xF << SK_R4444_SHIFT)) * (1.0f / (0xF << SK_R4444_SHIFT));
+    *g = SkNx_cast<float>(_32_bit & (0xF << SK_G4444_SHIFT)) * (1.0f / (0xF << SK_G4444_SHIFT));
+    *b = SkNx_cast<float>(_32_bit & (0xF << SK_B4444_SHIFT)) * (1.0f / (0xF << SK_B4444_SHIFT));
+    *a = SkNx_cast<float>(_32_bit & (0xF << SK_A4444_SHIFT)) * (1.0f / (0xF << SK_A4444_SHIFT));
+}
+
 SI void from_565(const SkNh& _565, SkNf* r, SkNf* g, SkNf* b) {
     auto _32_bit = SkNx_cast<int>(_565);
 
@@ -779,11 +788,52 @@
 
 STAGE(accum_a8, true) {}  // TODO
 
-STAGE(accum_g8,      true) {}  // TODO
-STAGE(accum_g8_srgb, true) {}  // TODO
 STAGE(accum_i8,      true) {}  // TODO
 STAGE(accum_i8_srgb, true) {}  // TODO
 
+STAGE(accum_g8, true) {
+    const uint8_t* p;
+    SkNi offset = offset_and_ptr(&p, ctx, r, g);
+
+    uint8_t px[N];
+    for (size_t i = 0; i < N; i++) {
+        if (kIsTail && i >= tail) {
+            px[i] = 0;
+            continue;
+        }
+        px[i] = p[offset[i]];
+    }
+
+    SkNf gray = SkNx_cast<float>(SkNb::Load(px)) * (1/255.0f);
+
+    SkNf scale = b;
+    dr += scale * gray;
+    dg += scale * gray;
+    db += scale * gray;
+    da += scale;
+}
+STAGE(accum_g8_srgb, true) {
+    const uint8_t* p;
+    SkNi offset = offset_and_ptr(&p, ctx, r, g);
+
+    uint8_t px[N];
+    for (size_t i = 0; i < N; i++) {
+        if (kIsTail && i >= tail) {
+            px[i] = 0;
+            continue;
+        }
+        px[i] = p[offset[i]];
+    }
+
+    SkNf gray = sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(px)));
+
+    SkNf scale = b;
+    dr += scale * gray;
+    dg += scale * gray;
+    db += scale * gray;
+    da += scale;
+}
+
 STAGE(accum_565, true) {
     const uint16_t* p;
     SkNi offset = offset_and_ptr(&p, ctx, r, g);
@@ -827,8 +877,50 @@
     da += scale;
 }
 
-STAGE(accum_4444,      true) {}  // TODO
-STAGE(accum_4444_srgb, true) {}  // TODO
+STAGE(accum_4444, true) {
+    const uint16_t* p;
+    SkNi offset = offset_and_ptr(&p, ctx, r, g);
+
+    uint16_t px[N];
+    for (size_t i = 0; i < N; i++) {
+        if (kIsTail && i >= tail) {
+            px[i] = 0;
+            continue;
+        }
+        px[i] = p[offset[i]];
+    }
+
+    SkNf R,G,B,A;
+    from_4444(SkNh::Load(px), &R, &G, &B, &A);
+
+    SkNf scale = b;
+    dr += scale * R;
+    dg += scale * G;
+    db += scale * B;
+    da += scale * A;
+}
+STAGE(accum_4444_srgb, true) {
+    const uint16_t* p;
+    SkNi offset = offset_and_ptr(&p, ctx, r, g);
+
+    uint16_t px[N];
+    for (size_t i = 0; i < N; i++) {
+        if (kIsTail && i >= tail) {
+            px[i] = 0;
+            continue;
+        }
+        px[i] = p[offset[i]];
+    }
+
+    SkNf R,G,B,A;
+    from_4444(SkNh::Load(px), &R, &G, &B, &A);
+
+    SkNf scale = b;
+    dr += scale * sk_linear_from_srgb_math(R);
+    dg += scale * sk_linear_from_srgb_math(G);
+    db += scale * sk_linear_from_srgb_math(B);
+    da += scale * A;
+}
 
 STAGE(accum_8888, true) {
     const uint32_t* p;