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 "GrCaps.h" 11 #include "GrCoordTransform.h" 12 #include "GrFragmentProcessor.h" 13 #include "GrPipeline.h" 14 #include "GrProcessor.h" 15 #include "GrShaderCaps.h" 16 #include "glsl/GrGLSLBlend.h" 17 #include "glsl/GrGLSLFragmentProcessor.h" 18 #include "glsl/GrGLSLFragmentShaderBuilder.h" 19 #include "glsl/GrGLSLProgramDataManager.h" 20 #include "glsl/GrGLSLUniformHandler.h" 21 #include "glsl/GrGLSLXferProcessor.h" 22 23 bool GrCustomXfermode::IsSupportedMode(SkBlendMode mode) { 24 return (int)mode > (int)SkBlendMode::kLastCoeffMode && 25 (int)mode <= (int)SkBlendMode::kLastMode; 26 } 27 28 /////////////////////////////////////////////////////////////////////////////// 29 // Static helpers 30 /////////////////////////////////////////////////////////////////////////////// 31 32 static constexpr GrBlendEquation hw_blend_equation(SkBlendMode mode) { 33 // In C++14 this could be a constexpr int variable. 34 #define EQ_OFFSET (kOverlay_GrBlendEquation - (int)SkBlendMode::kOverlay) 35 GR_STATIC_ASSERT(kOverlay_GrBlendEquation == (int)SkBlendMode::kOverlay + EQ_OFFSET); 36 GR_STATIC_ASSERT(kDarken_GrBlendEquation == (int)SkBlendMode::kDarken + EQ_OFFSET); 37 GR_STATIC_ASSERT(kLighten_GrBlendEquation == (int)SkBlendMode::kLighten + EQ_OFFSET); 38 GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == (int)SkBlendMode::kColorDodge + EQ_OFFSET); 39 GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == (int)SkBlendMode::kColorBurn + EQ_OFFSET); 40 GR_STATIC_ASSERT(kHardLight_GrBlendEquation == (int)SkBlendMode::kHardLight + EQ_OFFSET); 41 GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == (int)SkBlendMode::kSoftLight + EQ_OFFSET); 42 GR_STATIC_ASSERT(kDifference_GrBlendEquation == (int)SkBlendMode::kDifference + EQ_OFFSET); 43 GR_STATIC_ASSERT(kExclusion_GrBlendEquation == (int)SkBlendMode::kExclusion + EQ_OFFSET); 44 GR_STATIC_ASSERT(kMultiply_GrBlendEquation == (int)SkBlendMode::kMultiply + EQ_OFFSET); 45 GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == (int)SkBlendMode::kHue + EQ_OFFSET); 46 GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == (int)SkBlendMode::kSaturation + EQ_OFFSET); 47 GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == (int)SkBlendMode::kColor + EQ_OFFSET); 48 GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == (int)SkBlendMode::kLuminosity + EQ_OFFSET); 49 GR_STATIC_ASSERT(kGrBlendEquationCnt == (int)SkBlendMode::kLastMode + 1 + EQ_OFFSET); 50 return static_cast<GrBlendEquation>((int)mode + EQ_OFFSET); 51 #undef EQ_OFFSET 52 } 53 54 static bool can_use_hw_blend_equation(GrBlendEquation equation, 55 GrProcessorAnalysisCoverage coverage, const GrCaps& caps) { 56 if (!caps.advancedBlendEquationSupport()) { 57 return false; 58 } 59 if (GrProcessorAnalysisCoverage::kLCD == coverage) { 60 return false; // LCD coverage must be applied after the blend equation. 61 } 62 if (caps.canUseAdvancedBlendEquation(equation)) { 63 return false; 64 } 65 return true; 66 } 67 68 /////////////////////////////////////////////////////////////////////////////// 69 // Xfer Processor 70 /////////////////////////////////////////////////////////////////////////////// 71 72 class CustomXP : public GrXferProcessor { 73 public: 74 CustomXP(SkBlendMode mode, GrBlendEquation hwBlendEquation) 75 : fMode(mode) 76 , fHWBlendEquation(hwBlendEquation) { 77 this->initClassID<CustomXP>(); 78 } 79 80 CustomXP(bool hasMixedSamples, SkBlendMode mode, GrProcessorAnalysisCoverage coverage) 81 : INHERITED(true, hasMixedSamples, coverage) 82 , fMode(mode) 83 , fHWBlendEquation(static_cast<GrBlendEquation>(-1)) { 84 this->initClassID<CustomXP>(); 85 } 86 87 const char* name() const override { return "Custom Xfermode"; } 88 89 GrGLSLXferProcessor* createGLSLInstance() const override; 90 91 SkBlendMode mode() const { return fMode; } 92 bool hasHWBlendEquation() const { return -1 != static_cast<int>(fHWBlendEquation); } 93 94 GrBlendEquation hwBlendEquation() const { 95 SkASSERT(this->hasHWBlendEquation()); 96 return fHWBlendEquation; 97 } 98 99 GrXferBarrierType xferBarrierType(const GrCaps&) const override; 100 101 private: 102 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; 103 104 void onGetBlendInfo(BlendInfo*) const override; 105 106 bool onIsEqual(const GrXferProcessor& xpBase) const override; 107 108 const SkBlendMode fMode; 109 const GrBlendEquation fHWBlendEquation; 110 111 typedef GrXferProcessor INHERITED; 112 }; 113 114 /////////////////////////////////////////////////////////////////////////////// 115 116 class GLCustomXP : public GrGLSLXferProcessor { 117 public: 118 GLCustomXP(const GrXferProcessor&) {} 119 ~GLCustomXP() override {} 120 121 static void GenKey(const GrXferProcessor& p, const GrShaderCaps& caps, 122 GrProcessorKeyBuilder* b) { 123 const CustomXP& xp = p.cast<CustomXP>(); 124 uint32_t key = 0; 125 if (xp.hasHWBlendEquation()) { 126 SkASSERT(caps.advBlendEqInteraction() > 0); // 0 will mean !xp.hasHWBlendEquation(). 127 key |= caps.advBlendEqInteraction(); 128 GR_STATIC_ASSERT(GrShaderCaps::kLast_AdvBlendEqInteraction < 4); 129 } 130 if (!xp.hasHWBlendEquation() || caps.mustEnableSpecificAdvBlendEqs()) { 131 key |= (int)xp.mode() << 3; 132 } 133 b->add32(key); 134 } 135 136 private: 137 void emitOutputsForBlendState(const EmitArgs& args) override { 138 const CustomXP& xp = args.fXP.cast<CustomXP>(); 139 SkASSERT(xp.hasHWBlendEquation()); 140 141 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; 142 fragBuilder->enableAdvancedBlendEquationIfNeeded(xp.hwBlendEquation()); 143 144 // Apply coverage by multiplying it into the src color before blending. Mixed samples will 145 // "just work" automatically. (See onGetOptimizations()) 146 fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputCoverage, 147 args.fInputColor); 148 } 149 150 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, 151 GrGLSLUniformHandler* uniformHandler, 152 const char* srcColor, 153 const char* srcCoverage, 154 const char* dstColor, 155 const char* outColor, 156 const char* outColorSecondary, 157 const GrXferProcessor& proc) override { 158 const CustomXP& xp = proc.cast<CustomXP>(); 159 SkASSERT(!xp.hasHWBlendEquation()); 160 161 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.mode()); 162 163 // Apply coverage. 164 INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor, 165 outColorSecondary, xp); 166 } 167 168 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {} 169 170 typedef GrGLSLXferProcessor INHERITED; 171 }; 172 173 /////////////////////////////////////////////////////////////////////////////// 174 175 void CustomXP::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { 176 GLCustomXP::GenKey(*this, caps, b); 177 } 178 179 GrGLSLXferProcessor* CustomXP::createGLSLInstance() const { 180 SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation()); 181 return new GLCustomXP(*this); 182 } 183 184 bool CustomXP::onIsEqual(const GrXferProcessor& other) const { 185 const CustomXP& s = other.cast<CustomXP>(); 186 return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation; 187 } 188 189 GrXferBarrierType CustomXP::xferBarrierType(const GrCaps& caps) const { 190 if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) { 191 return kBlend_GrXferBarrierType; 192 } 193 return kNone_GrXferBarrierType; 194 } 195 196 void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const { 197 if (this->hasHWBlendEquation()) { 198 blendInfo->fEquation = this->hwBlendEquation(); 199 } 200 } 201 202 /////////////////////////////////////////////////////////////////////////////// 203 204 // See the comment above GrXPFactory's definition about this warning suppression. 205 #if defined(__GNUC__) || defined(__clang) 206 #pragma GCC diagnostic push 207 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 208 #endif 209 class CustomXPFactory : public GrXPFactory { 210 public: 211 constexpr CustomXPFactory(SkBlendMode mode) 212 : fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {} 213 214 private: 215 sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&, 216 GrProcessorAnalysisCoverage, 217 bool hasMixedSamples, 218 const GrCaps&) const override; 219 220 AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&, 221 const GrProcessorAnalysisCoverage&, 222 const GrCaps&) const override; 223 224 GR_DECLARE_XP_FACTORY_TEST 225 226 SkBlendMode fMode; 227 GrBlendEquation fHWBlendEquation; 228 229 typedef GrXPFactory INHERITED; 230 }; 231 #if defined(__GNUC__) || defined(__clang) 232 #pragma GCC diagnostic pop 233 #endif 234 235 sk_sp<const GrXferProcessor> CustomXPFactory::makeXferProcessor( 236 const GrProcessorAnalysisColor&, 237 GrProcessorAnalysisCoverage coverage, 238 bool hasMixedSamples, 239 const GrCaps& caps) const { 240 SkASSERT(GrCustomXfermode::IsSupportedMode(fMode)); 241 if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) { 242 return sk_sp<GrXferProcessor>(new CustomXP(fMode, fHWBlendEquation)); 243 } 244 return sk_sp<GrXferProcessor>(new CustomXP(hasMixedSamples, fMode, coverage)); 245 } 246 247 GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties( 248 const GrProcessorAnalysisColor&, const GrProcessorAnalysisCoverage& coverage, 249 const GrCaps& caps) const { 250 /* 251 The general SVG blend equation is defined in the spec as follows: 252 253 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa) 254 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa) 255 256 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha, 257 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied 258 RGB colors.) 259 260 For every blend mode supported by this class, i.e. the "advanced" blend 261 modes, X=Y=Z=1 and this equation reduces to the PDF blend equation. 262 263 It can be shown that when X=Y=Z=1, these equations can modulate alpha for 264 coverage. 265 266 267 == Color == 268 269 We substitute Y=Z=1 and define a blend() function that calculates Dca' in 270 terms of premultiplied alpha only: 271 272 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0, 273 Sca : if Da == 0, 274 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if 275 Sa,Da != 0} 276 277 And for coverage modulation, we use a post blend src-over model: 278 279 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 280 281 (Where f is the fractional coverage.) 282 283 Next we show that canTweakAlphaForCoverage() is true by proving the 284 following relationship: 285 286 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 287 288 General case (f,Sa,Da != 0): 289 290 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 291 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca [Sa,Da != 292 0, definition of blend()] 293 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca 294 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca 295 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca 296 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca 297 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) 298 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0] 299 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()] 300 301 Corner cases (Sa=0, Da=0, and f=0): 302 303 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 304 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()] 305 = Dca 306 = blend(0, Dca, 0, Da) [definition of blend()] 307 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0] 308 309 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 310 = f * Sca + (1-f) * Dca [Da=0, definition of blend()] 311 = f * Sca [Da=0] 312 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()] 313 = blend(f*Sca, Dca, f*Sa, Da) [Da=0] 314 315 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 316 = Dca [f=0] 317 = blend(0, Dca, 0, Da) [definition of blend()] 318 = blend(f*Sca, Dca, f*Sa, Da) [f=0] 319 320 == Alpha == 321 322 We substitute X=Y=Z=1 and define a blend() function that calculates Da': 323 324 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa) 325 = Sa * Da + Sa - Sa * Da + Da - Da * Sa 326 = Sa + Da - Sa * Da 327 328 We use the same model for coverage modulation as we did with color: 329 330 Da'' = f * blend(Sa, Da) + (1-f) * Da 331 332 And show that canTweakAlphaForCoverage() is true by proving the following 333 relationship: 334 335 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da 336 337 338 f * blend(Sa, Da) + (1-f) * Da 339 = f * (Sa + Da - Sa * Da) + (1-f) * Da 340 = f*Sa + f*Da - f*Sa * Da + Da - f*Da 341 = f*Sa - f*Sa * Da + Da 342 = f*Sa + Da - f*Sa * Da 343 = blend(f*Sa, Da) 344 */ 345 if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) { 346 if (caps.blendEquationSupport() == GrCaps::kAdvancedCoherent_BlendEquationSupport) { 347 return AnalysisProperties::kCompatibleWithAlphaAsCoverage; 348 } else { 349 return AnalysisProperties::kCompatibleWithAlphaAsCoverage | 350 AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws; 351 } 352 } 353 return AnalysisProperties::kCompatibleWithAlphaAsCoverage | 354 AnalysisProperties::kReadsDstInShader; 355 } 356 357 GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory); 358 #if GR_TEST_UTILS 359 const GrXPFactory* CustomXPFactory::TestGet(GrProcessorTestData* d) { 360 int mode = d->fRandom->nextRangeU((int)SkBlendMode::kLastCoeffMode + 1, 361 (int)SkBlendMode::kLastSeparableMode); 362 363 return GrCustomXfermode::Get((SkBlendMode)mode); 364 } 365 #endif 366 367 /////////////////////////////////////////////////////////////////////////////// 368 369 const GrXPFactory* GrCustomXfermode::Get(SkBlendMode mode) { 370 // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are 371 // null. 372 #ifdef SK_BUILD_FOR_WIN 373 #define _CONSTEXPR_ 374 #else 375 #define _CONSTEXPR_ constexpr 376 #endif 377 static _CONSTEXPR_ const CustomXPFactory gOverlay(SkBlendMode::kOverlay); 378 static _CONSTEXPR_ const CustomXPFactory gDarken(SkBlendMode::kDarken); 379 static _CONSTEXPR_ const CustomXPFactory gLighten(SkBlendMode::kLighten); 380 static _CONSTEXPR_ const CustomXPFactory gColorDodge(SkBlendMode::kColorDodge); 381 static _CONSTEXPR_ const CustomXPFactory gColorBurn(SkBlendMode::kColorBurn); 382 static _CONSTEXPR_ const CustomXPFactory gHardLight(SkBlendMode::kHardLight); 383 static _CONSTEXPR_ const CustomXPFactory gSoftLight(SkBlendMode::kSoftLight); 384 static _CONSTEXPR_ const CustomXPFactory gDifference(SkBlendMode::kDifference); 385 static _CONSTEXPR_ const CustomXPFactory gExclusion(SkBlendMode::kExclusion); 386 static _CONSTEXPR_ const CustomXPFactory gMultiply(SkBlendMode::kMultiply); 387 static _CONSTEXPR_ const CustomXPFactory gHue(SkBlendMode::kHue); 388 static _CONSTEXPR_ const CustomXPFactory gSaturation(SkBlendMode::kSaturation); 389 static _CONSTEXPR_ const CustomXPFactory gColor(SkBlendMode::kColor); 390 static _CONSTEXPR_ const CustomXPFactory gLuminosity(SkBlendMode::kLuminosity); 391 #undef _CONSTEXPR_ 392 switch (mode) { 393 case SkBlendMode::kOverlay: 394 return &gOverlay; 395 case SkBlendMode::kDarken: 396 return &gDarken; 397 case SkBlendMode::kLighten: 398 return &gLighten; 399 case SkBlendMode::kColorDodge: 400 return &gColorDodge; 401 case SkBlendMode::kColorBurn: 402 return &gColorBurn; 403 case SkBlendMode::kHardLight: 404 return &gHardLight; 405 case SkBlendMode::kSoftLight: 406 return &gSoftLight; 407 case SkBlendMode::kDifference: 408 return &gDifference; 409 case SkBlendMode::kExclusion: 410 return &gExclusion; 411 case SkBlendMode::kMultiply: 412 return &gMultiply; 413 case SkBlendMode::kHue: 414 return &gHue; 415 case SkBlendMode::kSaturation: 416 return &gSaturation; 417 case SkBlendMode::kColor: 418 return &gColor; 419 case SkBlendMode::kLuminosity: 420 return &gLuminosity; 421 default: 422 SkASSERT(!GrCustomXfermode::IsSupportedMode(mode)); 423 return nullptr; 424 } 425 } 426