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/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;