Add mixed samples support to XPs
authorcdalton <cdalton@nvidia.com>
Mon, 8 Jun 2015 22:11:04 +0000 (15:11 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 8 Jun 2015 22:11:04 +0000 (15:11 -0700)
BUG=skia:

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

17 files changed:
include/gpu/GrXferProcessor.h
include/gpu/effects/GrCoverageSetOpXP.h
include/gpu/effects/GrPorterDuffXferProcessor.h
src/effects/SkArithmeticMode_gpu.cpp
src/effects/SkArithmeticMode_gpu.h
src/gpu/GrPipeline.cpp
src/gpu/GrPipelineBuilder.cpp
src/gpu/GrPipelineBuilder.h
src/gpu/GrXferProcessor.cpp
src/gpu/effects/GrCoverageSetOpXP.cpp
src/gpu/effects/GrCustomXfermode.cpp
src/gpu/effects/GrCustomXfermodePriv.h
src/gpu/effects/GrDisableColorXP.cpp
src/gpu/effects/GrDisableColorXP.h
src/gpu/effects/GrPorterDuffXferProcessor.cpp
src/gpu/gl/GrGLXferProcessor.cpp
tests/GrPorterDuffTest.cpp

index 7ed98a3..8f2c69d 100644 (file)
@@ -252,6 +252,13 @@ public:
     }
 
     /**
+     * If we are performing a dst read, returns whether the base class will use mixed samples to
+     * antialias the shader's final output. If not doing a dst read, the subclass is responsible
+     * for antialiasing and this returns false.
+     */
+    bool dstReadUsesMixedSamples() const { return fDstReadUsesMixedSamples; }
+
+    /**
      * Returns whether or not the XP will look at coverage when doing its blending.
      */
     bool readsCoverage() const { return fReadsCoverage; }
@@ -285,12 +292,15 @@ public:
         if (this->fDstTextureOffset != that.fDstTextureOffset) {
             return false;
         }
+        if (this->fDstReadUsesMixedSamples != that.fDstReadUsesMixedSamples) {
+            return false;
+        }
         return this->onIsEqual(that);
     }
    
 protected:
     GrXferProcessor();
-    GrXferProcessor(const DstTexture*, bool willReadDstColor);
+    GrXferProcessor(const DstTexture*, bool willReadDstColor, bool hasMixedSamples);
 
 private:
     virtual OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
@@ -318,21 +328,22 @@ private:
 
     /**
      * If we are not performing a dst read, returns whether the subclass will set a secondary
-     * output. When using dst reads, the base class disables the secondary output and this method
+     * output. When using dst reads, the base class controls the secondary output and this method
      * will not be called.
      */
     virtual bool onHasSecondaryOutput() const { return false; }
 
     /**
      * If we are not performing a dst read, retrieves the fixed-function blend state required by the
-     * subclass. When using dst reads, the base class disables fixed-function blending and this
-     * method will not be called. The BlendInfo struct comes initialized to "no blending".
+     * subclass. When using dst reads, the base class controls the fixed-function blend state and
+     * this method will not be called. The BlendInfo struct comes initialized to "no blending".
      */
     virtual void onGetBlendInfo(BlendInfo*) const {}
 
     virtual bool onIsEqual(const GrXferProcessor&) const = 0;
 
     bool                    fWillReadDstColor;
+    bool                    fDstReadUsesMixedSamples;
     bool                    fReadsCoverage;
     SkIPoint                fDstTextureOffset;
     GrTextureAccess         fDstTexture;
@@ -360,6 +371,7 @@ public:
     typedef GrXferProcessor::DstTexture DstTexture;
     GrXferProcessor* createXferProcessor(const GrProcOptInfo& colorPOI,
                                          const GrProcOptInfo& coveragePOI,
+                                         bool hasMixedSamples,
                                          const DstTexture*,
                                          const GrCaps& caps) const;
 
