diff options
author | Brian Osman <brianosman@google.com> | 2017-10-19 12:54:28 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-10-19 20:07:44 +0000 |
commit | a4aa1332a4c6a70d6c54a3bbc6172d26fc2dce15 (patch) | |
tree | e6ab58d4ba8a3f636acb357ed75fe12cb31f6f53 | |
parent | 5f379a8b117f68b2087ab4b400b7d2f110f5600c (diff) |
Remove color space xform from alpha threshold FP
This does math on the sampled color. In order to do that math in the
destination color space, I split the behavior up - the threshold FP
now operates on the input color, and we construct a series with a
simple texture effect (possibly wrapped in a color xform), then the
threshold.
I also added a GM that verifies this behavior. All other GMs using
this effect were operating on a layer source, which is always
created in the destination color space. The new GM explicitly makes
a DAG with an image source, so the alpha threshold filter needs to
handle any color space mismatch.
Bug: skia:
Change-Id: I1ed08c99f4eed17f68176bf751677a3ae1614fe3
Reviewed-on: https://skia-review.googlesource.com/61942
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
-rw-r--r-- | gm/imagealphathreshold.cpp | 42 | ||||
-rw-r--r-- | src/effects/GrAlphaThresholdFragmentProcessor.cpp | 47 | ||||
-rw-r--r-- | src/effects/GrAlphaThresholdFragmentProcessor.fp | 26 | ||||
-rw-r--r-- | src/effects/GrAlphaThresholdFragmentProcessor.h | 21 | ||||
-rw-r--r-- | src/effects/SkAlphaThresholdFilter.cpp | 27 |
5 files changed, 76 insertions, 87 deletions
diff --git a/gm/imagealphathreshold.cpp b/gm/imagealphathreshold.cpp index 4a35018435..6d01722d0a 100644 --- a/gm/imagealphathreshold.cpp +++ b/gm/imagealphathreshold.cpp @@ -7,7 +7,9 @@ #include "gm.h" #include "SkAlphaThresholdFilter.h" +#include "SkImageSource.h" #include "SkOffsetImageFilter.h" +#include "SkRandom.h" #include "SkRegion.h" #include "SkSurface.h" @@ -153,3 +155,43 @@ private: DEF_GM(return new ImageAlphaThresholdGM(true);) DEF_GM(return new ImageAlphaThresholdGM(false);) DEF_GM(return new ImageAlphaThresholdSurfaceGM();) + +////////////////////////////////////////////////////////////////////////////// + +static sk_sp<SkImage> make_img() { + SkBitmap bitmap; + bitmap.allocPixels(SkImageInfo::MakeS32(WIDTH, HEIGHT, kPremul_SkAlphaType)); + SkCanvas canvas(bitmap); + + SkPaint paint; + SkRect rect = SkRect::MakeWH(WIDTH, HEIGHT); + SkRandom rnd; + + while (!rect.isEmpty()) { + paint.setColor(rnd.nextU() | (0xFF << 24)); + canvas.drawRect(rect, paint); + rect.inset(25, 25); + } + + return SkImage::MakeFromBitmap(bitmap); +} + +DEF_SIMPLE_GM_BG(imagealphathreshold_image, canvas, WIDTH * 2, HEIGHT, SK_ColorBLACK) { + sk_sp<SkImage> image(make_img()); + + SkIRect rects[2]; + rects[0] = SkIRect::MakeXYWH(0, 150, WIDTH, HEIGHT - 300); + rects[1] = SkIRect::MakeXYWH(150, 0, WIDTH - 300, HEIGHT); + SkRegion region; + region.setRects(rects, 2); + + SkPaint filterPaint; + sk_sp<SkImageFilter> imageSource(SkImageSource::Make(image)); + filterPaint.setImageFilter(SkAlphaThresholdFilter::Make(region, 0.2f, 0.7f, + std::move(imageSource))); + + canvas->saveLayer(nullptr, &filterPaint); + canvas->restore(); + canvas->translate(WIDTH, 0); + canvas->drawImage(image, 0, 0); +} diff --git a/src/effects/GrAlphaThresholdFragmentProcessor.cpp b/src/effects/GrAlphaThresholdFragmentProcessor.cpp index 5ef0221be7..871d6084d1 100644 --- a/src/effects/GrAlphaThresholdFragmentProcessor.cpp +++ b/src/effects/GrAlphaThresholdFragmentProcessor.cpp @@ -34,39 +34,25 @@ public: const GrAlphaThresholdFragmentProcessor& _outer = args.fFp.cast<GrAlphaThresholdFragmentProcessor>(); (void)_outer; - auto colorXform = _outer.colorXform(); - (void)colorXform; auto innerThreshold = _outer.innerThreshold(); (void)innerThreshold; auto outerThreshold = _outer.outerThreshold(); (void)outerThreshold; - fColorSpaceHelper.emitCode(args.fUniformHandler, _outer.colorXform().get()); fInnerThresholdVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kHalf_GrSLType, kDefault_GrSLPrecision, "innerThreshold"); fOuterThresholdVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kHalf_GrSLType, kDefault_GrSLPrecision, "outerThreshold"); SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); - SkString sk_TransformedCoords2D_1 = fragBuilder->ensureCoords2D(args.fTransformedCoords[1]); fragBuilder->codeAppendf( - "half4 _tmpVar1;half4 color = %stexture(%s, %s).%s%s;\nhalf4 mask_color = " - "texture(%s, %s).%s;\nif (float(mask_color.w) < 0.5) {\n if (color.w > %s) {\n " - " half scale = %s / color.w;\n color.xyz *= scale;\n color.w = " - "%s;\n }\n} else if (color.w < %s) {\n half scale = float(%s) / max(0.001, " - "float(color.w));\n color.xyz *= scale;\n color.w = %s;\n}\n%s = color;\n", - fColorSpaceHelper.isValid() ? "(_tmpVar1 = " : "", + "half4 color = %s;\nhalf4 mask_color = texture(%s, %s).%s;\nif " + "(float(mask_color.w) < 0.5) {\n if (color.w > %s) {\n half scale = %s / " + "color.w;\n color.xyz *= scale;\n color.w = %s;\n }\n} else if " + "(color.w < %s) {\n half scale = float(%s) / max(0.001, float(color.w));\n " + "color.xyz *= scale;\n color.w = %s;\n}\n%s = color;\n", + args.fInputColor ? args.fInputColor : "half4(1)", fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), sk_TransformedCoords2D_0.c_str(), fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(), - fColorSpaceHelper.isValid() - ? SkStringPrintf(", half4(clamp((%s * half4(_tmpVar1.rgb, 1.0)).rgb, 0.0, " - "_tmpVar1.a), _tmpVar1.a))", - args.fUniformHandler->getUniformCStr( - fColorSpaceHelper.gamutXformUniform())) - .c_str() - : "", - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[1]).c_str(), - sk_TransformedCoords2D_1.c_str(), - fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[1]).c_str(), args.fUniformHandler->getUniformCStr(fOuterThresholdVar), args.fUniformHandler->getUniformCStr(fOuterThresholdVar), args.fUniformHandler->getUniformCStr(fOuterThresholdVar), @@ -81,31 +67,22 @@ private: const GrAlphaThresholdFragmentProcessor& _outer = _proc.cast<GrAlphaThresholdFragmentProcessor>(); { - if (fColorSpaceHelper.isValid()) { - fColorSpaceHelper.setData(pdman, _outer.colorXform().get()); - } pdman.set1f(fInnerThresholdVar, _outer.innerThreshold()); pdman.set1f(fOuterThresholdVar, _outer.outerThreshold()); } } - UniformHandle fImageVar; UniformHandle fMaskVar; UniformHandle fInnerThresholdVar; UniformHandle fOuterThresholdVar; - GrGLSLColorSpaceXformHelper fColorSpaceHelper; }; GrGLSLFragmentProcessor* GrAlphaThresholdFragmentProcessor::onCreateGLSLInstance() const { return new GrGLSLAlphaThresholdFragmentProcessor(); } void GrAlphaThresholdFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const { - b->add32(GrColorSpaceXform::XformKey(fColorXform.get())); -} + GrProcessorKeyBuilder* b) const {} bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const { const GrAlphaThresholdFragmentProcessor& that = other.cast<GrAlphaThresholdFragmentProcessor>(); (void)that; - if (fImage != that.fImage) return false; - if (fColorXform != that.fColorXform) return false; if (fMask != that.fMask) return false; if (fInnerThreshold != that.fInnerThreshold) return false; if (fOuterThreshold != that.fOuterThreshold) return false; @@ -114,16 +91,11 @@ bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& oth GrAlphaThresholdFragmentProcessor::GrAlphaThresholdFragmentProcessor( const GrAlphaThresholdFragmentProcessor& src) : INHERITED(kGrAlphaThresholdFragmentProcessor_ClassID, src.optimizationFlags()) - , fImage(src.fImage) - , fColorXform(src.fColorXform) , fMask(src.fMask) , fInnerThreshold(src.fInnerThreshold) , fOuterThreshold(src.fOuterThreshold) - , fImageCoordTransform(src.fImageCoordTransform) , fMaskCoordTransform(src.fMaskCoordTransform) { - this->addTextureSampler(&fImage); this->addTextureSampler(&fMask); - this->addCoordTransform(&fImageCoordTransform); this->addCoordTransform(&fMaskCoordTransform); } std::unique_ptr<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::clone() const { @@ -133,7 +105,6 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAlphaThresholdFragmentProcessor); #if GR_TEST_UTILS std::unique_ptr<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::TestCreate( GrProcessorTestData* testData) { - sk_sp<GrTextureProxy> bmpProxy = testData->textureProxy(GrProcessorUnitTest::kSkiaPMTextureIdx); sk_sp<GrTextureProxy> maskProxy = testData->textureProxy(GrProcessorUnitTest::kAlphaTextureIdx); // Make the inner and outer thresholds be in (0, 1) exclusive and be sorted correctly. float innerThresh = testData->fRandom->nextUScalar1() * .99f + 0.005f; @@ -145,9 +116,7 @@ std::unique_ptr<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::TestCrea uint32_t x = testData->fRandom->nextULessThan(kMaxWidth - width); uint32_t y = testData->fRandom->nextULessThan(kMaxHeight - height); SkIRect bounds = SkIRect::MakeXYWH(x, y, width, height); - sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(testData->fRandom); - return GrAlphaThresholdFragmentProcessor::Make(std::move(bmpProxy), colorSpaceXform, - std::move(maskProxy), innerThresh, outerThresh, + return GrAlphaThresholdFragmentProcessor::Make(std::move(maskProxy), innerThresh, outerThresh, bounds); } #endif diff --git a/src/effects/GrAlphaThresholdFragmentProcessor.fp b/src/effects/GrAlphaThresholdFragmentProcessor.fp index 51e15b4f59..f4470cab42 100644 --- a/src/effects/GrAlphaThresholdFragmentProcessor.fp +++ b/src/effects/GrAlphaThresholdFragmentProcessor.fp @@ -1,5 +1,3 @@ -in uniform sampler2D image; -in uniform colorSpaceXform colorXform; in uniform sampler2D mask; in uniform half innerThreshold; in uniform half outerThreshold; @@ -13,21 +11,15 @@ in uniform half outerThreshold; } @make { - static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> image, - sk_sp<GrColorSpaceXform> colorXform, - sk_sp<GrTextureProxy> mask, + static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> mask, float innerThreshold, float outerThreshold, const SkIRect& bounds) { return std::unique_ptr<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor( - image, colorXform, mask, innerThreshold, outerThreshold, bounds)); + mask, innerThreshold, outerThreshold, bounds)); } } -@coordTransform(image) { - SkMatrix::I() -} - @coordTransform(mask) { SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())) } @@ -45,8 +37,8 @@ in uniform half outerThreshold; } void main() { - half4 color = texture(image, sk_TransformedCoords2D[0], colorXform); - half4 mask_color = texture(mask, sk_TransformedCoords2D[1]); + half4 color = sk_InColor; + half4 mask_color = texture(mask, sk_TransformedCoords2D[0]); if (mask_color.a < 0.5) { if (color.a > outerThreshold) { half scale = outerThreshold / color.a; @@ -62,7 +54,6 @@ void main() { } @test(testData) { - sk_sp<GrTextureProxy> bmpProxy = testData->textureProxy(GrProcessorUnitTest::kSkiaPMTextureIdx); sk_sp<GrTextureProxy> maskProxy = testData->textureProxy(GrProcessorUnitTest::kAlphaTextureIdx); // Make the inner and outer thresholds be in (0, 1) exclusive and be sorted correctly. float innerThresh = testData->fRandom->nextUScalar1() * .99f + 0.005f; @@ -74,11 +65,6 @@ void main() { uint32_t x = testData->fRandom->nextULessThan(kMaxWidth - width); uint32_t y = testData->fRandom->nextULessThan(kMaxHeight - height); SkIRect bounds = SkIRect::MakeXYWH(x, y, width, height); - sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(testData->fRandom); - return GrAlphaThresholdFragmentProcessor::Make( - std::move(bmpProxy), - colorSpaceXform, - std::move(maskProxy), - innerThresh, outerThresh, - bounds); + return GrAlphaThresholdFragmentProcessor::Make(std::move(maskProxy), innerThresh, outerThresh, + bounds); } diff --git a/src/effects/GrAlphaThresholdFragmentProcessor.h b/src/effects/GrAlphaThresholdFragmentProcessor.h index 0d8a8e68ad..c376bb1a80 100644 --- a/src/effects/GrAlphaThresholdFragmentProcessor.h +++ b/src/effects/GrAlphaThresholdFragmentProcessor.h @@ -18,55 +18,40 @@ class GrAlphaThresholdFragmentProcessor : public GrFragmentProcessor { public: inline OptimizationFlags optFlags(float outerThreshold); - sk_sp<GrColorSpaceXform> colorXform() const { return fColorXform; } float innerThreshold() const { return fInnerThreshold; } float outerThreshold() const { return fOuterThreshold; } - static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> image, - sk_sp<GrColorSpaceXform> - colorXform, - sk_sp<GrTextureProxy> - mask, + static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> mask, float innerThreshold, float outerThreshold, const SkIRect& bounds) { return std::unique_ptr<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor( - image, colorXform, mask, innerThreshold, outerThreshold, bounds)); + mask, innerThreshold, outerThreshold, bounds)); } GrAlphaThresholdFragmentProcessor(const GrAlphaThresholdFragmentProcessor& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "AlphaThresholdFragmentProcessor"; } private: - GrAlphaThresholdFragmentProcessor(sk_sp<GrTextureProxy> image, - sk_sp<GrColorSpaceXform> colorXform, - sk_sp<GrTextureProxy> mask, float innerThreshold, + GrAlphaThresholdFragmentProcessor(sk_sp<GrTextureProxy> mask, float innerThreshold, float outerThreshold, const SkIRect& bounds) : INHERITED(kGrAlphaThresholdFragmentProcessor_ClassID, kNone_OptimizationFlags) - , fImage(std::move(image)) - , fColorXform(colorXform) , fMask(std::move(mask)) , fInnerThreshold(innerThreshold) , fOuterThreshold(outerThreshold) - , fImageCoordTransform(SkMatrix::I(), fImage.proxy()) , fMaskCoordTransform( SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())), fMask.proxy()) { - this->addTextureSampler(&fImage); this->addTextureSampler(&fMask); - this->addCoordTransform(&fImageCoordTransform); this->addCoordTransform(&fMaskCoordTransform); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST - TextureSampler fImage; - sk_sp<GrColorSpaceXform> fColorXform; TextureSampler fMask; float fInnerThreshold; float fOuterThreshold; - GrCoordTransform fImageCoordTransform; GrCoordTransform fMaskCoordTransform; typedef GrFragmentProcessor INHERITED; }; diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp index 634e6ae08b..f5e4a689e0 100644 --- a/src/effects/SkAlphaThresholdFilter.cpp +++ b/src/effects/SkAlphaThresholdFilter.cpp @@ -20,6 +20,7 @@ #include "GrFixedClip.h" #include "GrRenderTargetContext.h" #include "GrTextureProxy.h" +#include "effects/GrSimpleTextureEffect.h" #endif class SK_API SkAlphaThresholdFilterImpl : public SkImageFilter { @@ -170,19 +171,25 @@ sk_sp<SkSpecialImage> SkAlphaThresholdFilterImpl::onFilterImage(SkSpecialImage* } const OutputProperties& outProps = ctx.outputProperties(); - sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(input->getColorSpace(), - outProps.colorSpace()); - - auto fp = GrAlphaThresholdFragmentProcessor::Make(std::move(inputProxy), - std::move(colorSpaceXform), - std::move(maskProxy), - fInnerThreshold, - fOuterThreshold, - bounds); - if (!fp) { + auto textureFP = GrSimpleTextureEffect::Make(std::move(inputProxy), SkMatrix::I()); + textureFP = GrColorSpaceXformEffect::Make(std::move(textureFP), input->getColorSpace(), + outProps.colorSpace()); + if (!textureFP) { return nullptr; } + auto thresholdFP = GrAlphaThresholdFragmentProcessor::Make(std::move(maskProxy), + fInnerThreshold, + fOuterThreshold, + bounds); + if (!thresholdFP) { + return nullptr; + } + + std::unique_ptr<GrFragmentProcessor> fpSeries[] = { std::move(textureFP), + std::move(thresholdFP) }; + auto fp = GrFragmentProcessor::RunInSeries(fpSeries, 2); + return DrawWithFP(context, std::move(fp), bounds, outProps); } #endif |