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/GrPorterDuffXferProcessor.h" 9 10 #include "GrBlend.h" 11 #include "GrDrawTargetCaps.h" 12 #include "GrProcessor.h" 13 #include "GrProcOptInfo.h" 14 #include "GrTypes.h" 15 #include "GrXferProcessor.h" 16 #include "gl/GrGLXferProcessor.h" 17 #include "gl/builders/GrGLFragmentShaderBuilder.h" 18 #include "gl/builders/GrGLProgramBuilder.h" 19 20 static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) { 21 /* 22 The fractional coverage is f. 23 The src and dst coeffs are Cs and Cd. 24 The dst and src colors are S and D. 25 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha 26 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second 27 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we 28 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D. 29 */ 30 return kOne_GrBlendCoeff == dstCoeff || 31 kISA_GrBlendCoeff == dstCoeff || 32 kISC_GrBlendCoeff == dstCoeff; 33 } 34 35 class PorterDuffXferProcessor : public GrXferProcessor { 36 public: 37 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 38 GrColor constant, const GrDeviceCoordTexture* dstCopy, 39 bool willReadDstColor) { 40 return SkNEW_ARGS(PorterDuffXferProcessor, (srcBlend, dstBlend, constant, dstCopy, 41 willReadDstColor)); 42 } 43 44 ~PorterDuffXferProcessor() override; 45 46 const char* name() const override { return "Porter Duff"; } 47 48 GrGLXferProcessor* createGLInstance() const override; 49 50 bool hasSecondaryOutput() const override; 51 52 /////////////////////////////////////////////////////////////////////////// 53 /// @name Stage Output Types 54 //// 55 56 enum PrimaryOutputType { 57 kNone_PrimaryOutputType, 58 kColor_PrimaryOutputType, 59 kCoverage_PrimaryOutputType, 60 // Modulate color and coverage, write result as the color output. 61 kModulate_PrimaryOutputType, 62 // Custom Porter-Duff output, used for when we explictly are reading the dst and blending 63 // in the shader. Secondary Output must be none if you use this. The custom blend uses the 64 // equation: cov * (coeffS * S + coeffD * D) + (1 - cov) * D 65 kCustom_PrimaryOutputType 66 }; 67 68 enum SecondaryOutputType { 69 // There is no secondary output 70 kNone_SecondaryOutputType, 71 // Writes coverage as the secondary output. Only set if dual source blending is supported 72 // and primary output is kModulate. 73 kCoverage_SecondaryOutputType, 74 // Writes coverage * (1 - colorA) as the secondary output. Only set if dual source blending 75 // is supported and primary output is kModulate. 76 kCoverageISA_SecondaryOutputType, 77 // Writes coverage * (1 - colorRGBA) as the secondary output. Only set if dual source 78 // blending is supported and primary output is kModulate. 79 kCoverageISC_SecondaryOutputType, 80 81 kSecondaryOutputTypeCnt, 82 }; 83 84 PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; } 85 SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputType; } 86 87 GrBlendCoeff getSrcBlend() const { return fSrcBlend; } 88 GrBlendCoeff getDstBlend() const { return fDstBlend; } 89 90 private: 91 PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant, 92 const GrDeviceCoordTexture* dstCopy, bool willReadDstColor); 93 94 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, 95 const GrProcOptInfo& coveragePOI, 96 bool doesStencilWrite, 97 GrColor* overrideColor, 98 const GrDrawTargetCaps& caps) override; 99 100 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; 101 102 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { 103 if (!this->willReadDstColor()) { 104 blendInfo->fSrcBlend = fSrcBlend; 105 blendInfo->fDstBlend = fDstBlend; 106 } else { 107 blendInfo->fSrcBlend = kOne_GrBlendCoeff; 108 blendInfo->fDstBlend = kZero_GrBlendCoeff; 109 } 110 blendInfo->fBlendConstant = fBlendConstant; 111 } 112 113 bool onIsEqual(const GrXferProcessor& xpBase) const override { 114 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>(); 115 if (fSrcBlend != xp.fSrcBlend || 116 fDstBlend != xp.fDstBlend || 117 fBlendConstant != xp.fBlendConstant || 118 fPrimaryOutputType != xp.fPrimaryOutputType || 119 fSecondaryOutputType != xp.fSecondaryOutputType) { 120 return false; 121 } 122 return true; 123 } 124 125 GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colorPOI, 126 const GrProcOptInfo& coveragePOI, 127 bool doesStencilWrite); 128 129 void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrDrawTargetCaps& caps, 130 bool hasSolidCoverage); 131 132 GrBlendCoeff fSrcBlend; 133 GrBlendCoeff fDstBlend; 134 GrColor fBlendConstant; 135 PrimaryOutputType fPrimaryOutputType; 136 SecondaryOutputType fSecondaryOutputType; 137 138 typedef GrXferProcessor INHERITED; 139 }; 140 141 /////////////////////////////////////////////////////////////////////////////// 142 143 bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff, 144 const char* colorName, const char* srcColorName, 145 const char* dstColorName, bool hasPrevious) { 146 if (kZero_GrBlendCoeff == coeff) { 147 return hasPrevious; 148 } else { 149 if (hasPrevious) { 150 fsBuilder->codeAppend(" + "); 151 } 152 fsBuilder->codeAppendf("%s", colorName); 153 switch (coeff) { 154 case kOne_GrBlendCoeff: 155 break; 156 case kSC_GrBlendCoeff: 157 fsBuilder->codeAppendf(" * %s", srcColorName); 158 break; 159 case kISC_GrBlendCoeff: 160 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); 161 break; 162 case kDC_GrBlendCoeff: 163 fsBuilder->codeAppendf(" * %s", dstColorName); 164 break; 165 case kIDC_GrBlendCoeff: 166 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); 167 break; 168 case kSA_GrBlendCoeff: 169 fsBuilder->codeAppendf(" * %s.a", srcColorName); 170 break; 171 case kISA_GrBlendCoeff: 172 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); 173 break; 174 case kDA_GrBlendCoeff: 175 fsBuilder->codeAppendf(" * %s.a", dstColorName); 176 break; 177 case kIDA_GrBlendCoeff: 178 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); 179 break; 180 default: 181 SkFAIL("Unsupported Blend Coeff"); 182 } 183 return true; 184 } 185 } 186 187 class GLPorterDuffXferProcessor : public GrGLXferProcessor { 188 public: 189 GLPorterDuffXferProcessor(const GrProcessor&) {} 190 191 virtual ~GLPorterDuffXferProcessor() {} 192 193 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, 194 GrProcessorKeyBuilder* b) { 195 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>(); 196 b->add32(xp.primaryOutputType()); 197 b->add32(xp.secondaryOutputType()); 198 if (xp.willReadDstColor()) { 199 b->add32(xp.getSrcBlend()); 200 b->add32(xp.getDstBlend()); 201 } 202 }; 203 204 private: 205 void onEmitCode(const EmitArgs& args) override { 206 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>(); 207 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 208 if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutputType()) { 209 SkASSERT(!xp.willReadDstColor()); 210 switch(xp.secondaryOutputType()) { 211 case PorterDuffXferProcessor::kNone_SecondaryOutputType: 212 break; 213 case PorterDuffXferProcessor::kCoverage_SecondaryOutputType: 214 fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, 215 args.fInputCoverage); 216 break; 217 case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType: 218 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", 219 args.fOutputSecondary, args.fInputColor, 220 args.fInputCoverage); 221 break; 222 case PorterDuffXferProcessor::kCoverageISC_SecondaryOutputType: 223 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", 224 args.fOutputSecondary, args.fInputColor, 225 args.fInputCoverage); 226 break; 227 default: 228 SkFAIL("Unexpected Secondary Output"); 229 } 230 231 switch (xp.primaryOutputType()) { 232 case PorterDuffXferProcessor::kNone_PrimaryOutputType: 233 fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary); 234 break; 235 case PorterDuffXferProcessor::kColor_PrimaryOutputType: 236 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor); 237 break; 238 case PorterDuffXferProcessor::kCoverage_PrimaryOutputType: 239 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage); 240 break; 241 case PorterDuffXferProcessor::kModulate_PrimaryOutputType: 242 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor, 243 args.fInputCoverage); 244 break; 245 default: 246 SkFAIL("Unexpected Primary Output"); 247 } 248 } else { 249 SkASSERT(xp.willReadDstColor()); 250 251 const char* dstColor = fsBuilder->dstColor(); 252 253 fsBuilder->codeAppend("vec4 colorBlend ="); 254 // append src blend 255 bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(), 256 args.fInputColor, args.fInputColor, 257 dstColor, false); 258 // append dst blend 259 SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(), 260 dstColor, args.fInputColor, 261 dstColor, didAppend)); 262 fsBuilder->codeAppend(";"); 263 264 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s;", 265 args.fOutputPrimary, args.fInputCoverage, args.fInputCoverage, 266 dstColor); 267 } 268 } 269 270 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}; 271 272 typedef GrGLXferProcessor INHERITED; 273 }; 274 275 /////////////////////////////////////////////////////////////////////////////// 276 277 PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend, 278 GrBlendCoeff dstBlend, 279 GrColor constant, 280 const GrDeviceCoordTexture* dstCopy, 281 bool willReadDstColor) 282 : INHERITED(dstCopy, willReadDstColor) 283 , fSrcBlend(srcBlend) 284 , fDstBlend(dstBlend) 285 , fBlendConstant(constant) 286 , fPrimaryOutputType(kModulate_PrimaryOutputType) 287 , fSecondaryOutputType(kNone_SecondaryOutputType) { 288 this->initClassID<PorterDuffXferProcessor>(); 289 } 290 291 PorterDuffXferProcessor::~PorterDuffXferProcessor() { 292 } 293 294 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps, 295 GrProcessorKeyBuilder* b) const { 296 GLPorterDuffXferProcessor::GenKey(*this, caps, b); 297 } 298 299 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const { 300 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this)); 301 } 302 303 GrXferProcessor::OptFlags 304 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI, 305 const GrProcOptInfo& coveragePOI, 306 bool doesStencilWrite, 307 GrColor* overrideColor, 308 const GrDrawTargetCaps& caps) { 309 GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI, 310 coveragePOI, 311 doesStencilWrite); 312 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite()); 313 return optFlags; 314 } 315 316 void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags, 317 const GrDrawTargetCaps& caps, 318 bool hasSolidCoverage) { 319 if (this->willReadDstColor()) { 320 fPrimaryOutputType = kCustom_PrimaryOutputType; 321 return; 322 } 323 324 if (optFlags & kIgnoreColor_OptFlag) { 325 if (optFlags & kIgnoreCoverage_OptFlag) { 326 fPrimaryOutputType = kNone_PrimaryOutputType; 327 return; 328 } else { 329 fPrimaryOutputType = kCoverage_PrimaryOutputType; 330 return; 331 } 332 } else if (optFlags & kIgnoreCoverage_OptFlag) { 333 fPrimaryOutputType = kColor_PrimaryOutputType; 334 return; 335 } 336 337 // If we do have coverage determine whether it matters. Dual source blending is expensive so 338 // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source 339 // blending if we have any effective coverage stages OR the geometry processor doesn't emits 340 // solid coverage. 341 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) { 342 if (caps.shaderCaps()->dualSourceBlendingSupport()) { 343 if (kZero_GrBlendCoeff == fDstBlend) { 344 // write the coverage value to second color 345 fSecondaryOutputType = kCoverage_SecondaryOutputType; 346 fDstBlend = kIS2C_GrBlendCoeff; 347 } else if (kSA_GrBlendCoeff == fDstBlend) { 348 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 349 fSecondaryOutputType = kCoverageISA_SecondaryOutputType; 350 fDstBlend = kIS2C_GrBlendCoeff; 351 } else if (kSC_GrBlendCoeff == fDstBlend) { 352 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 353 fSecondaryOutputType = kCoverageISC_SecondaryOutputType; 354 fDstBlend = kIS2C_GrBlendCoeff; 355 } 356 } 357 } 358 } 359 360 GrXferProcessor::OptFlags 361 PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI, 362 const GrProcOptInfo& coveragePOI, 363 bool doesStencilWrite) { 364 if (this->willReadDstColor()) { 365 return GrXferProcessor::kNone_Opt; 366 } 367 368 bool srcAIsOne = colorPOI.isOpaque(); 369 bool hasCoverage = !coveragePOI.isSolidWhite(); 370 371 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || 372 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); 373 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend || 374 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne); 375 376 // When coeffs are (0,1) there is no reason to draw at all, unless 377 // stenciling is enabled. Having color writes disabled is effectively 378 // (0,1). 379 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) { 380 if (doesStencilWrite) { 381 return GrXferProcessor::kIgnoreColor_OptFlag | 382 GrXferProcessor::kSetCoverageDrawing_OptFlag; 383 } else { 384 fDstBlend = kOne_GrBlendCoeff; 385 return GrXferProcessor::kSkipDraw_OptFlag; 386 } 387 } 388 389 // if we don't have coverage we can check whether the dst 390 // has to read at all. If not, we'll disable blending. 391 if (!hasCoverage) { 392 if (dstCoeffIsZero) { 393 if (kOne_GrBlendCoeff == fSrcBlend) { 394 // if there is no coverage and coeffs are (1,0) then we 395 // won't need to read the dst at all, it gets replaced by src 396 fDstBlend = kZero_GrBlendCoeff; 397 return GrXferProcessor::kNone_Opt | 398 GrXferProcessor::kIgnoreCoverage_OptFlag; 399 } else if (kZero_GrBlendCoeff == fSrcBlend) { 400 // if the op is "clear" then we don't need to emit a color 401 // or blend, just write transparent black into the dst. 402 fSrcBlend = kOne_GrBlendCoeff; 403 fDstBlend = kZero_GrBlendCoeff; 404 return GrXferProcessor::kIgnoreColor_OptFlag | 405 GrXferProcessor::kIgnoreCoverage_OptFlag; 406 } 407 } 408 return GrXferProcessor::kIgnoreCoverage_OptFlag; 409 } 410 411 // check whether coverage can be safely rolled into alpha 412 // of if we can skip color computation and just emit coverage 413 if (can_tweak_alpha_for_coverage(fDstBlend)) { 414 if (colorPOI.allStagesMultiplyInput()) { 415 return GrXferProcessor::kSetCoverageDrawing_OptFlag | 416 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; 417 } else { 418 return GrXferProcessor::kSetCoverageDrawing_OptFlag; 419 420 } 421 } 422 if (dstCoeffIsZero) { 423 if (kZero_GrBlendCoeff == fSrcBlend) { 424 // the source color is not included in the blend 425 // the dst coeff is effectively zero so blend works out to: 426 // (c)(0)D + (1-c)D = (1-c)D. 427 fDstBlend = kISA_GrBlendCoeff; 428 return GrXferProcessor::kIgnoreColor_OptFlag | 429 GrXferProcessor::kSetCoverageDrawing_OptFlag; 430 } else if (srcAIsOne) { 431 // the dst coeff is effectively zero so blend works out to: 432 // cS + (c)(0)D + (1-c)D = cS + (1-c)D. 433 // If Sa is 1 then we can replace Sa with c 434 // and set dst coeff to 1-Sa. 435 fDstBlend = kISA_GrBlendCoeff; 436 if (colorPOI.allStagesMultiplyInput()) { 437 return GrXferProcessor::kSetCoverageDrawing_OptFlag | 438 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; 439 } else { 440 return GrXferProcessor::kSetCoverageDrawing_OptFlag; 441 442 } 443 } 444 } else if (dstCoeffIsOne) { 445 // the dst coeff is effectively one so blend works out to: 446 // cS + (c)(1)D + (1-c)D = cS + D. 447 fDstBlend = kOne_GrBlendCoeff; 448 if (colorPOI.allStagesMultiplyInput()) { 449 return GrXferProcessor::kSetCoverageDrawing_OptFlag | 450 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; 451 } else { 452 return GrXferProcessor::kSetCoverageDrawing_OptFlag; 453 454 } 455 return GrXferProcessor::kSetCoverageDrawing_OptFlag; 456 } 457 458 return GrXferProcessor::kNone_Opt; 459 } 460 461 bool PorterDuffXferProcessor::hasSecondaryOutput() const { 462 return kNone_SecondaryOutputType != fSecondaryOutputType; 463 } 464 465 /////////////////////////////////////////////////////////////////////////////// 466 467 class PDLCDXferProcessor : public GrXferProcessor { 468 public: 469 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 470 const GrProcOptInfo& colorPOI); 471 472 ~PDLCDXferProcessor() override; 473 474 const char* name() const override { return "Porter Duff LCD"; } 475 476 GrGLXferProcessor* createGLInstance() const override; 477 478 bool hasSecondaryOutput() const override { return false; } 479 480 private: 481 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha); 482 483 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, 484 const GrProcOptInfo& coveragePOI, 485 bool doesStencilWrite, 486 GrColor* overrideColor, 487 const GrDrawTargetCaps& caps) override; 488 489 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; 490 491 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { 492 blendInfo->fSrcBlend = kConstC_GrBlendCoeff; 493 blendInfo->fDstBlend = kISC_GrBlendCoeff; 494 blendInfo->fBlendConstant = fBlendConstant; 495 } 496 497 bool onIsEqual(const GrXferProcessor& xpBase) const override { 498 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>(); 499 if (fBlendConstant != xp.fBlendConstant || 500 fAlpha != xp.fAlpha) { 501 return false; 502 } 503 return true; 504 } 505 506 GrColor fBlendConstant; 507 uint8_t fAlpha; 508 509 typedef GrXferProcessor INHERITED; 510 }; 511 512 /////////////////////////////////////////////////////////////////////////////// 513 514 class GLPDLCDXferProcessor : public GrGLXferProcessor { 515 public: 516 GLPDLCDXferProcessor(const GrProcessor&) {} 517 518 virtual ~GLPDLCDXferProcessor() {} 519 520 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, 521 GrProcessorKeyBuilder* b) {} 522 523 private: 524 void onEmitCode(const EmitArgs& args) override { 525 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 526 527 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor, 528 args.fInputCoverage); 529 } 530 531 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}; 532 533 typedef GrGLXferProcessor INHERITED; 534 }; 535 536 /////////////////////////////////////////////////////////////////////////////// 537 538 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha) 539 : fBlendConstant(blendConstant) 540 , fAlpha(alpha) { 541 this->initClassID<PDLCDXferProcessor>(); 542 } 543 544 GrXferProcessor* PDLCDXferProcessor::Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 545 const GrProcOptInfo& colorPOI) { 546 if (kOne_GrBlendCoeff != srcBlend || kISA_GrBlendCoeff != dstBlend) { 547 return NULL; 548 } 549 550 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) { 551 return NULL; 552 } 553 554 GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); 555 uint8_t alpha = GrColorUnpackA(blendConstant); 556 blendConstant |= (0xff << GrColor_SHIFT_A); 557 558 return SkNEW_ARGS(PDLCDXferProcessor, (blendConstant, alpha)); 559 } 560 561 PDLCDXferProcessor::~PDLCDXferProcessor() { 562 } 563 564 void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps, 565 GrProcessorKeyBuilder* b) const { 566 GLPDLCDXferProcessor::GenKey(*this, caps, b); 567 } 568 569 GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const { 570 return SkNEW_ARGS(GLPDLCDXferProcessor, (*this)); 571 } 572 573 GrXferProcessor::OptFlags 574 PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI, 575 const GrProcOptInfo& coveragePOI, 576 bool doesStencilWrite, 577 GrColor* overrideColor, 578 const GrDrawTargetCaps& caps) { 579 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha 580 // value of the blend the constant. We should already have valid blend coeff's if we are at 581 // a point where we have RGB coverage. We don't need any color stages since the known color 582 // output is already baked into the blendConstant. 583 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha); 584 return GrXferProcessor::kOverrideColor_OptFlag; 585 } 586 587 /////////////////////////////////////////////////////////////////////////////// 588 GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) 589 : fSrcCoeff(src), fDstCoeff(dst) { 590 this->initClassID<GrPorterDuffXPFactory>(); 591 } 592 593 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { 594 switch (mode) { 595 case SkXfermode::kClear_Mode: { 596 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff); 597 return SkRef(&gClearPDXPF); 598 break; 599 } 600 case SkXfermode::kSrc_Mode: { 601 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff); 602 return SkRef(&gSrcPDXPF); 603 break; 604 } 605 case SkXfermode::kDst_Mode: { 606 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff); 607 return SkRef(&gDstPDXPF); 608 break; 609 } 610 case SkXfermode::kSrcOver_Mode: { 611 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff); 612 return SkRef(&gSrcOverPDXPF); 613 break; 614 } 615 case SkXfermode::kDstOver_Mode: { 616 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff); 617 return SkRef(&gDstOverPDXPF); 618 break; 619 } 620 case SkXfermode::kSrcIn_Mode: { 621 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff); 622 return SkRef(&gSrcInPDXPF); 623 break; 624 } 625 case SkXfermode::kDstIn_Mode: { 626 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff); 627 return SkRef(&gDstInPDXPF); 628 break; 629 } 630 case SkXfermode::kSrcOut_Mode: { 631 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff); 632 return SkRef(&gSrcOutPDXPF); 633 break; 634 } 635 case SkXfermode::kDstOut_Mode: { 636 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff); 637 return SkRef(&gDstOutPDXPF); 638 break; 639 } 640 case SkXfermode::kSrcATop_Mode: { 641 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff); 642 return SkRef(&gSrcATopPDXPF); 643 break; 644 } 645 case SkXfermode::kDstATop_Mode: { 646 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff); 647 return SkRef(&gDstATopPDXPF); 648 break; 649 } 650 case SkXfermode::kXor_Mode: { 651 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff); 652 return SkRef(&gXorPDXPF); 653 break; 654 } 655 case SkXfermode::kPlus_Mode: { 656 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff); 657 return SkRef(&gPlusPDXPF); 658 break; 659 } 660 case SkXfermode::kModulate_Mode: { 661 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff); 662 return SkRef(&gModulatePDXPF); 663 break; 664 } 665 case SkXfermode::kScreen_Mode: { 666 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff); 667 return SkRef(&gScreenPDXPF); 668 break; 669 } 670 default: 671 return NULL; 672 } 673 } 674 675 GrXferProcessor* 676 GrPorterDuffXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, 677 const GrProcOptInfo& colorPOI, 678 const GrProcOptInfo& covPOI, 679 const GrDeviceCoordTexture* dstCopy) const { 680 if (covPOI.isFourChannelOutput()) { 681 return PDLCDXferProcessor::Create(fSrcCoeff, fDstCoeff, colorPOI); 682 } else { 683 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy, 684 this->willReadDstColor(caps, colorPOI, covPOI)); 685 } 686 } 687 688 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, 689 uint32_t knownColorFlags) const { 690 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff && 691 kRGBA_GrColorComponentFlags == knownColorFlags) { 692 return true; 693 } 694 return false; 695 } 696 697 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, 698 const GrProcOptInfo& coveragePOI, 699 GrXPFactory::InvariantOutput* output) const { 700 if (!coveragePOI.isSolidWhite()) { 701 output->fWillBlendWithDst = true; 702 output->fBlendedColorFlags = 0; 703 return; 704 } 705 706 GrBlendCoeff srcCoeff = fSrcCoeff; 707 GrBlendCoeff dstCoeff = fDstCoeff; 708 709 // TODO: figure out to merge this simplify with other current optimization code paths and 710 // eventually remove from GrBlend 711 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(), 712 0, 0, 0); 713 714 if (GrBlendCoeffRefsDst(srcCoeff)) { 715 output->fWillBlendWithDst = true; 716 output->fBlendedColorFlags = 0; 717 return; 718 } 719 720 if (kZero_GrBlendCoeff != dstCoeff) { 721 bool srcAIsOne = colorPOI.isOpaque(); 722 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) { 723 output->fWillBlendWithDst = true; 724 } 725 output->fBlendedColorFlags = 0; 726 return; 727 } 728 729 switch (srcCoeff) { 730 case kZero_GrBlendCoeff: 731 output->fBlendedColor = 0; 732 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags; 733 break; 734 735 case kOne_GrBlendCoeff: 736 output->fBlendedColor = colorPOI.color(); 737 output->fBlendedColorFlags = colorPOI.validFlags(); 738 break; 739 740 // The src coeff should never refer to the src and if it refers to dst then opaque 741 // should have been false. 742 case kSC_GrBlendCoeff: 743 case kISC_GrBlendCoeff: 744 case kDC_GrBlendCoeff: 745 case kIDC_GrBlendCoeff: 746 case kSA_GrBlendCoeff: 747 case kISA_GrBlendCoeff: 748 case kDA_GrBlendCoeff: 749 case kIDA_GrBlendCoeff: 750 default: 751 SkFAIL("srcCoeff should not refer to src or dst."); 752 break; 753 754 // TODO: update this once GrPaint actually has a const color. 755 case kConstC_GrBlendCoeff: 756 case kIConstC_GrBlendCoeff: 757 case kConstA_GrBlendCoeff: 758 case kIConstA_GrBlendCoeff: 759 output->fBlendedColorFlags = 0; 760 break; 761 } 762 763 output->fWillBlendWithDst = false; 764 } 765 766 bool GrPorterDuffXPFactory::willReadDstColor(const GrDrawTargetCaps& caps, 767 const GrProcOptInfo& colorPOI, 768 const GrProcOptInfo& coveragePOI) const { 769 // We can always blend correctly if we have dual source blending. 770 if (caps.shaderCaps()->dualSourceBlendingSupport()) { 771 return false; 772 } 773 774 if (can_tweak_alpha_for_coverage(fDstCoeff)) { 775 return false; 776 } 777 778 bool srcAIsOne = colorPOI.isOpaque(); 779 780 if (kZero_GrBlendCoeff == fDstCoeff) { 781 if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) { 782 return false; 783 } 784 } 785 786 // Reduces to: coeffS * (Cov*S) + D 787 if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) { 788 return false; 789 } 790 791 // We can always blend correctly if we have solid coverage. 792 if (coveragePOI.isSolidWhite()) { 793 return false; 794 } 795 796 return true; 797 } 798 799 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); 800 801 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random, 802 GrContext*, 803 const GrDrawTargetCaps&, 804 GrTexture*[]) { 805 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::kLastCoeffMode)); 806 return GrPorterDuffXPFactory::Create(mode); 807 } 808 809