@@ -389,7 +401,7 @@ public:
                                           InvariantBlendedColor*) const = 0;
 
     bool willNeedDstTexture(const GrCaps& caps, const GrProcOptInfo& colorPOI,
-                            const GrProcOptInfo& coveragePOI) const;
+                            const GrProcOptInfo& coveragePOI, bool hasMixedSamples) const;
 
     bool isEqual(const GrXPFactory& that) const {
         if (this->classID() != that.classID()) {
@@ -419,6 +431,7 @@ private:
     virtual GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
                                                    const GrProcOptInfo& colorPOI,
                                                    const GrProcOptInfo& coveragePOI,
+                                                   bool hasMixedSamples,
                                                    const DstTexture*) const = 0;
     /**
      *  Returns true if the XP generated by this factory will explicitly read dst in the fragment
@@ -426,7 +439,8 @@ private:
      */
     virtual bool willReadDstColor(const GrCaps& caps,
                                   const GrProcOptInfo& colorPOI,
-                                  const GrProcOptInfo& coveragePOI) const = 0;
+                                  const GrProcOptInfo& coveragePOI,
+                                  bool hasMixedSamples) const = 0;
 
     virtual bool onIsEqual(const GrXPFactory&) const = 0;
 
index 6067b5e..8511074 100644 (file)
@@ -37,11 +37,13 @@ private:
     GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
                                            const GrProcOptInfo& colorPOI,
                                            const GrProcOptInfo& coveragePOI,
+                                           bool hasMixedSamples,
                                            const DstTexture*) const override;
 
     bool willReadDstColor(const GrCaps& /*caps*/,
                           const GrProcOptInfo& /*colorPOI*/,
-                          const GrProcOptInfo& /*coveragePOI*/) const override {
+                          const GrProcOptInfo& /*coveragePOI*/,
+                          bool /*hasMixedSamples*/) const override {
         return false;
     }
 
index ca7de94..a26a892 100644 (file)
@@ -29,11 +29,13 @@ private:
     GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
                                            const GrProcOptInfo& colorPOI,
                                            const GrProcOptInfo& coveragePOI,
+                                           bool hasMixedSamples,
                                            const DstTexture*) const override;
 
     bool willReadDstColor(const GrCaps& caps,
                           const GrProcOptInfo& colorPOI,
-                          const GrProcOptInfo& coveragePOI) const override;
+                          const GrProcOptInfo& coveragePOI,
+                          bool hasMixedSamples) const override;
 
     bool onIsEqual(const GrXPFactory& xpfBase) const override {
         const GrPorterDuffXPFactory& xpf = xpfBase.cast<GrPorterDuffXPFactory>();
index 0d81c79..074cada 100644 (file)
@@ -160,13 +160,8 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);
 
 class ArithmeticXP : public GrXferProcessor {
 public:
-    static GrXferProcessor* Create(float k1, float k2, float k3, float k4, bool enforcePMColor,
-                                   const DstTexture* dstTexture, bool willReadDstColor) {
-        return SkNEW_ARGS(ArithmeticXP, (k1, k2, k3, k4, enforcePMColor, dstTexture,
-                                         willReadDstColor));
-    }
-
-    ~ArithmeticXP() override {};
+    ArithmeticXP(const DstTexture*, bool hasMixedSamples,
+                 float k1, float k2, float k3, float k4, bool enforcePMColor);
 
     const char* name() const override { return "Arithmetic"; }
 
@@ -179,9 +174,6 @@ public:
     bool enforcePMColor() const { return fEnforcePMColor; }
 
 private:
-    ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor,
-                   const DstTexture*, bool willReadDstColor);
-
     GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
                                                  const GrProcOptInfo& coveragePOI,
                                                  bool doesStencilWrite,
@@ -253,9 +245,9 @@ private:
 
 ///////////////////////////////////////////////////////////////////////////////
 
-ArithmeticXP::ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor,
-                           const DstTexture* dstTexture, bool willReadDstColor)
-    : INHERITED(dstTexture, willReadDstColor)
+ArithmeticXP::ArithmeticXP(const DstTexture* dstTexture, bool hasMixedSamples,
+                           float k1, float k2, float k3, float k4, bool enforcePMColor)
+    : INHERITED(dstTexture, true, hasMixedSamples)
     , fK1(k1)
     , fK2(k2)
     , fK3(k3)
