Index: src/gpu/GrRODrawState.cpp |
diff --git a/src/gpu/GrRODrawState.cpp b/src/gpu/GrRODrawState.cpp |
index 8d6c283f7af04ee101f3274448578cd202e8d7b5..b79e8fce4340df6253c676610b6682a05dea7037 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)); |
+} |
+ |