From: cdalton Date: Mon, 8 Jun 2015 22:11:04 +0000 (-0700) Subject: Add mixed samples support to XPs X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~2147 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=86ae0a9e465f157eaa263ef7515e10619946ff83;p=platform%2Fupstream%2FlibSkiaSharp.git Add mixed samples support to XPs BUG=skia: Review URL: https://codereview.chromium.org/1164973002 --- diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h index 7ed98a3..8f2c69d 100644 --- a/include/gpu/GrXferProcessor.h +++ b/include/gpu/GrXferProcessor.h @@ -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; diff --git a/include/gpu/effects/GrCoverageSetOpXP.h b/include/gpu/effects/GrCoverageSetOpXP.h index 6067b5e..8511074 100644 --- a/include/gpu/effects/GrCoverageSetOpXP.h +++ b/include/gpu/effects/GrCoverageSetOpXP.h @@ -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; } diff --git a/include/gpu/effects/GrPorterDuffXferProcessor.h b/include/gpu/effects/GrPorterDuffXferProcessor.h index ca7de94..a26a892 100644 --- a/include/gpu/effects/GrPorterDuffXferProcessor.h +++ b/include/gpu/effects/GrPorterDuffXferProcessor.h @@ -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(); diff --git a/src/effects/SkArithmeticMode_gpu.cpp b/src/effects/SkArithmeticMode_gpu.cpp index 0d81c79..074cada 100644 --- a/src/effects/SkArithmeticMode_gpu.cpp +++ b/src/effects/SkArithmeticMode_gpu.cpp @@ -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)); } diff --git a/src/effects/SkArithmeticMode_gpu.h b/src/effects/SkArithmeticMode_gpu.h index 3334e2d..b9235b3 100644 --- a/src/effects/SkArithmeticMode_gpu.h +++ b/src/effects/SkArithmeticMode_gpu.h @@ -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; } diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp index d9d3d94..4feddb0 100644 --- a/src/gpu/GrPipeline.cpp +++ b/src/gpu/GrPipeline.cpp @@ -23,7 +23,7 @@ GrPipeline::GrPipeline(const GrPipelineBuilder& pipelineBuilder, // Create XferProcessor from DS's XPFactory SkAutoTUnref xferProcessor( pipelineBuilder.getXPFactory()->createXferProcessor( - colorPOI, coveragePOI, dstTexture, caps)); + colorPOI, coveragePOI, pipelineBuilder.hasMixedSamples(), dstTexture, caps)); GrColor overrideColor = GrColor_ILLEGAL; if (colorPOI.firstEffectiveStageIndex() != 0) { diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp index 8af89e8..26422fd 100644 --- a/src/gpu/GrPipelineBuilder.cpp +++ b/src/gpu/GrPipelineBuilder.cpp @@ -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) { diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h index dbbf98a..6a0e137 100644 --- a/src/gpu/GrPipelineBuilder.h +++ b/src/gpu/GrPipelineBuilder.h @@ -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(); + } + /// @} /////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp index 67c5dd8..1ead010 100644 --- a/src/gpu/GrXferProcessor.cpp +++ b/src/gpu/GrXferProcessor.cpp @@ -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()); } diff --git a/src/gpu/effects/GrCoverageSetOpXP.cpp b/src/gpu/effects/GrCoverageSetOpXP.cpp index 0023752..c732098 100644 --- a/src/gpu/effects/GrCoverageSetOpXP.cpp +++ b/src/gpu/effects/GrCoverageSetOpXP.cpp @@ -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); } diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp index 3439a82..b43d2d4 100644 --- a/src/gpu/effects/GrCustomXfermode.cpp +++ b/src/gpu/effects/GrCustomXfermode.cpp @@ -524,8 +524,8 @@ public: this->initClassID(); } - 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(-1)) { this->initClassID(); @@ -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); } diff --git a/src/gpu/effects/GrCustomXfermodePriv.h b/src/gpu/effects/GrCustomXfermodePriv.h index 0b893b8..9157f36 100644 --- a/src/gpu/effects/GrCustomXfermodePriv.h +++ b/src/gpu/effects/GrCustomXfermodePriv.h @@ -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(); diff --git a/src/gpu/effects/GrDisableColorXP.cpp b/src/gpu/effects/GrDisableColorXP.cpp index 365a569..e3f588a 100644 --- a/src/gpu/effects/GrDisableColorXP.cpp +++ b/src/gpu/effects/GrDisableColorXP.cpp @@ -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(); } diff --git a/src/gpu/effects/GrDisableColorXP.h b/src/gpu/effects/GrDisableColorXP.h index ee2ed53..2f57064 100644 --- a/src/gpu/effects/GrDisableColorXP.h +++ b/src/gpu/effects/GrDisableColorXP.h @@ -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; } diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index ecaa87f..df44a1b 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -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(); } 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(); - } - 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(); } 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(); - } - 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); diff --git a/src/gpu/gl/GrGLXferProcessor.cpp b/src/gpu/gl/GrGLXferProcessor.cpp index 3d3ab49..e624971 100644 --- a/src/gpu/gl/GrGLXferProcessor.cpp +++ b/src/gpu/gl/GrGLXferProcessor.cpp @@ -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); diff --git a/tests/GrPorterDuffTest.cpp b/tests/GrPorterDuffTest.cpp index c56af1d..730d7bd 100644 --- a/tests/GrPorterDuffTest.cpp +++ b/tests/GrPorterDuffTest.cpp @@ -75,10 +75,11 @@ public: XPInfo(skiatest::Reporter* reporter, SkXfermode::Mode xfermode, const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI) { SkAutoTUnref xpf(GrPorterDuffXPFactory::Create(xfermode)); - SkAutoTUnref xp(xpf->createXferProcessor(colorPOI, covPOI, 0, caps)); - TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI)); + SkAutoTUnref 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 xpf(GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode)); - TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI)); + TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI, false)); - SkAutoTUnref xp(xpf->createXferProcessor(colorPOI, covPOI, 0, caps)); + SkAutoTUnref 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(m); SkAutoTUnref xpf(GrPorterDuffXPFactory::Create(xfermode)); - SkAutoTUnref 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 xp( + xpf->createXferProcessor(colorPOI, covPOI, false, dstTexture, caps)); if (!xp) { ERRORF(reporter, "Failed to create an XP without dual source blending."); return;