@@ -292,9 +284,10 @@ GrXferProcessor*
 GrArithmeticXPFactory::onCreateXferProcessor(const GrCaps& caps,
                                              const GrProcOptInfo& colorPOI,
                                              const GrProcOptInfo& coveragePOI,
+                                             bool hasMixedSamples,
                                              const DstTexture* dstTexture) const {
-    return ArithmeticXP::Create(fK1, fK2, fK3, fK4, fEnforcePMColor, dstTexture,
-                                this->willReadDstColor(caps, colorPOI, coveragePOI));
+    return SkNEW_ARGS(ArithmeticXP, (dstTexture, hasMixedSamples, fK1, fK2, fK3, fK4,
+                                     fEnforcePMColor));
 }
 
 
index 3334e2d..b9235b3 100644 (file)
@@ -90,11 +90,13 @@ private:
     GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
                                            const GrProcOptInfo& colorPOI,
                                            const GrProcOptInfo& coveragePOI,
+                                           bool hasMixedSamples,
                                            const DstTexture*) const override; 
 
     bool willReadDstColor(const GrCaps& caps,
                           const GrProcOptInfo& colorPOI,
-                          const GrProcOptInfo& coveragePOI) const override {
+                          const GrProcOptInfo& coveragePOI,
+                          bool hasMixedSamples) const override {
         return true;
     }
 
