diff options
-rw-r--r-- | gm/shadermaskfilter.cpp | 52 | ||||
-rw-r--r-- | src/core/SkBlendMode.cpp | 17 | ||||
-rw-r--r-- | src/core/SkCoverageModePriv.h | 8 | ||||
-rw-r--r-- | src/core/SkMaskFilter.cpp | 38 | ||||
-rw-r--r-- | src/gpu/GrProcessorSet.cpp | 3 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice_drawTexture.cpp | 3 |
6 files changed, 93 insertions, 28 deletions
diff --git a/gm/shadermaskfilter.cpp b/gm/shadermaskfilter.cpp index 73a9cda65f..c3efdc832c 100644 --- a/gm/shadermaskfilter.cpp +++ b/gm/shadermaskfilter.cpp @@ -7,13 +7,14 @@ #include "gm.h" #include "sk_tool_utils.h" +#include "SkBlendModePriv.h" #include "SkBlurMaskFilter.h" #include "SkCanvas.h" #include "SkImage.h" #include "SkShaderMaskFilter.h" static void draw_masked_image(SkCanvas* canvas, const SkImage* image, SkScalar x, SkScalar y, - const SkImage* mask, sk_sp<SkMaskFilter> outer = nullptr) { + const SkImage* mask, sk_sp<SkMaskFilter> outer, SkBlendMode mode) { SkMatrix matrix = SkMatrix::MakeScale(SkIntToScalar(image->width()) / mask->width(), SkIntToScalar(image->height() / mask->height())); SkPaint paint; @@ -23,6 +24,7 @@ static void draw_masked_image(SkCanvas* canvas, const SkImage* image, SkScalar x } paint.setMaskFilter(mf); paint.setAntiAlias(true); + paint.setBlendMode(mode); canvas->drawImage(image, x, y, &paint); } @@ -51,19 +53,25 @@ DEF_SIMPLE_GM(shadermaskfilter_gradient, canvas, 512, 512) { } #include "Resources.h" -DEF_SIMPLE_GM(shadermaskfilter_image, canvas, 512, 512) { +DEF_SIMPLE_GM(shadermaskfilter_image, canvas, 560, 370) { canvas->scale(1.25f, 1.25f); auto image = GetResourceAsImage("images/mandrill_128.png"); auto mask = GetResourceAsImage("images/color_wheel.png"); auto blurmf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 5); + auto gradmf = SkShaderMaskFilter::Make(make_shader(SkRect::MakeIWH(mask->width(), + mask->height()))); - canvas->drawImage(image, 10, 10, nullptr); - canvas->drawImage(mask, 10 + image->width() + 10.f, 10, nullptr); - - draw_masked_image(canvas, image.get(), 10, 10 + image->height() + 10.f, mask.get()); - draw_masked_image(canvas, image.get(), 10 + image->width() + 10.f, 10 + image->height() + 10.f, - mask.get(), blurmf); + const sk_sp<SkMaskFilter> array[] = { nullptr , blurmf, gradmf }; + for (SkBlendMode mode : {SkBlendMode::kSrcOver, SkBlendMode::kSrcIn}) { + canvas->save(); + for (sk_sp<SkMaskFilter> mf : array) { + draw_masked_image(canvas, image.get(), 10, 10, mask.get(), mf, mode); + canvas->translate(image->width() + 20.f, 0); + } + canvas->restore(); + canvas->translate(0, image->height() + 20.f); + } } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -90,7 +98,7 @@ const char* gCoverageName[] = { "union", "sect", "diff", "rev-diff", "xor" }; -DEF_SIMPLE_GM(combinemaskfilter, canvas, 565, 250) { +DEF_SIMPLE_GM(combinemaskfilter, canvas, 560, 510) { const SkRect r = { 0, 0, 100, 100 }; SkPaint paint; @@ -102,8 +110,8 @@ DEF_SIMPLE_GM(combinemaskfilter, canvas, 565, 250) { labelP.setTextAlign(SkPaint::kCenter_Align); const SkRect r2 = r.makeOutset(1.5f, 1.5f); - SkPaint paint2; - paint2.setStyle(SkPaint::kStroke_Style); + SkPaint strokePaint; + strokePaint.setStyle(SkPaint::kStroke_Style); auto proc0 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) { pathA->moveTo(r.fLeft, r.fBottom); @@ -132,13 +140,23 @@ DEF_SIMPLE_GM(combinemaskfilter, canvas, 565, 250) { for (int i = 0; i < 5; ++i) { canvas->drawText(gCoverageName[i], strlen(gCoverageName[i]), r.width()*0.5f, -10, labelP); - SkCoverageMode mode = static_cast<SkCoverageMode>(i); + SkCoverageMode cmode = static_cast<SkCoverageMode>(i); canvas->save(); - for (int j = 0; j < 2; ++j) { - paint.setMaskFilter(SkMaskFilter::MakeCombine(mfA[j], mfB[j], mode)); - canvas->drawRect(r2, paint2); - canvas->drawRect(r, paint); - canvas->translate(0, r.height() + 10); + // esp. on gpu side, its valuable to exercise modes that do and do-not convolve coverage + // with alpha. SrcOver and SrcIn have these properties, but also happen to "look" the same + // for this test. + const SkBlendMode bmodes[] = { SkBlendMode::kSrcOver, SkBlendMode::kSrcIn }; + SkASSERT( SkBlendMode_SupportsCoverageAsAlpha(bmodes[0])); // test as-alpha + SkASSERT(!SkBlendMode_SupportsCoverageAsAlpha(bmodes[1])); // test not-as-alpha + for (auto bmode : bmodes) { + paint.setBlendMode(bmode); + for (int j = 0; j < 2; ++j) { + paint.setMaskFilter(SkMaskFilter::MakeCombine(mfA[j], mfB[j], cmode)); + canvas->drawRect(r2, strokePaint); + canvas->drawRect(r, paint); + canvas->translate(0, r.height() + 10); + } + canvas->translate(0, 40); } canvas->restore(); canvas->translate(r.width() + 10, 0); diff --git a/src/core/SkBlendMode.cpp b/src/core/SkBlendMode.cpp index 548106f1c4..661ade6188 100644 --- a/src/core/SkBlendMode.cpp +++ b/src/core/SkBlendMode.cpp @@ -6,6 +6,7 @@ */ #include "SkBlendModePriv.h" +#include "SkCoverageModePriv.h" #include "SkRasterPipeline.h" #include "../jumper/SkJumper.h" @@ -148,3 +149,19 @@ SkPM4f SkBlendMode_Apply(SkBlendMode mode, const SkPM4f& src, const SkPM4f& dst) p.run(0,0, 1,1); return res_storage; } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +const SkBlendMode gUncorrelatedCoverageToBlend[] = { + SkBlendMode::kSrcOver, // or DstOver + SkBlendMode::kSrcIn, // or kDstIn + SkBlendMode::kSrcOut, + SkBlendMode::kDstOut, + SkBlendMode::kXor, +}; + +SkBlendMode SkUncorrelatedCoverageModeToBlendMode(SkCoverageMode cm) { + unsigned index = static_cast<unsigned>(cm); + SkASSERT(index < SK_ARRAY_COUNT(gUncorrelatedCoverageToBlend)); + return gUncorrelatedCoverageToBlend[index]; +} diff --git a/src/core/SkCoverageModePriv.h b/src/core/SkCoverageModePriv.h index d019e60bda..e8b8939ade 100644 --- a/src/core/SkCoverageModePriv.h +++ b/src/core/SkCoverageModePriv.h @@ -11,13 +11,7 @@ #include "SkBlendMode.h" #include "SkCoverageMode.h" -const SkBlendMode gUncorrelatedCoverageToBlend[] = { - SkBlendMode::kSrcOver, // or DstOver - SkBlendMode::kSrcIn, // or kDstIn - SkBlendMode::kSrcOut, - SkBlendMode::kDstOut, - SkBlendMode::kXor, -}; +SkBlendMode SkUncorrelatedCoverageModeToBlendMode(SkCoverageMode); #if 0 // Experimental idea to extend to overlap types diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp index 59baa4fbff..83d5608ecf 100644 --- a/src/core/SkMaskFilter.cpp +++ b/src/core/SkMaskFilter.cpp @@ -21,6 +21,7 @@ #if SK_SUPPORT_GPU #include "GrTextureProxy.h" #include "GrFragmentProcessor.h" +#include "effects/GrXfermodeFragmentProcessor.h" #endif SkMaskFilterBase::NinePatch::~NinePatch() { @@ -411,6 +412,24 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeMF) +protected: +#if SK_SUPPORT_GPU + std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{ + std::unique_ptr<GrFragmentProcessor> array[2] = { + as_MFB(fInner)->asFragmentProcessor(args), + as_MFB(fOuter)->asFragmentProcessor(args), + }; + if (!array[0] || !array[1]) { + return nullptr; + } + return GrFragmentProcessor::RunInSeries(array, 2); + } + + bool onHasFragmentProcessor() const override { + return as_MFB(fInner)->hasFragmentProcessor() && as_MFB(fOuter)->hasFragmentProcessor(); + } +#endif + private: sk_sp<SkMaskFilter> fOuter; sk_sp<SkMaskFilter> fInner; @@ -488,6 +507,23 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkCombineMF) +protected: +#if SK_SUPPORT_GPU + std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{ + auto src = as_MFB(fSrc)->asFragmentProcessor(args); + auto dst = as_MFB(fDst)->asFragmentProcessor(args); + if (!src || !dst) { + return nullptr; + } + return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(src), std::move(dst), + SkUncorrelatedCoverageModeToBlendMode(fMode)); + } + + bool onHasFragmentProcessor() const override { + return as_MFB(fSrc)->hasFragmentProcessor() && as_MFB(fDst)->hasFragmentProcessor(); + } +#endif + private: sk_sp<SkMaskFilter> fDst; sk_sp<SkMaskFilter> fSrc; @@ -570,7 +606,7 @@ bool SkCombineMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm p.setBlendMode(SkBlendMode::kSrc); dstM.fBounds.offset(-dst->fBounds.fLeft, -dst->fBounds.fTop); md.drawAsBitmap(dstM, p); - p.setBlendMode(gUncorrelatedCoverageToBlend[static_cast<int>(fMode)]); + p.setBlendMode(SkUncorrelatedCoverageModeToBlendMode(fMode)); srcM.fBounds.offset(-dst->fBounds.fLeft, -dst->fBounds.fTop); md.drawAsBitmap(srcM, p); diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp index 0601d92db8..919ff47e3f 100644 --- a/src/gpu/GrProcessorSet.cpp +++ b/src/gpu/GrProcessorSet.cpp @@ -181,9 +181,6 @@ GrProcessorSet::Analysis GrProcessorSet::finalize(const GrProcessorAnalysisColor for (int i = 0; i < n; ++i) { if (!fps[i]->compatibleWithCoverageAsAlpha()) { analysis.fCompatibleWithCoverageAsAlpha = false; - // Other than tests that exercise atypical behavior we expect all coverage FPs to be - // compatible with the coverage-as-alpha optimization. - GrCapsDebugf(&caps, "Coverage FP is not compatible with coverage as alpha.\n"); } coverageUsesLocalCoords |= fps[i]->usesLocalCoords(); } diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp index 0798f1e012..b6b1e619c0 100644 --- a/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/src/gpu/SkGpuDevice_drawTexture.cpp @@ -248,6 +248,9 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, // FP. In the future this should be an opaque optimization enabled by the combination of // GrDrawOp/GP and FP. const SkMaskFilter* mf = paint.getMaskFilter(); + if (mf && as_MFB(mf)->hasFragmentProcessor()) { + mf = nullptr; + } // The shader expects proper local coords, so we can't replace local coords with texture coords // if the shader will be used. If we have a mask filter we will change the underlying geometry // that is rendered. |