/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/core/SkBlendModePriv.h" #include "src/gpu/GrAppliedClip.h" #include "src/gpu/GrCaps.h" #include "src/gpu/GrProcessorSet.h" #include "src/gpu/GrUserStencilSettings.h" #include "src/gpu/GrXferProcessor.h" #include "src/gpu/effects/GrPorterDuffXferProcessor.h" const GrProcessorSet& GrProcessorSet::EmptySet() { static GrProcessorSet gEmpty(GrProcessorSet::Empty::kEmpty); return gEmpty; } GrProcessorSet GrProcessorSet::MakeEmptySet() { return GrProcessorSet(GrProcessorSet::Empty::kEmpty); } GrProcessorSet::GrProcessorSet(GrPaint&& paint) : fXP(paint.getXPFactory()) { fColorFragmentProcessor = std::move(paint.fColorFragmentProcessor); fCoverageFragmentProcessor = std::move(paint.fCoverageFragmentProcessor); SkDEBUGCODE(paint.fAlive = false;) } GrProcessorSet::GrProcessorSet(SkBlendMode mode) : fXP(SkBlendMode_AsXPFactory(mode)) {} GrProcessorSet::GrProcessorSet(std::unique_ptr colorFP) : fXP((const GrXPFactory*)nullptr) { SkASSERT(colorFP); fColorFragmentProcessor = std::move(colorFP); } GrProcessorSet::GrProcessorSet(GrProcessorSet&& that) : fColorFragmentProcessor(std::move(that.fColorFragmentProcessor)) , fCoverageFragmentProcessor(std::move(that.fCoverageFragmentProcessor)) , fXP(std::move(that.fXP)) , fFlags(that.fFlags) {} GrProcessorSet::~GrProcessorSet() { if (this->isFinalized() && this->xferProcessor()) { this->xferProcessor()->unref(); } } #if GR_TEST_UTILS SkString GrProcessorSet::dumpProcessors() const { SkString result; if (this->hasColorFragmentProcessor()) { result.append("Color Fragment Processor:\n"); result += this->colorFragmentProcessor()->dumpTreeInfo(); } else { result.append("No color fragment processor.\n"); } if (this->hasCoverageFragmentProcessor()) { result.append("Coverage Fragment Processor:\n"); result += this->coverageFragmentProcessor()->dumpTreeInfo(); } else { result.append("No coverage fragment processors.\n"); } if (this->isFinalized()) { result.append("Xfer Processor: "); if (this->xferProcessor()) { result.appendf("%s\n", this->xferProcessor()->name()); } else { result.append("SrcOver\n"); } } else { result.append("XP Factory dumping not implemented.\n"); } return result; } #endif bool GrProcessorSet::operator==(const GrProcessorSet& that) const { SkASSERT(this->isFinalized()); SkASSERT(that.isFinalized()); if (((fFlags ^ that.fFlags) & ~kFinalized_Flag) || this->hasColorFragmentProcessor() != that.hasColorFragmentProcessor() || this->hasCoverageFragmentProcessor() != that.hasCoverageFragmentProcessor()) { return false; } if (this->hasColorFragmentProcessor()) { if (!colorFragmentProcessor()->isEqual(*that.colorFragmentProcessor())) { return false; } } if (this->hasCoverageFragmentProcessor()) { if (!coverageFragmentProcessor()->isEqual(*that.coverageFragmentProcessor())) { return false; } } // Most of the time both of these are null if (!this->xferProcessor() && !that.xferProcessor()) { return true; } const GrXferProcessor& thisXP = this->xferProcessor() ? *this->xferProcessor() : GrPorterDuffXPFactory::SimpleSrcOverXP(); const GrXferProcessor& thatXP = that.xferProcessor() ? *that.xferProcessor() : GrPorterDuffXPFactory::SimpleSrcOverXP(); return thisXP.isEqual(thatXP); } GrProcessorSet::Analysis GrProcessorSet::finalize( const GrProcessorAnalysisColor& colorInput, const GrProcessorAnalysisCoverage coverageInput, const GrAppliedClip* clip, const GrUserStencilSettings* userStencil, const GrCaps& caps, GrClampType clampType, SkPMColor4f* overrideInputColor) { SkASSERT(!this->isFinalized()); GrProcessorSet::Analysis analysis; analysis.fCompatibleWithCoverageAsAlpha = GrProcessorAnalysisCoverage::kLCD != coverageInput; GrColorFragmentProcessorAnalysis colorAnalysis(colorInput, &fColorFragmentProcessor, this->hasColorFragmentProcessor() ? 1 : 0); bool hasCoverageFP = this->hasCoverageFragmentProcessor(); bool coverageUsesLocalCoords = false; if (hasCoverageFP) { if (!fCoverageFragmentProcessor->compatibleWithCoverageAsAlpha()) { analysis.fCompatibleWithCoverageAsAlpha = false; } coverageUsesLocalCoords |= fCoverageFragmentProcessor->usesSampleCoords(); } if (clip && clip->hasCoverageFragmentProcessor()) { hasCoverageFP = true; const GrFragmentProcessor* clipFP = clip->coverageFragmentProcessor(); analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha(); coverageUsesLocalCoords |= clipFP->usesSampleCoords(); } int colorFPsToEliminate = colorAnalysis.initialProcessorsToEliminate(overrideInputColor); analysis.fInputColorType = static_cast( colorFPsToEliminate ? Analysis::kOverridden_InputColorType : Analysis::kOriginal_InputColorType); GrProcessorAnalysisCoverage outputCoverage; if (GrProcessorAnalysisCoverage::kLCD == coverageInput) { outputCoverage = GrProcessorAnalysisCoverage::kLCD; } else if (hasCoverageFP || GrProcessorAnalysisCoverage::kSingleChannel == coverageInput) { outputCoverage = GrProcessorAnalysisCoverage::kSingleChannel; } else { outputCoverage = GrProcessorAnalysisCoverage::kNone; } GrXPFactory::AnalysisProperties props = GrXPFactory::GetAnalysisProperties( this->xpFactory(), colorAnalysis.outputColor(), outputCoverage, caps, clampType); analysis.fRequiresDstTexture = (props & GrXPFactory::AnalysisProperties::kRequiresDstTexture) || colorAnalysis.requiresDstTexture(caps); analysis.fCompatibleWithCoverageAsAlpha &= SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithCoverageAsAlpha); analysis.fRequiresNonOverlappingDraws = (props & GrXPFactory::AnalysisProperties::kRequiresNonOverlappingDraws) || analysis.fRequiresDstTexture; analysis.fUsesNonCoherentHWBlending = SkToBool(props & GrXPFactory::AnalysisProperties::kUsesNonCoherentHWBlending); analysis.fUnaffectedByDstValue = SkToBool(props & GrXPFactory::AnalysisProperties::kUnaffectedByDstValue); if (props & GrXPFactory::AnalysisProperties::kIgnoresInputColor) { colorFPsToEliminate = this->hasColorFragmentProcessor() ? 1 : 0; analysis.fInputColorType = static_cast(Analysis::kIgnored_InputColorType); analysis.fUsesLocalCoords = coverageUsesLocalCoords; } else { analysis.fCompatibleWithCoverageAsAlpha &= colorAnalysis.allProcessorsCompatibleWithCoverageAsAlpha(); analysis.fUsesLocalCoords = coverageUsesLocalCoords || colorAnalysis.usesLocalCoords(); } if (colorFPsToEliminate) { SkASSERT(colorFPsToEliminate == 1); fColorFragmentProcessor = nullptr; } analysis.fHasColorFragmentProcessor = this->hasColorFragmentProcessor(); auto xp = GrXPFactory::MakeXferProcessor(this->xpFactory(), colorAnalysis.outputColor(), outputCoverage, caps, clampType); fXP.fProcessor = xp.release(); fFlags |= kFinalized_Flag; analysis.fIsInitialized = true; #ifdef SK_DEBUG bool hasXferBarrier = fXP.fProcessor && GrXferBarrierType::kNone_GrXferBarrierType != fXP.fProcessor->xferBarrierType(caps); bool needsNonOverlappingDraws = analysis.fRequiresDstTexture || hasXferBarrier; SkASSERT(analysis.fRequiresNonOverlappingDraws == needsNonOverlappingDraws); #endif return analysis; } void GrProcessorSet::visitProxies(const GrVisitProxyFunc& func) const { if (this->hasColorFragmentProcessor()) { fColorFragmentProcessor->visitProxies(func); } if (this->hasCoverageFragmentProcessor()) { fCoverageFragmentProcessor->visitProxies(func); } }