add store(PixelFormat,...)

Add store(PixelFormat,...) to mirror earlier load/gather.
Use store() in SkVMBlitter to let us to write to any format
supported by SkColorType_to_PixelFormat().

This means we can read and write all the same formats now.  There's a
note on the SkColorType enum about some SkColorTypes being read-only,
but I've taken that to be descriptive and not proscriptive.

It's worth paying attention to grayscale.  Gray PixelFormats hold the
same bit size and shift for each of r,g,b so load/gather just naturally
unpack the same value into each channel.  When we want to store gray we
need to dot r,g,b together, here back into the red channel to
accommodate future gray-alpha.

Change-Id: I81ad252a35e2534d2d8c6123354b1d19c7018898
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/302330
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/src/core/SkVM.cpp b/src/core/SkVM.cpp
index 2c95b69..908f8a2 100644
--- a/src/core/SkVM.cpp
+++ b/src/core/SkVM.cpp
@@ -1190,6 +1190,34 @@
         return {};
     }
 
+    bool Builder::store(PixelFormat f, Arg ptr, Color c) {
+        // Detect a grayscale PixelFormat: r,g,b bit counts and shifts all equal.
+        if (f.r_bits  == f.g_bits  && f.g_bits  == f.b_bits &&
+            f.r_shift == f.g_shift && f.g_shift == f.b_shift) {
+
+            // TODO: pull these coefficients from an SkColorSpace?  This is sRGB luma/luminance.
+            c.r = c.r * 0.2126f
+                + c.g * 0.7152f
+                + c.b * 0.0722f;
+            f.g_bits = f.b_bits = 0;
+        }
+
+        I32 bits = splat(0);
+        if (f.r_bits) { bits = pack(bits, to_unorm(f.r_bits, c.r), f.r_shift); }
+        if (f.g_bits) { bits = pack(bits, to_unorm(f.g_bits, c.g), f.g_shift); }
+        if (f.b_bits) { bits = pack(bits, to_unorm(f.b_bits, c.b), f.b_shift); }
+        if (f.a_bits) { bits = pack(bits, to_unorm(f.a_bits, c.a), f.a_shift); }
+
+        switch (byte_size(f)) {
+            case 1: store8 (ptr, bits); return true;
+            case 2: store16(ptr, bits); return true;
+            case 4: store32(ptr, bits); return true;
+            // TODO: 8,16
+            default: SkUNREACHABLE;
+        }
+        return false;
+    }
+
     void Builder::unpremul(F32* r, F32* g, F32* b, F32 a) {
         skvm::F32 invA = 1.0f / a,
                   inf  = bit_cast(splat(0x7f800000));
diff --git a/src/core/SkVM.h b/src/core/SkVM.h
index 5b27da1..262f1fe 100644
--- a/src/core/SkVM.h
+++ b/src/core/SkVM.h
@@ -718,6 +718,7 @@
         I32   to_unorm(int bits, F32);   // E.g.   to_unorm(8, x) -> round(x * 255)
 
         Color   load(PixelFormat, Arg ptr);
+        bool   store(PixelFormat, Arg ptr, Color);
         Color gather(PixelFormat, Arg ptr, int offset, I32 index);
         Color gather(PixelFormat f, Uniform u, I32 index) {
             return gather(f, u.ptr, u.offset, index);
@@ -1041,6 +1042,7 @@
     static inline F32 from_unorm(int bits, I32 x) { return x->from_unorm(bits,x); }
     static inline I32   to_unorm(int bits, F32 x) { return x->  to_unorm(bits,x); }
 
+    static inline bool store(PixelFormat f, Arg p, Color c) { return c->store(f,p,c); }
     static inline Color gather(PixelFormat f, Arg p, int off, I32 ix) {
         return ix->gather(f,p,off,ix);
     }
diff --git a/src/core/SkVMBlitter.cpp b/src/core/SkVMBlitter.cpp
index 620f535..c25909b 100644
--- a/src/core/SkVMBlitter.cpp
+++ b/src/core/SkVMBlitter.cpp
@@ -159,18 +159,9 @@
             }
         }
 
-        switch (params.dst.colorType()) {
-            default: *ok = false;
-                     break;
-
-            case kRGB_565_SkColorType:
-            case kRGB_888x_SkColorType:
-            case kRGBA_8888_SkColorType:
-            case kBGRA_8888_SkColorType:
-            case kRGBA_1010102_SkColorType:
-            case kBGRA_1010102_SkColorType:
-            case kRGB_101010x_SkColorType:
-            case kBGR_101010x_SkColorType:  break;
+        skvm::PixelFormat unused;
+        if (!SkColorType_to_PixelFormat(params.dst.colorType(), &unused)) {
+            *ok = false;
         }
 
         return {
@@ -359,36 +350,7 @@
             src.a = clamp01(src.a);
         }
 
-        // Store back to the destination.
-        // TODO: use PixelFormat like we do for unpacking.
-        switch (params.dst.colorType()) {
-            default: SkUNREACHABLE;
-
-            case kRGB_565_SkColorType:
-                store16(dst_ptr, pack(pack(to_unorm(5,src.b),
-                                           to_unorm(6,src.g), 5),
-                                           to_unorm(5,src.r),11));
-                break;
-
-            case kBGRA_8888_SkColorType: std::swap(src.r, src.b);  [[fallthrough]];
-            case  kRGB_888x_SkColorType:                           [[fallthrough]];
-            case kRGBA_8888_SkColorType:
-                 store32(dst_ptr, pack(pack(to_unorm(8, src.r),
-                                            to_unorm(8, src.g), 8),
-                                       pack(to_unorm(8, src.b),
-                                            to_unorm(8, src.a), 8), 16));
-                 break;
-
-            case  kBGR_101010x_SkColorType:                          [[fallthrough]];
-            case kBGRA_1010102_SkColorType: std::swap(src.r, src.b); [[fallthrough]];
-            case  kRGB_101010x_SkColorType:                          [[fallthrough]];
-            case kRGBA_1010102_SkColorType:
-                 store32(dst_ptr, pack(pack(to_unorm(10, src.r),
-                                            to_unorm(10, src.g), 10),
-                                       pack(to_unorm(10, src.b),
-                                            to_unorm( 2, src.a), 10), 20));
-                 break;
-        }
+        SkAssertResult(store(pixelFormat, dst_ptr, src));
     }