aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/shadermaskfilter.cpp52
-rw-r--r--src/core/SkBlendMode.cpp17
-rw-r--r--src/core/SkCoverageModePriv.h8
-rw-r--r--src/core/SkMaskFilter.cpp38
-rw-r--r--src/gpu/GrProcessorSet.cpp3
-rw-r--r--src/gpu/SkGpuDevice_drawTexture.cpp3
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.