aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gpu/GrDrawState.cpp218
-rw-r--r--src/gpu/GrDrawState.h131
-rw-r--r--src/gpu/GrOptDrawState.cpp147
-rw-r--r--src/gpu/GrOptDrawState.h67
-rw-r--r--src/gpu/GrRODrawState.cpp183
-rw-r--r--src/gpu/GrRODrawState.h60
6 files changed, 552 insertions, 254 deletions
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index ffec6627ca..642ec2669f 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -6,8 +6,22 @@
*/
#include "GrDrawState.h"
-#include "GrPaint.h"
+
#include "GrDrawTargetCaps.h"
+#include "GrOptDrawState.h"
+#include "GrPaint.h"
+
+//////////////////////////////////////////////////////////////////////////////s
+
+GrOptDrawState* GrDrawState::createOptState() const {
+ if (NULL == fCachedOptState) {
+ fCachedOptState = SkNEW_ARGS(GrOptDrawState, (*this));
+ } else {
+ SkASSERT(GrOptDrawState(*this) == *fCachedOptState);
+ }
+ fCachedOptState->ref();
+ return fCachedOptState;
+}
//////////////////////////////////////////////////////////////////////////////s
@@ -50,7 +64,8 @@ GrDrawState::CombinedState GrDrawState::CombineIfPossible(
//////////////////////////////////////////////////////////////////////////////s
-GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
+GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix)
+ : fCachedOptState(NULL) {
SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
*this = state;
if (!preConcatMatrix.isIdentity()) {
@@ -63,7 +78,7 @@ GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatr
for (int i = 0; i < this->numCoverageStages(); ++i) {
fCoverageStages[i].localCoordChange(preConcatMatrix);
}
- this->invalidateBlendOptFlags();
+ this->invalidateOptState();
}
}
@@ -97,6 +112,8 @@ GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
fHints = that.fHints;
+ SkRefCnt_SafeAssign(fCachedOptState, that.fCachedOptState);
+
memcpy(fFixedFunctionVertexAttribIndices,
that.fFixedFunctionVertexAttribIndices,
sizeof(fFixedFunctionVertexAttribIndices));
@@ -131,7 +148,7 @@ void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
fHints = 0;
- this->invalidateBlendOptFlags();
+ this->invalidateOptState();
}
bool GrDrawState::setIdentityViewMatrix() {
@@ -151,6 +168,7 @@ bool GrDrawState::setIdentityViewMatrix() {
fCoverageStages[s].localCoordChange(invVM);
}
}
+ this->invalidateOptState();
fViewMatrix.reset();
return true;
}
@@ -190,7 +208,7 @@ void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRende
this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
this->setCoverage(paint.getCoverage());
- this->invalidateBlendOptFlags();
+ this->invalidateOptState();
}
////////////////////////////////////////////////////////////////////////////////
@@ -247,7 +265,7 @@ void GrDrawState::internalSetVertexAttribs(const GrVertexAttrib* attribs, int co
overlapCheck |= (mask << offsetShift);
#endif
}
- this->invalidateBlendOptFlags();
+ this->invalidateOptState();
// Positions must be specified.
SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
}
@@ -267,7 +285,7 @@ void GrDrawState::setDefaultVertexAttribs() {
0xff,
sizeof(fFixedFunctionVertexAttribIndices));
fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
- this->invalidateBlendOptFlags();
+ this->invalidateOptState();
}
////////////////////////////////////////////////////////////////////////////////
@@ -289,8 +307,7 @@ bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
//////////////////////////////////////////////////////////////////////////////
-GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(
- GrDrawState* drawState) {
+GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(GrDrawState* drawState) {
SkASSERT(drawState);
fDrawState = drawState;
fVAPtr = drawState->fVAPtr;
@@ -320,7 +337,7 @@ void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
SkASSERT(n >= 0);
fDrawState->fCoverageStages.pop_back_n(n);
if (m + n > 0) {
- fDrawState->invalidateBlendOptFlags();
+ fDrawState->invalidateOptState();
}
SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
}
@@ -338,118 +355,6 @@ void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
////////////////////////////////////////////////////////////////////////////////
-GrRODrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
- GrBlendCoeff* srcCoeff,
- GrBlendCoeff* dstCoeff) const {
- GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
- if (NULL == srcCoeff) {
- srcCoeff = &bogusSrcCoeff;
- }
- if (NULL == dstCoeff) {
- dstCoeff = &bogusDstCoeff;
- }
-
- if (forceCoverage) {
- return this->calcBlendOpts(true, srcCoeff, dstCoeff);
- }
-
- if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
- *srcCoeff = fOptSrcBlend;
- *dstCoeff = fOptDstBlend;
- return fBlendOptFlags;
- }
-
- fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
- fOptSrcBlend = *srcCoeff;
- fOptDstBlend = *dstCoeff;
-
- return fBlendOptFlags;
-}
-
-GrRODrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
- GrBlendCoeff* srcCoeff,
- GrBlendCoeff* dstCoeff) const {
- *srcCoeff = this->getSrcBlendCoeff();
- *dstCoeff = this->getDstBlendCoeff();
-
- if (this->isColorWriteDisabled()) {
- *srcCoeff = kZero_GrBlendCoeff;
- *dstCoeff = kOne_GrBlendCoeff;
- }
-
- bool srcAIsOne = this->srcAlphaWillBeOne();
- bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
- (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
- bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
- (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
-
- // When coeffs are (0,1) there is no reason to draw at all, unless
- // stenciling is enabled. Having color writes disabled is effectively
- // (0,1).
- if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
- if (this->getStencil().doesWrite()) {
- return kEmitCoverage_BlendOptFlag;
- } else {
- return kSkipDraw_BlendOptFlag;
- }
- }
-
- bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
-
- // if we don't have coverage we can check whether the dst
- // has to read at all. If not, we'll disable blending.
- if (!hasCoverage) {
- if (dstCoeffIsZero) {
- if (kOne_GrBlendCoeff == *srcCoeff) {
- // if there is no coverage and coeffs are (1,0) then we
- // won't need to read the dst at all, it gets replaced by src
- *dstCoeff = kZero_GrBlendCoeff;
- return kNone_BlendOpt;
- } else if (kZero_GrBlendCoeff == *srcCoeff) {
- // if the op is "clear" then we don't need to emit a color
- // or blend, just write transparent black into the dst.
- *srcCoeff = kOne_GrBlendCoeff;
- *dstCoeff = kZero_GrBlendCoeff;
- return kEmitTransBlack_BlendOptFlag;
- }
- }
- } else if (this->isCoverageDrawing()) {
- // we have coverage but we aren't distinguishing it from alpha by request.
- return kCoverageAsAlpha_BlendOptFlag;
- } else {
- // check whether coverage can be safely rolled into alpha
- // of if we can skip color computation and just emit coverage
- if (this->canTweakAlphaForCoverage()) {
- return kCoverageAsAlpha_BlendOptFlag;
- }
- if (dstCoeffIsZero) {
- if (kZero_GrBlendCoeff == *srcCoeff) {
- // the source color is not included in the blend
- // the dst coeff is effectively zero so blend works out to:
- // (c)(0)D + (1-c)D = (1-c)D.
- *dstCoeff = kISA_GrBlendCoeff;
- return kEmitCoverage_BlendOptFlag;
- } else if (srcAIsOne) {
- // the dst coeff is effectively zero so blend works out to:
- // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
- // If Sa is 1 then we can replace Sa with c
- // and set dst coeff to 1-Sa.
- *dstCoeff = kISA_GrBlendCoeff;
- return kCoverageAsAlpha_BlendOptFlag;
- }
- } else if (dstCoeffIsOne) {
- // the dst coeff is effectively one so blend works out to:
- // cS + (c)(1)D + (1-c)D = cS + D.
- *dstCoeff = kOne_GrBlendCoeff;
- return kCoverageAsAlpha_BlendOptFlag;
- }
- }
-
- return kNone_BlendOpt;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
void GrDrawState::AutoViewMatrixRestore::restore() {
if (fDrawState) {
SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
@@ -469,6 +374,7 @@ void GrDrawState::AutoViewMatrixRestore::restore() {
for (int s = 0; s < numCoverageStages; ++s, ++i) {
fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
}
+ fDrawState->invalidateOptState();
fDrawState = NULL;
}
}
@@ -488,6 +394,7 @@ void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
this->doEffectCoordChanges(preconcatMatrix);
SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
+ drawState->invalidateOptState();
}
bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
@@ -501,6 +408,7 @@ bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
return true;
}
+ drawState->invalidateOptState();
fViewMatrix = drawState->getViewMatrix();
if (0 == drawState->numTotalStages()) {
drawState->fViewMatrix.reset();
@@ -547,69 +455,3 @@ void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& co
}
}
-bool GrDrawState::srcAlphaWillBeOne() const {
- uint32_t validComponentFlags;
- GrColor color;
- // Check if per-vertex or constant color may have partial alpha
- if (this->hasColorVertexAttribute()) {
- if (fHints & kVertexColorsAreOpaque_Hint) {
- validComponentFlags = kA_GrColorComponentFlag;
- color = 0xFF << GrColor_SHIFT_A;
- } else {
- validComponentFlags = 0;
- color = 0; // not strictly necessary but we get false alarms from tools about uninit.
- }
- } else {
- validComponentFlags = kRGBA_GrColorComponentFlags;
- color = this->getColor();
- }
-
- // Run through the color stages
- for (int s = 0; s < this->numColorStages(); ++s) {
- const GrEffect* effect = this->getColorStage(s).getEffect();
- effect->getConstantColorComponents(&color, &validComponentFlags);
- }
-
- // Check whether coverage is treated as color. If so we run through the coverage computation.
- 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.
- GrColor coverage;
- uint32_t coverageComponentFlags;
- if (this->hasCoverageVertexAttribute()) {
- coverageComponentFlags = 0;
- coverage = 0; // suppresses any warnings.
- } else {
- coverageComponentFlags = kRGBA_GrColorComponentFlags;
- coverage = this->getCoverageColor();
- }
-
- // Run through the coverage stages
- if (this->hasGeometryProcessor()) {
- const GrEffect* effect = fGeometryProcessor->getEffect();
- effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
- }
- for (int s = 0; s < this->numCoverageStages(); ++s) {
- const GrEffect* effect = this->getCoverageStage(s).getEffect();
- effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
- }
-
- // 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 (kA_GrColorComponentFlag & validComponentFlags & coverageComponentFlags) &&
- 0xFF == GrColorUnpackA(color) && 0xFF == GrColorUnpackA(coverage);
-
- }
-
- return (kA_GrColorComponentFlag & validComponentFlags) && 0xFF == GrColorUnpackA(color);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-bool GrDrawState::canIgnoreColorAttribute() const {
- if (fBlendOptFlags & kInvalid_BlendOptFlag) {
- this->getBlendOpts();
- }
- return SkToBool(fBlendOptFlags & (GrRODrawState::kEmitTransBlack_BlendOptFlag |
- GrRODrawState::kEmitCoverage_BlendOptFlag));
-}
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 2fe56a3d34..4850fc911c 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -9,6 +9,7 @@
#define GrDrawState_DEFINED
#include "GrBlend.h"
+#include "GrOptDrawState.h"
#include "GrProgramResource.h"
#include "GrRODrawState.h"
#include "effects/GrSimpleTextureEffect.h"
@@ -23,12 +24,12 @@ class GrDrawState : public GrRODrawState {
public:
SK_DECLARE_INST_COUNT(GrDrawState)
- GrDrawState() {
+ GrDrawState() : fCachedOptState(NULL) {
SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
this->reset();
}
- GrDrawState(const SkMatrix& initialViewMatrix) {
+ GrDrawState(const SkMatrix& initialViewMatrix) : fCachedOptState(NULL) {
SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
this->reset(initialViewMatrix);
}
@@ -36,7 +37,7 @@ public:
/**
* Copies another draw state.
**/
- GrDrawState(const GrDrawState& state) : INHERITED() {
+ GrDrawState(const GrDrawState& state) : INHERITED(), fCachedOptState(NULL) {
SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
*this = state;
}
@@ -46,7 +47,10 @@ public:
**/
GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix);
- virtual ~GrDrawState() { SkASSERT(0 == fBlockEffectRemovalCnt); }
+ virtual ~GrDrawState() {
+ SkSafeUnref(fCachedOptState);
+ SkASSERT(0 == fBlockEffectRemovalCnt);
+ }
/**
* Resets to the default state. GrEffects will be removed from all stages.
@@ -100,7 +104,8 @@ public:
public:
AutoVertexAttribRestore(GrDrawState* drawState);
- ~AutoVertexAttribRestore() { fDrawState->internalSetVertexAttribs(fVAPtr, fVACount, fVAStride); }
+ ~AutoVertexAttribRestore() { fDrawState->internalSetVertexAttribs(fVAPtr, fVACount,
+ fVAStride); }
private:
GrDrawState* fDrawState;
@@ -135,8 +140,10 @@ public:
* @param color the color to set.
*/
void setColor(GrColor color) {
- fColor = color;
- this->invalidateBlendOptFlags();
+ if (color != fColor) {
+ fColor = color;
+ this->invalidateOptState();
+ }
}
/**
@@ -159,8 +166,10 @@ public:
* coverage is ignored when per-vertex coverage is provided.
*/
void setCoverage(uint8_t coverage) {
- fCoverage = coverage;
- this->invalidateBlendOptFlags();
+ if (coverage != fCoverage) {
+ fCoverage = coverage;
+ this->invalidateOptState();
+ }
}
/// @}
@@ -175,7 +184,7 @@ public:
SkASSERT(effect);
SkASSERT(!this->hasGeometryProcessor());
fGeometryProcessor.reset(new GrEffectStage(effect, attr0, attr1));
- this->invalidateBlendOptFlags();
+ this->invalidateOptState();
return effect;
}
@@ -202,14 +211,14 @@ public:
const GrEffect* addColorEffect(const GrEffect* effect, int attr0 = -1, int attr1 = -1) {
SkASSERT(effect);
SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect, attr0, attr1));
- this->invalidateBlendOptFlags();
+ this->invalidateOptState();
return effect;
}
const GrEffect* addCoverageEffect(const GrEffect* effect, int attr0 = -1, int attr1 = -1) {
SkASSERT(effect);
SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect, attr0, attr1));
- this->invalidateBlendOptFlags();
+ this->invalidateOptState();
return effect;
}
@@ -301,9 +310,11 @@ public:
* @param dstCoef coefficient applied to the dst color.
*/
void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
- fSrcBlend = srcCoeff;
- fDstBlend = dstCoeff;
- this->invalidateBlendOptFlags();
+ if (srcCoeff != fSrcBlend || dstCoeff != fDstBlend) {
+ fSrcBlend = srcCoeff;
+ fDstBlend = dstCoeff;
+ this->invalidateOptState();
+ }
#ifdef SK_DEBUG
if (GrBlendCoeffRefsDst(dstCoeff)) {
GrPrintf("Unexpected dst blend coeff. Won't work correctly with coverage stages.\n");
@@ -325,34 +336,12 @@ public:
* @param constant the constant to set
*/
void setBlendConstant(GrColor constant) {
- fBlendConstant = constant;
- this->invalidateBlendOptFlags();
+ if (constant != fBlendConstant) {
+ fBlendConstant = constant;
+ this->invalidateOptState();
+ }
}
- /**
- * Determines what optimizations can be applied based on the blend. The coefficients may have
- * to be tweaked in order for the optimization to work. srcCoeff and dstCoeff are optional
- * params that receive the tweaked coefficients. Normally the function looks at the current
- * state to see if coverage is enabled. By setting forceCoverage the caller can speculatively
- * determine the blend optimizations that would be used if there was partial pixel coverage.
- *
- * Subclasses of GrDrawTarget that actually draw (as opposed to those that just buffer for
- * playback) must call this function and respect the flags that replace the output color.
- *
- * If the cached BlendOptFlags does not have the invalidate bit set, then getBlendOpts will
- * simply returned the cached flags and coefficients. Otherwise it will calculate the values.
- */
- BlendOptFlags getBlendOpts(bool forceCoverage = false,
- GrBlendCoeff* srcCoeff = NULL,
- GrBlendCoeff* dstCoeff = NULL) const;
-
- /**
- * We don't use suplied vertex color attributes if our blend mode is EmitCoverage or
- * EmitTransBlack
- */
- bool canIgnoreColorAttribute() const;
-
-
/// @}
///////////////////////////////////////////////////////////////////////////
@@ -416,6 +405,7 @@ public:
*/
void setRenderTarget(GrRenderTarget* target) {
fRenderTarget.setResource(SkSafeRef(target), GrProgramResource::kWrite_IOType);
+ this->invalidateOptState();
}
/// @}
@@ -432,16 +422,20 @@ public:
* @param settings the stencil settings to use.
*/
void setStencil(const GrStencilSettings& settings) {
- fStencilSettings = settings;
- this->invalidateBlendOptFlags();
+ if (settings != fStencilSettings) {
+ fStencilSettings = settings;
+ this->invalidateOptState();
+ }
}
/**
* Shortcut to disable stencil testing and ops.
*/
void disableStencil() {
- fStencilSettings.setDisabled();
- this->invalidateBlendOptFlags();
+ if (!fStencilSettings.isDisabled()) {
+ fStencilSettings.setDisabled();
+ this->invalidateOptState();
+ }
}
GrStencilSettings* stencil() { return &fStencilSettings; }
@@ -453,8 +447,10 @@ public:
////
void resetStateFlags() {
- fFlagBits = 0;
- this->invalidateBlendOptFlags();
+ if (0 != fFlagBits) {
+ fFlagBits = 0;
+ this->invalidateOptState();
+ }
}
/**
@@ -463,8 +459,10 @@ public:
* @param stateBits bitfield of StateBits specifying the states to enable
*/
void enableState(uint32_t stateBits) {
- fFlagBits |= stateBits;
- this->invalidateBlendOptFlags();
+ if (stateBits & ~fFlagBits) {
+ fFlagBits |= stateBits;
+ this->invalidateOptState();
+ }
}
/**
@@ -473,8 +471,10 @@ public:
* @param stateBits bitfield of StateBits specifying the states to disable
*/
void disableState(uint32_t stateBits) {
- fFlagBits &= ~(stateBits);
- this->invalidateBlendOptFlags();
+ if (stateBits & fFlagBits) {
+ fFlagBits &= ~(stateBits);
+ this->invalidateOptState();
+ }
}
/**
@@ -513,8 +513,6 @@ public:
/// Hints that when provided can enable optimizations.
////
- enum Hints { kVertexColorsAreOpaque_Hint = 0x1, };
-
void setHint(Hints hint, bool value) { fHints = value ? (fHints | hint) : (fHints & ~hint); }
/// @}
@@ -542,33 +540,34 @@ public:
GrDrawState& operator= (const GrDrawState& that);
-private:
- void onReset(const SkMatrix* initialViewMatrix);
-
/**
- * Determines whether src alpha is guaranteed to be one for all src pixels
+ * Returns a snapshot of the current optimized state. If the current drawState has a valid
+ * cached optimiezed state it will simply return a pointer to it otherwise it will create a new
+ * GrOptDrawState. In all cases the GrOptDrawState is reffed and ownership is given to the
+ * caller.
*/
- bool srcAlphaWillBeOne() const;
+ GrOptDrawState* createOptState() const;
- /**
- * Helper function for getBlendOpts.
- */
- BlendOptFlags calcBlendOpts(bool forceCoverage = false,
- GrBlendCoeff* srcCoeff = NULL,
- GrBlendCoeff* dstCoeff = NULL) const;
+private:
+ void invalidateOptState() const {
+ SkSafeSetNull(fCachedOptState);
+ fBlendOptFlags = kInvalid_BlendOptFlag;
+ }
+
+ void onReset(const SkMatrix* initialViewMatrix);
void invalidateBlendOptFlags() {
fBlendOptFlags = kInvalid_BlendOptFlag;
}
- uint32_t fHints;
-
// Some of the auto restore objects assume that no effects are removed during their lifetime.
// This is used to assert that this condition holds.
SkDEBUGCODE(int fBlockEffectRemovalCnt;)
void internalSetVertexAttribs(const GrVertexAttrib attribs[], int count, size_t stride);
+ mutable GrOptDrawState* fCachedOptState;
+
typedef GrRODrawState INHERITED;
};
diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp
new file mode 100644
index 0000000000..83546ba3b7
--- /dev/null
+++ b/src/gpu/GrOptDrawState.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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 "GrOptDrawState.h"
+
+#include "GrDrawState.h"
+
+GrOptDrawState::GrOptDrawState(const GrDrawState& drawState) : INHERITED(drawState) {
+ fColor = drawState.getColor();
+ fCoverage = drawState.getCoverage();
+ fViewMatrix = drawState.getViewMatrix();
+ fBlendConstant = drawState.getBlendConstant();
+ fFlagBits = drawState.getFlagBits();
+ fVAPtr = drawState.getVertexAttribs();
+ fVACount = drawState.getVertexAttribCount();
+ fVAStride = drawState.getVertexStride();
+ fStencilSettings = drawState.getStencil();
+ fDrawFace = drawState.getDrawFace();
+
+ fBlendOptFlags = drawState.getBlendOpts(false, &fSrcBlend, &fDstBlend);
+
+ memcpy(fFixedFunctionVertexAttribIndices,
+ drawState.getFixedFunctionVertexAttribIndices(),
+ sizeof(fFixedFunctionVertexAttribIndices));
+
+ fInputColorIsUsed = true;
+ fInputCoverageIsUsed = true;
+
+ if (drawState.hasGeometryProcessor()) {
+ fGeometryProcessor.reset(SkNEW_ARGS(GrEffectStage, (*drawState.getGeometryProcessor())));
+ } else {
+ fGeometryProcessor.reset(NULL);
+ }
+
+ this->copyEffectiveColorStages(drawState);
+ this->copyEffectiveCoverageStages(drawState);
+};
+
+void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
+ int numToRemove = 0;
+ uint8_t maskCheck = 0x1;
+ // Count the number of vertex attributes that we will actually remove
+ for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
+ if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
+ ++numToRemove;
+ }
+ maskCheck <<= 1;
+ }
+ fOptVA.reset(fVACount - numToRemove);
+
+ GrVertexAttrib* dst = fOptVA.get();
+ const GrVertexAttrib* src = fVAPtr;
+
+ for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) {
+ const GrVertexAttrib& currAttrib = *src;
+ if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
+ uint8_t maskCheck = 0x1 << currAttrib.fBinding;
+ if (maskCheck & removeVAFlag) {
+ SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
+ fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
+ continue;
+ }
+ }
+ memcpy(dst, src, sizeof(GrVertexAttrib));
+ fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
+ ++newIdx;
+ ++dst;
+ }
+ fVACount -= numToRemove;
+ fVAPtr = fOptVA.get();
+}
+
+void GrOptDrawState::copyEffectiveColorStages(const GrDrawState& ds) {
+ int firstColorStage = 0;
+
+ // Set up color and flags for ConstantColorComponent checks
+ GrColor color;
+ uint32_t validComponentFlags;
+ if (!this->hasColorVertexAttribute()) {
+ color = ds.getColor();
+ validComponentFlags = kRGBA_GrColorComponentFlags;
+ } else {
+ if (ds.vertexColorsAreOpaque()) {
+ color = 0xFF << GrColor_SHIFT_A;
+ validComponentFlags = kA_GrColorComponentFlag;
+ } else {
+ validComponentFlags = 0;
+ color = 0; // not strictly necessary but we get false alarms from tools about uninit.
+ }
+ }
+
+ for (int i = 0; i < ds.numColorStages(); ++i) {
+ const GrEffect* effect = ds.getColorStage(i).getEffect();
+ if (!effect->willUseInputColor()) {
+ firstColorStage = i;
+ fInputColorIsUsed = false;
+ }
+ effect->getConstantColorComponents(&color, &validComponentFlags);
+ if (kRGBA_GrColorComponentFlags == validComponentFlags) {
+ firstColorStage = i + 1;
+ fColor = color;
+ fInputColorIsUsed = true;
+ this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
+ }
+ }
+ if (firstColorStage < ds.numColorStages()) {
+ fColorStages.reset(&ds.getColorStage(firstColorStage),
+ ds.numColorStages() - firstColorStage);
+ } else {
+ fColorStages.reset();
+ }
+}
+
+void GrOptDrawState::copyEffectiveCoverageStages(const GrDrawState& ds) {
+ int firstCoverageStage = 0;
+
+ // We do not try to optimize out constantColor coverage effects here. It is extremely rare
+ // to have a coverage effect that returns a constant value for all four channels. Thus we
+ // save having to make extra virtual calls by not checking for it.
+
+ // Don't do any optimizations on coverage stages. It should not be the case where we do not use
+ // input coverage in an effect
+#ifdef OptCoverageStages
+ for (int i = 0; i < ds.numCoverageStages(); ++i) {
+ const GrEffect* effect = ds.getCoverageStage(i).getEffect();
+ if (!effect->willUseInputColor()) {
+ firstCoverageStage = i;
+ fInputCoverageIsUsed = false;
+ }
+ }
+#endif
+ if (ds.numCoverageStages() > 0) {
+ fCoverageStages.reset(&ds.getCoverageStage(firstCoverageStage),
+ ds.numCoverageStages() - firstCoverageStage);
+ } else {
+ fCoverageStages.reset();
+ }
+}
+
+bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
+ return this->isEqual(that);
+}
+
diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h
new file mode 100644
index 0000000000..a4edc01c8a
--- /dev/null
+++ b/src/gpu/GrOptDrawState.h
@@ -0,0 +1,67 @@
+/*
+ * 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 GrOptDrawState_DEFINED
+#define GrOptDrawState_DEFINED
+
+#include "GrRODrawState.h"
+
+class GrDrawState;
+
+/**
+ * Subclass of GrRODrawState that holds an optimized version of a GrDrawState. Like it's parent
+ * it is meant to be an immutable class, and simply adds a few helpful data members not in the
+ * base class.
+ */
+class GrOptDrawState : public GrRODrawState {
+public:
+ /**
+ * Constructs and optimized drawState out of a GrRODrawState.
+ */
+ explicit GrOptDrawState(const GrDrawState& drawState);
+
+ bool operator== (const GrOptDrawState& that) const;
+
+private:
+ /*
+ * Loops through all the color stage effects to check if the stage will ignore color input or
+ * always output a constant color. In the ignore color input case we can ignore all previous
+ * stages. In the constant color case, we can ignore all previous stages and
+ * the current one and set the state color to the constant color. Once we determine the so
+ * called first effective stage, we copy all the effective stages into our optimized
+ * state.
+ */
+ void copyEffectiveColorStages(const GrDrawState& ds);
+
+ /*
+ * Loops through all the coverage stage effects to check if the stage will ignore color input.
+ * If a coverage stage will ignore input, then we can ignore all coverage stages before it. We
+ * loop to determine the first effective coverage stage, and then copy all of our effective
+ * coverage stages into our optimized state.
+ */
+ void copyEffectiveCoverageStages(const GrDrawState& ds);
+
+ /*
+ * This function takes in a flag and removes the corresponding fixed function vertex attributes.
+ * The flags are in the same order as GrVertexAttribBinding array. If bit i of removeVAFlags is
+ * set, then vertex attributes with binding (GrVertexAttribute)i will be removed.
+ */
+ void removeFixedFunctionVertexAttribs(uint8_t removeVAFlags);
+
+ void removeColorVertexAttrib();
+
+ // These flags are needed to protect the code from creating an unused uniform color/coverage
+ // which will cause shader compiler errors.
+ bool fInputColorIsUsed;
+ bool fInputCoverageIsUsed;
+
+ SkAutoSTArray<4, GrVertexAttrib> fOptVA;
+
+ typedef GrRODrawState INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrRODrawState.cpp b/src/gpu/GrRODrawState.cpp
index 8d6c283f7a..b79e8fce43 100644
--- a/src/gpu/GrRODrawState.cpp
+++ b/src/gpu/GrRODrawState.cpp
@@ -6,10 +6,17 @@
*/
#include "GrRODrawState.h"
+
#include "GrDrawTargetCaps.h"
+#include "GrRenderTarget.h"
////////////////////////////////////////////////////////////////////////////////
+GrRODrawState::GrRODrawState(const GrRODrawState& drawState) : INHERITED() {
+ fRenderTarget.setResource(SkSafeRef(drawState.fRenderTarget.getResource()),
+ GrProgramResource::kWrite_IOType);
+}
+
bool GrRODrawState::isEqual(const GrRODrawState& that) const {
bool usingVertexColors = this->hasColorVertexAttribute();
if (!usingVertexColors && this->fColor != that.fColor) {
@@ -164,6 +171,118 @@ bool GrRODrawState::willEffectReadDstColor() const {
////////////////////////////////////////////////////////////////////////////////
+GrRODrawState::BlendOptFlags GrRODrawState::getBlendOpts(bool forceCoverage,
+ GrBlendCoeff* srcCoeff,
+ GrBlendCoeff* dstCoeff) const {
+ GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
+ if (NULL == srcCoeff) {
+ srcCoeff = &bogusSrcCoeff;
+ }
+ if (NULL == dstCoeff) {
+ dstCoeff = &bogusDstCoeff;
+ }
+
+ if (forceCoverage) {
+ return this->calcBlendOpts(true, srcCoeff, dstCoeff);
+ }
+
+ if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
+ *srcCoeff = fOptSrcBlend;
+ *dstCoeff = fOptDstBlend;
+ return fBlendOptFlags;
+ }
+
+ fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
+ fOptSrcBlend = *srcCoeff;
+ fOptDstBlend = *dstCoeff;
+
+ return fBlendOptFlags;
+}
+
+GrRODrawState::BlendOptFlags GrRODrawState::calcBlendOpts(bool forceCoverage,
+ GrBlendCoeff* srcCoeff,
+ GrBlendCoeff* dstCoeff) const {
+ *srcCoeff = this->getSrcBlendCoeff();
+ *dstCoeff = this->getDstBlendCoeff();
+
+ if (this->isColorWriteDisabled()) {
+ *srcCoeff = kZero_GrBlendCoeff;
+ *dstCoeff = kOne_GrBlendCoeff;
+ }
+
+ bool srcAIsOne = this->srcAlphaWillBeOne();
+ bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
+ (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
+ bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
+ (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
+
+ // When coeffs are (0,1) there is no reason to draw at all, unless
+ // stenciling is enabled. Having color writes disabled is effectively
+ // (0,1).
+ if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
+ if (this->getStencil().doesWrite()) {
+ return kEmitCoverage_BlendOptFlag;
+ } else {
+ return kSkipDraw_BlendOptFlag;
+ }
+ }
+
+ bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
+
+ // if we don't have coverage we can check whether the dst
+ // has to read at all. If not, we'll disable blending.
+ if (!hasCoverage) {
+ if (dstCoeffIsZero) {
+ if (kOne_GrBlendCoeff == *srcCoeff) {
+ // if there is no coverage and coeffs are (1,0) then we
+ // won't need to read the dst at all, it gets replaced by src
+ *dstCoeff = kZero_GrBlendCoeff;
+ return kNone_BlendOpt;
+ } else if (kZero_GrBlendCoeff == *srcCoeff) {
+ // if the op is "clear" then we don't need to emit a color
+ // or blend, just write transparent black into the dst.
+ *srcCoeff = kOne_GrBlendCoeff;
+ *dstCoeff = kZero_GrBlendCoeff;
+ return kEmitTransBlack_BlendOptFlag;
+ }
+ }
+ } else if (this->isCoverageDrawing()) {
+ // we have coverage but we aren't distinguishing it from alpha by request.
+ return kCoverageAsAlpha_BlendOptFlag;
+ } else {
+ // check whether coverage can be safely rolled into alpha
+ // of if we can skip color computation and just emit coverage
+ if (this->canTweakAlphaForCoverage()) {
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ if (dstCoeffIsZero) {
+ if (kZero_GrBlendCoeff == *srcCoeff) {
+ // the source color is not included in the blend
+ // the dst coeff is effectively zero so blend works out to:
+ // (c)(0)D + (1-c)D = (1-c)D.
+ *dstCoeff = kISA_GrBlendCoeff;
+ return kEmitCoverage_BlendOptFlag;
+ } else if (srcAIsOne) {
+ // the dst coeff is effectively zero so blend works out to:
+ // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
+ // If Sa is 1 then we can replace Sa with c
+ // and set dst coeff to 1-Sa.
+ *dstCoeff = kISA_GrBlendCoeff;
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ } else if (dstCoeffIsOne) {
+ // the dst coeff is effectively one so blend works out to:
+ // cS + (c)(1)D + (1-c)D = cS + D.
+ *dstCoeff = kOne_GrBlendCoeff;
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ }
+
+ return kNone_BlendOpt;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
// others will blend incorrectly.
bool GrRODrawState::canTweakAlphaForCoverage() const {
@@ -197,3 +316,67 @@ void GrRODrawState::convertToPendingExec() {
fCoverageStages[i].convertToPendingExec();
}
}
+
+bool GrRODrawState::srcAlphaWillBeOne() const {
+ uint32_t validComponentFlags;
+ GrColor color;
+ // Check if per-vertex or constant color may have partial alpha
+ if (this->hasColorVertexAttribute()) {
+ if (fHints & kVertexColorsAreOpaque_Hint) {
+ validComponentFlags = kA_GrColorComponentFlag;
+ color = 0xFF << GrColor_SHIFT_A;
+ } else {
+ validComponentFlags = 0;
+ color = 0; // not strictly necessary but we get false alarms from tools about uninit.
+ }
+ } else {
+ validComponentFlags = kRGBA_GrColorComponentFlags;
+ color = this->getColor();
+ }
+
+ // Run through the color stages
+ for (int s = 0; s < this->numColorStages(); ++s) {
+ const GrEffect* effect = this->getColorStage(s).getEffect();
+ effect->getConstantColorComponents(&color, &validComponentFlags);
+ }
+
+ // Check whether coverage is treated as color. If so we run through the coverage computation.
+ 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.
+ GrColor coverage;
+ uint32_t coverageComponentFlags;
+ if (this->hasCoverageVertexAttribute()) {
+ coverageComponentFlags = 0;
+ coverage = 0; // suppresses any warnings.
+ } else {
+ coverageComponentFlags = kRGBA_GrColorComponentFlags;
+ coverage = this->getCoverageColor();
+ }
+
+ // Run through the coverage stages
+ for (int s = 0; s < this->numCoverageStages(); ++s) {
+ const GrEffect* effect = this->getCoverageStage(s).getEffect();
+ effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
+ }
+
+ // 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 (kA_GrColorComponentFlag & validComponentFlags & coverageComponentFlags) &&
+ 0xFF == GrColorUnpackA(color) && 0xFF == GrColorUnpackA(coverage);
+
+ }
+
+ return (kA_GrColorComponentFlag & validComponentFlags) && 0xFF == GrColorUnpackA(color);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool GrRODrawState::canIgnoreColorAttribute() const {
+ if (fBlendOptFlags & kInvalid_BlendOptFlag) {
+ this->getBlendOpts();
+ }
+ return SkToBool(fBlendOptFlags & (GrRODrawState::kEmitTransBlack_BlendOptFlag |
+ GrRODrawState::kEmitCoverage_BlendOptFlag));
+}
+
diff --git a/src/gpu/GrRODrawState.h b/src/gpu/GrRODrawState.h
index 718f017de3..d748e7d83a 100644
--- a/src/gpu/GrRODrawState.h
+++ b/src/gpu/GrRODrawState.h
@@ -13,6 +13,7 @@
#include "GrStencil.h"
#include "SkMatrix.h"
+class GrDrawState;
class GrDrawTargetCaps;
class GrPaint;
class GrTexture;
@@ -26,6 +27,10 @@ class GrRODrawState : public SkRefCnt {
public:
SK_DECLARE_INST_COUNT(GrRODrawState)
+ GrRODrawState() {}
+
+ GrRODrawState& operator= (const GrRODrawState& that);
+
///////////////////////////////////////////////////////////////////////////
/// @name Vertex Attributes
////
@@ -68,6 +73,10 @@ public:
return -1 != fFixedFunctionVertexAttribIndices[kCoverage_GrVertexAttribBinding];
}
+ const int* getFixedFunctionVertexAttribIndices() const {
+ return fFixedFunctionVertexAttribIndices;
+ }
+
bool validateVertexAttribs() const;
/// @}
@@ -158,6 +167,12 @@ public:
GrColor getBlendConstant() const { return fBlendConstant; }
/**
+ * We don't use supplied vertex color attributes if our blend mode is EmitCoverage or
+ * EmitTransBlack
+ */
+ bool canIgnoreColorAttribute() const;
+
+ /**
* Determines whether multiplying the computed per-pixel color by the pixel's fractional
* coverage before the blend will give the correct final destination color. In general it
* will not as coverage is applied after blending.
@@ -198,6 +213,22 @@ public:
};
GR_DECL_BITFIELD_OPS_FRIENDS(BlendOptFlags);
+ /**
+ * Determines what optimizations can be applied based on the blend. The coefficients may have
+ * to be tweaked in order for the optimization to work. srcCoeff and dstCoeff are optional
+ * params that receive the tweaked coefficients. Normally the function looks at the current
+ * state to see if coverage is enabled. By setting forceCoverage the caller can speculatively
+ * determine the blend optimizations that would be used if there was partial pixel coverage.
+ *
+ * Subclasses of GrDrawTarget that actually draw (as opposed to those that just buffer for
+ * playback) must call this function and respect the flags that replace the output color.
+ *
+ * If the cached BlendOptFlags does not have the invalidate bit set, then getBlendOpts will
+ * simply returned the cached flags and coefficients. Otherwise it will calculate the values.
+ */
+ BlendOptFlags getBlendOpts(bool forceCoverage = false,
+ GrBlendCoeff* srcCoeff = NULL,
+ GrBlendCoeff* dstCoeff = NULL) const;
/// @}
///////////////////////////////////////////////////////////////////////////
@@ -301,6 +332,8 @@ public:
kLastPublicStateBit = kDummyStateBit-1,
};
+ uint32_t getFlagBits() const { return fFlagBits; }
+
bool isStateFlagEnabled(uint32_t stateBit) const { return 0 != (stateBit & fFlagBits); }
bool isDitherState() const { return 0 != (fFlagBits & kDither_StateBit); }
@@ -333,6 +366,17 @@ public:
/// @}
///////////////////////////////////////////////////////////////////////////
+ /// @name Hints
+ /// Hints that when provided can enable optimizations.
+ ////
+
+ enum Hints { kVertexColorsAreOpaque_Hint = 0x1, };
+
+ bool vertexColorsAreOpaque() const { return kVertexColorsAreOpaque_Hint & fHints; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
/** Return type for CombineIfPossible. */
enum CombinedState {
@@ -359,6 +403,8 @@ protected:
friend class GrDrawTarget;
+ explicit GrRODrawState(const GrRODrawState& drawState);
+
bool isEqual(const GrRODrawState& that) const;
// These fields are roughly sorted by decreasing likelihood of being different in op==
@@ -381,6 +427,8 @@ protected:
EffectStageArray fColorStages;
EffectStageArray fCoverageStages;
+ uint32_t fHints;
+
mutable GrBlendCoeff fOptSrcBlend;
mutable GrBlendCoeff fOptDstBlend;
mutable BlendOptFlags fBlendOptFlags;
@@ -390,6 +438,18 @@ protected:
int fFixedFunctionVertexAttribIndices[kGrFixedFunctionVertexAttribBindingCnt];
private:
+ /**
+ * Determines whether src alpha is guaranteed to be one for all src pixels
+ */
+ bool srcAlphaWillBeOne() const;
+
+ /**
+ * Helper function for getBlendOpts.
+ */
+ BlendOptFlags calcBlendOpts(bool forceCoverage = false,
+ GrBlendCoeff* srcCoeff = NULL,
+ GrBlendCoeff* dstCoeff = NULL) const;
+
typedef SkRefCnt INHERITED;
};