index d9d3d94..4feddb0 100644 (file)
@@ -23,7 +23,7 @@ GrPipeline::GrPipeline(const GrPipelineBuilder& pipelineBuilder,
     // Create XferProcessor from DS's XPFactory
     SkAutoTUnref<GrXferProcessor> xferProcessor(
         pipelineBuilder.getXPFactory()->createXferProcessor(
-            colorPOI, coveragePOI, dstTexture, caps));
+            colorPOI, coveragePOI, pipelineBuilder.hasMixedSamples(), dstTexture, caps));
 
     GrColor overrideColor = GrColor_ILLEGAL;
     if (colorPOI.firstEffectiveStageIndex() != 0) {
index 8af89e8..26422fd 100644 (file)
@@ -89,7 +89,8 @@ void GrPipelineBuilder::setFromPaint(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);
+    return this->getXPFactory()->willNeedDstTexture(caps, colorPOI, coveragePOI,
+                                                    this->hasMixedSamples());
 }
 
 void GrPipelineBuilder::AutoRestoreFragmentProcessors::set(GrPipelineBuilder* pipelineBuilder) {
index dbbf98a..6a0e137 100644 (file)
@@ -205,6 +205,14 @@ public:
      */
     void setRenderTarget(GrRenderTarget* target) { fRenderTarget.reset(SkSafeRef(target)); }
 
+    /**
+     * Returns whether the rasterizer and stencil test (if any) will run at a higher sample rate
+     * than the color buffer. In is scenario, the higher sample rate is resolved during blending.
+     */
+    bool hasMixedSamples() const {
+        return this->isHWAntialias() && !fRenderTarget->isMultisampled();
+    }
+
     /// @}
 
     ///////////////////////////////////////////////////////////////////////////
index 67c5dd8..1ead010 100644 (file)
@@ -6,15 +6,22 @@
  */
 
 #include "GrXferProcessor.h"
+#include "GrPipelineBuilder.h"
 #include "GrProcOptInfo.h"
 #include "gl/GrGLCaps.h"
 
 GrXferProcessor::GrXferProcessor()
-    : fWillReadDstColor(false), fReadsCoverage(true), fDstTextureOffset() {
+    : fWillReadDstColor(false)
+    , fDstReadUsesMixedSamples(false)
+    , fReadsCoverage(true)
+    , fDstTextureOffset() {
 }
 
-GrXferProcessor::GrXferProcessor(const DstTexture* dstTexture, bool willReadDstColor)
+GrXferProcessor::GrXferProcessor(const DstTexture* dstTexture,
+                                 bool willReadDstColor,
+                                 bool hasMixedSamples)
     : fWillReadDstColor(willReadDstColor)
+    , fDstReadUsesMixedSamples(willReadDstColor && hasMixedSamples)
     , fReadsCoverage(true)
     , fDstTextureOffset() {
     if (dstTexture && dstTexture->texture()) {
@@ -54,13 +61,15 @@ bool GrXferProcessor::hasSecondaryOutput() const {
     if (!this->willReadDstColor()) {
         return this->onHasSecondaryOutput();
     }
-    return false;
+    return this->dstReadUsesMixedSamples();
 }
 
 void GrXferProcessor::getBlendInfo(BlendInfo* blendInfo) const {
     blendInfo->reset();
     if (!this->willReadDstColor()) {
         this->onGetBlendInfo(blendInfo);
+    } else if (this->dstReadUsesMixedSamples()) {
+        blendInfo->fDstBlend = kIS2A_GrBlendCoeff;
     }
 }
 
@@ -76,6 +85,9 @@ void GrXferProcessor::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBu
         if (this->readsCoverage()) {
             key |= 0x8;
         }
+        if (this->dstReadUsesMixedSamples()) {
+            key |= 0x10;
+        }
     }
     b->add32(key);
     this->onGetGLProcessorKey(caps, b);
@@ -192,10 +204,11 @@ SkString GrXferProcessor::BlendInfo::dump() const {
 
 GrXferProcessor* GrXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI,
                                                   const GrProcOptInfo& coveragePOI,
+                                                  bool hasMixedSamples,
                                                   const DstTexture* dstTexture,
                                                   const GrCaps& caps) const {
 #ifdef SK_DEBUG
-    if (this->willReadDstColor(caps, colorPOI, coveragePOI)) {
+    if (this->willReadDstColor(caps, colorPOI, coveragePOI, hasMixedSamples)) {
         if (!caps.shaderCaps()->dstReadInShaderSupport()) {
             SkASSERT(dstTexture && dstTexture->texture());
         } else {
@@ -204,12 +217,15 @@ GrXferProcessor* GrXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI,
     } else {
         SkASSERT(!dstTexture || !dstTexture->texture()); 
     }
+    SkASSERT(!hasMixedSamples || caps.shaderCaps()->dualSourceBlendingSupport());
 #endif
-    return this->onCreateXferProcessor(caps, colorPOI, coveragePOI, dstTexture);
+    return this->onCreateXferProcessor(caps, colorPOI, coveragePOI, hasMixedSamples, dstTexture);
 }
 
-bool GrXPFactory::willNeedDstTexture(const GrCaps& caps, const GrProcOptInfo& colorPOI,
-                                    const GrProcOptInfo& coveragePOI) const {
-    return (this->willReadDstColor(caps, colorPOI, coveragePOI) 
-            && !caps.shaderCaps()->dstReadInShaderSupport());
+bool GrXPFactory::willNeedDstTexture(const GrCaps& caps,
+                                     const GrProcOptInfo& colorPOI,
+                                     const GrProcOptInfo& coveragePOI,
+                                     bool hasMixedSamples) const {
+    return (this->willReadDstColor(caps, colorPOI, coveragePOI, hasMixedSamples) &&
+            !caps.shaderCaps()->dstReadInShaderSupport());
 }
index 0023752..c732098 100644 (file)
@@ -224,7 +224,16 @@ GrXferProcessor*
 GrCoverageSetOpXPFactory::onCreateXferProcessor(const GrCaps& caps,
                                                 const GrProcOptInfo& colorPOI,
                                                 const GrProcOptInfo& covPOI,
+                                                bool hasMixedSamples,
                                                 const DstTexture* dst) const {
+    // We don't support inverting coverage with mixed samples. We don't expect to ever want this in
+    // the future, however we could at some point make this work using an inverted coverage
+    // modulation table. Note that an inverted table still won't work if there are coverage procs.
+    if (fInvertCoverage && hasMixedSamples) {
+        SkASSERT(false);
+        return NULL;
+    }
+
     return CoverageSetOpXP::Create(fRegionOp, fInvertCoverage);
 }
 
index 3439a82..b43d2d4 100644 (file)
@@ -524,8 +524,8 @@ public:
         this->initClassID<CustomXP>();
     }
 
-    CustomXP(SkXfermode::Mode mode, const DstTexture* dstTexture)
-        : INHERITED(dstTexture, true),
+    CustomXP(const DstTexture* dstTexture, bool hasMixedSamples, SkXfermode::Mode mode)
+        : INHERITED(dstTexture, true, hasMixedSamples),
           fMode(mode),
           fHWBlendEquation(static_cast<GrBlendEquation>(-1)) {
         this->initClassID<CustomXP>();
@@ -606,8 +606,8 @@ private:
         GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
         fsBuilder->enableAdvancedBlendEquationIfNeeded(xp.hwBlendEquation());
 
-        // Apply coverage by multiplying it into the src color before blending.
-        // (See onGetOptimizations())
+        // Apply coverage by multiplying it into the src color before blending. Mixed samples will
+        // "just work" automatically. (See onGetOptimizations())
         if (xp.readsCoverage()) {
             fsBuilder->codeAppendf("%s = %s * %s;",
                                    args.fOutputPrimary, args.fInputCoverage, args.fInputColor);
@@ -786,17 +786,19 @@ GrXferProcessor*
 GrCustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
                                          const GrProcOptInfo& colorPOI,
                                          const GrProcOptInfo& coveragePOI,
+                                         bool hasMixedSamples,
                                          const DstTexture* dstTexture) const {
     if (can_use_hw_blend_equation(coveragePOI, caps)) {
         SkASSERT(!dstTexture || !dstTexture->texture());
         return SkNEW_ARGS(CustomXP, (fMode, fHWBlendEquation));
     }
-    return SkNEW_ARGS(CustomXP, (fMode, dstTexture));
+    return SkNEW_ARGS(CustomXP, (dstTexture, hasMixedSamples, fMode));
 }
 
 bool GrCustomXPFactory::willReadDstColor(const GrCaps& caps,
                                          const GrProcOptInfo& colorPOI,
-                                         const GrProcOptInfo& coveragePOI) const {
+                                         const GrProcOptInfo& coveragePOI,
+                                         bool hasMixedSamples) const {
     return !can_use_hw_blend_equation(coveragePOI, caps);
 }
 
index 0b893b8..9157f36 100644 (file)
@@ -71,11 +71,13 @@ private:
     GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
                                            const GrProcOptInfo& colorPOI,
                                            const GrProcOptInfo& coveragePOI,
+                                           bool hasMixedSamples,
                                            const DstTexture*) const override; 
 
     bool willReadDstColor(const GrCaps& caps,
                           const GrProcOptInfo& colorPOI,
-                          const GrProcOptInfo& coveragePOI) const override;
+                          const GrProcOptInfo& coveragePOI,
+                          bool hasMixedSamples) const override;
 
     bool onIsEqual(const GrXPFactory& xpfBase) const override {
         const GrCustomXPFactory& xpf = xpfBase.cast<GrCustomXPFactory>();
index 365a569..e3f588a 100644 (file)
@@ -101,6 +101,7 @@ GrXferProcessor*
 GrDisableColorXPFactory::onCreateXferProcessor(const GrCaps& caps,
                                                const GrProcOptInfo& colorPOI,
                                                const GrProcOptInfo& covPOI,
+                                               bool hasMixedSamples,
                                                const DstTexture* dst) const {
     return DisableColorXP::Create();
 }
index ee2ed53..2f57064 100644 (file)
@@ -35,11 +35,13 @@ private:
     GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
                                            const GrProcOptInfo& colorPOI,
                                            const GrProcOptInfo& coveragePOI,
+                                           bool hasMixedSamples,
                                            const DstTexture* dstTexture) const override;
 
     bool willReadDstColor(const GrCaps& caps,
                           const GrProcOptInfo& colorPOI,
-                          const GrProcOptInfo& coveragePOI) const override {
+                          const GrProcOptInfo& coveragePOI,
+                          bool hasMixedSamples) const override {
         return false;
     }
 
index ecaa87f..df44a1b 100644 (file)
@@ -288,21 +288,23 @@ static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
     /* screen */     COEFF_FORMULA(   kOne_GrBlendCoeff,    kISC_GrBlendCoeff),
 }}};
 
-static BlendFormula get_blend_formula(SkXfermode::Mode xfermode,
-                                      const GrProcOptInfo& colorPOI,
-                                      const GrProcOptInfo& coveragePOI) {
+static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
+                                      const GrProcOptInfo& coveragePOI,
+                                      bool hasMixedSamples,
+                                      SkXfermode::Mode xfermode) {
     SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
     SkASSERT(!coveragePOI.isFourChannelOutput());
 
-    return gBlendTable[colorPOI.isOpaque()][!coveragePOI.isSolidWhite()][xfermode];
+    bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples;
+    return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 class PorterDuffXferProcessor : public GrXferProcessor {
 public:
-    static GrXferProcessor* Create(BlendFormula blendFormula) {
-        return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula));
+    PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
+        this->initClassID<PorterDuffXferProcessor>();
     }
 
     const char* name() const override { return "Porter Duff"; }
@@ -312,10 +314,6 @@ public:
     BlendFormula getBlendFormula() const { return fBlendFormula; }
 
 private:
-    PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
-        this->initClassID<PorterDuffXferProcessor>();
-    }
-
     GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
                                                  const GrProcOptInfo& coveragePOI,
                                                  bool doesStencilWrite,
