/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "effects/GrCoverageSetOpXP.h" #include "GrCaps.h" #include "GrColor.h" #include "GrDrawContext.h" #include "GrPipeline.h" #include "GrProcessor.h" #include "GrProcOptInfo.h" #include "glsl/GrGLSLBlend.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLXferProcessor.h" class CoverageSetOpXP : public GrXferProcessor { public: static GrXferProcessor* Create(SkRegion::Op regionOp, bool invertCoverage) { return new CoverageSetOpXP(regionOp, invertCoverage); } ~CoverageSetOpXP() override; const char* name() const override { return "Coverage Set Op"; } GrGLSLXferProcessor* createGLSLInstance() const override; bool invertCoverage() const { return fInvertCoverage; } private: CoverageSetOpXP(SkRegion::Op regionOp, bool fInvertCoverage); GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, bool doesStencilWrite, GrColor* color, const GrCaps& caps) const override; void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override; bool onIsEqual(const GrXferProcessor& xpBase) const override { const CoverageSetOpXP& xp = xpBase.cast(); return (fRegionOp == xp.fRegionOp && fInvertCoverage == xp.fInvertCoverage); } SkRegion::Op fRegionOp; bool fInvertCoverage; typedef GrXferProcessor INHERITED; }; /////////////////////////////////////////////////////////////////////////////// class GLCoverageSetOpXP : public GrGLSLXferProcessor { public: GLCoverageSetOpXP(const GrProcessor&) {} ~GLCoverageSetOpXP() override {} static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) { const CoverageSetOpXP& xp = processor.cast(); uint32_t key = xp.invertCoverage() ? 0x0 : 0x1; b->add32(key); }; private: void emitOutputsForBlendState(const EmitArgs& args) override { const CoverageSetOpXP& xp = args.fXP.cast(); GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; if (xp.invertCoverage()) { fragBuilder->codeAppendf("%s = 1.0 - %s;", args.fOutputPrimary, args.fInputCoverage); } else { fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage); } } void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}; typedef GrGLSLXferProcessor INHERITED; }; /////////////////////////////////////////////////////////////////////////////// CoverageSetOpXP::CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage) : fRegionOp(regionOp) , fInvertCoverage(invertCoverage) { this->initClassID(); } CoverageSetOpXP::~CoverageSetOpXP() { } void CoverageSetOpXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { GLCoverageSetOpXP::GenKey(*this, caps, b); } GrGLSLXferProcessor* CoverageSetOpXP::createGLSLInstance() const { return new GLCoverageSetOpXP(*this); } GrXferProcessor::OptFlags CoverageSetOpXP::onGetOptimizations(const GrPipelineOptimizations& optimizations, bool doesStencilWrite, GrColor* color, const GrCaps& caps) const { // We never look at the color input return GrXferProcessor::kIgnoreColor_OptFlag; } void CoverageSetOpXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const { switch (fRegionOp) { case SkRegion::kReplace_Op: blendInfo->fSrcBlend = kOne_GrBlendCoeff; blendInfo->fDstBlend = kZero_GrBlendCoeff; break; case SkRegion::kIntersect_Op: blendInfo->fSrcBlend = kDC_GrBlendCoeff; blendInfo->fDstBlend = kZero_GrBlendCoeff; break; case SkRegion::kUnion_Op: blendInfo->fSrcBlend = kOne_GrBlendCoeff; blendInfo->fDstBlend = kISC_GrBlendCoeff; break; case SkRegion::kXOR_Op: blendInfo->fSrcBlend = kIDC_GrBlendCoeff; blendInfo->fDstBlend = kISC_GrBlendCoeff; break; case SkRegion::kDifference_Op: blendInfo->fSrcBlend = kZero_GrBlendCoeff; blendInfo->fDstBlend = kISC_GrBlendCoeff; break; case SkRegion::kReverseDifference_Op: blendInfo->fSrcBlend = kIDC_GrBlendCoeff; blendInfo->fDstBlend = kZero_GrBlendCoeff; break; } blendInfo->fBlendConstant = 0; } /////////////////////////////////////////////////////////////////////////////// class ShaderCSOXferProcessor : public GrXferProcessor { public: ShaderCSOXferProcessor(const DstTexture* dstTexture, bool hasMixedSamples, SkRegion::Op regionOp, bool invertCoverage) : INHERITED(dstTexture, true, hasMixedSamples) , fRegionOp(regionOp) , fInvertCoverage(invertCoverage) { this->initClassID(); } const char* name() const override { return "Coverage Set Op Shader"; } GrGLSLXferProcessor* createGLSLInstance() const override; SkRegion::Op regionOp() const { return fRegionOp; } bool invertCoverage() const { return fInvertCoverage; } private: GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations&, bool, GrColor*, const GrCaps&) const override { // We never look at the color input return GrXferProcessor::kIgnoreColor_OptFlag; } void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; bool onIsEqual(const GrXferProcessor& xpBase) const override { const ShaderCSOXferProcessor& xp = xpBase.cast(); return (fRegionOp == xp.fRegionOp && fInvertCoverage == xp.fInvertCoverage); } SkRegion::Op fRegionOp; bool fInvertCoverage; typedef GrXferProcessor INHERITED; }; /////////////////////////////////////////////////////////////////////////////// class GLShaderCSOXferProcessor : public GrGLSLXferProcessor { public: static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) { const ShaderCSOXferProcessor& xp = processor.cast(); b->add32(xp.regionOp()); uint32_t key = xp.invertCoverage() ? 0x0 : 0x1; b->add32(key); } private: void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, GrGLSLUniformHandler* uniformHandler, const char* srcColor, const char* srcCoverage, const char* dstColor, const char* outColor, const char* outColorSecondary, const GrXferProcessor& proc) override { const ShaderCSOXferProcessor& xp = proc.cast(); if (xp.invertCoverage()) { fragBuilder->codeAppendf("%s = 1.0 - %s;", outColor, srcCoverage); } else { fragBuilder->codeAppendf("%s = %s;", outColor, srcCoverage); } GrGLSLBlend::AppendRegionOp(fragBuilder, outColor, dstColor, outColor, xp.regionOp()); } void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {} typedef GrGLSLXferProcessor INHERITED; }; /////////////////////////////////////////////////////////////////////////////// void ShaderCSOXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder* b) const { GLShaderCSOXferProcessor::GenKey(*this, b); } GrGLSLXferProcessor* ShaderCSOXferProcessor::createGLSLInstance() const { return new GLShaderCSOXferProcessor; } /////////////////////////////////////////////////////////////////////////////// // GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) : fRegionOp(regionOp) , fInvertCoverage(invertCoverage) { this->initClassID(); } sk_sp GrCoverageSetOpXPFactory::Make(SkRegion::Op regionOp, bool invertCoverage) { switch (regionOp) { case SkRegion::kReplace_Op: { if (invertCoverage) { static GrCoverageSetOpXPFactory gReplaceCDXPFI(regionOp, invertCoverage); return sk_sp(SkRef(&gReplaceCDXPFI)); } else { static GrCoverageSetOpXPFactory gReplaceCDXPF(regionOp, invertCoverage); return sk_sp(SkRef(&gReplaceCDXPF)); } break; } case SkRegion::kIntersect_Op: { if (invertCoverage) { static GrCoverageSetOpXPFactory gIntersectCDXPFI(regionOp, invertCoverage); return sk_sp(SkRef(&gIntersectCDXPFI)); } else { static GrCoverageSetOpXPFactory gIntersectCDXPF(regionOp, invertCoverage); return sk_sp(SkRef(&gIntersectCDXPF)); } break; } case SkRegion::kUnion_Op: { if (invertCoverage) { static GrCoverageSetOpXPFactory gUnionCDXPFI(regionOp, invertCoverage); return sk_sp(SkRef(&gUnionCDXPFI)); } else { static GrCoverageSetOpXPFactory gUnionCDXPF(regionOp, invertCoverage); return sk_sp(SkRef(&gUnionCDXPF)); } break; } case SkRegion::kXOR_Op: { if (invertCoverage) { static GrCoverageSetOpXPFactory gXORCDXPFI(regionOp, invertCoverage); return sk_sp(SkRef(&gXORCDXPFI)); } else { static GrCoverageSetOpXPFactory gXORCDXPF(regionOp, invertCoverage); return sk_sp(SkRef(&gXORCDXPF)); } break; } case SkRegion::kDifference_Op: { if (invertCoverage) { static GrCoverageSetOpXPFactory gDifferenceCDXPFI(regionOp, invertCoverage); return sk_sp(SkRef(&gDifferenceCDXPFI)); } else { static GrCoverageSetOpXPFactory gDifferenceCDXPF(regionOp, invertCoverage); return sk_sp(SkRef(&gDifferenceCDXPF)); } break; } case SkRegion::kReverseDifference_Op: { if (invertCoverage) { static GrCoverageSetOpXPFactory gRevDiffCDXPFI(regionOp, invertCoverage); return sk_sp(SkRef(&gRevDiffCDXPFI)); } else { static GrCoverageSetOpXPFactory gRevDiffCDXPF(regionOp, invertCoverage); return sk_sp(SkRef(&gRevDiffCDXPF)); } break; } default: return nullptr; } } GrXferProcessor* GrCoverageSetOpXPFactory::onCreateXferProcessor(const GrCaps& caps, const GrPipelineOptimizations& optimizations, 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 nullptr; } if (optimizations.fOverrides.fUsePLSDstRead) { return new ShaderCSOXferProcessor(dst, hasMixedSamples, fRegionOp, fInvertCoverage); } return CoverageSetOpXP::Create(fRegionOp, fInvertCoverage); } void GrCoverageSetOpXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, InvariantBlendedColor* blendedColor) const { blendedColor->fWillBlendWithDst = SkRegion::kReplace_Op != fRegionOp; blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; } GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory); sk_sp GrCoverageSetOpXPFactory::TestCreate(GrProcessorTestData* d) { SkRegion::Op regionOp = SkRegion::Op(d->fRandom->nextULessThan(SkRegion::kLastOp + 1)); bool invertCoverage = !d->fDrawContext->hasMixedSamples() && d->fRandom->nextBool(); return GrCoverageSetOpXPFactory::Make(regionOp, invertCoverage); }