Always send premul paint color to shader FPs

Fixes a bug with alpha-only image shaders not being modulated by paint
alpha (demonstrated by included GM). Compose shaders were the only
thing relaying on the old behavior, so make those manually unpremul the
input color, with a comment explaining the rationale.

This makes runtime shaders (and other new FPs) simpler to reason about:
sampling a child shader always produces a premul color, even if that
child is null (eg, the input color).

Bug: skia:10556
Change-Id: Ie629a9129d04ea80dae0b263c3811ca754202aab
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/306947
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Osman 2020-07-30 16:49:54 -04:00 committed by Skia Commit-Bot
parent fbd050bd0b
commit e7809c74bc
3 changed files with 30 additions and 4 deletions

View File

@ -58,3 +58,29 @@ DEF_SIMPLE_GM(alpha_image, canvas, 256, 256) {
paint.setMaskFilter(nullptr);
canvas->drawImage(image.get(), 144, 144, &paint);
}
// Created to demonstrate skbug.com/10556 - GPU backend was failing to apply paint alpha to
// alpha-only image shaders. The two boxes should look the same.
DEF_SIMPLE_GM(alpha_image_alpha_tint, canvas, 152, 80) {
canvas->clear(SK_ColorGRAY);
SkBitmap bm;
bm.allocPixels(SkImageInfo::MakeA8(64, 64));
for (int y = 0; y < bm.height(); ++y) {
for (int x = 0; x < bm.width(); ++x) {
*bm.getAddr8(x, y) = y * 4;
}
}
bm.setImmutable();
auto image = SkImage::MakeFromBitmap(bm);
SkPaint paint;
paint.setColor4f({ 0, 1, 0, 0.5f });
canvas->translate(8, 8);
canvas->drawImage(image.get(), 0, 0, &paint);
canvas->translate(72, 0);
paint.setShader(image->makeShader());
canvas->drawRect({ 0, 0, 64, 64 }, paint);
}

View File

@ -266,9 +266,7 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context,
std::move(paintFP), {paintAlpha, paintAlpha, paintAlpha, paintAlpha});
}
} else {
// The shader's FP sees the paint *unpremul* color
SkPMColor4f origColorAsPM = { origColor.fR, origColor.fG, origColor.fB, origColor.fA };
grPaint->setColor4f(origColorAsPM);
grPaint->setColor4f(origColor.premul());
}
} else {
if (primColorMode) {

View File

@ -287,7 +287,9 @@ void GLBlendFragmentProcessor::emitCode(EmitArgs& args) {
case BlendBehavior::kComposeTwoBehavior:
// Compose-two operations historically have forced the input color to opaque.
fragBuilder->codeAppendf("half4 inputOpaque = %s.rgb1;\n", args.fInputColor);
// We're going to re-apply the input color's alpha below, so feed the *unpremul* RGB
// to the children, to avoid double-applying alpha.
fragBuilder->codeAppendf("half4 inputOpaque = unpremul(%s).rgb1;\n", args.fInputColor);
srcColor = this->invokeChild(0, "inputOpaque", args);
dstColor = this->invokeChild(1, "inputOpaque", args);
break;