@@ -353,6 +351,7 @@ static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmen
             fsBuilder->codeAppendf("%s = vec4(0.0);", output);
             break;
         case BlendFormula::kCoverage_OutputType:
+            // We can have a coverage formula while not reading coverage if there are mixed samples.
             fsBuilder->codeAppendf("%s = %s;",
                                    output, xp.readsCoverage() ? inCoverage : "vec4(1.0)");
             break;
@@ -455,8 +454,12 @@ PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
 
 class ShaderPDXferProcessor : public GrXferProcessor {
 public:
-    static GrXferProcessor* Create(SkXfermode::Mode xfermode, const DstTexture* dstTexture) {
-        return SkNEW_ARGS(ShaderPDXferProcessor, (xfermode, dstTexture));
+    ShaderPDXferProcessor(const DstTexture* dstTexture,
+                          bool hasMixedSamples,
+                          SkXfermode::Mode xfermode)
+        : INHERITED(dstTexture, true, hasMixedSamples)
+        , fXfermode(xfermode) {
+        this->initClassID<ShaderPDXferProcessor>();
     }
 
     const char* name() const override { return "Porter Duff Shader"; }
@@ -466,12 +469,6 @@ public:
     SkXfermode::Mode getXfermode() const { return fXfermode; }
 
 private:
-    ShaderPDXferProcessor(SkXfermode::Mode xfermode, const DstTexture* dstTexture)
-        : INHERITED(dstTexture, true)
-        , fXfermode(xfermode) {
-        this->initClassID<ShaderPDXferProcessor>();
-    }
-
     GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrProcOptInfo&,
                                                  bool, GrColor*, const GrCaps&) override {
         return kNone_Opt;
@@ -738,19 +735,20 @@ GrXferProcessor*
 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
                                              const GrProcOptInfo& colorPOI,
                                              const GrProcOptInfo& covPOI,
+                                             bool hasMixedSamples,
                                              const DstTexture* dstTexture) const {
     if (covPOI.isFourChannelOutput()) {
         SkASSERT(!dstTexture || !dstTexture->texture());
         return PDLCDXferProcessor::Create(fXfermode, colorPOI);
     }
 
-    BlendFormula blendFormula = get_blend_formula(fXfermode, colorPOI, covPOI);
+    BlendFormula blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
     if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
-        return ShaderPDXferProcessor::Create(fXfermode, dstTexture);
+        return SkNEW_ARGS(ShaderPDXferProcessor, (dstTexture, hasMixedSamples, fXfermode));
     }
 
     SkASSERT(!dstTexture || !dstTexture->texture());
-    return PorterDuffXferProcessor::Create(blendFormula);
+    return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula));
 }
 
 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
