handle unpremul in skvm blitter
- Centralize unpremul() and premul(). - Handle unpremul surfaces. - Handle unpremul images. Change-Id: I99967c66f73fefe5940bb17d1ecc3e6d85559cf8 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/262504 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
d9ecf8bb93
commit
4bc86d590e
@ -85,18 +85,8 @@ bool SkColorFilter_Matrix::onProgram(skvm::Builder* p,
|
||||
skvm::F32* r, skvm::F32* g, skvm::F32* b, skvm::F32* a) const {
|
||||
// TODO: specialize generated code on the 0/1 values of fMatrix?
|
||||
if (fDomain == Domain::kRGBA) {
|
||||
// Unpremul.
|
||||
skvm::F32 invA = p->div(p->splat(1.0f), *a),
|
||||
inf = p->bit_cast(p->splat(0x7f800000));
|
||||
p->unpremul(r,g,b,*a);
|
||||
|
||||
// If *a is 0, so are *r,*g,*b, so set invA to 0 to avoid 0*inf=NaN (instead 0*0 = 0).
|
||||
invA = p->bit_cast(p->bit_and(p->lt(invA, inf),
|
||||
p->bit_cast(invA)));
|
||||
*r = p->mul(*r, invA);
|
||||
*g = p->mul(*g, invA);
|
||||
*b = p->mul(*b, invA);
|
||||
|
||||
// Apply matrix.
|
||||
skvm::Builder::Uniform u = uniforms->pushF(fMatrix, 20);
|
||||
auto m = [&](int i) { return p->uniformF(u.ptr, u.offset + 4*i); };
|
||||
|
||||
@ -113,11 +103,7 @@ bool SkColorFilter_Matrix::onProgram(skvm::Builder* p,
|
||||
*b = rgba[2];
|
||||
*a = rgba[3];
|
||||
|
||||
// Premul.
|
||||
*r = p->mul(*r, *a);
|
||||
*g = p->mul(*g, *a);
|
||||
*b = p->mul(*b, *a);
|
||||
|
||||
p->premul(r,g,b,*a);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -797,6 +797,22 @@ namespace skvm {
|
||||
};
|
||||
}
|
||||
|
||||
void Builder::unpremul(F32* r, F32* g, F32* b, F32 a) {
|
||||
skvm::F32 invA = div(splat(1.0f), a),
|
||||
inf = bit_cast(splat(0x7f800000));
|
||||
// If a is 0, so are *r,*g,*b, so set invA to 0 to avoid 0*inf=NaN (instead 0*0 = 0).
|
||||
invA = bit_cast(bit_and(lt(invA, inf),
|
||||
bit_cast(invA)));
|
||||
*r = mul(*r, invA);
|
||||
*g = mul(*g, invA);
|
||||
*b = mul(*b, invA);
|
||||
}
|
||||
|
||||
void Builder::premul(F32* r, F32* g, F32* b, F32 a) {
|
||||
*r = mul(*r, a);
|
||||
*g = mul(*g, a);
|
||||
*b = mul(*b, a);
|
||||
}
|
||||
|
||||
// ~~~~ Program::eval() and co. ~~~~ //
|
||||
|
||||
|
@ -489,6 +489,9 @@ namespace skvm {
|
||||
Color unpack_8888(I32 rgba);
|
||||
Color unpack_565 (I32 bgr ); // bottom 16 bits
|
||||
|
||||
void premul(F32* r, F32* g, F32* b, F32 a);
|
||||
void unpremul(F32* r, F32* g, F32* b, F32 a);
|
||||
|
||||
void dump(SkWStream* = nullptr) const;
|
||||
|
||||
uint32_t hash() const;
|
||||
|
@ -145,8 +145,6 @@ namespace {
|
||||
case kBGRA_8888_SkColorType: break;
|
||||
}
|
||||
|
||||
if (params.alphaType == kUnpremul_SkAlphaType) { *ok = false; }
|
||||
|
||||
if (!skvm::BlendModeSupported(params.blendMode)) {
|
||||
*ok = false;
|
||||
}
|
||||
@ -279,10 +277,11 @@ namespace {
|
||||
// opaque, ignoring any math that disagrees. So anything involving force_opaque is
|
||||
// optional, and sometimes helps cut a small amount of work in these programs.
|
||||
const bool force_opaque = true && params.alphaType == kOpaque_SkAlphaType;
|
||||
if (force_opaque) { dst.a = splat(1.0f); }
|
||||
|
||||
// We'd need to premul dst after loading and unpremul before storing.
|
||||
if (params.alphaType == kUnpremul_SkAlphaType) { SkUNREACHABLE; }
|
||||
if (force_opaque) {
|
||||
dst.a = splat(1.0f);
|
||||
} else if (params.alphaType == kUnpremul_SkAlphaType) {
|
||||
premul(&dst.r, &dst.g, &dst.b, dst.a);
|
||||
}
|
||||
|
||||
src = skvm::BlendModeProgram(this, params.blendMode, src, dst);
|
||||
|
||||
@ -304,7 +303,11 @@ namespace {
|
||||
assert_true(gte(src.a, splat(0.0f)));
|
||||
assert_true(lte(src.a, splat(1.0f)));
|
||||
}
|
||||
if (force_opaque) { src.a = splat(1.0f); }
|
||||
if (force_opaque) {
|
||||
src.a = splat(1.0f);
|
||||
} else if (params.alphaType == kUnpremul_SkAlphaType) {
|
||||
unpremul(&src.r, &src.g, &src.b, src.a);
|
||||
}
|
||||
|
||||
// Store back to the destination.
|
||||
switch (params.colorType) {
|
||||
|
@ -663,11 +663,6 @@ bool SkImageShader::onProgram(skvm::Builder* p,
|
||||
quality = state.quality();
|
||||
tweak_quality_and_inv_matrix(&quality, &inv);
|
||||
|
||||
// TODO: and need to extend lifetime of this too once supporting steps.flags.mask() != 0.
|
||||
SkColorSpaceXformSteps steps{pm.colorSpace(), pm.alphaType(),
|
||||
dstCS, kPremul_SkAlphaType};
|
||||
|
||||
if (steps.flags.mask() != 0) { return false; }
|
||||
if (quality != kNone_SkFilterQuality) { return false; }
|
||||
|
||||
// Apply matrix to convert dst coords to sample coords.
|
||||
@ -765,10 +760,25 @@ bool SkImageShader::onProgram(skvm::Builder* p,
|
||||
c.a = p->bit_cast(p->bit_and(mask, p->bit_cast(c.a)));
|
||||
}
|
||||
|
||||
// This point corresponds roughly to when we're done with individual
|
||||
// samples and resolve our final color. The distinction is moot while
|
||||
// we only support kNone quality, which is one sample.
|
||||
*r = c.r;
|
||||
*g = c.g;
|
||||
*b = c.b;
|
||||
*a = c.a;
|
||||
|
||||
// Follow SkColorSpaceXformSteps to match shader output convention (dstCS, premul).
|
||||
// TODO: may need to extend lifetime once doing actual transforms? maybe all in uniforms.
|
||||
auto flags = SkColorSpaceXformSteps{pm.colorSpace(), pm.alphaType(),
|
||||
dstCS, kPremul_SkAlphaType}.flags;
|
||||
|
||||
// TODO: once this all works, move it to SkColorSpaceXformSteps
|
||||
if (flags.unpremul) { p->unpremul(r,g,b,*a); }
|
||||
if (flags.linearize) { return false; }
|
||||
if (flags.gamut_transform) { return false; }
|
||||
if (flags.encode) { return false; }
|
||||
if (flags.premul) { p->premul(r,g,b,*a); }
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user