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>
This commit is contained in:
Mike Klein 2020-07-16 10:45:39 -05:00 committed by Skia Commit-Bot
parent 7fe0359130
commit 6514832226
2 changed files with 45 additions and 4 deletions

View File

@ -1204,12 +1204,43 @@ namespace skvm {
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 {};

View File

@ -788,12 +788,22 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p,
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 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p,
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