Add GrProcOptInfo class to track various output information for color and coverage stages.
BUG=skia:
Review URL: https://codereview.chromium.org/719203002
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 513c3bf..6558b0d 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -8,9 +8,9 @@
#include "GrDrawState.h"
#include "GrBlend.h"
-#include "GrInvariantOutput.h"
#include "GrOptDrawState.h"
#include "GrPaint.h"
+#include "GrProcOptInfo.h"
//////////////////////////////////////////////////////////////////////////////s
@@ -151,6 +151,15 @@
fHints = that.fHints;
+ fColorProcInfoValid = that.fColorProcInfoValid;
+ fCoverageProcInfoValid = that.fCoverageProcInfoValid;
+ if (fColorProcInfoValid) {
+ fColorProcInfo = that.fColorProcInfo;
+ }
+ if (fCoverageProcInfoValid) {
+ fCoverageProcInfo = that.fCoverageProcInfo;
+ }
+
memcpy(fFixedFunctionVertexAttribIndices,
that.fFixedFunctionVertexAttribIndices,
sizeof(fFixedFunctionVertexAttribIndices));
@@ -184,6 +193,9 @@
fDrawFace = kBoth_DrawFace;
fHints = 0;
+
+ fColorProcInfoValid = false;
+ fCoverageProcInfoValid = false;
}
bool GrDrawState::setIdentityViewMatrix() {
@@ -239,6 +251,8 @@
this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
this->setCoverage(0xFF);
+ fColorProcInfoValid = false;
+ fCoverageProcInfoValid = false;
}
////////////////////////////////////////////////////////////////////////////////
@@ -336,6 +350,8 @@
overlapCheck |= (mask << offsetShift);
#endif
}
+ fColorProcInfoValid = false;
+ fCoverageProcInfoValid = false;
// Positions must be specified.
SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
}
@@ -355,6 +371,8 @@
0xff,
sizeof(fFixedFunctionVertexAttribIndices));
fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
+ fColorProcInfoValid = false;
+ fCoverageProcInfoValid = false;
}
////////////////////////////////////////////////////////////////////////////////
@@ -384,24 +402,8 @@
return false;
}
- GrColor color;
- GrColorComponentFlags flags;
- // Initialize to an unknown starting coverage if per-vertex coverage is specified.
- if (this->hasCoverageVertexAttribute()) {
- color = 0;
- flags = static_cast<GrColorComponentFlags>(0);
- } else {
- color = this->getCoverageColor();
- flags = kRGBA_GrColorComponentFlags;
- }
- GrInvariantOutput inout(color, flags, true);
-
- // check the coverage output from the GP
- if (this->hasGeometryProcessor()) {
- fGeometryProcessor->computeInvariantOutput(&inout);
- }
-
- return inout.isSolidWhite();
+ this->calcCoverageInvariantOutput();
+ return fCoverageProcInfo.isSolidWhite();
}
//////////////////////////////////////////////////////////////////////////////
@@ -419,18 +421,13 @@
bool GrDrawState::willEffectReadDstColor() const {
if (!this->isColorWriteDisabled()) {
- for (int s = 0; s < this->numColorStages(); ++s) {
- if (this->getColorStage(s).getProcessor()->willReadDstColor()) {
- return true;
- }
- }
- }
- for (int s = 0; s < this->numCoverageStages(); ++s) {
- if (this->getCoverageStage(s).getProcessor()->willReadDstColor()) {
+ this->calcColorInvariantOutput();
+ if (fColorProcInfo.readsDst()) {
return true;
}
}
- return false;
+ this->calcCoverageInvariantOutput();
+ return fCoverageProcInfo.readsDst();
}
void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
@@ -451,6 +448,10 @@
int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
SkASSERT(n >= 0);
fDrawState->fCoverageStages.pop_back_n(n);
+ if (m + n > 0) {
+ fDrawState->fColorProcInfoValid = false;
+ fDrawState->fCoverageProcInfoValid = false;
+ }
SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
}
fDrawState = ds;
@@ -689,60 +690,13 @@
return kNone_BlendOpt;
}
-
bool GrDrawState::srcAlphaWillBeOne() const {
- GrColor color;
- GrColorComponentFlags flags;
- // Check if per-vertex or constant color may have partial alpha
- if (this->hasColorVertexAttribute()) {
- if (fHints & kVertexColorsAreOpaque_Hint) {
- flags = kA_GrColorComponentFlag;
- color = 0xFF << GrColor_SHIFT_A;
- } else {
- flags = static_cast<GrColorComponentFlags>(0);
- color = 0;
- }
- } else {
- flags = kRGBA_GrColorComponentFlags;
- color = this->getColor();
- }
- GrInvariantOutput inoutColor(color, flags, false);
-
- // Run through the color stages
- for (int s = 0; s < this->numColorStages(); ++s) {
- const GrProcessor* processor = this->getColorStage(s).getProcessor();
- processor->computeInvariantOutput(&inoutColor);
- }
-
- // Check whether coverage is treated as color. If so we run through the coverage computation.
+ this->calcColorInvariantOutput();
if (this->isCoverageDrawing()) {
- // The shader generated for coverage drawing runs the full coverage computation and then
- // makes the shader output be the multiplication of color and coverage. We mirror that here.
- if (this->hasCoverageVertexAttribute()) {
- flags = static_cast<GrColorComponentFlags>(0);
- color = 0;
- } else {
- flags = kRGBA_GrColorComponentFlags;
- color = this->getCoverageColor();
- }
- GrInvariantOutput inoutCoverage(color, flags, true);
-
- if (this->hasGeometryProcessor()) {
- fGeometryProcessor->computeInvariantOutput(&inoutCoverage);
- }
-
- // Run through the coverage stages
- for (int s = 0; s < this->numCoverageStages(); ++s) {
- const GrProcessor* processor = this->getCoverageStage(s).getProcessor();
- processor->computeInvariantOutput(&inoutCoverage);
- }
-
- // Since the shader will multiply coverage and color, the only way the final A==1 is if
- // coverage and color both have A==1.
- return (inoutColor.isOpaque() && inoutCoverage.isOpaque());
+ this->calcCoverageInvariantOutput();
+ return (fColorProcInfo.isOpaque() && fCoverageProcInfo.isOpaque());
}
-
- return inoutColor.isOpaque();
+ return fColorProcInfo.isOpaque();
}
bool GrDrawState::willBlendWithDst() const {
@@ -767,3 +721,43 @@
return false;
}
+void GrDrawState::calcColorInvariantOutput() const {
+ if (!fColorProcInfoValid) {
+ GrColor color;
+ GrColorComponentFlags flags;
+ if (this->hasColorVertexAttribute()) {
+ if (fHints & kVertexColorsAreOpaque_Hint) {
+ flags = kA_GrColorComponentFlag;
+ color = 0xFF << GrColor_SHIFT_A;
+ } else {
+ flags = static_cast<GrColorComponentFlags>(0);
+ color = 0;
+ }
+ } else {
+ flags = kRGBA_GrColorComponentFlags;
+ color = this->getColor();
+ }
+ fColorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(),
+ color, flags, false);
+ fColorProcInfoValid = true;
+ }
+}
+
+void GrDrawState::calcCoverageInvariantOutput() const {
+ if (!fCoverageProcInfoValid) {
+ GrColor color;
+ GrColorComponentFlags flags;
+ // Check if per-vertex or constant color may have partial alpha
+ if (this->hasCoverageVertexAttribute()) {
+ flags = static_cast<GrColorComponentFlags>(0);
+ color = 0;
+ } else {
+ flags = kRGBA_GrColorComponentFlags;
+ color = this->getCoverageColor();
+ }
+ fCoverageProcInfo.calcWithInitialValues(fCoverageStages.begin(), this->numCoverageStages(),
+ color, flags, true, fGeometryProcessor.get());
+ fCoverageProcInfoValid = true;
+ }
+}
+
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 5c76aed..454390c 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -14,6 +14,7 @@
#include "GrGeometryProcessor.h"
#include "GrGpuResourceRef.h"
#include "GrProcessorStage.h"
+#include "GrProcOptInfo.h"
#include "GrRenderTarget.h"
#include "GrStencil.h"
#include "SkMatrix.h"
@@ -181,6 +182,7 @@
void setColor(GrColor color) {
if (color != fColor) {
fColor = color;
+ fColorProcInfoValid = false;
}
}
@@ -212,6 +214,7 @@
void setCoverage(uint8_t coverage) {
if (coverage != fCoverage) {
fCoverage = coverage;
+ fCoverageProcInfoValid = false;
}
}
@@ -227,6 +230,7 @@
SkASSERT(geometryProcessor);
SkASSERT(!this->hasGeometryProcessor());
fGeometryProcessor.reset(SkRef(geometryProcessor));
+ fCoverageProcInfoValid = false;
return geometryProcessor;
}
@@ -270,12 +274,14 @@
const GrFragmentProcessor* addColorProcessor(const GrFragmentProcessor* effect) {
SkASSERT(effect);
SkNEW_APPEND_TO_TARRAY(&fColorStages, GrFragmentStage, (effect));
+ fColorProcInfoValid = false;
return effect;
}
const GrFragmentProcessor* addCoverageProcessor(const GrFragmentProcessor* effect) {
SkASSERT(effect);
SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrFragmentStage, (effect));
+ fCoverageProcInfoValid = false;
return effect;
}
@@ -802,6 +808,18 @@
*/
bool srcAlphaWillBeOne() const;
+ /**
+ * If fColorProcInfoValid is false, function calculates the invariant output for the color
+ * stages and results are stored in fColorProcInfo.
+ */
+ void calcColorInvariantOutput() const;
+
+ /**
+ * If fCoverageProcInfoValid is false, function calculates the invariant output for the coverage
+ * stages and results are stored in fCoverageProcInfo.
+ */
+ void calcCoverageInvariantOutput() const;
+
void onReset(const SkMatrix* initialViewMatrix);
// Some of the auto restore objects assume that no effects are removed during their lifetime.
@@ -838,6 +856,11 @@
// not need to be compared in op==.
int fFixedFunctionVertexAttribIndices[kGrFixedFunctionVertexAttribBindingCnt];
+ mutable GrProcOptInfo fColorProcInfo;
+ mutable GrProcOptInfo fCoverageProcInfo;
+ mutable bool fColorProcInfoValid;
+ mutable bool fCoverageProcInfoValid;
+
friend class GrOptDrawState;
typedef SkRefCnt INHERITED;
diff --git a/src/gpu/GrInvariantOutput.cpp b/src/gpu/GrInvariantOutput.cpp
index 6f9a9d1..4c77df3 100644
--- a/src/gpu/GrInvariantOutput.cpp
+++ b/src/gpu/GrInvariantOutput.cpp
@@ -52,5 +52,6 @@
}
return true;
}
+
#endif // end DEBUG
diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp
index 7d8b06c..0f2fcf0 100644
--- a/src/gpu/GrOptDrawState.cpp
+++ b/src/gpu/GrOptDrawState.cpp
@@ -11,7 +11,7 @@
#include "GrDrawState.h"
#include "GrDrawTargetCaps.h"
#include "GrGpu.h"
-#include "GrInvariantOutput.h"
+#include "GrProcOptInfo.h"
GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
BlendOptFlags blendOptFlags,
@@ -239,23 +239,14 @@
color = 0;
}
}
- GrInvariantOutput inout(color, flags, false);
-
- for (int i = 0; i < ds.numColorStages(); ++i) {
- const GrFragmentProcessor* fp = ds.getColorStage(i).getProcessor();
- fp->computeInvariantOutput(&inout);
- if (!inout.willUseInputColor()) {
- *firstColorStageIdx = i;
- descInfo->fInputColorIsUsed = false;
- }
- if (kRGBA_GrColorComponentFlags == inout.validFlags()) {
- *firstColorStageIdx = i + 1;
- fColor = inout.color();
- descInfo->fInputColorIsUsed = true;
+ GrProcOptInfo poi;
+ if (ds.numColorStages() > 0) {
+ poi.calcWithInitialValues(&ds.getColorStage(0), ds.numColorStages(), color, flags, false);
+ *firstColorStageIdx = poi.firstEffectiveStageIndex();
+ descInfo->fInputColorIsUsed = poi.inputColorIsUsed();
+ fColor = poi.inputColorToEffectiveStage();
+ if (poi.removeVertexAttrib()) {
*fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
- // 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.
- inout.resetNonMulStageFound();
}
}
}
diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp
index 36637875..7d89535 100644
--- a/src/gpu/GrPaint.cpp
+++ b/src/gpu/GrPaint.cpp
@@ -9,7 +9,7 @@
#include "GrPaint.h"
#include "GrBlend.h"
-#include "GrInvariantOutput.h"
+#include "GrProcOptInfo.h"
#include "effects/GrSimpleTextureEffect.h"
void GrPaint::addColorTextureProcessor(GrTexture* texture, const SkMatrix& matrix) {
@@ -37,8 +37,8 @@
}
bool GrPaint::isOpaqueAndConstantColor(GrColor* color) const {
- GrColor tempColor;
- uint32_t colorComps;
+ GrColor tempColor = 0;
+ uint32_t colorComps = 0;
if (this->getOpaqueAndKnownColor(&tempColor, &colorComps)) {
if (kRGBA_GrColorComponentFlags == colorComps) {
*color = tempColor;
@@ -52,29 +52,24 @@
uint32_t* solidColorKnownComponents) const {
// TODO: Share this implementation with GrDrawState
+
+ GrProcOptInfo coverageProcInfo;
+ coverageProcInfo.calcWithInitialValues(fCoverageStages.begin(), this->numCoverageStages(),
+ 0xFFFFFFFF, kRGBA_GrColorComponentFlags, true);
- GrInvariantOutput inoutCoverage(0xFFFFFFFF,
- kRGBA_GrColorComponentFlags,
- true);
- int count = fCoverageStages.count();
- for (int i = 0; i < count; ++i) {
- fCoverageStages[i].getProcessor()->computeInvariantOutput(&inoutCoverage);
- }
- if (!inoutCoverage.isSolidWhite()) {
+ if (!coverageProcInfo.isSolidWhite()) {
return false;
}
- GrInvariantOutput inout(fColor, kRGBA_GrColorComponentFlags, false);
- count = fColorStages.count();
- for (int i = 0; i < count; ++i) {
- fColorStages[i].getProcessor()->computeInvariantOutput(&inout);
- }
+ GrProcOptInfo colorProcInfo;
+ colorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(), fColor,
+ kRGBA_GrColorComponentFlags, false);
SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents));
GrBlendCoeff srcCoeff = fSrcBlendCoeff;
GrBlendCoeff dstCoeff = fDstBlendCoeff;
- GrSimplifyBlend(&srcCoeff, &dstCoeff, inout.color(), inout.validFlags(),
+ GrSimplifyBlend(&srcCoeff, &dstCoeff, colorProcInfo.color(), colorProcInfo.validFlags(),
0, 0, 0);
bool opaque = kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoeff);
@@ -87,8 +82,8 @@
break;
case kOne_GrBlendCoeff:
- *solidColor = inout.color();
- *solidColorKnownComponents = inout.validFlags();
+ *solidColor = colorProcInfo.color();
+ *solidColorKnownComponents = colorProcInfo.validFlags();
break;
// The src coeff should never refer to the src and if it refers to dst then opaque
diff --git a/src/gpu/GrProcOptInfo.cpp b/src/gpu/GrProcOptInfo.cpp
new file mode 100644
index 0000000..c3ca100
--- /dev/null
+++ b/src/gpu/GrProcOptInfo.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrProcOptInfo.h"
+
+#include "GrGeometryProcessor.h"
+#include "GrProcessorStage.h"
+
+void GrProcOptInfo::calcWithInitialValues(const GrFragmentStage* stages,
+ int stageCount,
+ GrColor startColor,
+ GrColorComponentFlags flags,
+ bool areCoverageStages,
+ const GrGeometryProcessor* gp) {
+ fInOut.reset(startColor, flags, areCoverageStages);
+ fFirstEffectStageIndex = 0;
+ fInputColorIsUsed = true;
+ fInputColor = startColor;
+ fRemoveVertexAttrib = false;
+ fReadsDst = false;
+
+ if (areCoverageStages && gp) {
+ gp->computeInvariantOutput(&fInOut);
+ }
+
+ for (int i = 0; i < stageCount; ++i) {
+ const GrFragmentProcessor* processor = stages[i].getProcessor();
+ fInOut.resetWillUseInputColor();
+ processor->computeInvariantOutput(&fInOut);
+ #ifdef SK_DEBUG
+ fInOut.validate();
+ #endif
+ if (!fInOut.willUseInputColor()) {
+ fFirstEffectStageIndex = i;
+ fInputColorIsUsed = false;
+ fReadsDst = false; // Reset this since we don't care if previous stages read dst
+ }
+ if (processor->willReadDstColor()) {
+ fReadsDst = true;
+ }
+ if (kRGBA_GrColorComponentFlags == fInOut.validFlags()) {
+ fFirstEffectStageIndex = i + 1;
+ fInputColor = fInOut.color();
+ fInputColorIsUsed = true;
+ fRemoveVertexAttrib = true;
+ // 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();
+ fReadsDst = false; // Reset this since we don't care if previous stages read dst
+ }
+ }
+}
diff --git a/src/gpu/GrProcOptInfo.h b/src/gpu/GrProcOptInfo.h
new file mode 100644
index 0000000..5252e85
--- /dev/null
+++ b/src/gpu/GrProcOptInfo.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrProcOptInfo_DEFINED
+#define GrProcOptInfo_DEFINED
+
+#include "GrColor.h"
+#include "GrInvariantOutput.h"
+
+class GrFragmentStage;
+class GrGeometryProcessor;
+
+/**
+ * GrProcOptInfo gathers invariant data from a set of processor stages.It is used to recognize
+ * optimizations related to eliminating stages and vertex attributes that aren't necessary for a
+ * draw.
+ */
+class GrProcOptInfo {
+public:
+ GrProcOptInfo()
+ : fInOut(0, static_cast<GrColorComponentFlags>(0), false)
+ , fFirstEffectStageIndex(0)
+ , fInputColorIsUsed(true)
+ , fInputColor(0)
+ , fRemoveVertexAttrib(false)
+ , fReadsDst(false) {}
+
+ void calcWithInitialValues(const GrFragmentStage*, int stageCount, GrColor startColor,
+ GrColorComponentFlags flags, bool areCoverageStages,
+ const GrGeometryProcessor* gp = NULL);
+
+ bool isSolidWhite() const { return fInOut.isSolidWhite(); }
+ bool isOpaque() const { return fInOut.isOpaque(); }
+
+ GrColor color() const { return fInOut.color(); }
+ uint8_t validFlags() const { return fInOut.validFlags(); }
+
+ /**
+ * Returns the index of the first effective color stage. If an intermediate stage doesn't read
+ * its input or has a known output, then we can ignore all earlier stages since they will not
+ * affect the final output. Thus the first effective stage index is the index to the first stage
+ * that will have an effect on the final output.
+ *
+ * If stages before the firstEffectiveStageIndex are removed, corresponding values from
+ * inputColorIsUsed(), inputColorToEffectiveStage(), removeVertexAttribs(), and readsDst() must
+ * be used when setting up the draw to ensure correct drawing.
+ */
+ int firstEffectiveStageIndex() const { return fFirstEffectStageIndex; }
+
+ /**
+ * True if the first effective stage reads its input, false otherwise.
+ */
+ bool inputColorIsUsed() const { return fInputColorIsUsed; }
+
+ /**
+ * If input color is used and per-vertex colors are not used, this is the input color to the
+ * first effective stage.
+ */
+ GrColor inputColorToEffectiveStage() const { return fInputColor; }
+
+ /**
+ * Given the set of optimizations determined by GrProcOptInfo, should the caller remove the
+ * color/coverage vertex attribute that was input to the first stage.
+ */
+ bool removeVertexAttrib() const { return fRemoveVertexAttrib; }
+
+ /**
+ * Returns true if any of the stages preserved by GrProcOptInfo read the dst color.
+ */
+ bool readsDst() const { return fReadsDst; }
+
+private:
+ GrInvariantOutput fInOut;
+ int fFirstEffectStageIndex;
+ bool fInputColorIsUsed;
+ GrColor fInputColor;
+ bool fRemoveVertexAttrib;
+ bool fReadsDst;
+};
+
+#endif
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index 31f0004..01071da 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -130,11 +130,7 @@
}
void GrProcessor::computeInvariantOutput(GrInvariantOutput* inout) const {
- inout->resetWillUseInputColor();
this->onComputeInvariantOutput(inout);
-#ifdef SK_DEBUG
- inout->validate();
-#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////