Replace fWillReadFragmentPosition with a bitfield

Replaces fWillReadFragmentPosition on GrProcessor with a
"RequiredFeatures" bitfield. This will allow us to add additional
built-in features. Completely removes information about reading the
fragment position from GrPipeline and GrProcOptInfo.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1734163002

Review URL: https://codereview.chromium.org/1734163002
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index 4c3d0ee..495a7b3 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -96,9 +96,7 @@
     int index = fChildProcessors.count();
     fChildProcessors.push_back(SkRef(child));
 
-    if (child->willReadFragmentPosition()) {
-        this->setWillReadFragmentPosition();
-    }
+    this->combineRequiredFeatures(*child);
 
     if (child->usesLocalCoords()) {
         fUsesLocalCoords = true;
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index e1c733a..8e542d2 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -184,23 +184,14 @@
                                                 int* firstColorProcessorIdx,
                                                 int* firstCoverageProcessorIdx) {
     fIgnoresCoverage = SkToBool(flags & GrXferProcessor::kIgnoreCoverage_OptFlag);
-    fReadsFragPosition = this->getXferProcessor().willReadFragmentPosition();
 
     if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) ||
         (flags & GrXferProcessor::kOverrideColor_OptFlag)) {
         *firstColorProcessorIdx = pipelineBuilder.numColorFragmentProcessors();
-    } else {
-        if (colorPOI.readsFragPosition()) {
-            fReadsFragPosition = true;
-        }
     }
 
     if (flags & GrXferProcessor::kIgnoreCoverage_OptFlag) {
         *firstCoverageProcessorIdx = pipelineBuilder.numCoverageFragmentProcessors();
-    } else {
-        if (coveragePOI.readsFragPosition()) {
-            fReadsFragPosition = true;
-        }
     }
 }
 
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 4f81ae4..db7cb5b 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -160,7 +160,6 @@
 
     ///////////////////////////////////////////////////////////////////////////
 
-    bool readsFragPosition() const { return fReadsFragPosition; }
     bool ignoresCoverage() const { return fIgnoresCoverage; }
 
 private:
@@ -200,7 +199,6 @@
     uint32_t                            fFlags;
     ProgramXferProcessor                fXferProcessor;
     FragmentProcessorArray              fFragmentProcessors;
-    bool                                fReadsFragPosition;
     bool                                fIgnoresCoverage;
 
     // This value is also the index in fFragmentProcessors where coverage processors begin.
diff --git a/src/gpu/GrProcOptInfo.cpp b/src/gpu/GrProcOptInfo.cpp
index bfd9e9e..183a42f 100644
--- a/src/gpu/GrProcOptInfo.cpp
+++ b/src/gpu/GrProcOptInfo.cpp
@@ -23,7 +23,7 @@
     out.fValidFlags = flags;
     out.fIsLCDCoverage = isLCD;
     fInOut.reset(out);
-    this->internalCalc(processors, cnt, false);
+    this->internalCalc(processors, cnt);
 }
 
 void GrProcOptInfo::initUsingInvariantOutput(GrInitInvariantOutput invOutput) {
@@ -31,16 +31,13 @@
 }
 
 void GrProcOptInfo::completeCalculations(const GrFragmentProcessor * const processors[], int cnt) {
-    this->internalCalc(processors, cnt, false);
+    this->internalCalc(processors, cnt);
 }
 
