/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrProcessorSet_DEFINED #define GrProcessorSet_DEFINED #include "GrFragmentProcessor.h" #include "GrPaint.h" #include "GrProcessorAnalysis.h" #include "SkTemplates.h" #include "GrXferProcessor.h" class GrAppliedClip; class GrXPFactory; class GrProcessorSet { private: // Arbitrary constructor arg for empty set and analysis enum class Empty { kEmpty }; public: GrProcessorSet(GrPaint&&); GrProcessorSet(SkBlendMode); GrProcessorSet(std::unique_ptr<GrFragmentProcessor> colorFP); GrProcessorSet(GrProcessorSet&&); GrProcessorSet(const GrProcessorSet&) = delete; GrProcessorSet& operator=(const GrProcessorSet&) = delete; ~GrProcessorSet(); int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; } int numCoverageFragmentProcessors() const { return this->numFragmentProcessors() - fColorFragmentProcessorCnt; } const GrFragmentProcessor* colorFragmentProcessor(int idx) const { SkASSERT(idx < fColorFragmentProcessorCnt); return fFragmentProcessors[idx + fFragmentProcessorOffset].get(); } const GrFragmentProcessor* coverageFragmentProcessor(int idx) const { return fFragmentProcessors[idx + fColorFragmentProcessorCnt + fFragmentProcessorOffset].get(); } const GrXferProcessor* xferProcessor() const { SkASSERT(this->isFinalized()); return fXP.fProcessor; } sk_sp<const GrXferProcessor> refXferProcessor() const { SkASSERT(this->isFinalized()); return sk_ref_sp(fXP.fProcessor); } std::unique_ptr<const GrFragmentProcessor> detachColorFragmentProcessor(int idx) { SkASSERT(idx < fColorFragmentProcessorCnt); return std::move(fFragmentProcessors[idx + fFragmentProcessorOffset]); } std::unique_ptr<const GrFragmentProcessor> detachCoverageFragmentProcessor(int idx) { return std::move( fFragmentProcessors[idx + fFragmentProcessorOffset + fColorFragmentProcessorCnt]); } /** Comparisons are only legal on finalized processor sets. */ bool operator==(const GrProcessorSet& that) const; bool operator!=(const GrProcessorSet& that) const { return !(*this == that); } /** * This is used to report results of processor analysis when a processor set is finalized (see * below). */ class Analysis { public: Analysis(const Analysis&) = default; Analysis() { *reinterpret_cast<uint32_t*>(this) = 0; } bool isInitialized() const { return fIsInitialized; } bool usesLocalCoords() const { return fUsesLocalCoords; } bool requiresDstTexture() const { return fRequiresDstTexture; } bool canCombineOverlappedStencilAndCover() const { return fCanCombineOverlappedStencilAndCover; } bool requiresBarrierBetweenOverlappingDraws() const { return fRequiresBarrierBetweenOverlappingDraws; } bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; } bool inputColorIsIgnored() const { return fInputColorType == kIgnored_InputColorType; } bool inputColorIsOverridden() const { return fInputColorType == kOverridden_InputColorType; } private: constexpr Analysis(Empty) : fUsesLocalCoords(false) , fCompatibleWithCoverageAsAlpha(true) , fRequiresDstTexture(false) , fCanCombineOverlappedStencilAndCover(true) , fRequiresBarrierBetweenOverlappingDraws(false) , fIsInitialized(true) , fInputColorType(kOriginal_InputColorType) {} enum InputColorType : uint32_t { kOriginal_InputColorType, kOverridden_InputColorType, kIgnored_InputColorType }; // MSVS 2015 won't pack different underlying types using PackedBool = uint32_t; using PackedInputColorType = uint32_t; PackedBool fUsesLocalCoords : 1; PackedBool fCompatibleWithCoverageAsAlpha : 1; PackedBool fRequiresDstTexture : 1; PackedBool fCanCombineOverlappedStencilAndCover : 1; PackedBool fRequiresBarrierBetweenOverlappingDraws : 1; PackedBool fIsInitialized : 1; PackedInputColorType fInputColorType : 2; friend class GrProcessorSet; }; GR_STATIC_ASSERT(sizeof(Analysis) <= sizeof(uint32_t)); /** * This analyzes the processors given an op's input color and coverage as well as a clip. The * state of the processor set may change to an equivalent but more optimal set of processors. * This new state requires that the caller respect the returned 'inputColorOverride'. This is * indicated by the returned Analysis's inputColorIsOverriden(). 'inputColorOverride' will not * be written if the analysis does not override the input color. * * This must be called before the processor set is used to construct a GrPipeline and may only * be called once. * * This also puts the processors in "pending execution" state and must be called when an op * that owns a processor set is recorded to ensure pending and writes are propagated to * resources referred to by the processors. Otherwise, data hazards may occur. */ Analysis finalize(const GrProcessorAnalysisColor& colorInput, const GrProcessorAnalysisCoverage coverageInput, const GrAppliedClip*, bool isMixedSamples, const GrCaps&, GrPixelConfigIsClamped, GrColor* inputColorOverride); bool isFinalized() const { return SkToBool(kFinalized_Flag & fFlags); } /** These are valid only for non-LCD coverage. */ static const GrProcessorSet& EmptySet(); static GrProcessorSet MakeEmptySet(); static constexpr const Analysis EmptySetAnalysis() { return Analysis(Empty::kEmpty); } SkString dumpProcessors() const; void visitProxies(const std::function<void(GrSurfaceProxy*)>& func) const { for (int i = 0; i < this->numFragmentProcessors(); ++i) { GrFragmentProcessor::TextureAccessIter iter(this->fragmentProcessor(i)); while (const GrResourceIOProcessor::TextureSampler* sampler = iter.next()) { func(sampler->proxy()); } } } private: GrProcessorSet(Empty) : fXP((const GrXferProcessor*)nullptr), fFlags(kFinalized_Flag) {} int numFragmentProcessors() const { return fFragmentProcessors.count() - fFragmentProcessorOffset; } const GrFragmentProcessor* fragmentProcessor(int idx) const { return fFragmentProcessors[idx + fFragmentProcessorOffset].get(); } // This absurdly large limit allows Analysis and this to pack fields together. static constexpr int kMaxColorProcessors = UINT8_MAX; enum Flags : uint16_t { kFinalized_Flag = 0x1 }; union XP { XP(const GrXPFactory* factory) : fFactory(factory) {} XP(const GrXferProcessor* processor) : fProcessor(processor) {} explicit XP(XP&& that) : fProcessor(that.fProcessor) { SkASSERT(fProcessor == that.fProcessor); that.fProcessor = nullptr; } const GrXPFactory* fFactory; const GrXferProcessor* fProcessor; }; const GrXPFactory* xpFactory() const { SkASSERT(!this->isFinalized()); return fXP.fFactory; } SkAutoSTArray<4, std::unique_ptr<const GrFragmentProcessor>> fFragmentProcessors; XP fXP; uint8_t fColorFragmentProcessorCnt = 0; uint8_t fFragmentProcessorOffset = 0; uint8_t fFlags; }; #endif