From c4b72720e75313079212e69e46a5ef7c474b2305 Mon Sep 17 00:00:00 2001 From: egdaniel Date: Mon, 23 Nov 2015 13:20:41 -0800 Subject: [PATCH] Don't create a GXPFactory when blend is SrcOver BUG=skia: Review URL: https://codereview.chromium.org/1471053002 --- gm/beziereffects.cpp | 6 ++ gm/bigrrectaaeffect.cpp | 2 + gm/convexpolyeffect.cpp | 4 ++ gm/rrects.cpp | 2 + gm/texturedomaineffect.cpp | 2 + gm/yuvtorgbeffect.cpp | 2 + include/core/SkXfermode.h | 26 +++++--- include/gpu/GrPaint.h | 9 +-- include/gpu/GrXferProcessor.h | 8 --- include/gpu/effects/GrCoverageSetOpXP.h | 5 -- .../gpu/effects/GrPorterDuffXferProcessor.h | 31 ++++++++-- src/core/SkImageFilter.cpp | 1 + src/core/SkXfermode.cpp | 21 +------ src/effects/SkArithmeticMode_gpu.h | 4 -- src/effects/SkBlurMaskFilter.cpp | 2 + src/effects/SkDisplacementMapEffect.cpp | 1 + src/effects/SkGpuBlurUtils.cpp | 4 ++ src/effects/SkLightingImageFilter.cpp | 1 + src/effects/SkMorphologyImageFilter.cpp | 2 + src/effects/SkPerlinNoiseShader.cpp | 1 - src/effects/SkXfermodeImageFilter.cpp | 1 + src/gpu/GrContext.cpp | 6 +- src/gpu/GrDrawTarget.cpp | 2 + src/gpu/GrPaint.cpp | 9 ++- src/gpu/GrPipeline.cpp | 32 ++++++++-- src/gpu/GrPipelineBuilder.cpp | 10 ++- src/gpu/GrPipelineBuilder.h | 7 +-- src/gpu/GrYUVProvider.cpp | 1 + src/gpu/SkGr.cpp | 9 +-- src/gpu/batches/GrDefaultPathRenderer.cpp | 3 +- src/gpu/effects/GrConfigConversionEffect.cpp | 3 + src/gpu/effects/GrCustomXfermode.cpp | 4 -- src/gpu/effects/GrDisableColorXP.h | 4 -- src/gpu/effects/GrPorterDuffXferProcessor.cpp | 62 +++++++++++++++++++ tests/TessellatingPathRendererTests.cpp | 2 + 35 files changed, 199 insertions(+), 90 deletions(-) diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp index 58d7fef3d3..ba163a3840 100644 --- a/gm/beziereffects.cpp +++ b/gm/beziereffects.cpp @@ -221,6 +221,8 @@ protected: SkASSERT(tt.target()); GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.setRenderTarget(rt); BezierCubicOrConicTestBatch::Geometry geometry; @@ -366,6 +368,8 @@ protected: SkASSERT(tt.target()); GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.setRenderTarget(rt); BezierCubicOrConicTestBatch::Geometry geometry; @@ -604,6 +608,8 @@ protected: SkASSERT(tt.target()); GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.setRenderTarget(rt); GrPathUtils::QuadUVMatrix DevToUV(pts); diff --git a/gm/bigrrectaaeffect.cpp b/gm/bigrrectaaeffect.cpp index 472910b5df..18a0c6ef7d 100644 --- a/gm/bigrrectaaeffect.cpp +++ b/gm/bigrrectaaeffect.cpp @@ -71,6 +71,8 @@ protected: return; } GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); SkRRect rrect = fRRects[curRRect]; rrect.offset(SkIntToScalar(x), SkIntToScalar(y)); diff --git a/gm/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp index 4f38436726..f040b90ed2 100644 --- a/gm/convexpolyeffect.cpp +++ b/gm/convexpolyeffect.cpp @@ -190,6 +190,8 @@ protected: } GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.addCoverageFragmentProcessor(fp); pipelineBuilder.setRenderTarget(rt); @@ -239,6 +241,8 @@ protected: } GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.addCoverageFragmentProcessor(fp); pipelineBuilder.setRenderTarget(rt); diff --git a/gm/rrects.cpp b/gm/rrects.cpp index e48b8c8c8d..fbe7ad1836 100644 --- a/gm/rrects.cpp +++ b/gm/rrects.cpp @@ -107,6 +107,8 @@ protected: return; } GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); SkRRect rrect = fRRects[curRRect]; rrect.offset(SkIntToScalar(x), SkIntToScalar(y)); diff --git a/gm/texturedomaineffect.cpp b/gm/texturedomaineffect.cpp index a2dc4b01b8..3eaba90806 100644 --- a/gm/texturedomaineffect.cpp +++ b/gm/texturedomaineffect.cpp @@ -117,6 +117,8 @@ protected: for (int m = 0; m < GrTextureDomain::kModeCount; ++m) { GrTextureDomain::Mode mode = (GrTextureDomain::Mode) m; GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); SkAutoTUnref fp( GrTextureDomainEffect::Create(texture, textureMatrices[tm], GrTextureDomain::MakeTexelDomain(texture, diff --git a/gm/yuvtorgbeffect.cpp b/gm/yuvtorgbeffect.cpp index 5f7cc1314d..66ade25184 100644 --- a/gm/yuvtorgbeffect.cpp +++ b/gm/yuvtorgbeffect.cpp @@ -115,6 +115,8 @@ protected: for (int i = 0; i < 6; ++i) { GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); SkAutoTUnref fp( GrYUVtoRGBEffect::Create(texture[indices[i][0]], texture[indices[i][1]], diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index cb9557f92c..91268ab5f1 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -204,18 +204,26 @@ public: const GrFragmentProcessor* dst) const; /** A subclass may implement this factory function to work with the GPU backend. It is legal - to call this with xpf NULL to simply test the return value. If xpf is non-NULL then the - xfermode may optionally allocate a factory to return to the caller as *xpf. The caller - will install it and own a ref to it. Since the xfermode may or may not assign *xpf, the - caller should set *xpf to NULL beforehand. XferProcessors cannot use a background texture. - */ + to call this with xpf NULL to simply test the return value. If xpf is non-NULL then the + xfermode may optionally allocate a factory to return to the caller as *xpf. The caller + will install it and own a ref to it. Since the xfermode may or may not assign *xpf, the + caller should set *xpf to NULL beforehand. XferProcessors cannot use a background texture. + */ virtual bool asXPFactory(GrXPFactory** xpf) const; /** Returns true if the xfermode can be expressed as an xfer processor factory (xpFactory). - This helper calls the asXPFactory() virtual. If the xfermode is NULL, it is treated as - kSrcOver_Mode. It is legal to call this with xpf param NULL to simply test the return value. - */ - static bool AsXPFactory(SkXfermode*, GrXPFactory**); + This helper calls the asXPFactory() virtual. If the xfermode is NULL, it is treated as + kSrcOver_Mode. It is legal to call this with xpf param NULL to simply test the return value. + */ + static inline bool AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) { + if (nullptr == xfermode) { + if (xpf) { + *xpf = nullptr; + } + return true; + } + return xfermode->asXPFactory(xpf); + } SK_TO_STRING_PUREVIRT() SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h index 9d0fe5575e..152cb51d7e 100644 --- a/include/gpu/GrPaint.h +++ b/include/gpu/GrPaint.h @@ -57,7 +57,7 @@ public: bool isAntiAlias() const { return fAntiAlias; } const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) { - fXPFactory.reset(SkRef(xpFactory)); + fXPFactory.reset(SkSafeRef(xpFactory)); return xpFactory; } @@ -100,10 +100,7 @@ public: this->numCoverageFragmentProcessors(); } const GrXPFactory* getXPFactory() const { - if (!fXPFactory) { - fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode)); - } - return fXPFactory.get(); + return fXPFactory; } const GrFragmentProcessor* getColorFragmentProcessor(int i) const { @@ -127,7 +124,7 @@ public: fCoverageFragmentProcessors[i]->ref(); } - fXPFactory.reset(SkRef(paint.getXPFactory())); + fXPFactory.reset(SkSafeRef(paint.getXPFactory())); return *this; } diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h index 4accbc84fa..64a0e1ab55 100644 --- a/include/gpu/GrXferProcessor.h +++ b/include/gpu/GrXferProcessor.h @@ -316,14 +316,6 @@ public: bool hasMixedSamples, const DstTexture*, const GrCaps& caps) const; - - /** - * This function returns true if the GrXferProcessor generated from this factory will be able to - * correctly blend when using RGB coverage. The knownColor and knownColorFlags represent the - * final computed color from the color stages. - */ - virtual bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const = 0; - /** * Known color information after blending, but before accounting for any coverage. */ diff --git a/include/gpu/effects/GrCoverageSetOpXP.h b/include/gpu/effects/GrCoverageSetOpXP.h index 8511074cbd..a17cf81232 100644 --- a/include/gpu/effects/GrCoverageSetOpXP.h +++ b/include/gpu/effects/GrCoverageSetOpXP.h @@ -23,11 +23,6 @@ class GrCoverageSetOpXPFactory : public GrXPFactory { public: static GrXPFactory* Create(SkRegion::Op regionOp, bool invertCoverage = false); - bool supportsRGBCoverage(GrColor /*knownColor*/, - uint32_t /*knownColorFlags*/) const override { - return true; - } - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, GrXPFactory::InvariantBlendedColor*) const override; diff --git a/include/gpu/effects/GrPorterDuffXferProcessor.h b/include/gpu/effects/GrPorterDuffXferProcessor.h index d297e32908..3dc503305f 100644 --- a/include/gpu/effects/GrPorterDuffXferProcessor.h +++ b/include/gpu/effects/GrPorterDuffXferProcessor.h @@ -18,13 +18,36 @@ class GrPorterDuffXPFactory : public GrXPFactory { public: static GrXPFactory* Create(SkXfermode::Mode mode); - bool supportsRGBCoverage(GrColor /*knownColor*/, uint32_t /*knownColorFlags*/) const override { - return true; - } - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, GrXPFactory::InvariantBlendedColor*) const override; + static GrXferProcessor* CreateSrcOverXferProcessor(const GrCaps& caps, + const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool hasMixedSamples, + const GrXferProcessor::DstTexture*); + + static inline void SrcOverInvariantBlendedColor( + GrColor inputColor, + GrColorComponentFlags validColorFlags, + bool isOpaque, + GrXPFactory::InvariantBlendedColor* blendedColor) { + if (!isOpaque) { + blendedColor->fWillBlendWithDst = true; + blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; + return; + } + blendedColor->fWillBlendWithDst = false; + + blendedColor->fKnownColor = inputColor; + blendedColor->fKnownColorFlags = validColorFlags; + } + + static bool SrcOverWillNeedDstTexture(const GrCaps& caps, + const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool hasMixedSamples); + private: GrPorterDuffXPFactory(SkXfermode::Mode); diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp index abac24cf3f..6a3286ed67 100644 --- a/src/core/SkImageFilter.cpp +++ b/src/core/SkImageFilter.cpp @@ -377,6 +377,7 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Cont if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) { SkASSERT(fp); paint.addColorFragmentProcessor(fp)->unref(); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref drawContext(context->drawContext(dst->asRenderTarget())); if (drawContext) { diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 9083814d1a..79de322c2d 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -660,26 +660,6 @@ bool SkXfermode::asXPFactory(GrXPFactory**) const { return false; } - -#if SK_SUPPORT_GPU -#include "effects/GrPorterDuffXferProcessor.h" - -bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) { - if (nullptr == xfermode) { - if (xpf) { - *xpf = GrPorterDuffXPFactory::Create(kSrcOver_Mode); - } - return true; - } else { - return xfermode->asXPFactory(xpf); - } -} -#else -bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) { - return false; -} -#endif - SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{ // no-op. subclasses should override this return dst; @@ -920,6 +900,7 @@ void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst, #if SK_SUPPORT_GPU #include "effects/GrCustomXfermode.h" +#include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrXfermodeFragmentProcessor.h" bool SkProcCoeffXfermode::asFragmentProcessor(const GrFragmentProcessor** fp, diff --git a/src/effects/SkArithmeticMode_gpu.h b/src/effects/SkArithmeticMode_gpu.h index ee3e73abb0..b24d23a6e6 100644 --- a/src/effects/SkArithmeticMode_gpu.h +++ b/src/effects/SkArithmeticMode_gpu.h @@ -81,10 +81,6 @@ public: return new GrArithmeticXPFactory(k1, k2, k3, k4, enforcePMColor); } - bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override { - return true; - } - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, GrXPFactory::InvariantBlendedColor*) const override; diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index 0dedf0208c..8dd82c5ac3 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -1262,6 +1262,8 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src, // outer: dst = dst * (1 - src) // = 0 * src + (1 - src) * dst paint.setCoverageSetOpXPFactory(SkRegion::kDifference_Op); + } else { + paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); } SkAutoTUnref drawContext(context->drawContext((*result)->asRenderTarget())); diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp index 77d6cb84aa..fe918581c4 100644 --- a/src/effects/SkDisplacementMapEffect.cpp +++ b/src/effects/SkDisplacementMapEffect.cpp @@ -445,6 +445,7 @@ bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, offsetMatrix, color, colorBM.dimensions()))->unref(); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkIRect colorBounds = bounds; colorBounds.offset(-colorOffset); SkMatrix matrix; diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp index 2e6a7d6bde..8ab05dd862 100644 --- a/src/effects/SkGpuBlurUtils.cpp +++ b/src/effects/SkGpuBlurUtils.cpp @@ -59,6 +59,7 @@ static void convolve_gaussian_1d(GrDrawContext* drawContext, SkAutoTUnref conv(GrConvolutionEffect::CreateGaussian( texture, direction, radius, sigma, useBounds, bounds)); paint.addColorFragmentProcessor(conv); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkMatrix localMatrix = SkMatrix::MakeTrans(srcOffset.x(), srcOffset.y()); drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix); } @@ -89,6 +90,7 @@ static void convolve_gaussian_2d(GrDrawContext* drawContext, srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode, true, sigmaX, sigmaY)); paint.addColorFragmentProcessor(conv); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix); } @@ -247,6 +249,7 @@ GrTexture* GaussianBlur(GrContext* context, GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); paint.addColorTextureProcessor(srcTexture, matrix, params); } + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, i < scaleFactorY ? 0.5f : 1.0f); @@ -374,6 +377,7 @@ GrTexture* GaussianBlur(GrContext* context, // FIXME: this should be mitchell, not bilinear. GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); paint.addColorTextureProcessor(srcTexture, matrix, params); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkRect dstRect(srcRect); scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY); diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp index 4bb755e3ed..9b6a20f0ef 100644 --- a/src/effects/SkLightingImageFilter.cpp +++ b/src/effects/SkLightingImageFilter.cpp @@ -354,6 +354,7 @@ void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext, GrPaint paint; GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode); paint.addColorFragmentProcessor(fp)->unref(); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); } diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp index fbc071fe58..484ed57f37 100644 --- a/src/effects/SkMorphologyImageFilter.cpp +++ b/src/effects/SkMorphologyImageFilter.cpp @@ -479,6 +479,7 @@ void apply_morphology_rect(GrDrawContext* drawContext, radius, morphType, bounds))->unref(); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect), SkRect::Make(srcRect)); } @@ -496,6 +497,7 @@ void apply_morphology_rect_no_bounds(GrDrawContext* drawContext, direction, radius, morphType))->unref(); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect), SkRect::Make(srcRect)); } diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp index c1a6f701d7..916cf78f0d 100644 --- a/src/effects/SkPerlinNoiseShader.cpp +++ b/src/effects/SkPerlinNoiseShader.cpp @@ -608,7 +608,6 @@ const GrFragmentProcessor* GrPerlinNoiseEffect::TestCreate(GrProcessorTestData* SkPerlinNoiseShader::CreateTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed, stitchTiles ? &tileSize : nullptr)); - GrPaint grPaint; return shader->asFragmentProcessor(d->fContext, GrTest::TestMatrix(d->fRandom), nullptr, kNone_SkFilterQuality); diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp index 28d9a00c84..38d1e5e6b4 100644 --- a/src/effects/SkXfermodeImageFilter.cpp +++ b/src/effects/SkXfermodeImageFilter.cpp @@ -191,6 +191,7 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, if (xferFP) { paint.addColorFragmentProcessor(xferFP)->unref(); } + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 348cdbaaca..920e3c4bbd 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -276,7 +276,6 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, SkAutoTUnref fp; SkMatrix textureMatrix; textureMatrix.setIDiv(tempTexture->width(), tempTexture->height()); - GrPaint paint; if (applyPremulToSrc) { fp.reset(this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwapRAndB, textureMatrix)); @@ -324,7 +323,9 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, if (!drawContext) { return false; } + GrPaint paint; paint.addColorFragmentProcessor(fp); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); drawContext->drawRect(GrClip::WideOpen(), paint, matrix, rect, nullptr); @@ -412,7 +413,6 @@ bool GrContext::readSurfacePixels(GrSurface* src, SkMatrix textureMatrix; textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); textureMatrix.postIDiv(src->width(), src->height()); - GrPaint paint; SkAutoTUnref fp; if (unpremul) { fp.reset(this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwapRAndB, @@ -430,7 +430,9 @@ bool GrContext::readSurfacePixels(GrSurface* src, GrConfigConversionEffect::kNone_PMConversion, textureMatrix)); } if (fp) { + GrPaint paint; paint.addColorFragmentProcessor(fp); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); SkAutoTUnref drawContext(this->drawContext(temp->asRenderTarget())); drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, nullptr); diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index 062a42fc5b..01d4f63bc5 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -431,6 +431,8 @@ void GrDrawTarget::clear(const SkIRect* rect, } GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.setRenderTarget(renderTarget); this->drawNonAARect(pipelineBuilder, color, SkMatrix::I(), *rect); diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp index 6f218a4b0b..1ec8e502be 100644 --- a/src/gpu/GrPaint.cpp +++ b/src/gpu/GrPaint.cpp @@ -50,7 +50,14 @@ bool GrPaint::isConstantBlendedColor(GrColor* color) const { kRGBA_GrColorComponentFlags, false); GrXPFactory::InvariantBlendedColor blendedColor; - fXPFactory->getInvariantBlendedColor(colorProcInfo, &blendedColor); + if (fXPFactory) { + fXPFactory->getInvariantBlendedColor(colorProcInfo, &blendedColor); + } else { + GrPorterDuffXPFactory::SrcOverInvariantBlendedColor(colorProcInfo.color(), + colorProcInfo.validFlags(), + colorProcInfo.isOpaque(), + &blendedColor); + } if (kRGBA_GrColorComponentFlags == blendedColor.fKnownColorFlags) { *color = blendedColor.fKnownColor; diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp index 073349be1e..73b20a9042 100644 --- a/src/gpu/GrPipeline.cpp +++ b/src/gpu/GrPipeline.cpp @@ -21,10 +21,23 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args, const GrPipelineBuilder& builder = *args.fPipelineBuilder; // Create XferProcessor from DS's XPFactory - SkAutoTUnref xferProcessor( - builder.getXPFactory()->createXferProcessor(args.fColorPOI, args.fCoveragePOI, - builder.hasMixedSamples(), &args.fDstTexture, - *args.fCaps)); + const GrXPFactory* xpFactory = builder.getXPFactory(); + SkAutoTUnref xferProcessor; + if (xpFactory) { + xferProcessor.reset(xpFactory->createXferProcessor(args.fColorPOI, + args.fCoveragePOI, + builder.hasMixedSamples(), + &args.fDstTexture, + *args.fCaps)); + } else { + xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor( + *args.fCaps, + args.fColorPOI, + args.fCoveragePOI, + builder.hasMixedSamples(), + &args.fDstTexture)); + } + if (!xferProcessor) { return nullptr; } @@ -55,7 +68,7 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args, } GrPipeline* pipeline = new (memory) GrPipeline; - pipeline->fXferProcessor.reset(xferProcessor.get()); + pipeline->fXferProcessor.reset(xferProcessor); pipeline->fRenderTarget.reset(builder.fRenderTarget.get()); SkASSERT(pipeline->fRenderTarget); @@ -123,7 +136,14 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args, } GrXPFactory::InvariantBlendedColor blendedColor; - builder.fXPFactory->getInvariantBlendedColor(args.fColorPOI, &blendedColor); + if (xpFactory) { + xpFactory->getInvariantBlendedColor(args.fColorPOI, &blendedColor); + } else { + GrPorterDuffXPFactory::SrcOverInvariantBlendedColor(args.fColorPOI.color(), + args.fColorPOI.validFlags(), + args.fColorPOI.isOpaque(), + &blendedColor); + } if (blendedColor.fWillBlendWithDst) { opts->fFlags |= GrPipelineOptimizations::kWillColorBlendWithDst_Flag; } diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp index ab185505d6..ce465c1c71 100644 --- a/src/gpu/GrPipelineBuilder.cpp +++ b/src/gpu/GrPipelineBuilder.cpp @@ -31,7 +31,7 @@ GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, GrRenderTarget* rt, c fCoverageFragmentProcessors.push_back(SkRef(paint.getCoverageFragmentProcessor(i))); } - fXPFactory.reset(SkRef(paint.getXPFactory())); + fXPFactory.reset(SkSafeRef(paint.getXPFactory())); this->setRenderTarget(rt); @@ -51,8 +51,12 @@ GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, GrRenderTarget* rt, c bool GrPipelineBuilder::willXPNeedDstTexture(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const { - return this->getXPFactory()->willNeedDstTexture(caps, colorPOI, coveragePOI, - this->hasMixedSamples()); + if (this->getXPFactory()) { + return this->getXPFactory()->willNeedDstTexture(caps, colorPOI, coveragePOI, + this->hasMixedSamples()); + } + return GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(caps, colorPOI, coveragePOI, + this->hasMixedSamples()); } void GrPipelineBuilder::AutoRestoreFragmentProcessorState::set( diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h index 010685b3e2..bf0bed56c9 100644 --- a/src/gpu/GrPipelineBuilder.h +++ b/src/gpu/GrPipelineBuilder.h @@ -150,7 +150,7 @@ public: * and the dst color are blended. */ const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) { - fXPFactory.reset(SkRef(xpFactory)); + fXPFactory.reset(SkSafeRef(xpFactory)); return xpFactory; } @@ -171,10 +171,7 @@ public: } const GrXPFactory* getXPFactory() const { - if (!fXPFactory) { - fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode)); - } - return fXPFactory.get(); + return fXPFactory; } /** diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp index 93859483ad..014c30574a 100644 --- a/src/gpu/GrYUVProvider.cpp +++ b/src/gpu/GrYUVProvider.cpp @@ -128,6 +128,7 @@ GrTexture* GrYUVProvider::refAsTexture(GrContext* ctx, const GrSurfaceDesc& desc yuvInfo.fSize, yuvInfo.fColorSpace)); paint.addColorFragmentProcessor(yuvToRgbProcessor); + paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); const SkRect r = SkRect::MakeIWH(yuvInfo.fSize[0].fWidth, yuvInfo.fSize[0].fHeight); SkAutoTUnref drawContext(ctx->drawContext(renderTarget)); diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 411b5b2b60..954bb80852 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -489,13 +489,8 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context, SkXfermode* mode = skPaint.getXfermode(); GrXPFactory* xpFactory = nullptr; - if (!SkXfermode::AsXPFactory(mode, &xpFactory)) { - // Fall back to src-over - // return false here? - xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode); - } - SkASSERT(xpFactory); - grPaint->setXPFactory(xpFactory)->unref(); + SkXfermode::AsXPFactory(mode, &xpFactory); + SkSafeUnref(grPaint->setXPFactory(xpFactory)); #ifndef SK_IGNORE_GPU_DITHER if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) { diff --git a/src/gpu/batches/GrDefaultPathRenderer.cpp b/src/gpu/batches/GrDefaultPathRenderer.cpp index d0777e253f..fa2ffe0b4d 100644 --- a/src/gpu/batches/GrDefaultPathRenderer.cpp +++ b/src/gpu/batches/GrDefaultPathRenderer.cpp @@ -564,7 +564,8 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, const bool isHairline = stroke->isHairlineStyle(); // Save the current xp on the draw state so we can reset it if needed - SkAutoTUnref backupXPFactory(SkRef(pipelineBuilder->getXPFactory())); + const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory(); + SkAutoTUnref backupXPFactory(SkSafeRef(xpFactory)); // face culling doesn't make sense here SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace()); diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp index 2510b5c9d7..4df894b40a 100644 --- a/src/gpu/effects/GrConfigConversionEffect.cpp +++ b/src/gpu/effects/GrConfigConversionEffect.cpp @@ -223,6 +223,7 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context tempTex, false, *pmToUPMRule, SkMatrix::I())); paint1.addColorFragmentProcessor(pmToUPM1); + paint1.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref readDrawContext( @@ -241,6 +242,7 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context readTex->readPixels(0, 0, 256, 256, kRGBA_8888_GrPixelConfig, firstRead); paint2.addColorFragmentProcessor(upmToPM); + paint2.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref tempDrawContext( context->drawContext(tempTex->asRenderTarget())); @@ -255,6 +257,7 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context kSrcRect); paint3.addColorFragmentProcessor(pmToUPM2); + paint3.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); readDrawContext.reset(context->drawContext(readTex->asRenderTarget())); if (!readDrawContext) { diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp index 6b3a20ec2d..90ab030d24 100644 --- a/src/gpu/effects/GrCustomXfermode.cpp +++ b/src/gpu/effects/GrCustomXfermode.cpp @@ -321,10 +321,6 @@ class CustomXPFactory : public GrXPFactory { public: CustomXPFactory(SkXfermode::Mode mode); - bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override { - return true; - } - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, GrXPFactory::InvariantBlendedColor*) const override; diff --git a/src/gpu/effects/GrDisableColorXP.h b/src/gpu/effects/GrDisableColorXP.h index caa0eecec8..a79dd9b971 100644 --- a/src/gpu/effects/GrDisableColorXP.h +++ b/src/gpu/effects/GrDisableColorXP.h @@ -17,10 +17,6 @@ class GrDisableColorXPFactory : public GrXPFactory { public: static GrXPFactory* Create() { return new GrDisableColorXPFactory; } - bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override { - return true; - } - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, GrXPFactory::InvariantBlendedColor* blendedColor) const override { blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index 4245caafed..2323c67040 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -830,3 +830,65 @@ void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp, *outPrimary = blendFormula.fPrimaryOutputType; *outSecondary = blendFormula.fSecondaryOutputType; } + + +//////////////////////////////////////////////////////////////////////////////////////////////// +// SrcOver Global functions +//////////////////////////////////////////////////////////////////////////////////////////////// + +GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor( + const GrCaps& caps, + const GrProcOptInfo& colorPOI, + const GrProcOptInfo& covPOI, + bool hasMixedSamples, + const GrXferProcessor::DstTexture* dstTexture) { + BlendFormula blendFormula; + if (covPOI.isFourChannelOutput()) { + if (kRGBA_GrColorComponentFlags == colorPOI.validFlags() && + !caps.shaderCaps()->dualSourceBlendingSupport() && + !caps.shaderCaps()->dstReadInShaderSupport()) { + // If we don't have dual source blending or in shader dst reads, we fall + // back to this trick for rendering SrcOver LCD text instead of doing a + // dst copy. + SkASSERT(!dstTexture || !dstTexture->texture()); + return PDLCDXferProcessor::Create(SkXfermode::kSrcOver_Mode, colorPOI); + } + blendFormula = get_lcd_blend_formula(covPOI, SkXfermode::kSrcOver_Mode); + } else { + blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, + SkXfermode::kSrcOver_Mode); + } + + if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) { + return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode); + } + + SkASSERT(!dstTexture || !dstTexture->texture()); + return new PorterDuffXferProcessor(blendFormula); +} + +bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps, + const GrProcOptInfo& colorPOI, + const GrProcOptInfo& covPOI, + bool hasMixedSamples) { + if (caps.shaderCaps()->dstReadInShaderSupport() || + caps.shaderCaps()->dualSourceBlendingSupport()) { + return false; + } + + // When we have four channel coverage we always need to read the dst in order to correctly + // blend. The one exception is when we are using srcover mode and we know the input color + // into the XP. + if (covPOI.isFourChannelOutput()) { + if (kRGBA_GrColorComponentFlags == colorPOI.validFlags() && + !caps.shaderCaps()->dstReadInShaderSupport()) { + return false; + } + return get_lcd_blend_formula(covPOI, SkXfermode::kSrcOver_Mode).hasSecondaryOutput(); + } + // We fallback on the shader XP when the blend formula would use dual source blending but we + // don't have support for it. + return get_blend_formula(colorPOI, covPOI, + hasMixedSamples, SkXfermode::kSrcOver_Mode).hasSecondaryOutput(); +} + diff --git a/tests/TessellatingPathRendererTests.cpp b/tests/TessellatingPathRendererTests.cpp index 219397bc11..a6eabfdaaf 100644 --- a/tests/TessellatingPathRendererTests.cpp +++ b/tests/TessellatingPathRendererTests.cpp @@ -236,6 +236,8 @@ static void test_path(GrDrawTarget* dt, GrRenderTarget* rt, GrResourceProvider* const SkPath& path) { GrTessellatingPathRenderer tess; GrPipelineBuilder pipelineBuilder; + pipelineBuilder.setXPFactory( + GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.setRenderTarget(rt); GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); GrPathRenderer::DrawPathArgs args;