-void GrProcOptInfo::internalCalc(const GrFragmentProcessor* const processors[],
-                                 int cnt,
-                                 bool initWillReadFragmentPosition) {
+void GrProcOptInfo::internalCalc(const GrFragmentProcessor* const processors[], int cnt) {
     fFirstEffectiveProcessorIndex = 0;
     fInputColorIsUsed = true;
     fInputColor = fInOut.color();
-    fReadsFragPosition = initWillReadFragmentPosition;
 
     for (int i = 0; i < cnt; ++i) {
         const GrFragmentProcessor* processor = processors[i];
@@ -50,11 +47,6 @@
         if (!fInOut.willUseInputColor()) {
             fFirstEffectiveProcessorIndex = i;
             fInputColorIsUsed = false;
-            // Reset these since we don't care if previous stages read these values
-            fReadsFragPosition = initWillReadFragmentPosition;
-        }
-        if (processor->willReadFragmentPosition()) {
-            fReadsFragPosition = true;
         }
         if (kRGBA_GrColorComponentFlags == fInOut.validFlags()) {
             fFirstEffectiveProcessorIndex = i + 1;
@@ -63,8 +55,6 @@
             // Since we are clearing all previous color stages we are in a state where we have found
             // zero stages that don't multiply the inputColor.
             fInOut.resetNonMulStageFound();
-            // Reset these since we don't care if previous stages read these values
-            fReadsFragPosition = initWillReadFragmentPosition;
         }
     }
 }
diff --git a/src/gpu/GrProcOptInfo.h b/src/gpu/GrProcOptInfo.h
index 19f01a2..94f80e7 100644
--- a/src/gpu/GrProcOptInfo.h
+++ b/src/gpu/GrProcOptInfo.h
@@ -14,7 +14,6 @@
 class GrDrawBatch;
 class GrFragmentProcessor;
 class GrPrimitiveProcessor;
-class GrProcessor;
 
 /**
  * GrProcOptInfo gathers invariant data from a set of processor stages.It is used to recognize
@@ -27,8 +26,7 @@
         : fInOut(0, static_cast<GrColorComponentFlags>(0), false)
         , fFirstEffectiveProcessorIndex(0)
         , fInputColorIsUsed(true)
-        , fInputColor(0)
-        , fReadsFragPosition(false) {}
+        , fInputColor(0) {}
 
     void calcWithInitialValues(const GrFragmentProcessor* const *, int cnt, GrColor startColor,
                                GrColorComponentFlags, bool areCoverageStages, bool isLCD = false);
@@ -75,19 +73,13 @@
      */
     GrColor inputColorToFirstEffectiveProccesor() const { return fInputColor; }
 
-    /**
-     * Returns true if any of the processor preserved by GrProcOptInfo read the frag position.
-     */
-    bool readsFragPosition() const { return fReadsFragPosition; }
-
 private:
-    void internalCalc(const GrFragmentProcessor* const[], int cnt, bool initWillReadFragPosition);
+    void internalCalc(const GrFragmentProcessor* const[], int cnt);
 
     GrInvariantOutput fInOut;
     int fFirstEffectiveProcessorIndex;
     bool fInputColorIsUsed;
     GrColor fInputColor;
-    bool fReadsFragPosition;
 };
 
 #endif
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index a2dea87..789eb62 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -120,6 +120,7 @@
         glDesc->key().reset();
         return false;
     }
+    GrProcessor::RequiredFeatures requiredFeatures = primProc.requiredFeatures();
 
     for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
         const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
@@ -127,6 +128,7 @@
             glDesc->key().reset();
             return false;
         }
+        requiredFeatures |= fp.requiredFeatures();
     }
 
     const GrXferProcessor& xp = pipeline.getXferProcessor();
@@ -135,6 +137,7 @@
         glDesc->key().reset();
         return false;
     }
+    requiredFeatures |= xp.requiredFeatures();
 
     // --------DO NOT MOVE HEADER ABOVE THIS LINE--------------------------------------------------
     // Because header is a pointer into the dynamic array, we can't push any new data into the key
@@ -144,7 +147,7 @@
     // make sure any padding in the header is zeroed.
     memset(header, 0, kHeaderSize);
 
-    if (pipeline.readsFragPosition()) {
+    if (requiredFeatures & GrProcessor::kFragmentPosition_RequiredFeature) {
         header->fFragPosKey =
                 GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget());
     } else {
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index 44db57e..bd01084 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -74,10 +74,16 @@
     , fHasCustomColorOutput(false)
     , fCustomColorOutputIndex(-1)
     , fHasSecondaryOutput(false)
-    , fHasInitializedSampleMask(false)
-    , fHasReadDstColor(false)
-    , fHasReadFragmentPosition(false) {
+    , fHasInitializedSampleMask(false) {
     fSubstageIndices.push_back(0);
+#ifdef SK_DEBUG
+    fUsedProcessorFeatures = GrProcessor::kNone_RequiredFeatures;
+    fHasReadDstColor = false;
+#endif
+}
+
+bool GrGLSLFragmentShaderBuilder::hasFragmentPosition() const {
+    return 0 != fProgramBuilder->header().fFragPosKey;
 }
 
 bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
@@ -123,7 +129,8 @@
 }
 
 const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
-    fHasReadFragmentPosition = true;
+    SkASSERT(this->hasFragmentPosition());
+    SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kFragmentPosition_RequiredFeature;)
 
     const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
     // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
