Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "effects/GrCustomXfermode.h" | 8 #include "effects/GrCustomXfermode.h" |
| 9 #include "effects/GrCustomXfermodePriv.h" | 9 #include "effects/GrCustomXfermodePriv.h" |
| 10 | 10 |
| 11 #include "GrCoordTransform.h" | 11 #include "GrCoordTransform.h" |
| 12 #include "GrContext.h" | 12 #include "GrContext.h" |
| 13 #include "GrFragmentProcessor.h" | 13 #include "GrFragmentProcessor.h" |
| 14 #include "GrInvariantOutput.h" | 14 #include "GrInvariantOutput.h" |
| 15 #include "GrProcessor.h" | 15 #include "GrProcessor.h" |
| 16 #include "GrTexture.h" | 16 #include "GrTexture.h" |
| 17 #include "GrTextureAccess.h" | 17 #include "GrTextureAccess.h" |
| 18 #include "SkXfermode.h" | 18 #include "SkXfermode.h" |
| 19 #include "gl/GrGLCaps.h" | 19 #include "gl/GrGLCaps.h" |
| 20 #include "gl/GrGLGpu.h" | |
| 20 #include "gl/GrGLProcessor.h" | 21 #include "gl/GrGLProcessor.h" |
| 21 #include "gl/GrGLProgramDataManager.h" | 22 #include "gl/GrGLProgramDataManager.h" |
| 22 #include "gl/builders/GrGLProgramBuilder.h" | 23 #include "gl/builders/GrGLProgramBuilder.h" |
| 23 | 24 |
| 24 bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) { | 25 bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) { |
| 25 return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode; | 26 return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode; |
| 26 } | 27 } |
| 27 | 28 |
| 28 /////////////////////////////////////////////////////////////////////////////// | 29 /////////////////////////////////////////////////////////////////////////////// |
| 29 // Static helpers | 30 // Static helpers |
| (...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 | 504 |
| 504 bool hasSecondaryOutput() const override { return false; } | 505 bool hasSecondaryOutput() const override { return false; } |
| 505 | 506 |
| 506 GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI, | 507 GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI, |
| 507 const GrProcOptInfo& coveragePOI, | 508 const GrProcOptInfo& coveragePOI, |
| 508 bool doesStencilWrite, | 509 bool doesStencilWrite, |
| 509 GrColor* overrideColor, | 510 GrColor* overrideColor, |
| 510 const GrDrawTargetCaps& caps) ove rride; | 511 const GrDrawTargetCaps& caps) ove rride; |
| 511 | 512 |
| 512 SkXfermode::Mode mode() const { return fMode; } | 513 SkXfermode::Mode mode() const { return fMode; } |
| 514 bool hasCoverage() const { return fHasCoverage; } | |
| 515 bool hasHWBlendEquation() const { return kInvalid_GrBlendEquation != fHWBlen dEquation; } | |
| 516 | |
| 517 GrBlendEquation hwBlendEquation() const { | |
| 518 SkASSERT(this->hasHWBlendEquation()); | |
| 519 return fHWBlendEquation; | |
| 520 } | |
| 513 | 521 |
| 514 private: | 522 private: |
| 515 CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, bool wi llReadDstColor); | 523 CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, bool wi llReadDstColor); |
| 516 | 524 |
| 517 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override; | 525 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override; |
| 518 | 526 |
| 527 bool onWillNeedXferBarrier(const GrRenderTarget* rt, | |
| 528 const GrDrawTargetCaps& caps, | |
| 529 GrXferBarrierType* outBarrierType) const override ; | |
| 530 | |
| 531 void onGetBlendInfo(BlendInfo*) const override; | |
| 532 | |
| 519 bool onIsEqual(const GrXferProcessor& xpBase) const override; | 533 bool onIsEqual(const GrXferProcessor& xpBase) const override; |
| 520 | 534 |
| 521 SkXfermode::Mode fMode; | 535 SkXfermode::Mode fMode; |
| 536 bool fHasCoverage; | |
| 537 GrBlendEquation fHWBlendEquation; | |
| 522 | 538 |
| 523 typedef GrXferProcessor INHERITED; | 539 typedef GrXferProcessor INHERITED; |
| 524 }; | 540 }; |
| 525 | 541 |
| 526 /////////////////////////////////////////////////////////////////////////////// | 542 /////////////////////////////////////////////////////////////////////////////// |
| 527 | 543 |
| 528 GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) { | 544 GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) { |
| 529 if (!GrCustomXfermode::IsSupportedMode(mode)) { | 545 if (!GrCustomXfermode::IsSupportedMode(mode)) { |
| 530 return NULL; | 546 return NULL; |
| 531 } else { | 547 } else { |
| 532 return SkNEW_ARGS(GrCustomXPFactory, (mode)); | 548 return SkNEW_ARGS(GrCustomXPFactory, (mode)); |
| 533 } | 549 } |
| 534 } | 550 } |
| 535 | 551 |
| 536 /////////////////////////////////////////////////////////////////////////////// | 552 /////////////////////////////////////////////////////////////////////////////// |
| 537 | 553 |
| 538 class GLCustomXP : public GrGLXferProcessor { | 554 class GLCustomXP : public GrGLXferProcessor { |
| 539 public: | 555 public: |
| 540 GLCustomXP(const GrXferProcessor&) {} | 556 GLCustomXP(const GrXferProcessor&) {} |
| 541 ~GLCustomXP() override {} | 557 ~GLCustomXP() override {} |
| 542 | 558 |
| 543 static void GenKey(const GrXferProcessor& proc, const GrGLSLCaps&, GrProcess orKeyBuilder* b) { | 559 static void GenKey(const GrXferProcessor& p, const GrGLSLCaps& caps, GrProce ssorKeyBuilder* b) { |
| 544 uint32_t key = proc.numTextures(); | 560 const CustomXP& xp = p.cast<CustomXP>(); |
| 561 uint32_t key = xp.numTextures(); | |
| 545 SkASSERT(key <= 1); | 562 SkASSERT(key <= 1); |
| 546 key |= proc.cast<CustomXP>().mode() << 1; | 563 key |= xp.hasCoverage() << 1; |
| 564 if (!xp.hasHWBlendEquation() || caps.mustEnableAdvancedBlendEquations()) { | |
|
egdaniel
2015/05/04 19:51:21
just to confirm, mustEnableAdvBE() means that we n
Chris Dalton
2015/05/04 20:33:12
Yes, that's correct. And we need this check becaus
| |
| 565 key |= 1 << 2; // Differentiate the shaders that take this branch. | |
| 566 key |= xp.hasHWBlendEquation() << 3; | |
| 567 key |= xp.mode() << 4; | |
|
egdaniel
2015/05/04 19:51:21
When adding the case to switch between all and ind
Chris Dalton
2015/05/05 18:57:58
Done.
| |
| 568 } | |
| 547 b->add32(key); | 569 b->add32(key); |
| 548 } | 570 } |
| 549 | 571 |
| 550 private: | 572 private: |
| 551 void onEmitCode(const EmitArgs& args) override { | 573 void onEmitCode(const EmitArgs& args) override { |
| 552 SkXfermode::Mode mode = args.fXP.cast<CustomXP>().mode(); | 574 const CustomXP& xp = args.fXP.cast<CustomXP>(); |
| 553 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); | 575 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); |
| 554 const char* dstColor = fsBuilder->dstColor(); | |
| 555 | 576 |
| 556 emit_custom_xfermode_code(mode, fsBuilder, args.fOutputPrimary, args.fIn putColor, dstColor); | 577 if (xp.hasHWBlendEquation()) { |
| 578 // The blend mode will be implemented in hardware; only output the s rc color. | |
| 579 if (args.fPB->gpu()->glCaps().glslCaps()->mustEnableAdvancedBlendEqu ations()) { | |
| 580 fsBuilder->enableAdvancedBlendEquation(xp.hwBlendEquation()); | |
| 581 } | |
| 582 if (xp.hasCoverage()) { | |
| 583 // Do coverage modulation by multiplying it into the src color b efore blending. | |
| 584 // (See canTweakAlphaForCoverage()) | |
| 585 fsBuilder->codeAppendf("%s = %s * %s;", | |
| 586 args.fOutputPrimary, args.fInputCoverage, args.fInputColor); | |
| 587 } else { | |
| 588 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fIn putColor); | |
| 589 } | |
| 590 } else { | |
| 591 SkXfermode::Mode mode = xp.mode(); | |
| 592 const char* dstColor = fsBuilder->dstColor(); | |
| 557 | 593 |
| 558 fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;", | 594 emit_custom_xfermode_code(mode, fsBuilder, args.fOutputPrimary, args .fInputColor, dstColor); |
|
egdaniel
2015/05/04 19:51:21
100 chars
Chris Dalton
2015/05/04 20:33:12
Oops :)
Chris Dalton
2015/05/05 18:57:58
Done.
| |
| 559 args.fOutputPrimary, args.fOutputPrimary, args.fI nputCoverage, | 595 |
| 560 args.fInputCoverage, dstColor); | 596 if (xp.hasCoverage()) { |
| 597 fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;", | |
| 598 args.fOutputPrimary, args.fOutputPrimary, | |
| 599 args.fInputCoverage, args.fInputCoverage, dstColor); | |
| 600 } | |
| 601 } | |
| 561 } | 602 } |
| 562 | 603 |
| 563 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri de {} | 604 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri de {} |
| 564 | 605 |
| 565 typedef GrGLFragmentProcessor INHERITED; | 606 typedef GrGLFragmentProcessor INHERITED; |
| 566 }; | 607 }; |
| 567 | 608 |
| 568 /////////////////////////////////////////////////////////////////////////////// | 609 /////////////////////////////////////////////////////////////////////////////// |
| 569 | 610 |
| 570 CustomXP::CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, | 611 CustomXP::CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, |
| 571 bool willReadDstColor) | 612 bool willReadDstColor) |
| 572 : INHERITED(dstCopy, willReadDstColor), fMode(mode) { | 613 : INHERITED(dstCopy, willReadDstColor), |
| 614 fMode(mode), | |
| 615 fHasCoverage(true), | |
| 616 fHWBlendEquation(kInvalid_GrBlendEquation) { | |
| 573 this->initClassID<CustomXP>(); | 617 this->initClassID<CustomXP>(); |
| 574 } | 618 } |
| 575 | 619 |
| 576 void CustomXP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder * b) const { | 620 void CustomXP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder * b) const { |
| 577 GLCustomXP::GenKey(*this, caps, b); | 621 GLCustomXP::GenKey(*this, caps, b); |
| 578 } | 622 } |
| 579 | 623 |
| 580 GrGLXferProcessor* CustomXP::createGLInstance() const { | 624 GrGLXferProcessor* CustomXP::createGLInstance() const { |
| 625 SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation()); | |
| 581 return SkNEW_ARGS(GLCustomXP, (*this)); | 626 return SkNEW_ARGS(GLCustomXP, (*this)); |
| 582 } | 627 } |
| 583 | 628 |
| 584 bool CustomXP::onIsEqual(const GrXferProcessor& other) const { | 629 bool CustomXP::onIsEqual(const GrXferProcessor& other) const { |
| 585 const CustomXP& s = other.cast<CustomXP>(); | 630 const CustomXP& s = other.cast<CustomXP>(); |
| 586 return fMode == s.fMode; | 631 return fMode == s.fMode && |
| 632 fHasCoverage == s.fHasCoverage && | |
| 633 fHWBlendEquation == s.fHWBlendEquation; | |
| 587 } | 634 } |
| 588 | 635 |
| 589 GrXferProcessor::OptFlags CustomXP::getOptimizations(const GrProcOptInfo& colorP OI, | 636 GrXferProcessor::OptFlags CustomXP::getOptimizations(const GrProcOptInfo& colorP OI, |
| 590 const GrProcOptInfo& cove ragePOI, | 637 const GrProcOptInfo& cove ragePOI, |
| 591 bool doesStencilWrite, | 638 bool doesStencilWrite, |
| 592 GrColor* overrideColor, | 639 GrColor* overrideColor, |
| 593 const GrDrawTargetCaps& c aps) { | 640 const GrDrawTargetCaps& c aps) { |
| 594 return GrXferProcessor::kNone_Opt; | 641 OptFlags flags = kNone_Opt; |
| 642 if (colorPOI.allStagesMultiplyInput()) { | |
| 643 flags = flags | kCanTweakAlphaForCoverage_OptFlag; | |
| 644 } | |
| 645 if (coveragePOI.isSolidWhite()) { | |
| 646 flags = flags | kIgnoreCoverage_OptFlag; | |
| 647 fHasCoverage = false; | |
| 648 } | |
| 649 if (caps.advancedBlendEquationSupport() && !coveragePOI.isFourChannelOutput( )) { | |
| 650 // This blend mode can be implemented in hardware. | |
| 651 enum { kOffset = kOverlay_GrBlendEquation - SkXfermode::kOverlay_Mode }; | |
| 652 fHWBlendEquation = static_cast<GrBlendEquation>(fMode + kOffset); | |
| 653 | |
| 654 GR_STATIC_ASSERT(kOverlay_GrBlendEquation == SkXfermode::kOverlay_Mode + kOffset); | |
| 655 GR_STATIC_ASSERT(kDarken_GrBlendEquation == SkXfermode::kDarken_Mode + k Offset); | |
| 656 GR_STATIC_ASSERT(kLighten_GrBlendEquation == SkXfermode::kLighten_Mode + kOffset); | |
| 657 GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == SkXfermode::kColorDodge_ Mode + kOffset); | |
| 658 GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == SkXfermode::kColorBurn_Mo de + kOffset); | |
| 659 GR_STATIC_ASSERT(kHardLight_GrBlendEquation == SkXfermode::kHardLight_Mo de + kOffset); | |
| 660 GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == SkXfermode::kSoftLight_Mo de + kOffset); | |
| 661 GR_STATIC_ASSERT(kDifference_GrBlendEquation == SkXfermode::kDifference_ Mode + kOffset); | |
| 662 GR_STATIC_ASSERT(kExclusion_GrBlendEquation == SkXfermode::kExclusion_Mo de + kOffset); | |
| 663 GR_STATIC_ASSERT(kMultiply_GrBlendEquation == SkXfermode::kMultiply_Mode + kOffset); | |
| 664 GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == SkXfermode::kHue_Mode + kOff set); | |
| 665 GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == SkXfermode::kSaturati on_Mode + kOffset); | |
| 666 GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == SkXfermode::kColor_Mode + kOffset); | |
| 667 GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == SkXfermode::kLuminosi ty_Mode + kOffset); | |
| 668 GR_STATIC_ASSERT(kTotalGrBlendEquationCount == SkXfermode::kLastMode + 1 + kOffset); | |
| 669 } | |
| 670 return flags; | |
| 671 } | |
| 672 | |
| 673 bool CustomXP::onWillNeedXferBarrier(const GrRenderTarget* rt, | |
| 674 const GrDrawTargetCaps& caps, | |
| 675 GrXferBarrierType* outBarrierType) const { | |
| 676 if (this->hasHWBlendEquation() && | |
| 677 GrDrawTargetCaps::kAdvancedCoherent_BlendEquationSupport != caps.blendEq uationSupport()) { | |
| 678 *outBarrierType = kBlend_GrXferBarrierType; | |
| 679 return true; | |
| 680 } | |
| 681 return false; | |
| 682 } | |
| 683 | |
| 684 void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const { | |
| 685 if (this->hasHWBlendEquation()) { | |
| 686 blendInfo->fEquation = this->hwBlendEquation(); | |
| 687 } | |
| 595 } | 688 } |
| 596 | 689 |
| 597 /////////////////////////////////////////////////////////////////////////////// | 690 /////////////////////////////////////////////////////////////////////////////// |
| 598 | 691 |
| 599 GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode) | 692 GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode) |
| 600 : fMode(mode) { | 693 : fMode(mode) { |
| 601 this->initClassID<GrCustomXPFactory>(); | 694 this->initClassID<GrCustomXPFactory>(); |
| 602 } | 695 } |
| 603 | 696 |
| 604 GrXferProcessor* | 697 GrXferProcessor* |
| 605 GrCustomXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, | 698 GrCustomXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, |
| 606 const GrProcOptInfo& colorPOI, | 699 const GrProcOptInfo& colorPOI, |
| 607 const GrProcOptInfo& coveragePOI, | 700 const GrProcOptInfo& coveragePOI, |
| 608 const GrDeviceCoordTexture* dstCopy) co nst { | 701 const GrDeviceCoordTexture* dstCopy) co nst { |
| 609 return CustomXP::Create(fMode, dstCopy, this->willReadDstColor(caps, colorPO I, coveragePOI)); | 702 return CustomXP::Create(fMode, dstCopy, this->willReadDstColor(caps, colorPO I, coveragePOI)); |
| 610 } | 703 } |
| 611 | 704 |
| 705 bool GrCustomXPFactory::canTweakAlphaForCoverage() const { | |
|
egdaniel
2015/05/04 19:51:21
so we actually just removed this function since wi
Chris Dalton
2015/05/05 18:57:58
Done.
| |
| 706 /* | |
| 707 The general SVG blend equation is defined in the spec as follows: | |
| 708 | |
| 709 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa) | |
| 710 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa) | |
| 711 | |
| 712 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha, | |
| 713 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied | |
| 714 RGB colors.) | |
| 715 | |
| 716 For every blend mode supported by this class, i.e. the "advanced" blend | |
| 717 modes, X=Y=Z=1 and this equation reduces to the PDF blend equation. | |
| 718 | |
| 719 It can be shown that when X=Y=Z=1, canTweakAlphaForCoverage() is true. | |
| 720 | |
| 721 | |
| 722 == Color == | |
| 723 | |
| 724 We substitute Y=Z=1 and define a blend() function that calculates Dca' in | |
| 725 terms of premultiplied alpha only: | |
| 726 | |
| 727 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0, | |
| 728 Sca : if Da == 0, | |
| 729 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dc a * (1-Sa) : if Sa,Da != 0} | |
| 730 | |
| 731 And for coverage modulation, we use a post blend src-over model: | |
| 732 | |
| 733 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 734 | |
| 735 (Where f is the fractional coverage.) | |
| 736 | |
| 737 Next we show that canTweakAlphaForCoverage() is true by proving the | |
| 738 following relationship: | |
| 739 | |
| 740 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 741 | |
| 742 General case (f,Sa,Da != 0): | |
| 743 | |
| 744 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 745 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f ) * Dca [Sa,Da != 0, definition of blend()] | |
| 746 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca | |
| 747 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * S a + Dca - f*Dca | |
| 748 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca | |
| 749 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca | |
| 750 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) | |
| 751 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0] | |
| 752 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()] | |
| 753 | |
| 754 Corner cases (Sa=0, Da=0, and f=0): | |
| 755 | |
| 756 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 757 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()] | |
| 758 = Dca | |
| 759 = blend(0, Dca, 0, Da) [definition of blend()] | |
| 760 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0] | |
| 761 | |
| 762 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 763 = f * Sca + (1-f) * Dca [Da=0, definition of blend()] | |
| 764 = f * Sca [Da=0] | |
| 765 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()] | |
| 766 = blend(f*Sca, Dca, f*Sa, Da) [Da=0] | |
| 767 | |
| 768 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 769 = Dca [f=0] | |
| 770 = blend(0, Dca, 0, Da) [definition of blend()] | |
| 771 = blend(f*Sca, Dca, f*Sa, Da) [f=0] | |
| 772 | |
| 773 == Alpha == | |
| 774 | |
| 775 We substitute X=Y=Z=1 and define a blend() function that calculates Da': | |
| 776 | |
| 777 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa) | |
| 778 = Sa * Da + Sa - Sa * Da + Da - Da * Sa | |
| 779 = Sa + Da - Sa * Da | |
| 780 | |
| 781 We use the same model for coverage modulation as we did with color: | |
| 782 | |
| 783 Da'' = f * blend(Sa, Da) + (1-f) * Da | |
| 784 | |
| 785 And show that canTweakAlphaForCoverage() is true by proving the following | |
| 786 relationship: | |
| 787 | |
| 788 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da | |
| 789 | |
| 790 | |
| 791 f * blend(Sa, Da) + (1-f) * Da | |
| 792 = f * (Sa + Da - Sa * Da) + (1-f) * Da | |
| 793 = f*Sa + f*Da - f*Sa * Da + Da - f*Da | |
| 794 = f*Sa - f*Sa * Da + Da | |
| 795 = f*Sa + Da - f*Sa * Da | |
| 796 = blend(f*Sa, Da) | |
| 797 */ | |
| 798 | |
| 799 return true; | |
|
egdaniel
2015/05/04 19:51:21
so I read through the proof on your first path. Of
Chris Dalton
2015/05/04 20:33:12
Yes, it works for the dst read version because it
| |
| 800 } | |
| 801 | |
| 802 bool GrCustomXPFactory::willReadDstColor(const GrDrawTargetCaps& caps, | |
| 803 const GrProcOptInfo& colorPOI, | |
| 804 const GrProcOptInfo& coveragePOI) const { | |
| 805 if (!caps.advancedBlendEquationSupport()) { | |
| 806 // No hardware support for advanced blend modes; we will need to do it i n the shader. | |
| 807 return true; | |
| 808 } | |
| 809 if (coveragePOI.isFourChannelOutput()) { | |
| 810 // Hardware blend modes won't work with RGB coverage. For these modes we multiply coverage | |
| 811 // into the src color before the blend, but this only works if coverage is a scalar. | |
| 812 return true; | |
| 813 } | |
| 814 return false; | |
| 815 } | |
| 612 | 816 |
| 613 void GrCustomXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, | 817 void GrCustomXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, |
| 614 const GrProcOptInfo& coveragePOI, | 818 const GrProcOptInfo& coveragePOI, |
| 615 GrXPFactory::InvariantOutput* out put) const { | 819 GrXPFactory::InvariantOutput* out put) const { |
| 616 output->fWillBlendWithDst = true; | 820 output->fWillBlendWithDst = true; |
| 617 output->fBlendedColorFlags = 0; | 821 output->fBlendedColorFlags = 0; |
| 618 } | 822 } |
| 619 | 823 |
| 620 GR_DEFINE_XP_FACTORY_TEST(GrCustomXPFactory); | 824 GR_DEFINE_XP_FACTORY_TEST(GrCustomXPFactory); |
| 621 GrXPFactory* GrCustomXPFactory::TestCreate(SkRandom* rand, | 825 GrXPFactory* GrCustomXPFactory::TestCreate(SkRandom* rand, |
| 622 GrContext*, | 826 GrContext*, |
| 623 const GrDrawTargetCaps&, | 827 const GrDrawTargetCaps&, |
| 624 GrTexture*[]) { | 828 GrTexture*[]) { |
| 625 int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLas tSeparableMode); | 829 int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLas tSeparableMode); |
| 626 | 830 |
| 627 return SkNEW_ARGS(GrCustomXPFactory, (static_cast<SkXfermode::Mode>(mode))); | 831 return SkNEW_ARGS(GrCustomXPFactory, (static_cast<SkXfermode::Mode>(mode))); |
| 628 } | 832 } |
| 629 | 833 |
| OLD | NEW |