Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef GrProcessorSet_DEFINED
      9 #define GrProcessorSet_DEFINED
     10 
     11 #include "GrFragmentProcessor.h"
     12 #include "GrPaint.h"
     13 #include "GrPipelineAnalysis.h"
     14 #include "SkTemplates.h"
     15 
     16 class GrAppliedClip;
     17 class GrXPFactory;
     18 
     19 class GrProcessorSet : private SkNoncopyable {
     20 public:
     21     GrProcessorSet(GrPaint&& paint);
     22 
     23     ~GrProcessorSet();
     24 
     25     /**
     26      * If an op is recorded with this processor set then this must be called to ensure pending
     27      * reads and writes are propagated to resources referred to by the processors. Otherwise,
     28      * data hazards may occur.
     29      */
     30     void makePendingExecution();
     31     bool isPendingExecution() const { return SkToBool(kPendingExecution_Flag & fFlags); }
     32 
     33     int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; }
     34     int numCoverageFragmentProcessors() const {
     35         return this->numFragmentProcessors() - fColorFragmentProcessorCnt;
     36     }
     37     int numFragmentProcessors() const {
     38         return fFragmentProcessors.count() - fFragmentProcessorOffset;
     39     }
     40 
     41     const GrFragmentProcessor* colorFragmentProcessor(int idx) const {
     42         SkASSERT(idx < fColorFragmentProcessorCnt);
     43         return fFragmentProcessors[idx + fFragmentProcessorOffset];
     44     }
     45     const GrFragmentProcessor* coverageFragmentProcessor(int idx) const {
     46         return fFragmentProcessors[idx + fColorFragmentProcessorCnt + fFragmentProcessorOffset];
     47     }
     48 
     49     const GrXPFactory* xpFactory() const { return fXPFactory; }
     50 
     51     bool usesDistanceVectorField() const { return SkToBool(fFlags & kUseDistanceVectorField_Flag); }
     52     bool disableOutputConversionToSRGB() const {
     53         return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag);
     54     }
     55     bool allowSRGBInputs() const { return SkToBool(fFlags & kAllowSRGBInputs_Flag); }
     56 
     57     bool operator==(const GrProcessorSet& that) const;
     58     bool operator!=(const GrProcessorSet& that) const { return !(*this == that); }
     59 
     60     /**
     61      * This is used to track analysis of color and coverage values through the fragment processors.
     62      */
     63     class FragmentProcessorAnalysis {
     64     public:
     65         /**
     66          * This constructor allows an op to record its initial color in a FragmentProcessorAnalysis
     67          * member and then run analysis later when the analysis inputs are available. If the
     68          * analysis produces color fragment processor elimination then the input color is replaced
     69          * by the expected input to the first non-eliminated processor. Otherwise, the original
     70          * input color is preserved. The only reason to use this is to save space on the op by not
     71          * separately storing the initial color.
     72          */
     73         explicit FragmentProcessorAnalysis(GrColor initialColor) : FragmentProcessorAnalysis() {
     74             fInputColor = initialColor;
     75             fValidInputColor = true;
     76         }
     77 
     78         FragmentProcessorAnalysis()
     79                 : fIsInitializedWithProcessorSet(false)
     80                 , fCompatibleWithCoverageAsAlpha(true)
     81                 , fValidInputColor(false)
     82                 , fOutputCoverageType(static_cast<unsigned>(GrPipelineAnalysisCoverage::kNone))
     83                 , fOutputColorType(static_cast<unsigned>(ColorType::kUnknown))
     84                 , fInitialColorProcessorsToEliminate(0) {}
     85 
     86         // This version is used by a unit test that assumes no clip, no processors, and no PLS.
     87         FragmentProcessorAnalysis(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage,
     88                                   const GrCaps&);
     89 
     90         void init(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage, const GrProcessorSet&,
     91                   const GrAppliedClip*, const GrCaps&);
     92 
     93         bool isInitializedWithProcessorSet() const { return fIsInitializedWithProcessorSet; }
     94 
     95         /**
     96          * If the return is greater than or equal to zero then 'newInputColor' should be used as the
     97          * input color to the GrPipeline derived from this processor set, replacing the GrDrawOp's
     98          * initial color. If the return is less than zero then newInputColor has not been
     99          * modified and no modification need be made to the pipeline's input color by the op.
    100          */
    101         int getInputColorOverrideAndColorProcessorEliminationCount(GrColor* newInputColor) const {
    102             if (fValidInputColor) {
    103                 *newInputColor = fInputColor;
    104                 return fInitialColorProcessorsToEliminate;
    105             }
    106             SkASSERT(!fInitialColorProcessorsToEliminate);
    107             return -1;
    108         }
    109 
    110         /**
    111          * Valid if initialProcessorsToEliminate returns true or this analysis was initialized with
    112          * a known color via constructor or init(). If color fragment processors are eliminated then
    113          * this returns the expected input to the first non-eliminated processors. Otherwise it is
    114          * the color passed to the constructor or init().
    115          */
    116         GrColor inputColor() const {
    117             SkASSERT(fValidInputColor);
    118             return fInputColor;
    119         }
    120 
    121         bool usesLocalCoords() const { return fUsesLocalCoords; }
    122         bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
    123         bool isOutputColorOpaque() const {
    124             return ColorType::kOpaque == this->outputColorType() ||
    125                    ColorType::kOpaqueConstant == this->outputColorType();
    126         }
    127         bool hasKnownOutputColor(GrColor* color = nullptr) const {
    128             bool constant = ColorType::kConstant == this->outputColorType() ||
    129                             ColorType::kOpaqueConstant == this->outputColorType();
    130             if (constant && color) {
    131                 *color = fKnownOutputColor;
    132             }
    133             return constant;
    134         }
    135         GrPipelineAnalysisCoverage outputCoverageType() const {
    136             return static_cast<GrPipelineAnalysisCoverage>(fOutputCoverageType);
    137         }
    138         bool hasCoverage() const {
    139             return this->outputCoverageType() != GrPipelineAnalysisCoverage::kNone;
    140         }
    141 
    142     private:
    143         enum class ColorType : unsigned { kUnknown, kOpaqueConstant, kConstant, kOpaque };
    144 
    145         ColorType outputColorType() const { return static_cast<ColorType>(fOutputColorType); }
    146 
    147         void internalInit(const GrPipelineAnalysisColor&, const GrPipelineAnalysisCoverage,
    148                           const GrProcessorSet&, const GrFragmentProcessor* clipFP, const GrCaps&);
    149 
    150         // MSVS 2015 won't pack a bool with an unsigned.
    151         using PackedBool = unsigned;
    152 
    153         PackedBool fIsInitializedWithProcessorSet : 1;
    154         PackedBool fUsesLocalCoords : 1;
    155         PackedBool fCompatibleWithCoverageAsAlpha : 1;
    156         PackedBool fValidInputColor : 1;
    157         unsigned fOutputCoverageType : 2;
    158         unsigned fOutputColorType : 2;
    159         unsigned fInitialColorProcessorsToEliminate : 32 - 8;
    160 
    161         GrColor fInputColor;
    162         GrColor fKnownOutputColor;
    163 
    164         friend class GrProcessorSet;
    165     };
    166     GR_STATIC_ASSERT(sizeof(FragmentProcessorAnalysis) == 2 * sizeof(GrColor) + sizeof(uint32_t));
    167 
    168     void analyzeAndEliminateFragmentProcessors(FragmentProcessorAnalysis*,
    169                                                const GrPipelineAnalysisColor& colorInput,
    170                                                const GrPipelineAnalysisCoverage coverageInput,
    171                                                const GrAppliedClip*, const GrCaps&);
    172 
    173 private:
    174     // This absurdly large limit allows FragmentProcessorAnalysis and this to pack fields together.
    175     static constexpr int kMaxColorProcessors = UINT8_MAX;
    176 
    177     enum Flags : uint16_t {
    178         kUseDistanceVectorField_Flag = 0x1,
    179         kDisableOutputConversionToSRGB_Flag = 0x2,
    180         kAllowSRGBInputs_Flag = 0x4,
    181         kPendingExecution_Flag = 0x8
    182     };
    183 
    184     const GrXPFactory* fXPFactory = nullptr;
    185     SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors;
    186     uint8_t fColorFragmentProcessorCnt;
    187     uint8_t fFragmentProcessorOffset = 0;
    188     uint8_t fFlags;
    189 };
    190 
    191 #endif
    192