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 {