Add GrProcOptInfo class to track various output information for color and coverage stages.

BUG=skia:

Review URL: https://codereview.chromium.org/719203002
This commit is contained in:
egdaniel 2014-11-13 11:00:34 -08:00 committed by Commit bot
parent bc41538985
commit b6cbc38702
10 changed files with 285 additions and 132 deletions

View File

@ -122,6 +122,8 @@
'<(skia_src_path)/gpu/GrProgramDesc.h',
'<(skia_src_path)/gpu/GrProgramElement.cpp',
'<(skia_src_path)/gpu/GrProcessor.cpp',
'<(skia_src_path)/gpu/GrProcOptInfo.cpp',
'<(skia_src_path)/gpu/GrProcOptInfo.h',
'<(skia_src_path)/gpu/GrGpuResourceRef.cpp',
'<(skia_src_path)/gpu/GrPlotMgr.h',
'<(skia_src_path)/gpu/GrRecordReplaceDraw.cpp',

View File

@ -92,22 +92,9 @@ public:
}
}
bool isOpaque() const {
return ((fValidFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(fColor));
}
bool isSolidWhite() const {
return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor);
}
GrColor color() const { return fColor; }
uint8_t validFlags() const { return fValidFlags; }
bool willUseInputColor() const { return fWillUseInputColor; }
void resetWillUseInputColor() { fWillUseInputColor = true; }
void resetNonMulStageFound() { fNonMulStageFound = false; }
/**
* If isSingleComponent is true, then the flag values for r, g, b, and a must all be the
* same. If the flags are all set then all color components must be equal.
@ -122,6 +109,16 @@ protected:
bool fWillUseInputColor;
private:
friend class GrProcOptInfo;
void reset(GrColor color, GrColorComponentFlags flags, bool isSingleComponent) {
fColor = color;
fValidFlags = flags;
fIsSingleComponent = isSingleComponent;
fNonMulStageFound = false;
fWillUseInputColor = true;
}
void internalSetToTransparentBlack() {
fValidFlags = kRGBA_GrColorComponentFlags;
fColor = 0;
@ -137,6 +134,19 @@ private:
return ((fValidFlags & kA_GrColorComponentFlag) && 0 == GrColorUnpackA(fColor));
}
bool isOpaque() const {
return ((fValidFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(fColor));
}
bool isSolidWhite() const {
return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor);
}
bool willUseInputColor() const { return fWillUseInputColor; }
void resetWillUseInputColor() { fWillUseInputColor = true; }
void resetNonMulStageFound() { fNonMulStageFound = false; }
SkDEBUGCODE(bool colorComponentsAllEqual() const;)
/**
* If alpha is valid, check that any valid R,G,B values are <= A

View File

@ -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 @@ GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
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 @@ void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
fDrawFace = kBoth_DrawFace;
fHints = 0;
fColorProcInfoValid = false;
fCoverageProcInfoValid = false;
}
bool GrDrawState::setIdentityViewMatrix() {
@ -239,6 +251,8 @@ void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRende
this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
this->setCoverage(0xFF);
fColorProcInfoValid = false;
fCoverageProcInfoValid = false;
}
////////////////////////////////////////////////////////////////////////////////
@ -336,6 +350,8 @@ void GrDrawState::internalSetVertexAttribs(const GrVertexAttrib* attribs, int co
overlapCheck |= (mask << offsetShift);
#endif
}
fColorProcInfoValid = false;
fCoverageProcInfoValid = false;
// Positions must be specified.
SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
}
@ -355,6 +371,8 @@ void GrDrawState::setDefaultVertexAttribs() {
0xff,
sizeof(fFixedFunctionVertexAttribIndices));
fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
fColorProcInfoValid = false;
fCoverageProcInfoValid = false;
}
////////////////////////////////////////////////////////////////////////////////
@ -384,24 +402,8 @@ bool GrDrawState::hasSolidCoverage() const {
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 @@ GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(GrDrawState* drawS
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 @@ void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
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 @@ GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
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 @@ bool GrDrawState::willBlendWithDst() const {
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;
}
}

View File

@ -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 @@ public:
void setColor(GrColor color) {
if (color != fColor) {
fColor = color;
fColorProcInfoValid = false;
}
}
@ -212,6 +214,7 @@ public:
void setCoverage(uint8_t coverage) {
if (coverage != fCoverage) {
fCoverage = coverage;
fCoverageProcInfoValid = false;
}
}
@ -227,6 +230,7 @@ public:
SkASSERT(geometryProcessor);
SkASSERT(!this->hasGeometryProcessor());
fGeometryProcessor.reset(SkRef(geometryProcessor));
fCoverageProcInfoValid = false;
return geometryProcessor;
}
@ -270,12 +274,14 @@ public:
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 @@ private:
*/
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 @@ private:
// 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;

View File

@ -52,5 +52,6 @@ bool GrInvariantOutput::validPreMulColor() const {
}
return true;
}
#endif // end DEBUG

View File

@ -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 @@ void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds,
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();
}
}
}

View File

@ -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::isOpaque() const {
}
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 @@ bool GrPaint::getOpaqueAndKnownColor(GrColor* solidColor,
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 @@ bool GrPaint::getOpaqueAndKnownColor(GrColor* solidColor,
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

56
src/gpu/GrProcOptInfo.cpp Normal file
View File

@ -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
}
}
}

85
src/gpu/GrProcOptInfo.h Normal file
View File

@ -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

View File

@ -130,11 +130,7 @@ bool GrProcessor::hasSameTextureAccesses(const GrProcessor& that) const {
}
void GrProcessor::computeInvariantOutput(GrInvariantOutput* inout) const {
inout->resetWillUseInputColor();
this->onComputeInvariantOutput(inout);
#ifdef SK_DEBUG
inout->validate();
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////