| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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/GrPorterDuffXferProcessor.h" | 8 #include "effects/GrPorterDuffXferProcessor.h" |
| 9 | 9 |
| 10 #include "GrBlend.h" | 10 #include "GrBlend.h" |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), | 281 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 282 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out
putType), | 282 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out
putType), |
| 283 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), | 283 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 284 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), | 284 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), |
| 285 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), | 285 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 286 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), | 286 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), |
| 287 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_
OutputType), | 287 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_
OutputType), |
| 288 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), | 288 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), |
| 289 }}}; | 289 }}}; |
| 290 | 290 |
| 291 static BlendFormula get_blend_formula(SkXfermode::Mode xfermode, | 291 static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI, |
| 292 const GrProcOptInfo& colorPOI, | 292 const GrProcOptInfo& coveragePOI, |
| 293 const GrProcOptInfo& coveragePOI) { | 293 bool hasMixedSamples, |
| 294 SkXfermode::Mode xfermode) { |
| 294 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode); | 295 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode); |
| 295 SkASSERT(!coveragePOI.isFourChannelOutput()); | 296 SkASSERT(!coveragePOI.isFourChannelOutput()); |
| 296 | 297 |
| 297 return gBlendTable[colorPOI.isOpaque()][!coveragePOI.isSolidWhite()][xfermod
e]; | 298 bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples; |
| 299 return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode]; |
| 298 } | 300 } |
| 299 | 301 |
| 300 /////////////////////////////////////////////////////////////////////////////// | 302 /////////////////////////////////////////////////////////////////////////////// |
| 301 | 303 |
| 302 class PorterDuffXferProcessor : public GrXferProcessor { | 304 class PorterDuffXferProcessor : public GrXferProcessor { |
| 303 public: | 305 public: |
| 304 static GrXferProcessor* Create(BlendFormula blendFormula) { | 306 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendForm
ula) { |
| 305 return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula)); | 307 this->initClassID<PorterDuffXferProcessor>(); |
| 306 } | 308 } |
| 307 | 309 |
| 308 const char* name() const override { return "Porter Duff"; } | 310 const char* name() const override { return "Porter Duff"; } |
| 309 | 311 |
| 310 GrGLXferProcessor* createGLInstance() const override; | 312 GrGLXferProcessor* createGLInstance() const override; |
| 311 | 313 |
| 312 BlendFormula getBlendFormula() const { return fBlendFormula; } | 314 BlendFormula getBlendFormula() const { return fBlendFormula; } |
| 313 | 315 |
| 314 private: | 316 private: |
| 315 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendForm
ula) { | |
| 316 this->initClassID<PorterDuffXferProcessor>(); | |
| 317 } | |
| 318 | |
| 319 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, | 317 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, |
| 320 const GrProcOptInfo& coveragePO
I, | 318 const GrProcOptInfo& coveragePO
I, |
| 321 bool doesStencilWrite, | 319 bool doesStencilWrite, |
| 322 GrColor* overrideColor, | 320 GrColor* overrideColor, |
| 323 const GrCaps& caps) override; | 321 const GrCaps& caps) override; |
| 324 | 322 |
| 325 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override; | 323 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override; |
| 326 | 324 |
| 327 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSeconda
ryOutput(); } | 325 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSeconda
ryOutput(); } |
| 328 | 326 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 346 /////////////////////////////////////////////////////////////////////////////// | 344 /////////////////////////////////////////////////////////////////////////////// |
| 347 | 345 |
| 348 static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmen
tBuilder* fsBuilder, | 346 static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmen
tBuilder* fsBuilder, |
| 349 BlendFormula::OutputType outputType, const char*
output, | 347 BlendFormula::OutputType outputType, const char*
output, |
| 350 const char* inColor, const char* inCoverage) { | 348 const char* inColor, const char* inCoverage) { |
| 351 switch (outputType) { | 349 switch (outputType) { |
| 352 case BlendFormula::kNone_OutputType: | 350 case BlendFormula::kNone_OutputType: |
| 353 fsBuilder->codeAppendf("%s = vec4(0.0);", output); | 351 fsBuilder->codeAppendf("%s = vec4(0.0);", output); |
| 354 break; | 352 break; |
| 355 case BlendFormula::kCoverage_OutputType: | 353 case BlendFormula::kCoverage_OutputType: |
| 354 // We can have a coverage formula while not reading coverage if ther
e are mixed samples. |
| 356 fsBuilder->codeAppendf("%s = %s;", | 355 fsBuilder->codeAppendf("%s = %s;", |
| 357 output, xp.readsCoverage() ? inCoverage : "ve
c4(1.0)"); | 356 output, xp.readsCoverage() ? inCoverage : "ve
c4(1.0)"); |
| 358 break; | 357 break; |
| 359 case BlendFormula::kModulate_OutputType: | 358 case BlendFormula::kModulate_OutputType: |
| 360 if (xp.readsCoverage()) { | 359 if (xp.readsCoverage()) { |
| 361 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCover
age); | 360 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCover
age); |
| 362 } else { | 361 } else { |
| 363 fsBuilder->codeAppendf("%s = %s;", output, inColor); | 362 fsBuilder->codeAppendf("%s = %s;", output, inColor); |
| 364 } | 363 } |
| 365 break; | 364 break; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; | 447 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; |
| 449 } | 448 } |
| 450 } | 449 } |
| 451 return optFlags; | 450 return optFlags; |
| 452 } | 451 } |
| 453 | 452 |
| 454 /////////////////////////////////////////////////////////////////////////////// | 453 /////////////////////////////////////////////////////////////////////////////// |
| 455 | 454 |
| 456 class ShaderPDXferProcessor : public GrXferProcessor { | 455 class ShaderPDXferProcessor : public GrXferProcessor { |
| 457 public: | 456 public: |
| 458 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const DstTexture*
dstTexture) { | 457 ShaderPDXferProcessor(const DstTexture* dstTexture, |
| 459 return SkNEW_ARGS(ShaderPDXferProcessor, (xfermode, dstTexture)); | 458 bool hasMixedSamples, |
| 459 SkXfermode::Mode xfermode) |
| 460 : INHERITED(dstTexture, true, hasMixedSamples) |
| 461 , fXfermode(xfermode) { |
| 462 this->initClassID<ShaderPDXferProcessor>(); |
| 460 } | 463 } |
| 461 | 464 |
| 462 const char* name() const override { return "Porter Duff Shader"; } | 465 const char* name() const override { return "Porter Duff Shader"; } |
| 463 | 466 |
| 464 GrGLXferProcessor* createGLInstance() const override; | 467 GrGLXferProcessor* createGLInstance() const override; |
| 465 | 468 |
| 466 SkXfermode::Mode getXfermode() const { return fXfermode; } | 469 SkXfermode::Mode getXfermode() const { return fXfermode; } |
| 467 | 470 |
| 468 private: | 471 private: |
| 469 ShaderPDXferProcessor(SkXfermode::Mode xfermode, const DstTexture* dstTextur
e) | |
| 470 : INHERITED(dstTexture, true) | |
| 471 , fXfermode(xfermode) { | |
| 472 this->initClassID<ShaderPDXferProcessor>(); | |
| 473 } | |
| 474 | |
| 475 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrP
rocOptInfo&, | 472 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrP
rocOptInfo&, |
| 476 bool, GrColor*, const GrCaps&)
override { | 473 bool, GrColor*, const GrCaps&)
override { |
| 477 return kNone_Opt; | 474 return kNone_Opt; |
| 478 } | 475 } |
| 479 | 476 |
| 480 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override; | 477 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override; |
| 481 | 478 |
| 482 bool onIsEqual(const GrXferProcessor& xpBase) const override { | 479 bool onIsEqual(const GrXferProcessor& xpBase) const override { |
| 483 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>(); | 480 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>(); |
| 484 return fXfermode == xp.fXfermode; | 481 return fXfermode == xp.fXfermode; |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) { | 728 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) { |
| 732 return NULL; | 729 return NULL; |
| 733 } | 730 } |
| 734 return SkRef(gFactories[xfermode]); | 731 return SkRef(gFactories[xfermode]); |
| 735 } | 732 } |
| 736 | 733 |
| 737 GrXferProcessor* | 734 GrXferProcessor* |
| 738 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, | 735 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, |
| 739 const GrProcOptInfo& colorPOI, | 736 const GrProcOptInfo& colorPOI, |
| 740 const GrProcOptInfo& covPOI, | 737 const GrProcOptInfo& covPOI, |
| 738 bool hasMixedSamples, |
| 741 const DstTexture* dstTexture) const
{ | 739 const DstTexture* dstTexture) const
{ |
| 742 if (covPOI.isFourChannelOutput()) { | 740 if (covPOI.isFourChannelOutput()) { |
| 743 SkASSERT(!dstTexture || !dstTexture->texture()); | 741 SkASSERT(!dstTexture || !dstTexture->texture()); |
| 744 return PDLCDXferProcessor::Create(fXfermode, colorPOI); | 742 return PDLCDXferProcessor::Create(fXfermode, colorPOI); |
| 745 } | 743 } |
| 746 | 744 |
| 747 BlendFormula blendFormula = get_blend_formula(fXfermode, colorPOI, covPOI); | 745 BlendFormula blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamp
les, fXfermode); |
| 748 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlend
ingSupport()) { | 746 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlend
ingSupport()) { |
| 749 return ShaderPDXferProcessor::Create(fXfermode, dstTexture); | 747 return SkNEW_ARGS(ShaderPDXferProcessor, (dstTexture, hasMixedSamples, f
Xfermode)); |
| 750 } | 748 } |
| 751 | 749 |
| 752 SkASSERT(!dstTexture || !dstTexture->texture()); | 750 SkASSERT(!dstTexture || !dstTexture->texture()); |
| 753 return PorterDuffXferProcessor::Create(blendFormula); | 751 return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula)); |
| 754 } | 752 } |
| 755 | 753 |
| 756 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, | 754 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, |
| 757 uint32_t knownColorFlags) const
{ | 755 uint32_t knownColorFlags) const
{ |
| 758 if (SkXfermode::kSrcOver_Mode == fXfermode && | 756 if (SkXfermode::kSrcOver_Mode == fXfermode && |
| 759 kRGBA_GrColorComponentFlags == knownColorFlags) { | 757 kRGBA_GrColorComponentFlags == knownColorFlags) { |
| 760 return true; | 758 return true; |
| 761 } | 759 } |
| 762 return false; | 760 return false; |
| 763 } | 761 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 788 return; | 786 return; |
| 789 | 787 |
| 790 default: | 788 default: |
| 791 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; | 789 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; |
| 792 return; | 790 return; |
| 793 } | 791 } |
| 794 } | 792 } |
| 795 | 793 |
| 796 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, | 794 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, |
| 797 const GrProcOptInfo& colorPOI, | 795 const GrProcOptInfo& colorPOI, |
| 798 const GrProcOptInfo& coveragePOI) c
onst { | 796 const GrProcOptInfo& covPOI, |
| 799 if (coveragePOI.isFourChannelOutput()) { | 797 bool hasMixedSamples) const { |
| 800 return false; // The LCD XP never does a dst read. | 798 if (caps.shaderCaps()->dualSourceBlendingSupport()) { |
| 799 return false; |
| 801 } | 800 } |
| 802 | 801 if (covPOI.isFourChannelOutput()) { |
| 802 return false; // The LCD XP will abort rather than doing a dst read. |
| 803 } |
| 803 // We fallback on the shader XP when the blend formula would use dual source
blending but we | 804 // We fallback on the shader XP when the blend formula would use dual source
blending but we |
| 804 // don't have support for it. | 805 // don't have support for it. |
| 805 return !caps.shaderCaps()->dualSourceBlendingSupport() && | 806 return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSe
condaryOutput(); |
| 806 get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutpu
t(); | |
| 807 } | 807 } |
| 808 | 808 |
| 809 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); | 809 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); |
| 810 | 810 |
| 811 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random, | 811 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random, |
| 812 GrContext*, | 812 GrContext*, |
| 813 const GrCaps&, | 813 const GrCaps&, |
| 814 GrTexture*[]) { | 814 GrTexture*[]) { |
| 815 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k
LastCoeffMode)); | 815 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k
LastCoeffMode)); |
| 816 return GrPorterDuffXPFactory::Create(mode); | 816 return GrPorterDuffXPFactory::Create(mode); |
| 817 } | 817 } |
| 818 | 818 |
| 819 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp, | 819 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp, |
| 820 int* outPrimary, | 820 int* outPrimary, |
| 821 int* outSecondary) { | 821 int* outSecondary) { |
| 822 if (!!strcmp(xp->name(), "Porter Duff")) { | 822 if (!!strcmp(xp->name(), "Porter Duff")) { |
| 823 *outPrimary = *outSecondary = -1; | 823 *outPrimary = *outSecondary = -1; |
| 824 return; | 824 return; |
| 825 } | 825 } |
| 826 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)-
>getBlendFormula(); | 826 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)-
>getBlendFormula(); |
| 827 *outPrimary = blendFormula.fPrimaryOutputType; | 827 *outPrimary = blendFormula.fPrimaryOutputType; |
| 828 *outSecondary = blendFormula.fSecondaryOutputType; | 828 *outSecondary = blendFormula.fSecondaryOutputType; |
| 829 } | 829 } |
| 830 | 830 |
| OLD | NEW |