text: /*
   * 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<GrFragmentProcessor> 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->usesVaryingCoords();
      }
      if (clip && clip->hasCoverageFragmentProcessor()) {
          hasCoverageFP = true;
          const GrFragmentProcessor* clipFP = clip->coverageFragmentProcessor();
          analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
          coverageUsesLocalCoords |= clipFP->usesVaryingCoords();
      }
      int colorFPsToEliminate = colorAnalysis.initialProcessorsToEliminate(overrideInputColor);
      analysis.fInputColorType = static_cast<Analysis::PackedInputColorType>(
              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::PackedInputColorType>(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 GrOp::VisitProxyFunc& func) const {
      if (this->hasColorFragmentProcessor()) {
          fColorFragmentProcessor->visitProxies(func);
      }
      if (this->hasCoverageFragmentProcessor()) {
          fCoverageFragmentProcessor->visitProxies(func);
      }
  }
  