1 /* 2 * Copyright 2015 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/GrCustomXfermode.h" 9 10 #include "GrCoordTransform.h" 11 #include "GrContext.h" 12 #include "GrFragmentProcessor.h" 13 #include "GrInvariantOutput.h" 14 #include "GrPipeline.h" 15 #include "GrProcessor.h" 16 #include "GrTexture.h" 17 #include "GrTextureAccess.h" 18 #include "SkXfermode.h" 19 #include "glsl/GrGLSLBlend.h" 20 #include "glsl/GrGLSLCaps.h" 21 #include "glsl/GrGLSLFragmentProcessor.h" 22 #include "glsl/GrGLSLFragmentShaderBuilder.h" 23 #include "glsl/GrGLSLProgramDataManager.h" 24 #include "glsl/GrGLSLUniformHandler.h" 25 #include "glsl/GrGLSLXferProcessor.h" 26 27 bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) { 28 return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode; 29 } 30 31 /////////////////////////////////////////////////////////////////////////////// 32 // Static helpers 33 /////////////////////////////////////////////////////////////////////////////// 34 35 static GrBlendEquation hw_blend_equation(SkXfermode::Mode mode) { 36 enum { kOffset = kOverlay_GrBlendEquation - SkXfermode::kOverlay_Mode }; 37 return static_cast<GrBlendEquation>(mode + kOffset); 38 39 GR_STATIC_ASSERT(kOverlay_GrBlendEquation == SkXfermode::kOverlay_Mode + kOffset); 40 GR_STATIC_ASSERT(kDarken_GrBlendEquation == SkXfermode::kDarken_Mode + kOffset); 41 GR_STATIC_ASSERT(kLighten_GrBlendEquation == SkXfermode::kLighten_Mode + kOffset); 42 GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == SkXfermode::kColorDodge_Mode + kOffset); 43 GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == SkXfermode::kColorBurn_Mode + kOffset); 44 GR_STATIC_ASSERT(kHardLight_GrBlendEquation == SkXfermode::kHardLight_Mode + kOffset); 45 GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == SkXfermode::kSoftLight_Mode + kOffset); 46 GR_STATIC_ASSERT(kDifference_GrBlendEquation == SkXfermode::kDifference_Mode + kOffset); 47 GR_STATIC_ASSERT(kExclusion_GrBlendEquation == SkXfermode::kExclusion_Mode + kOffset); 48 GR_STATIC_ASSERT(kMultiply_GrBlendEquation == SkXfermode::kMultiply_Mode + kOffset); 49 GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == SkXfermode::kHue_Mode + kOffset); 50 GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == SkXfermode::kSaturation_Mode + kOffset); 51 GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == SkXfermode::kColor_Mode + kOffset); 52 GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == SkXfermode::kLuminosity_Mode + kOffset); 53 GR_STATIC_ASSERT(kGrBlendEquationCnt == SkXfermode::kLastMode + 1 + kOffset); 54 } 55 56 static bool can_use_hw_blend_equation(GrBlendEquation equation, 57 const GrPipelineOptimizations& opt, 58 const GrCaps& caps) { 59 if (!caps.advancedBlendEquationSupport()) { 60 return false; 61 } 62 if (opt.fOverrides.fUsePLSDstRead) { 63 return false; 64 } 65 if (opt.fCoveragePOI.isFourChannelOutput()) { 66 return false; // LCD coverage must be applied after the blend equation. 67 } 68 if (caps.canUseAdvancedBlendEquation(equation)) { 69 return false; 70 } 71 return true; 72 } 73 74 /////////////////////////////////////////////////////////////////////////////// 75 // Xfer Processor 76 /////////////////////////////////////////////////////////////////////////////// 77 78 class CustomXP : public GrXferProcessor { 79 public: 80 CustomXP(SkXfermode::Mode mode, GrBlendEquation hwBlendEquation) 81 : fMode(mode), 82 fHWBlendEquation(hwBlendEquation) { 83 this->initClassID<CustomXP>(); 84 } 85 86 CustomXP(const DstTexture* dstTexture, bool hasMixedSamples, SkXfermode::Mode mode) 87 : INHERITED(dstTexture, true, hasMixedSamples), 88 fMode(mode), 89 fHWBlendEquation(static_cast<GrBlendEquation>(-1)) { 90 this->initClassID<CustomXP>(); 91 } 92 93 const char* name() const override { return "Custom Xfermode"; } 94 95 GrGLSLXferProcessor* createGLSLInstance() const override; 96 97 SkXfermode::Mode mode() const { return fMode; } 98 bool hasHWBlendEquation() const { return -1 != static_cast<int>(fHWBlendEquation); } 99 100 GrBlendEquation hwBlendEquation() const { 101 SkASSERT(this->hasHWBlendEquation()); 102 return fHWBlendEquation; 103 } 104 105 private: 106 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, 107 bool doesStencilWrite, 108 GrColor* overrideColor, 109 const GrCaps& caps) const override; 110 111 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; 112 113 GrXferBarrierType onXferBarrier(const GrRenderTarget*, const GrCaps&) const override; 114 115 void onGetBlendInfo(BlendInfo*) const override; 116 117 bool onIsEqual(const GrXferProcessor& xpBase) const override; 118 119 const SkXfermode::Mode fMode; 120 const GrBlendEquation fHWBlendEquation; 121 122 typedef GrXferProcessor INHERITED; 123 }; 124 125 /////////////////////////////////////////////////////////////////////////////// 126 127 class GLCustomXP : public GrGLSLXferProcessor { 128 public: 129 GLCustomXP(const GrXferProcessor&) {} 130 ~GLCustomXP() override {} 131 132 static void GenKey(const GrXferProcessor& p, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) { 133 const CustomXP& xp = p.cast<CustomXP>(); 134 uint32_t key = 0; 135 if (xp.hasHWBlendEquation()) { 136 SkASSERT(caps.advBlendEqInteraction() > 0); // 0 will mean !xp.hasHWBlendEquation(). 137 key |= caps.advBlendEqInteraction(); 138 GR_STATIC_ASSERT(GrGLSLCaps::kLast_AdvBlendEqInteraction < 4); 139 } 140 if (!xp.hasHWBlendEquation() || caps.mustEnableSpecificAdvBlendEqs()) { 141 key |= xp.mode() << 3; 142 } 143 b->add32(key); 144 } 145 146 private: 147 void emitOutputsForBlendState(const EmitArgs& args) override { 148 const CustomXP& xp = args.fXP.cast<CustomXP>(); 149 SkASSERT(xp.hasHWBlendEquation()); 150 151 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; 152 fragBuilder->enableAdvancedBlendEquationIfNeeded(xp.hwBlendEquation()); 153 154 // Apply coverage by multiplying it into the src color before blending. Mixed samples will 155 // "just work" automatically. (See onGetOptimizations()) 156 if (args.fInputCoverage) { 157 fragBuilder->codeAppendf("%s = %s * %s;", 158 args.fOutputPrimary, args.fInputCoverage, args.fInputColor); 159 } else { 160 fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor); 161 } 162 } 163 164 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, 165 GrGLSLUniformHandler* uniformHandler, 166 const char* srcColor, 167 const char* srcCoverage, 168 const char* dstColor, 169 const char* outColor, 170 const char* outColorSecondary, 171 const GrXferProcessor& proc) override { 172 const CustomXP& xp = proc.cast<CustomXP>(); 173 SkASSERT(!xp.hasHWBlendEquation()); 174 175 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.mode()); 176 177 // Apply coverage. 178 INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor, 179 outColorSecondary, xp); 180 } 181 182 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {} 183 184 typedef GrGLSLXferProcessor INHERITED; 185 }; 186 187 /////////////////////////////////////////////////////////////////////////////// 188 189 void CustomXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { 190 GLCustomXP::GenKey(*this, caps, b); 191 } 192 193 GrGLSLXferProcessor* CustomXP::createGLSLInstance() const { 194 SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation()); 195 return new GLCustomXP(*this); 196 } 197 198 bool CustomXP::onIsEqual(const GrXferProcessor& other) const { 199 const CustomXP& s = other.cast<CustomXP>(); 200 return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation; 201 } 202 203 GrXferProcessor::OptFlags CustomXP::onGetOptimizations(const GrPipelineOptimizations& optimizations, 204 bool doesStencilWrite, 205 GrColor* overrideColor, 206 const GrCaps& caps) const { 207 /* 208 Most the optimizations we do here are based on tweaking alpha for coverage. 209 210 The general SVG blend equation is defined in the spec as follows: 211 212 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa) 213 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa) 214 215 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha, 216 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied 217 RGB colors.) 218 219 For every blend mode supported by this class, i.e. the "advanced" blend 220 modes, X=Y=Z=1 and this equation reduces to the PDF blend equation. 221 222 It can be shown that when X=Y=Z=1, these equations can modulate alpha for 223 coverage. 224 225 226 == Color == 227 228 We substitute Y=Z=1 and define a blend() function that calculates Dca' in 229 terms of premultiplied alpha only: 230 231 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0, 232 Sca : if Da == 0, 233 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if Sa,Da != 0} 234 235 And for coverage modulation, we use a post blend src-over model: 236 237 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 238 239 (Where f is the fractional coverage.) 240 241 Next we show that canTweakAlphaForCoverage() is true by proving the 242 following relationship: 243 244 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 245 246 General case (f,Sa,Da != 0): 247 248 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 249 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca [Sa,Da != 0, definition of blend()] 250 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca 251 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca 252 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca 253 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca 254 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) 255 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0] 256 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()] 257 258 Corner cases (Sa=0, Da=0, and f=0): 259 260 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 261 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()] 262 = Dca 263 = blend(0, Dca, 0, Da) [definition of blend()] 264 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0] 265 266 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 267 = f * Sca + (1-f) * Dca [Da=0, definition of blend()] 268 = f * Sca [Da=0] 269 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()] 270 = blend(f*Sca, Dca, f*Sa, Da) [Da=0] 271 272 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 273 = Dca [f=0] 274 = blend(0, Dca, 0, Da) [definition of blend()] 275 = blend(f*Sca, Dca, f*Sa, Da) [f=0] 276 277 == Alpha == 278 279 We substitute X=Y=Z=1 and define a blend() function that calculates Da': 280 281 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa) 282 = Sa * Da + Sa - Sa * Da + Da - Da * Sa 283 = Sa + Da - Sa * Da 284 285 We use the same model for coverage modulation as we did with color: 286 287 Da'' = f * blend(Sa, Da) + (1-f) * Da 288 289 And show that canTweakAlphaForCoverage() is true by proving the following 290 relationship: 291 292 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da 293 294 295 f * blend(Sa, Da) + (1-f) * Da 296 = f * (Sa + Da - Sa * Da) + (1-f) * Da 297 = f*Sa + f*Da - f*Sa * Da + Da - f*Da 298 = f*Sa - f*Sa * Da + Da 299 = f*Sa + Da - f*Sa * Da 300 = blend(f*Sa, Da) 301 */ 302 303 OptFlags flags = kNone_OptFlags; 304 if (optimizations.fColorPOI.allStagesMultiplyInput()) { 305 flags |= kCanTweakAlphaForCoverage_OptFlag; 306 } 307 if (this->hasHWBlendEquation() && optimizations.fCoveragePOI.isSolidWhite()) { 308 flags |= kIgnoreCoverage_OptFlag; 309 } 310 return flags; 311 } 312 313 GrXferBarrierType CustomXP::onXferBarrier(const GrRenderTarget* rt, const GrCaps& caps) const { 314 if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) { 315 return kBlend_GrXferBarrierType; 316 } 317 return kNone_GrXferBarrierType; 318 } 319 320 void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const { 321 if (this->hasHWBlendEquation()) { 322 blendInfo->fEquation = this->hwBlendEquation(); 323 } 324 } 325 326 /////////////////////////////////////////////////////////////////////////////// 327 class CustomXPFactory : public GrXPFactory { 328 public: 329 CustomXPFactory(SkXfermode::Mode mode); 330 331 void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, 332 GrXPFactory::InvariantBlendedColor*) const override; 333 334 private: 335 GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, 336 const GrPipelineOptimizations& optimizations, 337 bool hasMixedSamples, 338 const DstTexture*) const override; 339 340 bool onWillReadDstColor(const GrCaps& caps, 341 const GrPipelineOptimizations& optimizations, 342 bool hasMixedSamples) const override; 343 344 bool onIsEqual(const GrXPFactory& xpfBase) const override { 345 const CustomXPFactory& xpf = xpfBase.cast<CustomXPFactory>(); 346 return fMode == xpf.fMode; 347 } 348 349 GR_DECLARE_XP_FACTORY_TEST; 350 351 SkXfermode::Mode fMode; 352 GrBlendEquation fHWBlendEquation; 353 354 typedef GrXPFactory INHERITED; 355 }; 356 357 CustomXPFactory::CustomXPFactory(SkXfermode::Mode mode) 358 : fMode(mode), 359 fHWBlendEquation(hw_blend_equation(mode)) { 360 SkASSERT(GrCustomXfermode::IsSupportedMode(fMode)); 361 this->initClassID<CustomXPFactory>(); 362 } 363 364 GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps, 365 const GrPipelineOptimizations& opt, 366 bool hasMixedSamples, 367 const DstTexture* dstTexture) const { 368 if (can_use_hw_blend_equation(fHWBlendEquation, opt, caps)) { 369 SkASSERT(!dstTexture || !dstTexture->texture()); 370 return new CustomXP(fMode, fHWBlendEquation); 371 } 372 return new CustomXP(dstTexture, hasMixedSamples, fMode); 373 } 374 375 bool CustomXPFactory::onWillReadDstColor(const GrCaps& caps, 376 const GrPipelineOptimizations& optimizations, 377 bool hasMixedSamples) const { 378 return !can_use_hw_blend_equation(fHWBlendEquation, optimizations, caps); 379 } 380 381 void CustomXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, 382 InvariantBlendedColor* blendedColor) const { 383 blendedColor->fWillBlendWithDst = true; 384 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; 385 } 386 387 GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory); 388 const GrXPFactory* CustomXPFactory::TestCreate(GrProcessorTestData* d) { 389 int mode = d->fRandom->nextRangeU(SkXfermode::kLastCoeffMode + 1, 390 SkXfermode::kLastSeparableMode); 391 392 return new CustomXPFactory(static_cast<SkXfermode::Mode>(mode)); 393 } 394 395 /////////////////////////////////////////////////////////////////////////////// 396 397 GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) { 398 if (!GrCustomXfermode::IsSupportedMode(mode)) { 399 return nullptr; 400 } else { 401 return new CustomXPFactory(mode); 402 } 403 } 404