Implement SkBlender support in SkVM.
A lot of the SkVM-related setup was already hooked up in http://review.skia.org/416916. This CL finishes the job by hooking up the SkPaint's SkBlender field to SkVM, and adds various checks throughout Skia's software drawing code that can detect the presence of an SkBlender. Since only SkVM knows how to render an SkBlender correctly, we now need to avoid the legacy blitter and RasterPipeline blitter whenever an SkBlender is present on the paint. This CL fixes the cases that I've found so far, while testing rendering with ovals and images. I'm sure there are more cases lurking; these will be uncovered and dealt with in future CLs. Change-Id: I1a7b3d6625352b3cba8e4f8d4c61129d08ac6ae7 Bug: skia:12080 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/419576 Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com> Reviewed-by: Mike Reed <reed@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
3177f853ea
commit
9a2aa9708f
@ -467,6 +467,10 @@ void SkBitmapDevice::drawImageRect(const SkImage* image, const SkRect* src, cons
|
||||
}
|
||||
}
|
||||
|
||||
if (paint.getBlender()) {
|
||||
goto USE_SHADER;
|
||||
}
|
||||
|
||||
if (src && !src->contains(bitmapBounds) &&
|
||||
SkCanvas::kFast_SrcRectConstraint == constraint &&
|
||||
sampling != SkSamplingOptions()) {
|
||||
|
@ -662,6 +662,7 @@ bool SkBlitter::UseLegacyBlitter(const SkPixmap& device,
|
||||
|
||||
// The legacy blitters cannot handle any of these complex features (anymore).
|
||||
if (device.alphaType() == kUnpremul_SkAlphaType ||
|
||||
paint.getBlender() ||
|
||||
paint.getBlendMode() > SkBlendMode::kLastCoeffMode ||
|
||||
(mf && mf->getFormat() == SkMask::k3D_Format)) {
|
||||
return false;
|
||||
@ -703,26 +704,28 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device,
|
||||
// We may tweak the original paint as we go.
|
||||
SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
|
||||
|
||||
// We have the most fast-paths for SrcOver, so see if we can act like SrcOver.
|
||||
if (paint->getBlendMode() != SkBlendMode::kSrcOver) {
|
||||
switch (SkInterpretXfermode(*paint, SkColorTypeIsAlwaysOpaque(device.colorType()))) {
|
||||
case kSrcOver_SkXfermodeInterpretation:
|
||||
paint.writable()->setBlendMode(SkBlendMode::kSrcOver);
|
||||
break;
|
||||
case kSkipDrawing_SkXfermodeInterpretation:
|
||||
return alloc->make<SkNullBlitter>();
|
||||
default:
|
||||
break;
|
||||
if (!paint->getBlender()) {
|
||||
// We have the most fast-paths for SrcOver, so see if we can act like SrcOver.
|
||||
if (paint->getBlendMode() != SkBlendMode::kSrcOver) {
|
||||
switch (SkInterpretXfermode(*paint, SkColorTypeIsAlwaysOpaque(device.colorType()))) {
|
||||
case kSrcOver_SkXfermodeInterpretation:
|
||||
paint.writable()->setBlendMode(SkBlendMode::kSrcOver);
|
||||
break;
|
||||
case kSkipDrawing_SkXfermodeInterpretation:
|
||||
return alloc->make<SkNullBlitter>();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A Clear blend mode will ignore the entire color pipeline, as if Src mode with 0x00000000.
|
||||
if (paint->getBlendMode() == SkBlendMode::kClear) {
|
||||
SkPaint* p = paint.writable();
|
||||
p->setShader(nullptr);
|
||||
p->setColorFilter(nullptr);
|
||||
p->setBlendMode(SkBlendMode::kSrc);
|
||||
p->setColor(0x00000000);
|
||||
// A Clear blend mode will ignore the entire color pipeline, as if Src mode with 0x00000000.
|
||||
if (paint->getBlendMode() == SkBlendMode::kClear) {
|
||||
SkPaint* p = paint.writable();
|
||||
p->setShader(nullptr);
|
||||
p->setColorFilter(nullptr);
|
||||
p->setBlendMode(SkBlendMode::kSrc);
|
||||
p->setColor(0x00000000);
|
||||
}
|
||||
}
|
||||
|
||||
if (paint->getColorFilter()) {
|
||||
|
@ -2131,7 +2131,7 @@ void SkCanvas::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
|
||||
}
|
||||
|
||||
if (realPaint.getImageFilter() &&
|
||||
this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), sampling, realPaint) &&
|
||||
this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), sampling, realPaint) &&
|
||||
!image_to_color_filter(&realPaint)) {
|
||||
// Evaluate the image filter directly on the input image and then draw the result, instead
|
||||
// of first drawing the image to a temporary layer and filtering.
|
||||
|
@ -1127,7 +1127,8 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
|
||||
SkDraw draw(*this);
|
||||
draw.fMatrixProvider = &matrixProvider;
|
||||
|
||||
if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
|
||||
if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter() &&
|
||||
!paint->getBlender()) {
|
||||
draw.drawBitmapAsMask(bitmap, sampling, *paint);
|
||||
} else {
|
||||
SkPaint paintWithShader = make_paint_with_image(*paint, bitmap, sampling);
|
||||
|
@ -90,6 +90,11 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
|
||||
const SkMatrixProvider& matrixProvider,
|
||||
SkArenaAlloc* alloc,
|
||||
sk_sp<SkShader> clipShader) {
|
||||
if (paint.getBlender()) {
|
||||
// The raster pipeline doesn't support SkBlender.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkColorSpace* dstCS = dst.colorSpace();
|
||||
SkColorType dstCT = dst.colorType();
|
||||
SkColor4f paintColor = paint.getColor4f();
|
||||
|
@ -357,7 +357,7 @@ namespace {
|
||||
}
|
||||
|
||||
// Clamp to fit destination color format if needed.
|
||||
if (src_in_gamut) {
|
||||
if (!params.blender && src_in_gamut) {
|
||||
// An in-gamut src blended with an in-gamut dst should stay in gamut.
|
||||
// Being in-gamut implies all channels are in [0,1], so no need to clamp.
|
||||
// We allow one ulp error above 1.0f, and about that much (~1.2e-7) below 0.
|
||||
@ -556,6 +556,9 @@ namespace {
|
||||
shader = sk_make_sp<DitherShader>(std::move(shader));
|
||||
}
|
||||
|
||||
// Add the user blend function.
|
||||
sk_sp<SkBlender> blender = paint.refBlender();
|
||||
|
||||
// The most common blend mode is SrcOver, and it can be strength-reduced
|
||||
// _greatly_ to Src mode when the shader is opaque.
|
||||
//
|
||||
@ -570,8 +573,8 @@ namespace {
|
||||
// not just a property of the uniforms. The shader program hash includes
|
||||
// this information, making it safe to use anywhere in the blitter codegen.
|
||||
SkBlendMode blendMode = paint.getBlendMode();
|
||||
if (blendMode == SkBlendMode::kSrcOver && shader->isOpaque()) {
|
||||
blendMode = SkBlendMode::kSrc;
|
||||
if ((blendMode == SkBlendMode::kSrcOver && shader->isOpaque()) || blender) {
|
||||
blendMode = SkBlendMode::kSrc;
|
||||
}
|
||||
|
||||
SkColor4f paintColor = paint.getColor4f();
|
||||
@ -582,7 +585,7 @@ namespace {
|
||||
return {
|
||||
std::move(shader),
|
||||
std::move(clip),
|
||||
/*blender=*/nullptr,
|
||||
std::move(blender),
|
||||
{ device.colorType(), device.alphaType(), device.refColorSpace() },
|
||||
blendMode,
|
||||
Coverage::Full, // Placeholder... withCoverage() will change as needed.
|
||||
|
@ -604,8 +604,7 @@ static void test_RuntimeEffect_Blenders(skiatest::Reporter* r, GrRecordingContex
|
||||
}
|
||||
|
||||
DEF_TEST(SkRuntimeEffect_Blender_CPU, r) {
|
||||
// TODO(skia:12080): add CPU support for SkBlender
|
||||
// test_RuntimeEffect_Blenders(r, /*rContext=*/nullptr);
|
||||
test_RuntimeEffect_Blenders(r, /*rContext=*/nullptr);
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeEffect_Blender_GPU, r, ctxInfo) {
|
||||
|
Loading…
Reference in New Issue
Block a user