@@ -212,7 +219,7 @@
 }
 
 const char* GrGLSLFragmentShaderBuilder::dstColor() {
-    fHasReadDstColor = true;
+    SkDEBUGCODE(fHasReadDstColor = true;)
 
     const char* override = fProgramBuilder->primitiveProcessor().getDestColorOverride();
     if (override != nullptr) {
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
index b9816af..1219d34 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -10,6 +10,7 @@
 
 #include "GrGLSLShaderBuilder.h"
 
+#include "GrProcessor.h"
 #include "glsl/GrGLSLProcessorTypes.h"
 
 class GrRenderTarget;
@@ -165,20 +166,24 @@
     void enableAdvancedBlendEquationIfNeeded(GrBlendEquation) override;
 
 private:
+    bool hasFragmentPosition() const;
+
     // Private public interface, used by GrGLProgramBuilder to build a fragment shader
     void enableCustomOutput();
     void enableSecondaryOutput();
     const char* getPrimaryColorOutputName() const;
     const char* getSecondaryColorOutputName() const;
 
+#ifdef SK_DEBUG
     // As GLSLProcessors emit code, there are some conditions we need to verify.  We use the below
     // state to track this.  The reset call is called per processor emitted.
+    GrProcessor::RequiredFeatures usedProcessorFeatures() const { return fUsedProcessorFeatures; }
     bool hasReadDstColor() const { return fHasReadDstColor; }
-    bool hasReadFragmentPosition() const { return fHasReadFragmentPosition; }
-    void reset() {
+    void resetVerification() {
+        fUsedProcessorFeatures = GrProcessor::kNone_RequiredFeatures;
         fHasReadDstColor = false;
-        fHasReadFragmentPosition = false;
     }
+#endif
 
     static const char* DeclaredColorOutputName() { return "fsColorOut"; }
     static const char* DeclaredSecondaryColorOutputName() { return "fsSecondaryColorOut"; }
@@ -226,10 +231,12 @@
     bool fHasSecondaryOutput;
     bool fHasInitializedSampleMask;
 
+#ifdef SK_DEBUG
     // some state to verify shaders and effects are consistent, this is reset between effects by
     // the program creator
+    GrProcessor::RequiredFeatures fUsedProcessorFeatures;
     bool fHasReadDstColor;
-    bool fHasReadFragmentPosition;
+#endif
 
     friend class GrGLSLProgramBuilder;
     friend class GrGLProgramBuilder;
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 9201da9..417e924 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -99,7 +99,7 @@
 
     // We have to check that effects and the code they emit are consistent, ie if an effect
     // asks for dst color, then the emit code needs to follow suit
-    verify(proc);
+    SkDEBUGCODE(verify(proc);)
 
     fFS.codeAppend("}");
 }
@@ -147,7 +147,7 @@
 
     // We have to check that effects and the code they emit are consistent, ie if an effect
     // asks for dst color, then the emit code needs to follow suit
-    verify(fp);
+    SkDEBUGCODE(verify(fp);)
     fFragmentProcessors.push_back(fragProc);
 
     fFS.codeAppend("}");
@@ -194,7 +194,7 @@
 
     // We have to check that effects and the code they emit are consistent, ie if an effect
     // asks for dst color, then the emit code needs to follow suit
-    verify(xp);
+    SkDEBUGCODE(verify(xp);)
     fFS.codeAppend("}");
 }
 
@@ -214,17 +214,20 @@
     }
 }
 
+#ifdef SK_DEBUG
 void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
-    SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
+    SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures());
 }
 
 void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
+    SkASSERT(fFS.usedProcessorFeatures() == xp.requiredFeatures());
     SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
 }
 
 void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
-    SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
+    SkASSERT(fFS.usedProcessorFeatures() == fp.requiredFeatures());
 }
+#endif
 
 void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) {
     if ('\0' == prefix) {
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index 164423c..b8669bf 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -105,7 +105,7 @@
     // fragment shader are cleared.
     void reset() {
         this->addStage();
-        fFS.reset();
+        SkDEBUGCODE(fFS.resetVerification();)
     }
     void addStage() { fStageIndex++; }
 
@@ -141,9 +141,11 @@
                                 GrPixelLocalStorageState plsState);
     void emitFSOutputSwizzle(bool hasSecondaryOutput);
 
+#ifdef SK_DEBUG
     void verify(const GrPrimitiveProcessor&);
     void verify(const GrXferProcessor&);
     void verify(const GrFragmentProcessor&);
+#endif
 
     virtual void emitSamplers(const GrProcessor& processor,
                               GrGLSLTextureSampler::TextureSamplerArray* outSamplers) = 0;
diff --git a/src/gpu/vk/GrVkProgramDesc.cpp b/src/gpu/vk/GrVkProgramDesc.cpp
index 346dbb6..32357cd 100644
--- a/src/gpu/vk/GrVkProgramDesc.cpp
+++ b/src/gpu/vk/GrVkProgramDesc.cpp
@@ -107,6 +107,7 @@
         vkDesc->key().reset();
         return false;
     }
+    GrProcessor::RequiredFeatures requiredFeatures = primProc.requiredFeatures();
 
     for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
         const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
@@ -114,6 +115,7 @@
             vkDesc->key().reset();
             return false;
         }
+        requiredFeatures |= fp.requiredFeatures();
     }
 
     const GrXferProcessor& xp = pipeline.getXferProcessor();
@@ -122,6 +124,7 @@
         vkDesc->key().reset();
         return false;
     }
+    requiredFeatures |= xp.requiredFeatures();
 
     // --------DO NOT MOVE HEADER ABOVE THIS LINE--------------------------------------------------
     // Because header is a pointer into the dynamic array, we can't push any new data into the key
@@ -131,7 +134,7 @@
     // make sure any padding in the header is zeroed.
     memset(header, 0, kHeaderSize);
 
-    if (pipeline.readsFragPosition()) {
+    if (requiredFeatures & GrProcessor::kFragmentPosition_RequiredFeature) {
         header->fFragPosKey =
             GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget());
     } else {