support 64-bit gather()

This splits 64-bit PixelFormats into two 32-bit parts and gathers both
independently.  E.g.

    F16 = {HALF, 16,16,16,16,  0,16,32,48}
  ~> lo = {HALF, 16,16, 0, 0,  0,16,32,32}
  ~> hi = {HALF,  0, 0,16,16, 32,32, 0,16}

The logic at the end merges the channels we gather from each part.

This all does strongly assume no channel straddles lo/hi, which we
assert.  We'd need to get more clever to handle something like
20-20-20-4.  I'm working on load() and store() now, and they'll need
this same format assumption.

Since I've so far only added support for gather(), I've introduced a
little temporary hack in SkImageShader to let it work just to demo this
all.  This hack will go away when I add support for load and store.

Change-Id: Ic4cfda7922f2e51bb7698adedf6f655de43da630
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/303320
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/src/core/SkVM.cpp b/src/core/SkVM.cpp
index 2f2e086..bd31654 100644
--- a/src/core/SkVM.cpp
+++ b/src/core/SkVM.cpp
@@ -1204,12 +1204,43 @@
         return {};
     }
 
+    static void split_disjoint_8byte_format(PixelFormat f, PixelFormat* lo, PixelFormat* hi) {
+        SkASSERT(byte_size(f) == 8);
+        // We assume some of the channels are in the low 32 bits, some in the high 32 bits.
+        // The assert on byte_size(lo) will trigger if this assumption is violated.
+        *lo = f;
+        if (f.r_shift >= 32) { lo->r_bits = 0; lo->r_shift = 32; }
+        if (f.g_shift >= 32) { lo->g_bits = 0; lo->g_shift = 32; }
+        if (f.b_shift >= 32) { lo->b_bits = 0; lo->b_shift = 32; }
+        if (f.a_shift >= 32) { lo->a_bits = 0; lo->a_shift = 32; }
+        SkASSERT(byte_size(*lo) == 4);
+
+        *hi = f;
+        if (f.r_shift < 32) { hi->r_bits = 0; hi->r_shift = 32; } else { hi->r_shift -= 32; }
+        if (f.g_shift < 32) { hi->g_bits = 0; hi->g_shift = 32; } else { hi->g_shift -= 32; }
+        if (f.b_shift < 32) { hi->b_bits = 0; hi->b_shift = 32; } else { hi->b_shift -= 32; }
+        if (f.a_shift < 32) { hi->a_bits = 0; hi->a_shift = 32; } else { hi->a_shift -= 32; }
+        SkASSERT(byte_size(*hi) == 4);
+    }
+
     Color Builder::gather(PixelFormat f, Arg ptr, int offset, I32 index) {
         switch (byte_size(f)) {
             case 1: return unpack(f, gather8 (ptr, offset, index));
             case 2: return unpack(f, gather16(ptr, offset, index));
             case 4: return unpack(f, gather32(ptr, offset, index));
-            // TODO: 8,16
+            case 8: {
+                PixelFormat lo,hi;
+                split_disjoint_8byte_format(f, &lo,&hi);
+                Color l = unpack(lo, gather32(ptr, offset, (index<<1)+0)),
+                      h = unpack(hi, gather32(ptr, offset, (index<<1)+1));
+                return {
+                    lo.r_bits ? l.r : h.r,
+                    lo.g_bits ? l.g : h.g,
+                    lo.b_bits ? l.b : h.b,
+                    lo.a_bits ? l.a : h.a,
+                };
+            }
+            // TODO: 16
             default: SkUNREACHABLE;
         }
         return {};
diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp
index 77a569e..fcb0990 100755
--- a/src/shaders/SkImageShader.cpp
+++ b/src/shaders/SkImageShader.cpp
@@ -788,12 +788,22 @@
 
     skvm::Coord upperLocal = SkShaderBase::ApplyMatrix(p, upperInv, origLocal, uniforms);
 
+    // We "secretly" know that gather() will work with 64-bit pixel formats
+    // even if SkColorType_to_PixelFormat() returns false.
+    auto temporary_ct_to_pixel_format = [](SkColorType ct, skvm::PixelFormat* f) -> bool {
+        if (ct == kRGBA_F16_SkColorType) {
+            *f = {skvm::PixelFormat::HALF, 16,16,16,16, 0,16,32,48};
+            return true;
+        }
+        return SkColorType_to_PixelFormat(ct, f);
+    };
+
     // Bail out if sample() can't yet handle our image's color type(s).
     skvm::PixelFormat unused;
-    if (true  && !SkColorType_to_PixelFormat(upper->colorType(), &unused)) {
+    if (true  && !temporary_ct_to_pixel_format(upper->colorType(), &unused)) {
         return {};
     }
-    if (lower && !SkColorType_to_PixelFormat(lower->colorType(), &unused)) {
+    if (lower && !temporary_ct_to_pixel_format(lower->colorType(), &unused)) {
         return {};
     }
 
@@ -834,7 +844,7 @@
 
     auto setup_uniforms = [&](const SkPixmap& pm) -> Uniforms {
         skvm::PixelFormat pixelFormat;
-        SkAssertResult(SkColorType_to_PixelFormat(pm.colorType(), &pixelFormat));
+        SkAssertResult(temporary_ct_to_pixel_format(pm.colorType(), &pixelFormat));
         return {
             p->uniformF(uniforms->pushF(     pm.width())),
             p->uniformF(uniforms->pushF(1.0f/pm.width())), // iff tileX == kRepeat