diff options
-rw-r--r-- | gyp/gpu.gypi | 2 | ||||
-rw-r--r-- | src/gpu/GrDrawState.cpp | 350 | ||||
-rw-r--r-- | src/gpu/GrDrawState.h | 305 | ||||
-rw-r--r-- | src/gpu/GrRODrawState.cpp | 167 | ||||
-rw-r--r-- | src/gpu/GrRODrawState.h | 381 |
5 files changed, 682 insertions, 523 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index f00cfac733..4668ac47fd 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -116,6 +116,8 @@ '<(skia_src_path)/gpu/GrResourceCache.h', '<(skia_src_path)/gpu/GrResourceCache2.cpp', '<(skia_src_path)/gpu/GrResourceCache2.h', + '<(skia_src_path)/gpu/GrRODrawState.cpp', + '<(skia_src_path)/gpu/GrRODrawState.h', '<(skia_src_path)/gpu/GrStencil.cpp', '<(skia_src_path)/gpu/GrStencil.h', '<(skia_src_path)/gpu/GrStencilAndCoverPathRenderer.cpp', diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp index de97f68291..a6b3d68238 100644 --- a/src/gpu/GrDrawState.cpp +++ b/src/gpu/GrDrawState.cpp @@ -14,51 +14,13 @@ GrDrawState::CombinedState GrDrawState::CombineIfPossible( const GrDrawState& a, const GrDrawState& b, const GrDrawTargetCaps& caps) { - bool usingVertexColors = a.hasColorVertexAttribute(); - if (!usingVertexColors && a.fColor != b.fColor) { + if (!a.isEqual(b)) { return kIncompatible_CombinedState; } - if (a.fRenderTarget.get() != b.fRenderTarget.get() || - a.fColorStages.count() != b.fColorStages.count() || - a.fCoverageStages.count() != b.fCoverageStages.count() || - !a.fViewMatrix.cheapEqualTo(b.fViewMatrix) || - a.fSrcBlend != b.fSrcBlend || - a.fDstBlend != b.fDstBlend || - a.fBlendConstant != b.fBlendConstant || - a.fFlagBits != b.fFlagBits || - a.fVACount != b.fVACount || - memcmp(a.fVAPtr, b.fVAPtr, a.fVACount * sizeof(GrVertexAttrib)) || - a.fStencilSettings != b.fStencilSettings || - a.fDrawFace != b.fDrawFace) { - return kIncompatible_CombinedState; - } - - bool usingVertexCoverage = a.hasCoverageVertexAttribute(); - if (!usingVertexCoverage && a.fCoverage != b.fCoverage) { - return kIncompatible_CombinedState; - } - - bool explicitLocalCoords = a.hasLocalCoordAttribute(); - for (int i = 0; i < a.numColorStages(); i++) { - if (!GrEffectStage::AreCompatible(a.getColorStage(i), b.getColorStage(i), - explicitLocalCoords)) { - return kIncompatible_CombinedState; - } - } - for (int i = 0; i < a.numCoverageStages(); i++) { - if (!GrEffectStage::AreCompatible(a.getCoverageStage(i), b.getCoverageStage(i), - explicitLocalCoords)) { - return kIncompatible_CombinedState; - } - } - - SkASSERT(a.fVertexSize == b.fVertexSize); - SkASSERT(0 == memcmp(a.fFixedFunctionVertexAttribIndices, - b.fFixedFunctionVertexAttribIndices, - sizeof(a.fFixedFunctionVertexAttribIndices))); - - if (usingVertexColors) { + // If the general draw states are equal (from check above) we know hasColorVertexAttribute() + // is equivalent for both a and b + if (a.hasColorVertexAttribute()) { // If one is opaque and the other is not then the combined state is not opaque. Moreover, // if the opaqueness affects the ability to get color/coverage blending correct then we // don't combine the draw states. @@ -221,7 +183,7 @@ static size_t vertex_size(const GrVertexAttrib* attribs, int count) { #ifdef SK_DEBUG uint32_t overlapCheck = 0; #endif - SkASSERT(count <= GrDrawState::kMaxVertexAttribCnt); + SkASSERT(count <= GrRODrawState::kMaxVertexAttribCnt); size_t size = 0; for (int index = 0; index < count; ++index) { size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType); @@ -237,10 +199,6 @@ static size_t vertex_size(const GrVertexAttrib* attribs, int count) { return size; } -size_t GrDrawState::getVertexSize() const { - return fVertexSize; -} - //////////////////////////////////////////////////////////////////////////////// void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) { @@ -298,65 +256,6 @@ void GrDrawState::setDefaultVertexAttribs() { //////////////////////////////////////////////////////////////////////////////// -bool GrDrawState::validateVertexAttribs() const { - // check consistency of effects and attributes - GrSLType slTypes[kMaxVertexAttribCnt]; - for (int i = 0; i < kMaxVertexAttribCnt; ++i) { - slTypes[i] = static_cast<GrSLType>(-1); - } - int totalStages = this->numTotalStages(); - for (int s = 0; s < totalStages; ++s) { - int covIdx = s - this->numColorStages(); - const GrEffectStage& stage = covIdx < 0 ? this->getColorStage(s) : - this->getCoverageStage(covIdx); - const GrEffect* effect = stage.getEffect(); - SkASSERT(NULL != effect); - // make sure that any attribute indices have the correct binding type, that the attrib - // type and effect's shader lang type are compatible, and that attributes shared by - // multiple effects use the same shader lang type. - const int* attributeIndices = stage.getVertexAttribIndices(); - int numAttributes = stage.getVertexAttribIndexCount(); - for (int i = 0; i < numAttributes; ++i) { - int attribIndex = attributeIndices[i]; - if (attribIndex >= fVACount || - kEffect_GrVertexAttribBinding != fVAPtr[attribIndex].fBinding) { - return false; - } - - GrSLType effectSLType = effect->vertexAttribType(i); - GrVertexAttribType attribType = fVAPtr[attribIndex].fType; - int slVecCount = GrSLTypeVectorCount(effectSLType); - int attribVecCount = GrVertexAttribTypeVectorCount(attribType); - if (slVecCount != attribVecCount || - (static_cast<GrSLType>(-1) != slTypes[attribIndex] && - slTypes[attribIndex] != effectSLType)) { - return false; - } - slTypes[attribIndex] = effectSLType; - } - } - - return true; -} - -bool GrDrawState::willEffectReadDstColor() const { - if (!this->isColorWriteDisabled()) { - for (int s = 0; s < this->numColorStages(); ++s) { - if (this->getColorStage(s).getEffect()->willReadDstColor()) { - return true; - } - } - } - for (int s = 0; s < this->numCoverageStages(); ++s) { - if (this->getCoverageStage(s).getEffect()->willReadDstColor()) { - return true; - } - } - return false; -} - -//////////////////////////////////////////////////////////////////////////////// - bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const { if (caps.dualSourceBlendingSupport()) { return true; @@ -366,114 +265,52 @@ bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const { // or c) the src, dst blend coeffs are 1,0 and we will read Dst Color GrBlendCoeff srcCoeff; GrBlendCoeff dstCoeff; - GrDrawState::BlendOptFlags flag = this->getBlendOpts(true, &srcCoeff, &dstCoeff); - return GrDrawState::kNone_BlendOpt != flag || + GrRODrawState::BlendOptFlags flag = this->getBlendOpts(true, &srcCoeff, &dstCoeff); + return GrRODrawState::kNone_BlendOpt != flag || (this->willEffectReadDstColor() && kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff); } -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 - 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); +GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore( + GrDrawState* drawState) { + SkASSERT(NULL != drawState); + fDrawState = drawState; + fVAPtr = drawState->fVAPtr; + fVACount = drawState->fVACount; + fDrawState->setDefaultVertexAttribs(); } -bool GrDrawState::hasSolidCoverage() const { - // If we're drawing coverage directly then coverage is effectively treated as color. - if (this->isCoverageDrawing()) { - return true; - } +//////////////////////////////////////////////////////////////////////////////s - GrColor coverage; - uint32_t validComponentFlags; - // Initialize to an unknown starting coverage if per-vertex coverage is specified. - if (this->hasCoverageVertexAttribute()) { - validComponentFlags = 0; - } else { - coverage = this->getCoverageColor(); - validComponentFlags = kRGBA_GrColorComponentFlags; - } +void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) { + if (NULL != fDrawState) { + int m = fDrawState->numColorStages() - fColorEffectCnt; + SkASSERT(m >= 0); + fDrawState->fColorStages.pop_back_n(m); - // Run through the coverage stages and see if the coverage will be all ones at the end. - for (int s = 0; s < this->numCoverageStages(); ++s) { - const GrEffect* effect = this->getCoverageStage(s).getEffect(); - effect->getConstantColorComponents(&coverage, &validComponentFlags); + int n = fDrawState->numCoverageStages() - fCoverageEffectCnt; + SkASSERT(n >= 0); + fDrawState->fCoverageStages.pop_back_n(n); + if (m + n > 0) { + fDrawState->invalidateBlendOptFlags(); + } + SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;) + } + fDrawState = ds; + if (NULL != ds) { + fColorEffectCnt = ds->numColorStages(); + fCoverageEffectCnt = ds->numCoverageStages(); + SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;) } - return (kRGBA_GrColorComponentFlags == validComponentFlags) && (0xffffffff == coverage); } //////////////////////////////////////////////////////////////////////////////// -// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while -// others will blend incorrectly. -bool GrDrawState::canTweakAlphaForCoverage() const { - /* - The fractional coverage is f. - The src and dst coeffs are Cs and Cd. - The dst and src colors are S and D. - We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha - we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second - term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we - find that only 1, ISA, and ISC produce the correct destination when applied to S' and D. - Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as - color by definition. - */ - return kOne_GrBlendCoeff == fDstBlend || - kISA_GrBlendCoeff == fDstBlend || - kISC_GrBlendCoeff == fDstBlend || - this->isCoverageDrawing(); -} - -GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage, - GrBlendCoeff* srcCoeff, - GrBlendCoeff* dstCoeff) const { +GrRODrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage, + GrBlendCoeff* srcCoeff, + GrBlendCoeff* dstCoeff) const { GrBlendCoeff bogusSrcCoeff, bogusDstCoeff; if (NULL == srcCoeff) { srcCoeff = &bogusSrcCoeff; @@ -499,9 +336,9 @@ GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage, return fBlendOptFlags; } -GrDrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage, - GrBlendCoeff* srcCoeff, - GrBlendCoeff* dstCoeff) const { +GrRODrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage, + GrBlendCoeff* srcCoeff, + GrBlendCoeff* dstCoeff) const { *srcCoeff = this->getSrcBlendCoeff(); *dstCoeff = this->getDstBlendCoeff(); @@ -581,49 +418,6 @@ GrDrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage, return kNone_BlendOpt; } -bool GrDrawState::canIgnoreColorAttribute() const { - if (fBlendOptFlags & kInvalid_BlendOptFlag) { - this->getBlendOpts(); - } - return SkToBool(fBlendOptFlags & (GrDrawState::kEmitTransBlack_BlendOptFlag | - GrDrawState::kEmitCoverage_BlendOptFlag)); -} - -////////////////////////////////////////////////////////////////////////////// - -GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore( - GrDrawState* drawState) { - SkASSERT(NULL != drawState); - fDrawState = drawState; - fVAPtr = drawState->fVAPtr; - fVACount = drawState->fVACount; - fDrawState->setDefaultVertexAttribs(); -} - -//////////////////////////////////////////////////////////////////////////////s - -void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) { - if (NULL != fDrawState) { - int m = fDrawState->numColorStages() - fColorEffectCnt; - SkASSERT(m >= 0); - fDrawState->fColorStages.pop_back_n(m); - - int n = fDrawState->numCoverageStages() - fCoverageEffectCnt; - SkASSERT(n >= 0); - fDrawState->fCoverageStages.pop_back_n(n); - if (m + n > 0) { - fDrawState->invalidateBlendOptFlags(); - } - SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;) - } - fDrawState = ds; - if (NULL != ds) { - fColorEffectCnt = ds->numColorStages(); - fCoverageEffectCnt = ds->numCoverageStages(); - SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;) - } -} - //////////////////////////////////////////////////////////////////////////////// void GrDrawState::AutoViewMatrixRestore::restore() { @@ -710,3 +504,67 @@ void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& co fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix); } } + +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 + 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 cc1df05ec3..dcd6ff9aaf 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -8,20 +8,18 @@ #ifndef GrDrawState_DEFINED #define GrDrawState_DEFINED +#include "GrRODrawState.h" + #include "GrBlend.h" -#include "GrColor.h" -#include "GrEffectStage.h" -#include "GrStencil.h" #include "effects/GrSimpleTextureEffect.h" -#include "SkMatrix.h" - -class GrDrawTargetCaps; -class GrPaint; -class GrRenderTarget; -class GrTexture; - -class GrDrawState : public SkRefCnt { +/** + * Modifiable subclass derived from GrRODrawState. The majority of the data that represents a draw + * state is stored in the parent class. GrDrawState contains methods for setting, adding to, etc. + * various data members of the draw state. This class is used to configure the state used when + * issuing draws via GrDrawTarget. + */ +class GrDrawState : public GrRODrawState { public: SK_DECLARE_INST_COUNT(GrDrawState) @@ -69,10 +67,6 @@ public: /// @name Vertex Attributes //// - enum { - kMaxVertexAttribCnt = kLast_GrVertexAttribBinding + 4, - }; - /** * The format of vertices is represented as an array of GrVertexAttribs, with each representing * the type of the attribute, its offset, and semantic binding (see GrVertexAttrib in @@ -90,11 +84,6 @@ public: this->setVertexAttribs(A, count); } - const GrVertexAttrib* getVertexAttribs() const { return fVAPtr; } - int getVertexAttribCount() const { return fVACount; } - - size_t getVertexSize() const; - /** * Sets default vertex attributes for next draw. The default is a single attribute: * {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribType} @@ -102,37 +91,6 @@ public: void setDefaultVertexAttribs(); /** - * Getters for index into getVertexAttribs() for particular bindings. -1 is returned if the - * binding does not appear in the current attribs. These bindings should appear only once in - * the attrib array. - */ - - int positionAttributeIndex() const { - return fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]; - } - int localCoordAttributeIndex() const { - return fFixedFunctionVertexAttribIndices[kLocalCoord_GrVertexAttribBinding]; - } - int colorVertexAttributeIndex() const { - return fFixedFunctionVertexAttribIndices[kColor_GrVertexAttribBinding]; - } - int coverageVertexAttributeIndex() const { - return fFixedFunctionVertexAttribIndices[kCoverage_GrVertexAttribBinding]; - } - - bool hasLocalCoordAttribute() const { - return -1 != fFixedFunctionVertexAttribIndices[kLocalCoord_GrVertexAttribBinding]; - } - bool hasColorVertexAttribute() const { - return -1 != fFixedFunctionVertexAttribIndices[kColor_GrVertexAttribBinding]; - } - bool hasCoverageVertexAttribute() const { - return -1 != fFixedFunctionVertexAttribIndices[kCoverage_GrVertexAttribBinding]; - } - - bool validateVertexAttribs() const; - - /** * Helper to save/restore vertex attribs */ class AutoVertexAttribRestore { @@ -150,16 +108,6 @@ public: /// @} /** - * Determines whether src alpha is guaranteed to be one for all src pixels - */ - bool srcAlphaWillBeOne() const; - - /** - * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw. - */ - bool hasSolidCoverage() const; - - /** * Depending on features available in the underlying 3D API and the color blend mode requested * it may or may not be possible to correctly blend with fractional pixel coverage generated by * the fragment shader. @@ -187,8 +135,6 @@ public: this->invalidateBlendOptFlags(); } - GrColor getColor() const { return fColor; } - /** * Sets the color to be used for the next draw to be * (r,g,b,a) = (alpha, alpha, alpha, alpha). @@ -213,12 +159,6 @@ public: this->invalidateBlendOptFlags(); } - uint8_t getCoverage() const { return fCoverage; } - - GrColor getCoverageColor() const { - return GrColorPackRGBA(fCoverage, fCoverage, fCoverage, fCoverage); - } - /// @} /////////////////////////////////////////////////////////////////////////// @@ -302,18 +242,6 @@ public: int fCoverageEffectCnt; }; - int numColorStages() const { return fColorStages.count(); } - int numCoverageStages() const { return fCoverageStages.count(); } - int numTotalStages() const { return this->numColorStages() + this->numCoverageStages(); } - - 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. - */ - bool willEffectReadDstColor() const; - /// @} /////////////////////////////////////////////////////////////////////////// @@ -347,15 +275,6 @@ public: #endif } - GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlend; } - GrBlendCoeff getDstBlendCoeff() const { return fDstBlend; } - - void getDstBlendCoeff(GrBlendCoeff* srcBlendCoeff, - GrBlendCoeff* dstBlendCoeff) const { - *srcBlendCoeff = fSrcBlend; - *dstBlendCoeff = fDstBlend; - } - /** * Sets the blending function constant referenced by the following blending * coefficients: @@ -372,63 +291,6 @@ public: } /** - * Retrieves the last value set by setBlendConstant() - * @return the blending constant value - */ - GrColor getBlendConstant() const { return fBlendConstant; } - - /** - * 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. - */ - bool canTweakAlphaForCoverage() const; - - /** - * Optimizations for blending / coverage to that can be applied based on the current state. - */ - enum BlendOptFlags { - /** - * No optimization - */ - kNone_BlendOpt = 0, - /** - * Don't draw at all - */ - kSkipDraw_BlendOptFlag = 0x1, - /** - * The coverage value does not have to be computed separately from alpha, the the output - * color can be the modulation of the two. - */ - kCoverageAsAlpha_BlendOptFlag = 0x2, - /** - * Instead of emitting a src color, emit coverage in the alpha channel and r,g,b are - * "don't cares". - */ - kEmitCoverage_BlendOptFlag = 0x4, - /** - * Emit transparent black instead of the src color, no need to compute coverage. - */ - kEmitTransBlack_BlendOptFlag = 0x8, - /** - * Flag used to invalidate the cached BlendOptFlags, OptSrcCoeff, and OptDstCoeff cached by - * the get BlendOpts function. - */ - kInvalid_BlendOptFlag = 1 << 31, - }; - GR_DECL_BITFIELD_OPS_FRIENDS(BlendOptFlags); - - void invalidateBlendOptFlags() { - fBlendOptFlags = kInvalid_BlendOptFlag; - } - - /** - * We don't use suplied vertex color attributes if our blend mode is EmitCoverage or - * EmitTransBlack - */ - bool canIgnoreColorAttribute() const; - - /** * 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 @@ -445,6 +307,13 @@ public: 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; + + /// @} /////////////////////////////////////////////////////////////////////////// @@ -457,34 +326,6 @@ public: */ bool setIdentityViewMatrix(); - /** - * Retrieves the current view matrix - * @return the current view matrix. - */ - const SkMatrix& getViewMatrix() const { return fViewMatrix; } - - /** - * Retrieves the inverse of the current view matrix. - * - * If the current view matrix is invertible, return true, and if matrix - * is non-null, copy the inverse into it. If the current view matrix is - * non-invertible, return false and ignore the matrix parameter. - * - * @param matrix if not null, will receive a copy of the current inverse. - */ - bool getViewInverse(SkMatrix* matrix) const { - // TODO: determine whether we really need to leave matrix unmodified - // at call sites when inversion fails. - SkMatrix inverse; - if (fViewMatrix.invert(&inverse)) { - if (matrix) { - *matrix = inverse; - } - return true; - } - return false; - } - //////////////////////////////////////////////////////////////////////////// /** @@ -535,14 +376,6 @@ public: */ void setRenderTarget(GrRenderTarget* target) { fRenderTarget.reset(SkSafeRef(target)); } - /** - * Retrieves the currently set render-target. - * - * @return The currently set render target. - */ - const GrRenderTarget* getRenderTarget() const { return fRenderTarget.get(); } - GrRenderTarget* getRenderTarget() { return fRenderTarget.get(); } - class AutoRenderTargetRestore : public ::SkNoncopyable { public: AutoRenderTargetRestore() : fDrawState(NULL), fSavedTarget(NULL) {} @@ -603,8 +436,6 @@ public: this->invalidateBlendOptFlags(); } - const GrStencilSettings& getStencil() const { return fStencilSettings; } - GrStencilSettings* stencil() { return &fStencilSettings; } /// @} @@ -613,46 +444,6 @@ public: /// @name State Flags //// - /** - * Flags that affect rendering. Controlled using enable/disableState(). All - * default to disabled. - */ - enum StateBits { - /** - * Perform dithering. TODO: Re-evaluate whether we need this bit - */ - kDither_StateBit = 0x01, - /** - * Perform HW anti-aliasing. This means either HW FSAA, if supported by the render target, - * or smooth-line rendering if a line primitive is drawn and line smoothing is supported by - * the 3D API. - */ - kHWAntialias_StateBit = 0x02, - /** - * Draws will respect the clip, otherwise the clip is ignored. - */ - kClip_StateBit = 0x04, - /** - * Disables writing to the color buffer. Useful when performing stencil - * operations. - */ - kNoColorWrites_StateBit = 0x08, - - /** - * Usually coverage is applied after color blending. The color is blended using the coeffs - * specified by setBlendFunc(). The blended color is then combined with dst using coeffs - * of src_coverage, 1-src_coverage. Sometimes we are explicitly drawing a coverage mask. In - * this case there is no distinction between coverage and color and the caller needs direct - * control over the blend coeffs. When set, there will be a single blend step controlled by - * setBlendFunc() which will use coverage*color as the src color. - */ - kCoverageDrawing_StateBit = 0x10, - - // Users of the class may add additional bits to the vector - kDummyStateBit, - kLastPublicStateBit = kDummyStateBit-1, - }; - void resetStateFlags() { fFlagBits = 0; this->invalidateBlendOptFlags(); @@ -692,28 +483,12 @@ public: } } - bool isStateFlagEnabled(uint32_t stateBit) const { return 0 != (stateBit & fFlagBits); } - - bool isDitherState() const { return 0 != (fFlagBits & kDither_StateBit); } - bool isHWAntialiasState() const { return 0 != (fFlagBits & kHWAntialias_StateBit); } - bool isClipState() const { return 0 != (fFlagBits & kClip_StateBit); } - bool isColorWriteDisabled() const { return 0 != (fFlagBits & kNoColorWrites_StateBit); } - bool isCoverageDrawing() const { return 0 != (fFlagBits & kCoverageDrawing_StateBit); } - /// @} /////////////////////////////////////////////////////////////////////////// /// @name Face Culling //// - enum DrawFace { - kInvalid_DrawFace = -1, - - kBoth_DrawFace, - kCCW_DrawFace, - kCW_DrawFace, - }; - /** * Controls whether clockwise, counterclockwise, or both faces are drawn. * @param face the face(s) to draw. @@ -723,13 +498,6 @@ public: fDrawFace = face; } - /** - * Gets whether the target is drawing clockwise, counterclockwise, - * or both faces. - * @return the current draw face(s). - */ - DrawFace getDrawFace() const { return fDrawFace; } - /// @} /////////////////////////////////////////////////////////////////////////// @@ -769,38 +537,23 @@ public: private: void onReset(const SkMatrix* initialViewMatrix); + /** + * 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; - // These fields are roughly sorted by decreasing likelihood of being different in op== - SkAutoTUnref<GrRenderTarget> fRenderTarget; - GrColor fColor; - SkMatrix fViewMatrix; - GrBlendCoeff fSrcBlend; - GrBlendCoeff fDstBlend; - GrColor fBlendConstant; - uint32_t fFlagBits; - const GrVertexAttrib* fVAPtr; - int fVACount; - size_t fVertexSize; - GrStencilSettings fStencilSettings; - uint8_t fCoverage; - DrawFace fDrawFace; - - typedef SkSTArray<4, GrEffectStage> EffectStageArray; - EffectStageArray fColorStages; - EffectStageArray fCoverageStages; + void invalidateBlendOptFlags() { + fBlendOptFlags = kInvalid_BlendOptFlag; + } uint32_t fHints; - - mutable GrBlendCoeff fOptSrcBlend; - mutable GrBlendCoeff fOptDstBlend; - mutable BlendOptFlags fBlendOptFlags; - - // This is simply a different representation of info in fVertexAttribs and thus does - // not need to be compared in op==. - int fFixedFunctionVertexAttribIndices[kGrFixedFunctionVertexAttribBindingCnt]; // Some of the auto restore objects assume that no effects are removed during their lifetime. // This is used to assert that this condition holds. @@ -814,9 +567,7 @@ private: */ void setVertexAttribs(const GrVertexAttrib attribs[], int count); - typedef SkRefCnt INHERITED; + typedef GrRODrawState INHERITED; }; -GR_MAKE_BITFIELD_OPS(GrDrawState::BlendOptFlags); - #endif diff --git a/src/gpu/GrRODrawState.cpp b/src/gpu/GrRODrawState.cpp new file mode 100644 index 0000000000..1460f57320 --- /dev/null +++ b/src/gpu/GrRODrawState.cpp @@ -0,0 +1,167 @@ +/* + * 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 "GrRODrawState.h" +#include "GrDrawTargetCaps.h" + +//////////////////////////////////////////////////////////////////////////////// + +bool GrRODrawState::isEqual(const GrRODrawState& that) const { + bool usingVertexColors = this->hasColorVertexAttribute(); + if (!usingVertexColors && this->fColor != that.fColor) { + return false; + } + + if (this->fRenderTarget.get() != that.fRenderTarget.get() || + this->fColorStages.count() != that.fColorStages.count() || + this->fCoverageStages.count() != that.fCoverageStages.count() || + !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) || + this->fSrcBlend != that.fSrcBlend || + this->fDstBlend != that.fDstBlend || + this->fBlendConstant != that.fBlendConstant || + this->fFlagBits != that.fFlagBits || + this->fVACount != that.fVACount || + memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) || + this->fStencilSettings != that.fStencilSettings || + this->fDrawFace != that.fDrawFace) { + return false; + } + + bool usingVertexCoverage = this->hasCoverageVertexAttribute(); + if (!usingVertexCoverage && this->fCoverage != that.fCoverage) { + return false; + } + + bool explicitLocalCoords = this->hasLocalCoordAttribute(); + for (int i = 0; i < this->numColorStages(); i++) { + if (!GrEffectStage::AreCompatible(this->getColorStage(i), that.getColorStage(i), + explicitLocalCoords)) { + return false; + } + } + for (int i = 0; i < this->numCoverageStages(); i++) { + if (!GrEffectStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i), + explicitLocalCoords)) { + return false; + } + } + + SkASSERT(this->fVertexSize == that.fVertexSize); + SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices, + that.fFixedFunctionVertexAttribIndices, + sizeof(this->fFixedFunctionVertexAttribIndices))); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + +bool GrRODrawState::validateVertexAttribs() const { + // check consistency of effects and attributes + GrSLType slTypes[kMaxVertexAttribCnt]; + for (int i = 0; i < kMaxVertexAttribCnt; ++i) { + slTypes[i] = static_cast<GrSLType>(-1); + } + int totalStages = this->numTotalStages(); + for (int s = 0; s < totalStages; ++s) { + int covIdx = s - this->numColorStages(); + const GrEffectStage& stage = covIdx < 0 ? this->getColorStage(s) : + this->getCoverageStage(covIdx); + const GrEffect* effect = stage.getEffect(); + SkASSERT(NULL != effect); + // make sure that any attribute indices have the correct binding type, that the attrib + // type and effect's shader lang type are compatible, and that attributes shared by + // multiple effects use the same shader lang type. + const int* attributeIndices = stage.getVertexAttribIndices(); + int numAttributes = stage.getVertexAttribIndexCount(); + for (int i = 0; i < numAttributes; ++i) { + int attribIndex = attributeIndices[i]; + if (attribIndex >= fVACount || + kEffect_GrVertexAttribBinding != fVAPtr[attribIndex].fBinding) { + return false; + } + + GrSLType effectSLType = effect->vertexAttribType(i); + GrVertexAttribType attribType = fVAPtr[attribIndex].fType; + int slVecCount = GrSLTypeVectorCount(effectSLType); + int attribVecCount = GrVertexAttribTypeVectorCount(attribType); + if (slVecCount != attribVecCount || + (static_cast<GrSLType>(-1) != slTypes[attribIndex] && + slTypes[attribIndex] != effectSLType)) { + return false; + } + slTypes[attribIndex] = effectSLType; + } + } + + return true; +} + +bool GrRODrawState::hasSolidCoverage() const { + // If we're drawing coverage directly then coverage is effectively treated as color. + if (this->isCoverageDrawing()) { + return true; + } + + GrColor coverage; + uint32_t validComponentFlags; + // Initialize to an unknown starting coverage if per-vertex coverage is specified. + if (this->hasCoverageVertexAttribute()) { + validComponentFlags = 0; + } else { + coverage = fCoverage; + validComponentFlags = kRGBA_GrColorComponentFlags; + } + + // Run through the coverage stages and see if the coverage will be all ones at the end. + for (int s = 0; s < this->numCoverageStages(); ++s) { + const GrEffect* effect = this->getCoverageStage(s).getEffect(); + effect->getConstantColorComponents(&coverage, &validComponentFlags); + } + return (kRGBA_GrColorComponentFlags == validComponentFlags) && (0xffffffff == coverage); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool GrRODrawState::willEffectReadDstColor() const { + if (!this->isColorWriteDisabled()) { + for (int s = 0; s < this->numColorStages(); ++s) { + if (this->getColorStage(s).getEffect()->willReadDstColor()) { + return true; + } + } + } + for (int s = 0; s < this->numCoverageStages(); ++s) { + if (this->getCoverageStage(s).getEffect()->willReadDstColor()) { + return true; + } + } + return false; +} + +//////////////////////////////////////////////////////////////////////////////// + +// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while +// others will blend incorrectly. +bool GrRODrawState::canTweakAlphaForCoverage() const { + /* + The fractional coverage is f. + The src and dst coeffs are Cs and Cd. + The dst and src colors are S and D. + We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha + we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second + term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we + find that only 1, ISA, and ISC produce the correct destination when applied to S' and D. + Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as + color by definition. + */ + return kOne_GrBlendCoeff == fDstBlend || + kISA_GrBlendCoeff == fDstBlend || + kISC_GrBlendCoeff == fDstBlend || + this->isCoverageDrawing(); +} + diff --git a/src/gpu/GrRODrawState.h b/src/gpu/GrRODrawState.h new file mode 100644 index 0000000000..231560854f --- /dev/null +++ b/src/gpu/GrRODrawState.h @@ -0,0 +1,381 @@ +/* + * 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 GrRODrawState_DEFINED +#define GrRODrawState_DEFINED + +#include "GrStencil.h" +#include "GrEffectStage.h" +#include "SkMatrix.h" + +class GrDrawTargetCaps; +class GrPaint; +class GrRenderTarget; +class GrTexture; + +/** + * Read-only base class for GrDrawState. This class contains all the necessary data to represent a + * canonical DrawState. All methods in the class are const, thus once created the data in the class + * cannot be changed. + */ +class GrRODrawState : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(GrRODrawState) + + /////////////////////////////////////////////////////////////////////////// + /// @name Vertex Attributes + //// + + enum { + kMaxVertexAttribCnt = kLast_GrVertexAttribBinding + 4, + }; + + const GrVertexAttrib* getVertexAttribs() const { return fVAPtr; } + int getVertexAttribCount() const { return fVACount; } + + size_t getVertexSize() const { return fVertexSize; } + + /** + * Getters for index into getVertexAttribs() for particular bindings. -1 is returned if the + * binding does not appear in the current attribs. These bindings should appear only once in + * the attrib array. + */ + + int positionAttributeIndex() const { + return fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]; + } + int localCoordAttributeIndex() const { + return fFixedFunctionVertexAttribIndices[kLocalCoord_GrVertexAttribBinding]; + } + int colorVertexAttributeIndex() const { + return fFixedFunctionVertexAttribIndices[kColor_GrVertexAttribBinding]; + } + int coverageVertexAttributeIndex() const { + return fFixedFunctionVertexAttribIndices[kCoverage_GrVertexAttribBinding]; + } + + bool hasLocalCoordAttribute() const { + return -1 != fFixedFunctionVertexAttribIndices[kLocalCoord_GrVertexAttribBinding]; + } + bool hasColorVertexAttribute() const { + return -1 != fFixedFunctionVertexAttribIndices[kColor_GrVertexAttribBinding]; + } + bool hasCoverageVertexAttribute() const { + return -1 != fFixedFunctionVertexAttribIndices[kCoverage_GrVertexAttribBinding]; + } + + bool validateVertexAttribs() const; + + /// @} + + /** + * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw. + */ + bool hasSolidCoverage() const; + + /// @} + + /////////////////////////////////////////////////////////////////////////// + /// @name Color + //// + + GrColor getColor() const { return fColor; } + + /// @} + + /////////////////////////////////////////////////////////////////////////// + /// @name Coverage + //// + + uint8_t getCoverage() const { return fCoverage; } + + GrColor getCoverageColor() const { + return GrColorPackRGBA(fCoverage, fCoverage, fCoverage, fCoverage); + } + + /// @} + + /////////////////////////////////////////////////////////////////////////// + /// @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. + //// + + int numColorStages() const { return fColorStages.count(); } + int numCoverageStages() const { return fCoverageStages.count(); } + int numTotalStages() const { return this->numColorStages() + this->numCoverageStages(); } + + 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. + */ + bool willEffectReadDstColor() const; + + /// @} + + /////////////////////////////////////////////////////////////////////////// + /// @name Blending + //// + + GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlend; } + GrBlendCoeff getDstBlendCoeff() const { return fDstBlend; } + + void getDstBlendCoeff(GrBlendCoeff* srcBlendCoeff, + GrBlendCoeff* dstBlendCoeff) const { + *srcBlendCoeff = fSrcBlend; + *dstBlendCoeff = fDstBlend; + } + + /** + * Retrieves the last value set by setBlendConstant() + * @return the blending constant value + */ + GrColor getBlendConstant() const { return fBlendConstant; } + + /** + * 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. + */ + bool canTweakAlphaForCoverage() const; + + /** + * Optimizations for blending / coverage to that can be applied based on the current state. + */ + enum BlendOptFlags { + /** + * No optimization + */ + kNone_BlendOpt = 0, + /** + * Don't draw at all + */ + kSkipDraw_BlendOptFlag = 0x1, + /** + * The coverage value does not have to be computed separately from alpha, the output + * color can be the modulation of the two. + */ + kCoverageAsAlpha_BlendOptFlag = 0x2, + /** + * Instead of emitting a src color, emit coverage in the alpha channel and r,g,b are + * "don't cares". + */ + kEmitCoverage_BlendOptFlag = 0x4, + /** + * Emit transparent black instead of the src color, no need to compute coverage. + */ + kEmitTransBlack_BlendOptFlag = 0x8, + /** + * Flag used to invalidate the cached BlendOptFlags, OptSrcCoeff, and OptDstCoeff cached by + * the get BlendOpts function. + */ + kInvalid_BlendOptFlag = 1 << 31, + }; + GR_DECL_BITFIELD_OPS_FRIENDS(BlendOptFlags); + + /// @} + + /////////////////////////////////////////////////////////////////////////// + /// @name View Matrix + //// + + /** + * Retrieves the current view matrix + * @return the current view matrix. + */ + const SkMatrix& getViewMatrix() const { return fViewMatrix; } + + /** + * Retrieves the inverse of the current view matrix. + * + * If the current view matrix is invertible, return true, and if matrix + * is non-null, copy the inverse into it. If the current view matrix is + * non-invertible, return false and ignore the matrix parameter. + * + * @param matrix if not null, will receive a copy of the current inverse. + */ + bool getViewInverse(SkMatrix* matrix) const { + // TODO: determine whether we really need to leave matrix unmodified + // at call sites when inversion fails. + SkMatrix inverse; + if (fViewMatrix.invert(&inverse)) { + if (matrix) { + *matrix = inverse; + } + return true; + } + return false; + } + + /// @} + + /////////////////////////////////////////////////////////////////////////// + /// @name Render Target + //// + + /** + * Retrieves the currently set render-target. + * + * @return The currently set render target. + */ + const GrRenderTarget* getRenderTarget() const { return fRenderTarget.get(); } + GrRenderTarget* getRenderTarget() { return fRenderTarget.get(); } + + /// @} + + /////////////////////////////////////////////////////////////////////////// + /// @name Stencil + //// + + const GrStencilSettings& getStencil() const { return fStencilSettings; } + + /// @} + + /////////////////////////////////////////////////////////////////////////// + /// @name State Flags + //// + + /** + * Flags that affect rendering. Controlled using enable/disableState(). All + * default to disabled. + */ + enum StateBits { + /** + * Perform dithering. TODO: Re-evaluate whether we need this bit + */ + kDither_StateBit = 0x01, + /** + * Perform HW anti-aliasing. This means either HW FSAA, if supported by the render target, + * or smooth-line rendering if a line primitive is drawn and line smoothing is supported by + * the 3D API. + */ + kHWAntialias_StateBit = 0x02, + /** + * Draws will respect the clip, otherwise the clip is ignored. + */ + kClip_StateBit = 0x04, + /** + * Disables writing to the color buffer. Useful when performing stencil + * operations. + */ + kNoColorWrites_StateBit = 0x08, + + /** + * Usually coverage is applied after color blending. The color is blended using the coeffs + * specified by setBlendFunc(). The blended color is then combined with dst using coeffs + * of src_coverage, 1-src_coverage. Sometimes we are explicitly drawing a coverage mask. In + * this case there is no distinction between coverage and color and the caller needs direct + * control over the blend coeffs. When set, there will be a single blend step controlled by + * setBlendFunc() which will use coverage*color as the src color. + */ + kCoverageDrawing_StateBit = 0x10, + + // Users of the class may add additional bits to the vector + kDummyStateBit, + kLastPublicStateBit = kDummyStateBit-1, + }; + + bool isStateFlagEnabled(uint32_t stateBit) const { return 0 != (stateBit & fFlagBits); } + + bool isDitherState() const { return 0 != (fFlagBits & kDither_StateBit); } + bool isHWAntialiasState() const { return 0 != (fFlagBits & kHWAntialias_StateBit); } + bool isClipState() const { return 0 != (fFlagBits & kClip_StateBit); } + bool isColorWriteDisabled() const { return 0 != (fFlagBits & kNoColorWrites_StateBit); } + bool isCoverageDrawing() const { return 0 != (fFlagBits & kCoverageDrawing_StateBit); } + + /// @} + + /////////////////////////////////////////////////////////////////////////// + /// @name Face Culling + //// + + enum DrawFace { + kInvalid_DrawFace = -1, + + kBoth_DrawFace, + kCCW_DrawFace, + kCW_DrawFace, + }; + + /** + * Gets whether the target is drawing clockwise, counterclockwise, + * or both faces. + * @return the current draw face(s). + */ + DrawFace getDrawFace() const { return fDrawFace; } + + /// @} + + /////////////////////////////////////////////////////////////////////////// + + /** Return type for CombineIfPossible. */ + enum CombinedState { + /** The GrDrawStates cannot be combined. */ + kIncompatible_CombinedState, + /** Either draw state can be used in place of the other. */ + kAOrB_CombinedState, + /** Use the first draw state. */ + kA_CombinedState, + /** Use the second draw state. */ + kB_CombinedState, + }; + + GrRODrawState& operator= (const GrRODrawState& that); + +protected: + bool isEqual(const GrRODrawState& that) const; + + // These fields are roughly sorted by decreasing likelihood of being different in op== + SkAutoTUnref<GrRenderTarget> fRenderTarget; + GrColor fColor; + SkMatrix fViewMatrix; + GrColor fBlendConstant; + uint32_t fFlagBits; + const GrVertexAttrib* fVAPtr; + int fVACount; + size_t fVertexSize; + GrStencilSettings fStencilSettings; + uint8_t fCoverage; + DrawFace fDrawFace; + GrBlendCoeff fSrcBlend; + GrBlendCoeff fDstBlend; + + typedef SkSTArray<4, GrEffectStage> EffectStageArray; + EffectStageArray fColorStages; + EffectStageArray fCoverageStages; + + mutable GrBlendCoeff fOptSrcBlend; + mutable GrBlendCoeff fOptDstBlend; + mutable BlendOptFlags fBlendOptFlags; + + // This is simply a different representation of info in fVertexAttribs and thus does + // not need to be compared in op==. + int fFixedFunctionVertexAttribIndices[kGrFixedFunctionVertexAttribBindingCnt]; + +private: + typedef SkRefCnt INHERITED; +}; + +GR_MAKE_BITFIELD_OPS(GrRODrawState::BlendOptFlags); + +#endif |