@@ -795,15 +793,17 @@ void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorP
 
 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
                                              const GrProcOptInfo& colorPOI,
-                                             const GrProcOptInfo& coveragePOI) const {
-    if (coveragePOI.isFourChannelOutput()) {
-        return false; // The LCD XP never does a dst read.
+                                             const GrProcOptInfo& covPOI,
+                                             bool hasMixedSamples) const {
+    if (caps.shaderCaps()->dualSourceBlendingSupport()) {
+        return false;
+    }
+    if (covPOI.isFourChannelOutput()) {
+        return false; // The LCD XP will abort rather than doing a dst read.
     }
-
     // We fallback on the shader XP when the blend formula would use dual source blending but we
     // don't have support for it.
-    return !caps.shaderCaps()->dualSourceBlendingSupport() &&
-           get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutput();
+    return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput();
 }
 
 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
index 3d3ab49..e624971 100644 (file)
@@ -63,7 +63,14 @@ void GrGLXferProcessor::emitCode(const EmitArgs& args) {
                                   args.fXP);
 
     // Apply coverage.
-    if (args.fXP.readsCoverage()) {
+    if (args.fXP.dstReadUsesMixedSamples()) {
+        if (args.fXP.readsCoverage()) {
+            fsBuilder->codeAppendf("%s *= %s;", args.fOutputPrimary, args.fInputCoverage);
+            fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, args.fInputCoverage);
+        } else {
+            fsBuilder->codeAppendf("%s = vec4(1.0);", args.fOutputSecondary);
+        }
+    } else if (args.fXP.readsCoverage()) {
         fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
                                args.fOutputPrimary, args.fInputCoverage,
                                args.fOutputPrimary, args.fInputCoverage, dstColor);
index c56af1d..730d7bd 100644 (file)
@@ -75,10 +75,11 @@ public:
         XPInfo(skiatest::Reporter* reporter, SkXfermode::Mode xfermode, const GrCaps& caps,
                const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI) {
             SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(xfermode));
-            SkAutoTUnref<GrXferProcessor> xp(xpf->createXferProcessor(colorPOI, covPOI, 0, caps));
-            TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI));
+            SkAutoTUnref<GrXferProcessor> xp(
+                xpf->createXferProcessor(colorPOI, covPOI, false, NULL, caps));
+            TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI, false));
             xpf->getInvariantBlendedColor(colorPOI, &fBlendedColor);
