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