Don't create a GXPFactory when blend is SrcOver
authoregdaniel <egdaniel@google.com>
Mon, 23 Nov 2015 21:20:41 +0000 (13:20 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 23 Nov 2015 21:20:42 +0000 (13:20 -0800)
BUG=skia:

Review URL: https://codereview.chromium.org/1471053002

35 files changed:
gm/beziereffects.cpp
gm/bigrrectaaeffect.cpp
gm/convexpolyeffect.cpp
gm/rrects.cpp
gm/texturedomaineffect.cpp
gm/yuvtorgbeffect.cpp
include/core/SkXfermode.h
include/gpu/GrPaint.h
include/gpu/GrXferProcessor.h
include/gpu/effects/GrCoverageSetOpXP.h
include/gpu/effects/GrPorterDuffXferProcessor.h
src/core/SkImageFilter.cpp
src/core/SkXfermode.cpp
src/effects/SkArithmeticMode_gpu.h
src/effects/SkBlurMaskFilter.cpp
src/effects/SkDisplacementMapEffect.cpp
src/effects/SkGpuBlurUtils.cpp
src/effects/SkLightingImageFilter.cpp
src/effects/SkMorphologyImageFilter.cpp
src/effects/SkPerlinNoiseShader.cpp
src/effects/SkXfermodeImageFilter.cpp
src/gpu/GrContext.cpp
src/gpu/GrDrawTarget.cpp
src/gpu/GrPaint.cpp
src/gpu/GrPipeline.cpp
src/gpu/GrPipelineBuilder.cpp
src/gpu/GrPipelineBuilder.h
src/gpu/GrYUVProvider.cpp
src/gpu/SkGr.cpp
src/gpu/batches/GrDefaultPathRenderer.cpp
src/gpu/effects/GrConfigConversionEffect.cpp
src/gpu/effects/GrCustomXfermode.cpp
src/gpu/effects/GrDisableColorXP.h
src/gpu/effects/GrPorterDuffXferProcessor.cpp
tests/TessellatingPathRendererTests.cpp

index 58d7fef..ba163a3 100644 (file)
@@ -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);
index 472910b..18a0c6e 100644 (file)
@@ -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));
index 4f38436..f040b90 100644 (file)
@@ -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);
 
index e48b8c8..fbe7ad1 100644 (file)
@@ -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));
index a2dc4b0..3eaba90 100644 (file)
@@ -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<const GrFragmentProcessor> fp(
                         GrTextureDomainEffect::Create(texture, textureMatrices[tm],
                                                 GrTextureDomain::MakeTexelDomain(texture,
index 5f7cc13..66ade25 100644 (file)
@@ -115,6 +115,8 @@ protected:
 
             for (int i = 0; i < 6; ++i) {
                 GrPipelineBuilder pipelineBuilder;
+                pipelineBuilder.setXPFactory(
+                    GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
                 SkAutoTUnref<GrFragmentProcessor> fp(
                             GrYUVtoRGBEffect::Create(texture[indices[i][0]],
                                                      texture[indices[i][1]],
index cb9557f..91268ab 100644 (file)
@@ -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()
index 9d0fe55..152cb51 100644 (file)
@@ -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;
     }
index 4accbc8..64a0e1a 100644 (file)
@@ -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.
      */
index 8511074..a17cf81 100644 (file)
@@ -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;
 
index d297e32..3dc5033 100644 (file)
@@ -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);
 
index abac24c..6a3286e 100644 (file)
@@ -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<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
         if (drawContext) {
index 9083814..79de322 100644 (file)
@@ -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,
index ee3e73a..b24d23a 100644 (file)
@@ -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;
 
index 0dedf02..8dd82c5 100644 (file)
@@ -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<GrDrawContext> drawContext(context->drawContext((*result)->asRenderTarget()));
index 77d6cb8..fe91858 100644 (file)
@@ -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;
index 2e6a7d6..8ab05dd 100644 (file)
@@ -59,6 +59,7 @@ static void convolve_gaussian_1d(GrDrawContext* drawContext,
     SkAutoTUnref<GrFragmentProcessor> 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);
index 4bb755e..9b6a20f 100644 (file)
@@ -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);
 }
 
index fbc071f..484ed57 100644 (file)
@@ -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));
 }
index c1a6f70..916cf78 100644 (file)
@@ -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);
index 28d9a00..38d1e5e 100644 (file)
@@ -191,6 +191,7 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy,
     if (xferFP) {
         paint.addColorFragmentProcessor(xferFP)->unref();
     }
+    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
 
     SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
     if (!drawContext) {
index 348cdba..920e3c4 100644 (file)
@@ -276,7 +276,6 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
         SkAutoTUnref<const GrFragmentProcessor> 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<const GrFragmentProcessor> 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<GrDrawContext> drawContext(this->drawContext(temp->asRenderTarget()));
                 drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, nullptr);
index 062a42f..01d4f63 100644 (file)
@@ -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);
index 6f218a4..1ec8e50 100644 (file)
@@ -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;
index 073349b..73b20a9 100644 (file)
@@ -21,10 +21,23 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
     const GrPipelineBuilder& builder = *args.fPipelineBuilder;
 
     // Create XferProcessor from DS's XPFactory
-    SkAutoTUnref<GrXferProcessor> xferProcessor(
-        builder.getXPFactory()->createXferProcessor(args.fColorPOI, args.fCoveragePOI,
-                                                    builder.hasMixedSamples(), &args.fDstTexture,
-                                                    *args.fCaps));
+    const GrXPFactory* xpFactory = builder.getXPFactory();
+    SkAutoTUnref<GrXferProcessor> 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;
     }
index ab18550..ce465c1 100644 (file)
@@ -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(
index 010685b..bf0bed5 100644 (file)
@@ -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;
     }
 
     /**
index 9385948..014c305 100644 (file)
@@ -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<GrDrawContext> drawContext(ctx->drawContext(renderTarget));
index 411b5b2..954bb80 100644 (file)
@@ -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) {
index d0777e2..fa2ffe0 100644 (file)
@@ -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<const GrXPFactory> backupXPFactory(SkRef(pipelineBuilder->getXPFactory()));
+    const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
+    SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
     // face culling doesn't make sense here
     SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
 
index 2510b5c..4df894b 100644 (file)
@@ -223,6 +223,7 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context
                 tempTex, false, *pmToUPMRule, SkMatrix::I()));
 
         paint1.addColorFragmentProcessor(pmToUPM1);
+        paint1.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
 
 
         SkAutoTUnref<GrDrawContext> 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<GrDrawContext> 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) {
index 6b3a20e..90ab030 100644 (file)
@@ -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;
 
index caa0eec..a79dd9b 100644 (file)
@@ -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;
index 4245caa..2323c67 100644 (file)
@@ -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();
+}
+
index 219397b..a6eabfd 100644 (file)
@@ -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;