Gpu blend optimizations, handle more xfer modes with fractional pixel coverage
Review URL: http://codereview.appspot.com/5237062/
git-svn-id: http://skia.googlecode.com/svn/trunk@2464 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrDefaultPathRenderer.cpp b/gpu/src/GrDefaultPathRenderer.cpp
index fd56c07..14c032b 100644
--- a/gpu/src/GrDefaultPathRenderer.cpp
+++ b/gpu/src/GrDefaultPathRenderer.cpp
@@ -179,7 +179,7 @@
return hint == kConvex_ConvexHint ||
hint == kNonOverlappingConvexPieces_ConvexHint ||
(hint == kSameWindingConvexPieces_ConvexHint &&
- target.canDisableBlend() && !target.isDitherState());
+ !target.drawWillReadDst() && !target.isDitherState());
}
return false;
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 2169fc7..0ba7ead 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -825,7 +825,7 @@
// Some blend modes allow folding a partial coverage value into the color's
// alpha channel, while others will blend incorrectly.
-bool GrDrawTarget::CanTweakAlphaForCoverage(GrBlendCoeff dstCoeff) {
+bool GrDrawTarget::canTweakAlphaForCoverage() const {
/**
* The fractional coverage is f
* The src and dst coeffs are Cs and Cd
@@ -837,89 +837,186 @@
* for Cd we find that only 1, ISA, and ISC produce the correct depth
* coeffecient in terms of S' and D.
*/
- return kOne_BlendCoeff == dstCoeff ||
- kISA_BlendCoeff == dstCoeff ||
- kISC_BlendCoeff == dstCoeff;
+ return kOne_BlendCoeff == fCurrDrawState.fDstBlend||
+ kISA_BlendCoeff == fCurrDrawState.fDstBlend ||
+ kISC_BlendCoeff == fCurrDrawState.fDstBlend;
}
-bool GrDrawTarget::CanDisableBlend(GrVertexLayout layout, const DrState& state) {
- // If we compute a coverage value (using edge AA or a coverage stage) then
- // we can't force blending off.
- if (state.fEdgeAANumEdges > 0 ||
- (layout & kEdge_VertexLayoutBit) ||
- (layout & kCoverage_VertexLayoutBit)) {
- return false;
- }
- for (int s = state.fFirstCoverageStage; s < kNumStages; ++s) {
- if (StageWillBeUsed(s, layout, state)) {
- return false;
- }
- }
- if ((kOne_BlendCoeff == state.fSrcBlend) &&
- (kZero_BlendCoeff == state.fDstBlend)) {
- return true;
- }
+bool GrDrawTarget::srcAlphaWillBeOne() const {
+ const GrVertexLayout& layout = this->getGeomSrc().fVertexLayout;
- // If we have vertex color without alpha then we can't force blend off
+ // Check if per-vertex or constant color may have partial alpha
if ((layout & kColor_VertexLayoutBit) ||
- 0xff != GrColorUnpackA(state.fColor)) {
+ 0xff != GrColorUnpackA(fCurrDrawState.fColor)) {
return false;
}
-
- // If the src coef will always be 1...
- if (kSA_BlendCoeff != state.fSrcBlend &&
- kOne_BlendCoeff != state.fSrcBlend) {
+ // Check if color filter could introduce an alpha
+ // (TODO: Consider being more aggressive with regards to detecting 0xff
+ // final alpha from color filter).
+ if (SkXfermode::kDst_Mode != fCurrDrawState.fColorFilterXfermode) {
return false;
}
-
- // ...and the dst coef is always 0...
- if (kISA_BlendCoeff != state.fDstBlend &&
- kZero_BlendCoeff != state.fDstBlend) {
- return false;
- }
-
- // ...and there isn't a texture stage with an alpha channel...
- for (int s = 0; s < state.fFirstCoverageStage; ++s) {
- if (StageWillBeUsed(s, layout, state)) {
- GrAssert(NULL != state.fTextures[s]);
-
- GrPixelConfig config = state.fTextures[s]->config();
-
+ // Check if a color stage could create a partial alpha
+ for (int s = 0; s < fCurrDrawState.fFirstCoverageStage; ++s) {
+ if (StageWillBeUsed(s, layout, fCurrDrawState)) {
+ GrAssert(NULL != fCurrDrawState.fTextures[s]);
+ GrPixelConfig config = fCurrDrawState.fTextures[s]->config();
if (!GrPixelConfigIsOpaque(config)) {
return false;
}
}
}
-
- // ...and there isn't an interesting color filter...
- // TODO: Consider being more aggressive with regards to disabling
- // blending when a color filter is used.
- if (SkXfermode::kDst_Mode != state.fColorFilterXfermode) {
- return false;
- }
-
- // ...then we disable blend.
return true;
}
-bool GrDrawTarget::CanUseHWAALines(GrVertexLayout layout, const DrState& state) {
+GrDrawTarget::BlendOptFlags
+GrDrawTarget::getBlendOpts(bool forceCoverage,
+ GrBlendCoeff* srcCoeff,
+ GrBlendCoeff* dstCoeff) const {
+
+ const GrVertexLayout& layout = this->getGeomSrc().fVertexLayout;
+
+ GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
+ if (NULL == srcCoeff) {
+ srcCoeff = &bogusSrcCoeff;
+ }
+ *srcCoeff = fCurrDrawState.fSrcBlend;
+
+ if (NULL == dstCoeff) {
+ dstCoeff = &bogusDstCoeff;
+ }
+ *dstCoeff = fCurrDrawState.fDstBlend;
+
+ // We don't ever expect source coeffecients to reference the source
+ GrAssert(kSA_BlendCoeff != *srcCoeff &&
+ kISA_BlendCoeff != *srcCoeff &&
+ kSC_BlendCoeff != *srcCoeff &&
+ kISC_BlendCoeff != *srcCoeff);
+ // same for dst
+ GrAssert(kDA_BlendCoeff != *dstCoeff &&
+ kIDA_BlendCoeff != *dstCoeff &&
+ kDC_BlendCoeff != *dstCoeff &&
+ kIDC_BlendCoeff != *dstCoeff);
+
+ if (SkToBool(kNoColorWrites_StateBit & fCurrDrawState.fFlagBits)) {
+ *srcCoeff = kZero_BlendCoeff;
+ *dstCoeff = kOne_BlendCoeff;
+ }
+
+ bool srcAIsOne = this->srcAlphaWillBeOne();
+ bool dstCoeffIsOne = kOne_BlendCoeff == *dstCoeff ||
+ (kSA_BlendCoeff == *dstCoeff && srcAIsOne);
+ bool dstCoeffIsZero = kZero_BlendCoeff == *dstCoeff ||
+ (kISA_BlendCoeff == *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_BlendCoeff == *srcCoeff && dstCoeffIsOne)) {
+ if (fCurrDrawState.fStencilSettings.doesWrite()) {
+ if (fCaps.fShaderSupport) {
+ return kDisableBlend_BlendOptFlag |
+ kEmitTransBlack_BlendOptFlag;
+ } else {
+ return kDisableBlend_BlendOptFlag;
+ }
+ } else {
+ return kSkipDraw_BlendOptFlag;
+ }
+ }
+
+ // check for coverage due to edge aa or coverage texture stage
+ bool hasCoverage = forceCoverage ||
+ fCurrDrawState.fEdgeAANumEdges > 0 ||
+ (layout & kCoverage_VertexLayoutBit) ||
+ (layout & kEdge_VertexLayoutBit);
+ for (int s = fCurrDrawState.fFirstCoverageStage;
+ !hasCoverage && s < kNumStages;
+ ++s) {
+ if (StageWillBeUsed(s, layout, fCurrDrawState)) {
+ hasCoverage = true;
+ }
+ }
+
+ // 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_BlendCoeff == *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
+ return kDisableBlend_BlendOptFlag;
+ } else if (kZero_BlendCoeff == *srcCoeff &&
+ fCaps.fShaderSupport) {
+ // 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_BlendCoeff;
+ *dstCoeff = kZero_BlendCoeff;
+ return kDisableBlend_BlendOptFlag |
+ kEmitTransBlack_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;
+ }
+ // We haven't implemented support for these optimizations in the
+ // fixed pipe (which is on its deathbed)
+ if (fCaps.fShaderSupport) {
+ if (dstCoeffIsZero) {
+ if (kZero_BlendCoeff == *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_BlendCoeff;
+ 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_BlendCoeff;
+ 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_BlendCoeff;
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ }
+ }
+ return kNone_BlendOpt;
+}
+
+bool GrDrawTarget::willUseHWAALines() const {
// there is a conflict between using smooth lines and our use of
// premultiplied alpha. Smooth lines tweak the incoming alpha value
// but not in a premul-alpha way. So we only use them when our alpha
// is 0xff and tweaking the color for partial coverage is OK
- return (kAntialias_StateBit & state.fFlagBits) &&
- CanDisableBlend(layout, state) &&
- CanTweakAlphaForCoverage(state.fDstBlend);
+ if (!fCaps.fHWAALineSupport ||
+ !(kAntialias_StateBit & fCurrDrawState.fFlagBits)) {
+ return false;
+ }
+ BlendOptFlags opts = this->getBlendOpts();
+ return (kDisableBlend_BlendOptFlag & opts) &&
+ (kCoverageAsAlpha_BlendOptFlag & opts);
}
bool GrDrawTarget::canApplyCoverage() const {
+ // we can correctly apply coverage if a) we have dual source blending
+ // or b) one of our blend optimizations applies.
return this->getCaps().fDualSourceBlendingSupport ||
- CanTweakAlphaForCoverage(fCurrDrawState.fDstBlend);
+ kNone_BlendOpt != this->getBlendOpts(true);
}
-bool GrDrawTarget::canDisableBlend() const {
- return CanDisableBlend(this->getGeomSrc().fVertexLayout, fCurrDrawState);
+bool GrDrawTarget::drawWillReadDst() const {
+ return SkToBool((kDisableBlend_BlendOptFlag | kSkipDraw_BlendOptFlag) &
+ this->getBlendOpts());
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/gpu/src/GrDrawTarget.h b/gpu/src/GrDrawTarget.h
index e411338..10633f5 100644
--- a/gpu/src/GrDrawTarget.h
+++ b/gpu/src/GrDrawTarget.h
@@ -131,7 +131,6 @@
// pairs for convexity while
// rasterizing. Set this if the
// source polygon is non-convex.
-
// subclass may use additional bits internally
kDummyStateBit,
kLastPublicStateBit = kDummyStateBit-1
@@ -524,13 +523,13 @@
GrColor getBlendConstant() const { return fCurrDrawState.fBlendConstant; }
/**
- * Determines if blend is effectively disabled.
+ * Determines if blending will require a read of a dst given the current
+ * state set on the draw target
*
- * @return true if blend can be disabled without changing the rendering
- * result given the current state including the vertex layout specified
- * with the vertex source.
+ * @return true if the dst surface will be read at each pixel hit by the
+ * a draw operation.
*/
- bool canDisableBlend() const;
+ bool drawWillReadDst() const;
/**
* Color alpha and coverage are two inputs to the drawing pipeline. For some
@@ -550,9 +549,7 @@
* color specified by setColor or per-vertex colors will give the right
* blending result.
*/
- bool canTweakAlphaForCoverage() const {
- return CanTweakAlphaForCoverage(fCurrDrawState.fDstBlend);
- }
+ bool canTweakAlphaForCoverage() const;
/**
* Determines the interpretation per-vertex edge data when the
@@ -568,7 +565,7 @@
* lines be used (if line primitive type is drawn)? (Note that lines are
* always 1 pixel wide)
*/
- virtual bool willUseHWAALines() const = 0;
+ bool willUseHWAALines() const;
/**
* Sets the edge data required for edge antialiasing.
@@ -653,6 +650,7 @@
private:
static const int TEX_COORD_BIT_CNT = kNumStages*kMaxTexCoords;
+
public:
/**
* Generates a bit indicating that a texture stage uses the position
@@ -1299,15 +1297,57 @@
protected:
- // Determines whether it is correct to apply partial pixel coverage
- // by multiplying the src color by the fractional coverage.
- static bool CanTweakAlphaForCoverage(GrBlendCoeff dstCoeff);
-
- // determines whether HW blending can be disabled or not
- static bool CanDisableBlend(GrVertexLayout layout, const DrState& state);
+ /**
+ * Optimizations for blending / coverage to be applied based on the current
+ * state.
+ * Subclasses that actually draw (as opposed to those that just buffer for
+ * playback) must implement the flags that replace the output color.
+ */
+ enum BlendOptFlags {
+ /**
+ * No optimization
+ */
+ kNone_BlendOpt = 0,
+ /**
+ * Don't draw at all
+ */
+ kSkipDraw_BlendOptFlag = 0x2,
+ /**
+ * Emit the src color, disable HW blending (replace dst with src)
+ */
+ kDisableBlend_BlendOptFlag = 0x4,
+ /**
+ * 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 = 0x1,
+ /**
+ * Instead of emitting a src color, emit coverage in the alpha channel
+ * and r,g,b are "don't cares".
+ */
+ kEmitCoverage_BlendOptFlag = 0x10,
+ /**
+ * Emit transparent black instead of the src color, no need to compute
+ * coverage.
+ */
+ kEmitTransBlack_BlendOptFlag = 0x8,
+ };
+ GR_DECL_BITFIELD_OPS_FRIENDS(BlendOptFlags);
- // determines whether HW AA lines can be used or not
- static bool CanUseHWAALines(GrVertexLayout layout, const DrState& state);
+ // Determines what optimizations can be applied based on the blend.
+ // The coeffecients may have to be tweaked in order for the optimization
+ // to work. srcCoeff and dstCoeff are optional params that receive the
+ // tweaked coeffecients.
+ // 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
+ BlendOptFlags getBlendOpts(bool forceCoverage = false,
+ GrBlendCoeff* srcCoeff = NULL,
+ GrBlendCoeff* dstCoeff = NULL) const;
+
+ // determine if src alpha is guaranteed to be one for all src pixels
+ bool srcAlphaWillBeOne() const;
enum GeometrySrcType {
kNone_GeometrySrcType, //<! src has not been specified
@@ -1431,4 +1471,6 @@
};
+GR_MAKE_BITFIELD_OPS(GrDrawTarget::BlendOptFlags);
+
#endif
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index 4b97fab..4b4140d 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -598,6 +598,20 @@
uniformCoeff = SkXfermode::kZero_Coeff;
}
+ // If we know the final color is going to be all zeros then we can
+ // simplify the color filter coeffecients. needComputedColor will then
+ // come out false below.
+ if (ProgramDesc::kTransBlack_ColorType == fProgramDesc.fColorType) {
+ colorCoeff = SkXfermode::kZero_Coeff;
+ if (SkXfermode::kDC_Coeff == uniformCoeff ||
+ SkXfermode::kDA_Coeff == uniformCoeff) {
+ uniformCoeff = SkXfermode::kZero_Coeff;
+ } else if (SkXfermode::kIDC_Coeff == uniformCoeff ||
+ SkXfermode::kIDA_Coeff == uniformCoeff) {
+ uniformCoeff = SkXfermode::kOne_Coeff;
+ }
+ }
+
bool needColorFilterUniform;
bool needComputedColor;
needBlendInputs(uniformCoeff, colorCoeff,
@@ -645,8 +659,13 @@
programData->fUniLocations.fColorUni = kUseUniform;
inColor = COL_UNI_NAME;
break;
+ case ProgramDesc::kTransBlack_ColorType:
+ GrAssert(!"needComputedColor should be false.");
+ break;
+ case ProgramDesc::kSolidWhite_ColorType:
+ break;
default:
- GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
+ GrCrash("Unknown color type.");
break;
}
}
@@ -708,15 +727,18 @@
}
}
- // if have all ones for the "dst" input to the color filter then we can make
- // additional optimizations.
- if (needColorFilterUniform && !inColor.size() &&
- (SkXfermode::kIDC_Coeff == uniformCoeff ||
- SkXfermode::kIDA_Coeff == uniformCoeff)) {
- uniformCoeff = SkXfermode::kZero_Coeff;
- bool bogus;
- needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
- &needColorFilterUniform, &bogus);
+ // if have all ones or zeros for the "dst" input to the color filter then we
+ // may be able to make additional optimizations.
+ if (needColorFilterUniform && needComputedColor && !inColor.size()) {
+ GrAssert(ProgramDesc::kSolidWhite_ColorType == fProgramDesc.fColorType);
+ bool uniformCoeffIsZero = SkXfermode::kIDC_Coeff == uniformCoeff ||
+ SkXfermode::kIDA_Coeff == uniformCoeff;
+ if (uniformCoeffIsZero) {
+ uniformCoeff = SkXfermode::kZero_Coeff;
+ bool bogus;
+ needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
+ &needColorFilterUniform, &bogus);
+ }
}
if (needColorFilterUniform) {
segments.fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
@@ -733,7 +755,16 @@
wroteFragColorZero = true;
} else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
segments.fFSCode.appendf("\tvec4 filteredColor;\n");
- const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
+ const char* color;
+ if (inColor.size()) {
+ color = inColor.c_str();
+ } else {
+ if (ProgramDesc::kSolidWhite_ColorType == fProgramDesc.fColorType) {
+ color = all_ones_vec(4);
+ } else {
+ color = all_zeros_vec(4);
+ }
+ }
addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
colorCoeff, color);
inColor = "filteredColor";
diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h
index 197da5d..dafa79d 100644
--- a/gpu/src/GrGLProgram.h
+++ b/gpu/src/GrGLProgram.h
@@ -139,10 +139,15 @@
}
};
+ // Specifies where the intitial color comes from before the stages are
+ // applied.
enum ColorType {
- kNone_ColorType = 0,
- kAttribute_ColorType = 1,
- kUniform_ColorType = 2,
+ kSolidWhite_ColorType,
+ kTransBlack_ColorType,
+ kAttribute_ColorType,
+ kUniform_ColorType,
+
+ kColorTypeCnt
};
// Dual-src blending makes use of a secondary output color that can be
// used as a per-pixel blend coeffecient. This controls whether a
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index 850fa60..b05f2c0 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -140,13 +140,6 @@
////////////////////////////////////////////////////////////////////////////////
-bool GrGpu::willUseHWAALines() const {
- return (kAntialias_StateBit & fCurrDrawState.fFlagBits) &&
- CanUseHWAALines(this->getGeomSrc().fVertexLayout, fCurrDrawState);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
const void* srcData, size_t rowBytes) {
this->handleDirtyContext();
diff --git a/gpu/src/GrGpu.h b/gpu/src/GrGpu.h
index 3193a56..9107554 100644
--- a/gpu/src/GrGpu.h
+++ b/gpu/src/GrGpu.h
@@ -219,7 +219,6 @@
void removeResource(GrResource* resource);
// GrDrawTarget overrides
- virtual bool willUseHWAALines() const;
virtual void clear(const GrIRect* rect, GrColor color);
protected:
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index ffbb557..b27815b 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -1811,8 +1811,8 @@
}
}
-void GrGpuGL::flushBlend(GrPrimitiveType type,
- GrBlendCoeff srcCoeff,
+void GrGpuGL::flushBlend(GrPrimitiveType type,
+ GrBlendCoeff srcCoeff,
GrBlendCoeff dstCoeff) {
if (GrIsPrimTypeLines(type) && this->willUseHWAALines()) {
if (fHWBlendDisabled) {
@@ -1827,7 +1827,11 @@
fHWDrawState.fDstBlend = kISA_BlendCoeff;
}
} else {
- bool blendOff = canDisableBlend();
+ // any optimization to disable blending should
+ // have already been applied and tweaked the coeffs
+ // to (1, 0).
+ bool blendOff = kOne_BlendCoeff == srcCoeff &&
+ kZero_BlendCoeff == dstCoeff;
if (fHWBlendDisabled != blendOff) {
if (blendOff) {
GL_CALL(Disable(GR_GL_BLEND));
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index 353394f..a2630c8 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -123,7 +123,10 @@
// line width
bool flushGLStateCommon(GrPrimitiveType type);
- // subclass should call this to flush the blend state
+ // Subclasses should call this to flush the blend state.
+ // The params should be the final coeffecients to apply
+ // (after any blending optimizations or dual source blending considerations
+ // have been accounted for).
void flushBlend(GrPrimitiveType type,
GrBlendCoeff srcCoeff,
GrBlendCoeff dstCoeff);
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
index c9d5844..336b687 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -172,7 +172,13 @@
return false;
}
- this->flushBlend(type, fCurrDrawState.fSrcBlend, fCurrDrawState.fDstBlend);
+ GrBlendCoeff srcCoeff, dstCoeff;
+ if (kSkipDraw_BlendOptFlag &
+ this->getBlendOpts(false, &srcCoeff, &dstCoeff)) {
+ return false;
+ }
+
+ this->flushBlend(type, srcCoeff, dstCoeff);
if (fDirtyFlags.fRenderTargetChanged) {
flushProjectionMatrix();
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index 9c0c9cc..f1bc5ec 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -204,14 +204,8 @@
pdesc.fVertexLayout = 0;
pdesc.fEmitsPointSize = random.nextF() > .5f;
- float colorType = random.nextF();
- if (colorType < 1.f / 3.f) {
- pdesc.fColorType = ProgramDesc::kAttribute_ColorType;
- } else if (colorType < 2.f / 3.f) {
- pdesc.fColorType = ProgramDesc::kUniform_ColorType;
- } else {
- pdesc.fColorType = ProgramDesc::kNone_ColorType;
- }
+ pdesc.fColorType = static_cast<int>(random.nextF() *
+ ProgramDesc::kColorTypeCnt);
int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
@@ -589,7 +583,7 @@
GrColorUnpackA(color) * ONE_OVER_255 \
}
-void GrGpuGLShaders::flushColor() {
+void GrGpuGLShaders::flushColor(GrColor color) {
const ProgramDesc& desc = fCurrentProgram.getDesc();
if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
// color will be specified per-vertex as an attribute
@@ -598,27 +592,27 @@
} else {
switch (desc.fColorType) {
case ProgramDesc::kAttribute_ColorType:
- if (fHWDrawState.fColor != fCurrDrawState.fColor) {
+ if (fHWDrawState.fColor != color) {
// OpenGL ES only supports the float varities of glVertexAttrib
- float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
+ float c[] = GR_COLOR_TO_VEC4(color);
GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(),
c));
- fHWDrawState.fColor = fCurrDrawState.fColor;
+ fHWDrawState.fColor = color;
}
break;
case ProgramDesc::kUniform_ColorType:
- if (fProgramData->fColor != fCurrDrawState.fColor) {
+ if (fProgramData->fColor != color) {
// OpenGL ES only supports the float varities of glVertexAttrib
- float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
+ float c[] = GR_COLOR_TO_VEC4(color);
GrAssert(GrGLProgram::kUnusedUniform !=
fProgramData->fUniLocations.fColorUni);
GL_CALL(Uniform4fv(fProgramData->fUniLocations.fColorUni,
1, c));
- fProgramData->fColor = fCurrDrawState.fColor;
+ fProgramData->fColor = color;
}
break;
- case ProgramDesc::kNone_ColorType:
- GrAssert(0xffffffff == fCurrDrawState.fColor);
+ case ProgramDesc::kSolidWhite_ColorType:
+ case ProgramDesc::kTransBlack_ColorType:
break;
default:
GrCrash("Unknown color type.");
@@ -648,7 +642,14 @@
fProgramCache->invalidateViewMatrices();
}
- buildProgram(type);
+ GrBlendCoeff srcCoeff;
+ GrBlendCoeff dstCoeff;
+ BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
+ if (kSkipDraw_BlendOptFlag & blendOpts) {
+ return false;
+ }
+
+ this->buildProgram(type, blendOpts, dstCoeff);
fProgramData = fProgramCache->getProgramData(fCurrentProgram);
if (NULL == fProgramData) {
GrAssert(!"Failed to create program!");
@@ -659,13 +660,18 @@
GL_CALL(UseProgram(fProgramData->fProgramID));
fHWProgramID = fProgramData->fProgramID;
}
- GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
- GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
-
fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
this->flushBlend(type, srcCoeff, dstCoeff);
- this->flushColor();
+ GrColor color;
+ if (blendOpts & kEmitTransBlack_BlendOptFlag) {
+ color = 0;
+ } else if (blendOpts & kEmitCoverage_BlendOptFlag) {
+ color = 0xffffffff;
+ } else {
+ color = fCurrDrawState.fColor;
+ }
+ this->flushColor(color);
GrMatrix* currViewMatrix;
if (GrGLProgram::kSetAsAttribute ==
@@ -836,9 +842,19 @@
fHWGeometryState.fArrayPtrsDirty = false;
}
-void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
+void GrGpuGLShaders::buildProgram(GrPrimitiveType type,
+ BlendOptFlags blendOpts,
+ GrBlendCoeff dstCoeff) {
ProgramDesc& desc = fCurrentProgram.fProgramDesc;
+ // This should already have been caught
+ GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts));
+
+ bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
+
+ bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag |
+ kEmitCoverage_BlendOptFlag));
+
// The descriptor is used as a cache key. Thus when a field of the
// descriptor will not affect program generation (because of the vertex
// layout in use or other descriptor field settings) it should be set
@@ -849,35 +865,47 @@
desc.fEmitsPointSize = kPoints_PrimitiveType == type;
- bool requiresAttributeColors = 0 != (desc.fVertexLayout & kColor_VertexLayoutBit);
+ bool requiresAttributeColors =
+ !skipColor && SkToBool(desc.fVertexLayout & kColor_VertexLayoutBit);
// fColorType records how colors are specified for the program. Strip
// the bit from the layout to avoid false negatives when searching for an
// existing program in the cache.
desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
- desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
+ desc.fColorFilterXfermode = skipColor ?
+ SkXfermode::kDst_Mode :
+ fCurrDrawState.fColorFilterXfermode;
-#if GR_AGGRESSIVE_SHADER_OPTS
- if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
- desc.fColorType = ProgramDesc::kNone_ColorType;
- } else
-#endif
-#if GR_GL_NO_CONSTANT_ATTRIBUTES
- if (!requiresAttributeColors) {
+ // no reason to do edge aa or look at per-vertex coverage if coverage is
+ // ignored
+ if (skipCoverage) {
+ desc.fVertexLayout &= ~(kEdge_VertexLayoutBit |
+ kCoverage_VertexLayoutBit);
+ }
+
+ bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
+ bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) ||
+ (!requiresAttributeColors &&
+ 0xffffffff == fCurrDrawState.fColor);
+ if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) {
+ desc.fColorType = ProgramDesc::kTransBlack_ColorType;
+ } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) {
+ desc.fColorType = ProgramDesc::kSolidWhite_ColorType;
+ } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
desc.fColorType = ProgramDesc::kUniform_ColorType;
- } else
-#endif
- {
- if (requiresAttributeColors) {} // suppress unused var warning
+ } else {
desc.fColorType = ProgramDesc::kAttribute_ColorType;
}
- desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
- desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit);
+ desc.fEdgeAANumEdges = skipCoverage ? 0 : fCurrDrawState.fEdgeAANumEdges;
+ desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 &&
+ SkToBool(fCurrDrawState.fFlagBits &
+ kEdgeAAConcave_StateBit);
int lastEnabledStage = -1;
- if (desc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit) {
+ if (!skipCoverage && (desc.fVertexLayout &
+ GrDrawTarget::kEdge_VertexLayoutBit)) {
desc.fVertexEdgeType = fCurrDrawState.fVertexEdgeType;
} else {
// use canonical value when not set to avoid cache misses
@@ -890,7 +918,10 @@
stage.fOptFlags = 0;
stage.setEnabled(this->isStageEnabled(s));
- if (stage.isEnabled()) {
+ bool skip = s < fCurrDrawState.fFirstCoverageStage ? skipColor :
+ skipCoverage;
+
+ if (!skip && stage.isEnabled()) {
lastEnabledStage = s;
GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
GrAssert(NULL != texture);
@@ -1005,22 +1036,19 @@
desc.fFirstCoverageStage = firstCoverageStage;
}
- // We could consider cases where the final color is solid (0xff alpha)
- // and the dst coeff can correctly be set to a non-dualsrc gl value.
- // (e.g. solid draw, and dst coeff is kZero. It's correct to make
- // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
- // kOne).
- if (this->getCaps().fDualSourceBlendingSupport) {
- if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
+ if (this->getCaps().fDualSourceBlendingSupport &&
+ !(blendOpts & (kEmitCoverage_BlendOptFlag |
+ kCoverageAsAlpha_BlendOptFlag))) {
+ if (kZero_BlendCoeff == dstCoeff) {
// write the coverage value to second color
desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput;
desc.fFirstCoverageStage = firstCoverageStage;
- } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
+ } else if (kSA_BlendCoeff == dstCoeff) {
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
// cover
desc.fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
desc.fFirstCoverageStage = firstCoverageStage;
- } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
+ } else if (kSC_BlendCoeff == dstCoeff) {
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
// cover
desc.fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h
index 6d9cccd..0c8322b 100644
--- a/gpu/src/GrGpuGLShaders.h
+++ b/gpu/src/GrGpuGLShaders.h
@@ -57,7 +57,7 @@
void flushTextureDomain(int stage);
// sets the color specified by GrDrawTarget::setColor()
- void flushColor();
+ void flushColor(GrColor color);
// sets the MVP matrix uniform for currently bound program
void flushViewMatrix();
@@ -77,7 +77,9 @@
static void DeleteProgram(const GrGLInterface* gl,
CachedData* programData);
- void buildProgram(GrPrimitiveType type);
+ void buildProgram(GrPrimitiveType typeBlend,
+ BlendOptFlags blendOpts,
+ GrBlendCoeff dstCoeff);
ProgramCache* fProgramCache;
CachedData* fProgramData;
diff --git a/gpu/src/GrInOrderDrawBuffer.cpp b/gpu/src/GrInOrderDrawBuffer.cpp
index 946d31c..5e3c769 100644
--- a/gpu/src/GrInOrderDrawBuffer.cpp
+++ b/gpu/src/GrInOrderDrawBuffer.cpp
@@ -616,9 +616,3 @@
INHERITED::clipWillBeSet(newClip);
fClipSet = true;
}
-
-bool GrInOrderDrawBuffer::willUseHWAALines() const {
- return this->getCaps().fHWAALineSupport &&
- CanUseHWAALines(this->getGeomSrc().fVertexLayout, fCurrDrawState);
-}
-
diff --git a/gpu/src/GrInOrderDrawBuffer.h b/gpu/src/GrInOrderDrawBuffer.h
index 3d1ec8c..3273525 100644
--- a/gpu/src/GrInOrderDrawBuffer.h
+++ b/gpu/src/GrInOrderDrawBuffer.h
@@ -91,8 +91,6 @@
virtual void clear(const GrIRect* rect, GrColor color);
- virtual bool willUseHWAALines() const;
-
private:
struct Draw {