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:
parent
fbd050bd0b
commit
e7809c74bc
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user