Index: src/gpu/GrDrawState.h |
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h |
index 5b1194d0c2672da56904c819b50349fb2906b4fb..9d1e64d1fe41efcbd1146f8a8d9ccbcb88bbd8b9 100644 |
--- a/src/gpu/GrDrawState.h |
+++ b/src/gpu/GrDrawState.h |
@@ -27,43 +27,21 @@ class GrDrawState : public GrRefCnt { |
public: |
SK_DECLARE_INST_COUNT(GrDrawState) |
- /** |
- * Total number of effect stages. Each stage can host a GrEffect. A stage is enabled if it has a |
- * GrEffect. The effect produces an output color in the fragment shader. It's inputs are the |
- * output from the previous enabled stage and a position. The position is either derived from |
- * the interpolated vertex positions or explicit per-vertex coords, depending upon the |
- * GrAttribBindings used to draw. |
- * |
- * The stages are divided into two sets, color-computing and coverage-computing. The final color |
- * stage produces the final pixel color. The coverage-computing stages function exactly as the |
- * color-computing but the output of the final coverage stage is treated as a fractional pixel |
- * coverage rather than as input to the src/dst color blend step. |
- * |
- * The input color to the first enabled color-stage is either the constant color or interpolated |
- * per-vertex colors. The input to the first coverage stage is either a constant coverage |
- * (usually full-coverage) or interpolated per-vertex coverage. |
- * |
- * See the documentation of kCoverageDrawing_StateBit for information about disabling the |
- * the color / coverage distinction. |
- * |
- * Stages 0 through GrPaint::kTotalStages-1 are reserved for stages copied from the client's |
- * GrPaint. Stage GrPaint::kTotalStages is earmarked for use by GrTextContext, GrPathRenderer- |
- * derived classes, and the rect/oval helper classes. GrPaint::kTotalStages+1 is earmarked for |
- * clipping by GrClipMaskManager. TODO: replace fixed size array of stages with variable size |
- * arrays of color and coverage stages. |
- */ |
- enum { |
- kNumStages = GrPaint::kTotalStages + 2, |
- }; |
- |
- GrDrawState() { this->reset(); } |
+ GrDrawState() { |
+ GR_DEBUGCODE(fBlockEffectRemovalCnt = 0;) |
+ this->reset(); |
+ } |
- GrDrawState(const SkMatrix& initialViewMatrix) { this->reset(initialViewMatrix); } |
+ GrDrawState(const SkMatrix& initialViewMatrix) { |
+ GR_DEBUGCODE(fBlockEffectRemovalCnt = 0;) |
+ this->reset(initialViewMatrix); |
+ } |
/** |
* Copies another draw state. |
**/ |
GrDrawState(const GrDrawState& state) { |
+ GR_DEBUGCODE(fBlockEffectRemovalCnt = 0;) |
*this = state; |
} |
@@ -71,17 +49,19 @@ public: |
* Copies another draw state with a preconcat to the view matrix. |
**/ |
GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) { |
+ GR_DEBUGCODE(fBlockEffectRemovalCnt = 0;) |
*this = state; |
if (!preConcatMatrix.isIdentity()) { |
- for (int i = 0; i < kNumStages; ++i) { |
- if (this->isStageEnabled(i)) { |
- fStages[i].localCoordChange(preConcatMatrix); |
- } |
+ for (int i = 0; i < fColorStages.count(); ++i) { |
+ fColorStages[i].localCoordChange(preConcatMatrix); |
+ } |
+ for (int i = 0; i < fCoverageStages.count(); ++i) { |
+ fCoverageStages[i].localCoordChange(preConcatMatrix); |
} |
} |
} |
- virtual ~GrDrawState() { this->disableStages(); } |
+ virtual ~GrDrawState() { GrAssert(0 == fBlockEffectRemovalCnt); } |
/** |
* Resets to the default state. GrEffects will be removed from all stages. |
@@ -93,8 +73,7 @@ public: |
/** |
* Initializes the GrDrawState based on a GrPaint, view matrix and render target. Note that |
* GrDrawState encompasses more than GrPaint. Aspects of GrDrawState that have no GrPaint |
- * equivalents are set to default values. GrPaint has fewer stages than GrDrawState. The extra |
- * GrDrawState stages are disabled. Clipping will be enabled. |
+ * equivalents are set to default values. Clipping will be enabled. |
*/ |
void setFromPaint(const GrPaint& , const SkMatrix& viewMatrix, GrRenderTarget*); |
@@ -359,90 +338,105 @@ public: |
/////////////////////////////////////////////////////////////////////////// |
/// @name Effect Stages |
+ /// Each stage hosts a GrEffect. The effect produces an output color or coverage in the fragment |
+ /// shader. Its inputs are the output from the previous stage as well as some variables |
+ /// available to it in the fragment and vertex shader (e.g. the vertex position, the dst color, |
+ /// the fragment position, local coordinates). |
+ /// |
+ /// The stages are divided into two sets, color-computing and coverage-computing. The final |
+ /// color stage produces the final pixel color. The coverage-computing stages function exactly |
+ /// as the color-computing but the output of the final coverage stage is treated as a fractional |
+ /// pixel coverage rather than as input to the src/dst color blend step. |
+ /// |
+ /// The input color to the first color-stage is either the constant color or interpolated |
+ /// per-vertex colors. The input to the first coverage stage is either a constant coverage |
+ /// (usually full-coverage) or interpolated per-vertex coverage. |
+ /// |
+ /// See the documentation of kCoverageDrawing_StateBit for information about disabling the |
+ /// the color / coverage distinction. |
//// |
- const GrEffectRef* setEffect(int stageIdx, const GrEffectRef* effect) { |
- fStages[stageIdx].setEffect(effect); |
+ const GrEffectRef* addColorEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) { |
+ GrAssert(NULL != effect); |
+ SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect, attr0, attr1)); |
return effect; |
} |
- const GrEffectRef* setEffect(int stageIdx, const GrEffectRef* effect, |
- int attr0, int attr1 = -1) { |
- fStages[stageIdx].setEffect(effect, attr0, attr1); |
+ const GrEffectRef* addCoverageEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) { |
+ GrAssert(NULL != effect); |
+ SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect, attr0, attr1)); |
return effect; |
} |
/** |
* Creates a GrSimpleTextureEffect that uses local coords as texture coordinates. |
*/ |
- void createTextureEffect(int stageIdx, GrTexture* texture, const SkMatrix& matrix) { |
- GrAssert(!this->getStage(stageIdx).getEffect()); |
+ void addColorTextureEffect(GrTexture* texture, const SkMatrix& matrix) { |
GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix); |
- this->setEffect(stageIdx, effect)->unref(); |
+ this->addColorEffect(effect)->unref(); |
} |
- void createTextureEffect(int stageIdx, |
- GrTexture* texture, |
- const SkMatrix& matrix, |
- const GrTextureParams& params) { |
- GrAssert(!this->getStage(stageIdx).getEffect()); |
- GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params); |
- this->setEffect(stageIdx, effect)->unref(); |
+ |
+ void addCoverageTextureEffect(GrTexture* texture, const SkMatrix& matrix) { |
+ GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix); |
+ this->addCoverageEffect(effect)->unref(); |
} |
- bool stagesDisabled() { |
- for (int i = 0; i < kNumStages; ++i) { |
- if (NULL != fStages[i].getEffect()) { |
- return false; |
- } |
- } |
- return true; |
+ void addColorTextureEffect(GrTexture* texture, |
+ const SkMatrix& matrix, |
+ const GrTextureParams& params) { |
+ GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params); |
+ this->addColorEffect(effect)->unref(); |
} |
- void disableStage(int stageIdx) { |
- this->setEffect(stageIdx, NULL); |
+ void addCoverageTextureEffect(GrTexture* texture, |
+ const SkMatrix& matrix, |
+ const GrTextureParams& params) { |
+ GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params); |
+ this->addCoverageEffect(effect)->unref(); |
} |
/** |
- * Release all the GrEffects referred to by this draw state. |
+ * When this object is destroyed it will remove any effects from the draw state that were added |
+ * after its constructor. |
*/ |
- void disableStages() { |
- for (int i = 0; i < kNumStages; ++i) { |
- this->disableStage(i); |
- } |
- } |
- |
- class AutoStageDisable : public ::GrNoncopyable { |
+ class AutoRestoreEffects : public ::GrNoncopyable { |
public: |
- AutoStageDisable(GrDrawState* ds) : fDrawState(ds) {} |
- ~AutoStageDisable() { |
+ AutoRestoreEffects() : fDrawState(NULL) {} |
+ |
+ AutoRestoreEffects(GrDrawState* ds) : fDrawState(NULL) { this->set(ds); } |
+ |
+ ~AutoRestoreEffects() { this->set(NULL); } |
+ |
+ void set(GrDrawState* ds) { |
if (NULL != fDrawState) { |
- fDrawState->disableStages(); |
+ int n = fDrawState->fColorStages.count() - fColorEffectCnt; |
+ GrAssert(n >= 0); |
+ fDrawState->fColorStages.pop_back_n(n); |
+ n = fDrawState->fCoverageStages.count() - fCoverageEffectCnt; |
+ GrAssert(n >= 0); |
+ fDrawState->fCoverageStages.pop_back_n(n); |
+ GR_DEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;) |
+ } |
+ fDrawState = ds; |
+ if (NULL != ds) { |
+ fColorEffectCnt = ds->fColorStages.count(); |
+ fCoverageEffectCnt = ds->fCoverageStages.count(); |
+ GR_DEBUGCODE(++ds->fBlockEffectRemovalCnt;) |
} |
} |
+ |
private: |
GrDrawState* fDrawState; |
+ int fColorEffectCnt; |
+ int fCoverageEffectCnt; |
}; |
- /** |
- * Returns the current stage by index. |
- */ |
- const GrEffectStage& getStage(int stageIdx) const { |
- GrAssert((unsigned)stageIdx < kNumStages); |
- return fStages[stageIdx]; |
- } |
+ int numColorStages() const { return fColorStages.count(); } |
+ int numCoverageStages() const { return fCoverageStages.count(); } |
+ int numTotalStages() const { return this->numColorStages() + this->numCoverageStages(); } |
- /** |
- * Called when the source coord system is changing. This ensures that effects will see the |
- * correct local coordinates. oldToNew gives the transformation from the old coord system in |
- * which the geometry was specified to the new coordinate system from which it will be rendered. |
- */ |
- void localCoordChange(const SkMatrix& oldToNew) { |
- for (int i = 0; i < kNumStages; ++i) { |
- if (this->isStageEnabled(i)) { |
- fStages[i].localCoordChange(oldToNew); |
- } |
- } |
- } |
+ const GrEffectStage& getColorStage(int stageIdx) const { return fColorStages[stageIdx]; } |
+ const GrEffectStage& getCoverageStage(int stageIdx) const { return fCoverageStages[stageIdx]; } |
/** |
* Checks whether any of the effects will read the dst pixel color. |
@@ -452,33 +446,6 @@ public: |
/// @} |
/////////////////////////////////////////////////////////////////////////// |
- /// @name Coverage / Color Stages |
- //// |
- |
- /** |
- * A common pattern is to compute a color with the initial stages and then |
- * modulate that color by a coverage value in later stage(s) (AA, mask- |
- * filters, glyph mask, etc). Color-filters, xfermodes, etc should be |
- * computed based on the pre-coverage-modulated color. The division of |
- * stages between color-computing and coverage-computing is specified by |
- * this method. Initially this is kNumStages (all stages |
- * are color-computing). |
- */ |
- void setFirstCoverageStage(int firstCoverageStage) { |
- GrAssert((unsigned)firstCoverageStage <= kNumStages); |
- fCommon.fFirstCoverageStage = firstCoverageStage; |
- } |
- |
- /** |
- * Gets the index of the first coverage-computing stage. |
- */ |
- int getFirstCoverageStage() const { |
- return fCommon.fFirstCoverageStage; |
- } |
- |
- ///@} |
- |
- /////////////////////////////////////////////////////////////////////////// |
/// @name Blending |
//// |
@@ -674,10 +641,12 @@ public: |
bool setIdentity(GrDrawState* drawState); |
private: |
- GrDrawState* fDrawState; |
- SkMatrix fViewMatrix; |
- GrEffectStage::SavedCoordChange fSavedCoordChanges[GrDrawState::kNumStages]; |
- uint32_t fRestoreMask; |
+ void doEffectCoordChanges(const SkMatrix& coordChangeMatrix); |
+ |
+ GrDrawState* fDrawState; |
+ SkMatrix fViewMatrix; |
+ int fNumColorStages; |
+ SkAutoSTArray<8, GrEffectStage::SavedCoordChange> fSavedCoordChanges; |
}; |
/// @} |
@@ -905,21 +874,20 @@ public: |
/////////////////////////////////////////////////////////////////////////// |
- bool isStageEnabled(int s) const { |
- GrAssert((unsigned)s < kNumStages); |
- return (NULL != fStages[s].getEffect()); |
- } |
- |
bool operator ==(const GrDrawState& s) const { |
- if (fRenderTarget.get() != s.fRenderTarget.get() || fCommon != s.fCommon) { |
+ if (fRenderTarget.get() != s.fRenderTarget.get() || |
+ fColorStages.count() != s.fColorStages.count() || |
+ fCoverageStages.count() != s.fCoverageStages.count() || |
+ fCommon != s.fCommon) { |
return false; |
} |
- for (int i = 0; i < kNumStages; i++) { |
- bool enabled = this->isStageEnabled(i); |
- if (enabled != s.isStageEnabled(i)) { |
+ for (int i = 0; i < fColorStages.count(); i++) { |
+ if (fColorStages[i] != s.fColorStages[i]) { |
return false; |
} |
- if (enabled && this->fStages[i] != s.fStages[i]) { |
+ } |
+ for (int i = 0; i < fCoverageStages.count(); i++) { |
+ if (fCoverageStages[i] != s.fCoverageStages[i]) { |
return false; |
} |
} |
@@ -928,21 +896,20 @@ public: |
bool operator !=(const GrDrawState& s) const { return !(*this == s); } |
GrDrawState& operator= (const GrDrawState& s) { |
+ GrAssert(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages()); |
this->setRenderTarget(s.fRenderTarget.get()); |
fCommon = s.fCommon; |
- for (int i = 0; i < kNumStages; i++) { |
- if (s.isStageEnabled(i)) { |
- this->fStages[i] = s.fStages[i]; |
- } |
- } |
+ fColorStages = s.fColorStages; |
+ fCoverageStages = s.fCoverageStages; |
return *this; |
} |
private: |
void onReset(const SkMatrix* initialViewMatrix) { |
- |
- this->disableStages(); |
+ GrAssert(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages()); |
+ fColorStages.reset(); |
+ fCoverageStages.reset(); |
fRenderTarget.reset(NULL); |
@@ -959,7 +926,6 @@ private: |
fCommon.fBlendConstant = 0x0; |
fCommon.fFlagBits = 0x0; |
fCommon.fStencilSettings.setDisabled(); |
- fCommon.fFirstCoverageStage = kNumStages; |
fCommon.fCoverage = 0xffffffff; |
fCommon.fColorFilterMode = SkXfermode::kDst_Mode; |
fCommon.fColorFilterColor = 0x0; |
@@ -978,7 +944,6 @@ private: |
const GrVertexAttrib* fVAPtr; |
int fVACount; |
GrStencilSettings fStencilSettings; |
- int fFirstCoverageStage; |
GrColor fCoverage; |
SkXfermode::Mode fColorFilterMode; |
GrColor fColorFilterColor; |
@@ -998,7 +963,6 @@ private: |
fVACount == other.fVACount && |
!memcmp(fVAPtr, other.fVAPtr, fVACount * sizeof(GrVertexAttrib)) && |
fStencilSettings == other.fStencilSettings && |
- fFirstCoverageStage == other.fFirstCoverageStage && |
fCoverage == other.fCoverage && |
fColorFilterMode == other.fColorFilterMode && |
fColorFilterColor == other.fColorFilterColor && |
@@ -1042,8 +1006,13 @@ public: |
// Here we ref the effects directly rather than the effect-refs. TODO: When the effect- |
// ref gets fully unref'ed it will cause the underlying effect to unref its resources |
// and recycle them to the cache (if no one else is holding a ref to the resources). |
- for (int i = 0; i < kNumStages; ++i) { |
- fStages[i].saveFrom(drawState.fStages[i]); |
+ fStages.reset(drawState.fColorStages.count() + drawState.fCoverageStages.count()); |
+ fColorStageCnt = drawState.fColorStages.count(); |
+ for (int i = 0; i < fColorStageCnt; ++i) { |
+ fStages[i].saveFrom(drawState.fColorStages[i]); |
+ } |
+ for (int i = 0; i < drawState.fCoverageStages.count(); ++i) { |
+ fStages[i + fColorStageCnt].saveFrom(drawState.fCoverageStages[i]); |
} |
GR_DEBUGCODE(fInitialized = true;) |
} |
@@ -1052,17 +1021,35 @@ public: |
GrAssert(fInitialized); |
drawState->fCommon = fCommon; |
drawState->setRenderTarget(fRenderTarget); |
- for (int i = 0; i < kNumStages; ++i) { |
- fStages[i].restoreTo(&drawState->fStages[i]); |
+ // reinflate color/cov stage arrays. |
+ drawState->fColorStages.reset(fColorStageCnt); |
+ for (int i = 0; i < fColorStageCnt; ++i) { |
+ fStages[i].restoreTo(&drawState->fColorStages[i]); |
+ } |
+ int coverageStageCnt = fStages.count() - fColorStageCnt; |
+ drawState->fCoverageStages.reset(coverageStageCnt); |
+ for (int i = 0; i < coverageStageCnt; ++i) { |
+ fStages[fColorStageCnt + i].restoreTo(&drawState->fCoverageStages[i]); |
} |
} |
bool isEqual(const GrDrawState& state) const { |
- if (fRenderTarget != state.fRenderTarget.get() || fCommon != state.fCommon) { |
+ int numCoverageStages = fStages.count() - fColorStageCnt; |
+ if (fRenderTarget != state.fRenderTarget.get() || |
+ fColorStageCnt != state.fColorStages.count() || |
+ numCoverageStages != state.fCoverageStages.count() || |
+ fCommon != state.fCommon) { |
return false; |
} |
- for (int i = 0; i < kNumStages; ++i) { |
- if (!fStages[i].isEqual(state.fStages[i], state.hasLocalCoordAttribute())) { |
+ bool explicitLocalCoords = state.hasLocalCoordAttribute(); |
+ for (int i = 0; i < fColorStageCnt; ++i) { |
+ if (!fStages[i].isEqual(state.fColorStages[i], explicitLocalCoords)) { |
+ return false; |
+ } |
+ } |
+ for (int i = 0; i < numCoverageStages; ++i) { |
+ int s = fColorStageCnt + i; |
+ if (!fStages[s].isEqual(state.fCoverageStages[i], explicitLocalCoords)) { |
return false; |
} |
} |
@@ -1070,18 +1057,28 @@ public: |
} |
private: |
+ typedef SkAutoSTArray<8, GrEffectStage::DeferredStage> DeferredStageArray; |
+ |
GrRenderTarget* fRenderTarget; |
CommonState fCommon; |
- GrEffectStage::DeferredStage fStages[kNumStages]; |
+ int fColorStageCnt; |
+ DeferredStageArray fStages; |
GR_DEBUGCODE(bool fInitialized;) |
}; |
private: |
- SkAutoTUnref<GrRenderTarget> fRenderTarget; |
- CommonState fCommon; |
- GrEffectStage fStages[kNumStages]; |
+ SkAutoTUnref<GrRenderTarget> fRenderTarget; |
+ CommonState fCommon; |
+ |
+ typedef SkSTArray<4, GrEffectStage> EffectStageArray; |
+ EffectStageArray fColorStages; |
+ EffectStageArray fCoverageStages; |
+ |
+ // Some of the auto restore objects assume that no effects are removed during their lifetime. |
+ // This is used to assert that this condition holds. |
+ GR_DEBUGCODE(int fBlockEffectRemovalCnt;) |
/** |
* Sets vertex attributes for next draw. |