1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "effects/GrCoverageSetOpXP.h" 9 #include "GrCaps.h" 10 #include "GrColor.h" 11 #include "GrPipeline.h" 12 #include "GrProcessor.h" 13 #include "GrRenderTargetContext.h" 14 #include "glsl/GrGLSLBlend.h" 15 #include "glsl/GrGLSLFragmentShaderBuilder.h" 16 #include "glsl/GrGLSLUniformHandler.h" 17 #include "glsl/GrGLSLXferProcessor.h" 18 19 class CoverageSetOpXP : public GrXferProcessor { 20 public: 21 static GrXferProcessor* Create(SkRegion::Op regionOp, bool invertCoverage) { 22 return new CoverageSetOpXP(regionOp, invertCoverage); 23 } 24 25 ~CoverageSetOpXP() override; 26 27 const char* name() const override { return "Coverage Set Op"; } 28 29 GrGLSLXferProcessor* createGLSLInstance() const override; 30 31 bool invertCoverage() const { return fInvertCoverage; } 32 33 private: 34 CoverageSetOpXP(SkRegion::Op regionOp, bool fInvertCoverage); 35 36 GrXferProcessor::OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const override; 37 38 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; 39 40 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override; 41 42 bool onIsEqual(const GrXferProcessor& xpBase) const override { 43 const CoverageSetOpXP& xp = xpBase.cast<CoverageSetOpXP>(); 44 return (fRegionOp == xp.fRegionOp && 45 fInvertCoverage == xp.fInvertCoverage); 46 } 47 48 SkRegion::Op fRegionOp; 49 bool fInvertCoverage; 50 51 typedef GrXferProcessor INHERITED; 52 }; 53 54 /////////////////////////////////////////////////////////////////////////////// 55 56 class GLCoverageSetOpXP : public GrGLSLXferProcessor { 57 public: 58 GLCoverageSetOpXP(const GrProcessor&) {} 59 60 ~GLCoverageSetOpXP() override {} 61 62 static void GenKey(const GrProcessor& processor, const GrShaderCaps& caps, 63 GrProcessorKeyBuilder* b) { 64 const CoverageSetOpXP& xp = processor.cast<CoverageSetOpXP>(); 65 uint32_t key = xp.invertCoverage() ? 0x0 : 0x1; 66 b->add32(key); 67 } 68 69 private: 70 void emitOutputsForBlendState(const EmitArgs& args) override { 71 const CoverageSetOpXP& xp = args.fXP.cast<CoverageSetOpXP>(); 72 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; 73 74 if (xp.invertCoverage()) { 75 fragBuilder->codeAppendf("%s = 1.0 - %s;", args.fOutputPrimary, args.fInputCoverage); 76 } else { 77 fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage); 78 } 79 } 80 81 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {} 82 83 typedef GrGLSLXferProcessor INHERITED; 84 }; 85 86 /////////////////////////////////////////////////////////////////////////////// 87 88 CoverageSetOpXP::CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage) 89 : fRegionOp(regionOp) 90 , fInvertCoverage(invertCoverage) { 91 this->initClassID<CoverageSetOpXP>(); 92 } 93 94 CoverageSetOpXP::~CoverageSetOpXP() { 95 } 96 97 void CoverageSetOpXP::onGetGLSLProcessorKey(const GrShaderCaps& caps, 98 GrProcessorKeyBuilder* b) const { 99 GLCoverageSetOpXP::GenKey(*this, caps, b); 100 } 101 102 GrGLSLXferProcessor* CoverageSetOpXP::createGLSLInstance() const { 103 return new GLCoverageSetOpXP(*this); 104 } 105 106 GrXferProcessor::OptFlags CoverageSetOpXP::onGetOptimizations( 107 const FragmentProcessorAnalysis&) const { 108 // We never look at the color input 109 return GrXferProcessor::kIgnoreColor_OptFlag; 110 } 111 112 void CoverageSetOpXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const { 113 switch (fRegionOp) { 114 case SkRegion::kReplace_Op: 115 blendInfo->fSrcBlend = kOne_GrBlendCoeff; 116 blendInfo->fDstBlend = kZero_GrBlendCoeff; 117 break; 118 case SkRegion::kIntersect_Op: 119 blendInfo->fSrcBlend = kDC_GrBlendCoeff; 120 blendInfo->fDstBlend = kZero_GrBlendCoeff; 121 break; 122 case SkRegion::kUnion_Op: 123 blendInfo->fSrcBlend = kOne_GrBlendCoeff; 124 blendInfo->fDstBlend = kISC_GrBlendCoeff; 125 break; 126 case SkRegion::kXOR_Op: 127 blendInfo->fSrcBlend = kIDC_GrBlendCoeff; 128 blendInfo->fDstBlend = kISC_GrBlendCoeff; 129 break; 130 case SkRegion::kDifference_Op: 131 blendInfo->fSrcBlend = kZero_GrBlendCoeff; 132 blendInfo->fDstBlend = kISC_GrBlendCoeff; 133 break; 134 case SkRegion::kReverseDifference_Op: 135 blendInfo->fSrcBlend = kIDC_GrBlendCoeff; 136 blendInfo->fDstBlend = kZero_GrBlendCoeff; 137 break; 138 } 139 blendInfo->fBlendConstant = 0; 140 } 141 142 /////////////////////////////////////////////////////////////////////////////// 143 144 constexpr GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, 145 bool invertCoverage) 146 : fRegionOp(regionOp), fInvertCoverage(invertCoverage) {} 147 148 const GrXPFactory* GrCoverageSetOpXPFactory::Get(SkRegion::Op regionOp, bool invertCoverage) { 149 // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are 150 // null. 151 #ifdef SK_BUILD_FOR_WIN 152 #define _CONSTEXPR_ 153 #else 154 #define _CONSTEXPR_ constexpr 155 #endif 156 switch (regionOp) { 157 case SkRegion::kReplace_Op: { 158 if (invertCoverage) { 159 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gReplaceCDXPFI( 160 SkRegion::kReplace_Op, true); 161 return &gReplaceCDXPFI; 162 } else { 163 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gReplaceCDXPF( 164 SkRegion::kReplace_Op, false); 165 return &gReplaceCDXPF; 166 } 167 } 168 case SkRegion::kIntersect_Op: { 169 if (invertCoverage) { 170 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gIntersectCDXPFI( 171 SkRegion::kIntersect_Op, true); 172 return &gIntersectCDXPFI; 173 } else { 174 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gIntersectCDXPF( 175 SkRegion::kIntersect_Op, false); 176 return &gIntersectCDXPF; 177 } 178 } 179 case SkRegion::kUnion_Op: { 180 if (invertCoverage) { 181 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gUnionCDXPFI(SkRegion::kUnion_Op, 182 true); 183 return &gUnionCDXPFI; 184 } else { 185 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gUnionCDXPF(SkRegion::kUnion_Op, 186 false); 187 return &gUnionCDXPF; 188 } 189 } 190 case SkRegion::kXOR_Op: { 191 if (invertCoverage) { 192 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gXORCDXPFI(SkRegion::kXOR_Op, 193 true); 194 return &gXORCDXPFI; 195 } else { 196 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gXORCDXPF(SkRegion::kXOR_Op, 197 false); 198 return &gXORCDXPF; 199 } 200 } 201 case SkRegion::kDifference_Op: { 202 if (invertCoverage) { 203 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gDifferenceCDXPFI( 204 SkRegion::kDifference_Op, true); 205 return &gDifferenceCDXPFI; 206 } else { 207 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gDifferenceCDXPF( 208 SkRegion::kDifference_Op, false); 209 return &gDifferenceCDXPF; 210 } 211 } 212 case SkRegion::kReverseDifference_Op: { 213 if (invertCoverage) { 214 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gRevDiffCDXPFI( 215 SkRegion::kReverseDifference_Op, true); 216 return &gRevDiffCDXPFI; 217 } else { 218 static _CONSTEXPR_ const GrCoverageSetOpXPFactory gRevDiffCDXPF( 219 SkRegion::kReverseDifference_Op, false); 220 return &gRevDiffCDXPF; 221 } 222 } 223 } 224 #undef _CONSTEXPR_ 225 SkFAIL("Unknown region op."); 226 return nullptr; 227 } 228 229 GrXferProcessor* GrCoverageSetOpXPFactory::onCreateXferProcessor( 230 const GrCaps& caps, 231 const FragmentProcessorAnalysis& analysis, 232 bool hasMixedSamples, 233 const DstTexture* dst) const { 234 // We don't support inverting coverage with mixed samples. We don't expect to ever want this in 235 // the future, however we could at some point make this work using an inverted coverage 236 // modulation table. Note that an inverted table still won't work if there are coverage procs. 237 if (fInvertCoverage && hasMixedSamples) { 238 SkASSERT(false); 239 return nullptr; 240 } 241 242 return CoverageSetOpXP::Create(fRegionOp, fInvertCoverage); 243 } 244 245 GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory); 246 247 #if GR_TEST_UTILS 248 const GrXPFactory* GrCoverageSetOpXPFactory::TestGet(GrProcessorTestData* d) { 249 SkRegion::Op regionOp = SkRegion::Op(d->fRandom->nextULessThan(SkRegion::kLastOp + 1)); 250 bool invertCoverage = !d->fRenderTargetContext->hasMixedSamples() && d->fRandom->nextBool(); 251 return GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage); 252 } 253 #endif 254