support 64-bit PixelFormats

RGBA U16/F16 diffs both look pretty much good here.

There are a few F16 diffs to look at, but those are likely one-off diffs
in effect implementation (e.g. SkRasterPipeline clamping somewhere we've
since decided to not clamp in the new SkVM implementation).

Last thing TODO is JIT 64-bit loads and stores to get this all to JIT.

Change-Id: Iadc65c1fc13c32d67d7c7243312d4c90d921dbde
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/303272
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Klein 2020-07-16 15:11:27 -05:00 committed by Skia Commit-Bot
parent 278b4a6b99
commit 9662fd6cbd
2 changed files with 72 additions and 59 deletions

View File

@ -1146,11 +1146,11 @@ namespace skvm {
switch (ct) {
case kUnknown_SkColorType: SkASSERT(false); return false;
// TODO: >32-bit formats
case kRGBA_F16Norm_SkColorType:
case kRGBA_F16_SkColorType:
case kRGBA_F32_SkColorType:
case kR16G16B16A16_unorm_SkColorType: return false;
case kRGBA_F32_SkColorType: return false; // TODO?
case kRGBA_F16Norm_SkColorType: *f = {HALF ,16,16,16,16, 0,16,32,48}; return true;
case kRGBA_F16_SkColorType: *f = {HALF ,16,16,16,16, 0,16,32,48}; return true;
case kR16G16B16A16_unorm_SkColorType: *f = {UNORM,16,16,16,16, 0,16,32,48}; return true;
case kA16_float_SkColorType: *f = {HALF, 0, 0,0,16, 0, 0,0,0}; return true;
case kR16G16_float_SkColorType: *f = {HALF, 16,16,0, 0, 0,16,0,0}; return true;
@ -1177,7 +1177,18 @@ namespace skvm {
return false;
}
static int byte_size(PixelFormat f) {
// What's the highest bit we read?
int bits = std::max(f.r_bits + f.r_shift,
std::max(f.g_bits + f.g_shift,
std::max(f.b_bits + f.b_shift,
f.a_bits + f.a_shift)));
// Round up to bytes.
return (bits + 7) / 8;
}
static Color unpack(PixelFormat f, I32 x) {
SkASSERT(byte_size(f) <= 4);
auto unpack_channel = [=](int bits, int shift) {
I32 channel = extract(x, shift, (1<<bits)-1);
switch (f.encoding) {
@ -1194,27 +1205,6 @@ namespace skvm {
};
}
static int byte_size(PixelFormat f) {
// What's the highest bit we read?
int bits = std::max(f.r_bits + f.r_shift,
std::max(f.g_bits + f.g_shift,
std::max(f.b_bits + f.b_shift,
f.a_bits + f.a_shift)));
// Round up to bytes.
return (bits + 7) / 8;
}
Color Builder::load(PixelFormat f, Arg ptr) {
switch (byte_size(f)) {
case 1: return unpack(f, load8 (ptr));
case 2: return unpack(f, load16(ptr));
case 4: return unpack(f, load32(ptr));
// TODO: 8,16
default: SkUNREACHABLE;
}
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.
@ -1234,6 +1224,29 @@ namespace skvm {
SkASSERT(byte_size(*hi) == 4);
}
Color Builder::load(PixelFormat f, Arg ptr) {
switch (byte_size(f)) {
case 1: return unpack(f, load8 (ptr));
case 2: return unpack(f, load16(ptr));
case 4: return unpack(f, load32(ptr));
case 8: {
PixelFormat lo,hi;
split_disjoint_8byte_format(f, &lo,&hi);
Color l = unpack(lo, load64_lo(ptr)),
h = unpack(hi, load64_hi(ptr));
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 {};
}
Color Builder::gather(PixelFormat f, Arg ptr, int offset, I32 index) {
switch (byte_size(f)) {
case 1: return unpack(f, gather8 (ptr, offset, index));
@ -1251,12 +1264,30 @@ namespace skvm {
lo.a_bits ? l.a : h.a,
};
}
// TODO: 16
// TODO: 16?
default: SkUNREACHABLE;
}
return {};
}
static I32 pack32(PixelFormat f, Color c) {
SkASSERT(byte_size(f) <= 4);
I32 packed = c->splat(0);
auto pack_channel = [&](F32 channel, int bits, int shift) {
I32 encoded;
switch (f.encoding) {
case PixelFormat::UNORM: encoded = to_unorm(bits, channel); break;
case PixelFormat::HALF: encoded = to_half ( channel); break;
}
packed = pack(packed, encoded, shift);
};
if (f.r_bits) { pack_channel(c.r, f.r_bits, f.r_shift); }
if (f.g_bits) { pack_channel(c.g, f.g_bits, f.g_shift); }
if (f.b_bits) { pack_channel(c.b, f.b_bits, f.b_shift); }
if (f.a_bits) { pack_channel(c.a, f.a_bits, f.a_shift); }
return packed;
}
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 &&
@ -1269,26 +1300,18 @@ namespace skvm {
f.g_bits = f.b_bits = 0;
}
auto pack_channel = [=](I32 dst, F32 channel, int bits, int shift) {
I32 encoded;
switch (f.encoding) {
case PixelFormat::UNORM: encoded = to_unorm(bits, channel); break;
case PixelFormat::HALF: encoded = to_half ( channel); break;
}
return pack(dst, encoded, shift);
};
I32 dst = splat(0);
if (f.r_bits) { dst = pack_channel(dst, c.r, f.r_bits, f.r_shift); }
if (f.g_bits) { dst = pack_channel(dst, c.g, f.g_bits, f.g_shift); }
if (f.b_bits) { dst = pack_channel(dst, c.b, f.b_bits, f.b_shift); }
if (f.a_bits) { dst = pack_channel(dst, c.a, f.a_bits, f.a_shift); }
switch (byte_size(f)) {
case 1: store8 (ptr, dst); return true;
case 2: store16(ptr, dst); return true;
case 4: store32(ptr, dst); return true;
// TODO: 8,16
case 1: store8 (ptr, pack32(f,c)); return true;
case 2: store16(ptr, pack32(f,c)); return true;
case 4: store32(ptr, pack32(f,c)); return true;
case 8: {
PixelFormat lo,hi;
split_disjoint_8byte_format(f, &lo,&hi);
store64(ptr, pack32(lo,c)
, pack32(hi,c));
return true;
}
// TODO: 16?
default: SkUNREACHABLE;
}
return false;

View File

@ -791,22 +791,12 @@ 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 && !temporary_ct_to_pixel_format(upper->colorType(), &unused)) {
if (true && !SkColorType_to_PixelFormat(upper->colorType(), &unused)) {
return {};
}
if (lower && !temporary_ct_to_pixel_format(lower->colorType(), &unused)) {
if (lower && !SkColorType_to_PixelFormat(lower->colorType(), &unused)) {
return {};
}
@ -847,7 +837,7 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p,
auto setup_uniforms = [&](const SkPixmap& pm) -> Uniforms {
skvm::PixelFormat pixelFormat;
SkAssertResult(temporary_ct_to_pixel_format(pm.colorType(), &pixelFormat));
SkAssertResult(SkColorType_to_PixelFormat(pm.colorType(), &pixelFormat));
return {
p->uniformF(uniforms->pushF( pm.width())),
p->uniformF(uniforms->pushF(1.0f/pm.width())), // iff tileX == kRepeat