-            fOptFlags = xp->getOptimizations(colorPOI, covPOI, false, 0, caps);
+            fOptFlags = xp->getOptimizations(colorPOI, covPOI, false, NULL, caps);
             GetXPOutputTypes(xp, &fPrimaryOutputType, &fSecondaryOutputType);
             xp->getBlendInfo(&fBlendInfo);
             TEST_ASSERT(!xp->willReadDstColor());
@@ -922,9 +923,10 @@ static void test_lcd_coverage(skiatest::Reporter* reporter, const GrCaps& caps)
     SkASSERT(covPOI.isFourChannelOutput());
 
     SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode));
-    TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI));
+    TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI, false));
 
-    SkAutoTUnref<GrXferProcessor> xp(xpf->createXferProcessor(colorPOI, covPOI, 0, caps));
+    SkAutoTUnref<GrXferProcessor> xp(
+        xpf->createXferProcessor(colorPOI, covPOI, false, NULL, caps));
     if (!xp) {
         ERRORF(reporter, "Failed to create an XP with LCD coverage.");
         return;
@@ -994,12 +996,10 @@ static void test_no_dual_source_blending(skiatest::Reporter* reporter) {
             for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
                 SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
                 SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(xfermode));
-                SkAutoTUnref<GrXferProcessor> xp;
-                if (xpf->willNeedDstTexture(caps, colorPOI, covPOI)) {
-                    xp.reset(xpf->createXferProcessor(colorPOI, covPOI, &fakeDstTexture, caps));
-                } else {
-                    xp.reset(xpf->createXferProcessor(colorPOI, covPOI, NULL, caps));
-                }
+                GrXferProcessor::DstTexture* dstTexture =
+                    xpf->willNeedDstTexture(caps, colorPOI, covPOI, false) ? &fakeDstTexture : 0;
+                SkAutoTUnref<GrXferProcessor> xp(
+                    xpf->createXferProcessor(colorPOI, covPOI, false, dstTexture, caps));
                 if (!xp) {
                     ERRORF(reporter, "Failed to create an XP without dual source blending.");
                     return;