Add dual source blending support for proper blending with coverage.
Review URL: http://codereview.appspot.com/4535088/
git-svn-id: http://skia.googlecode.com/svn/trunk@1390 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index bbf9719..bf68def 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -195,6 +195,15 @@
pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
+ if (fDualSourceBlendingSupport) {
+ pdesc.fDualSrcOutput =
+ (GrGLProgram::ProgramDesc::DualSrcOutput)
+ (int)(random.nextF() * GrGLProgram::ProgramDesc::kDualSrcOutputCnt);
+ } else {
+ pdesc.fDualSrcOutput =
+ GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
+ }
+
for (int s = 0; s < kNumStages; ++s) {
// enable the stage?
if (random.nextF() > .5f) {
@@ -234,7 +243,17 @@
GrGpuGLShaders::GrGpuGLShaders() {
resetContext();
+ int major, minor;
+ gl_version(&major, &minor);
+
f4X4DownsampleFilterSupport = true;
+ if (GR_GL_SUPPORT_DESKTOP) {
+ fDualSourceBlendingSupport =
+ major > 3 ||(3 == major && 3 <= minor) ||
+ has_gl_extension("GL_ARB_blend_func_extended");
+ } else {
+ fDualSourceBlendingSupport = false;
+ }
fProgramData = NULL;
fProgramCache = new ProgramCache();
@@ -533,6 +552,11 @@
GR_GL(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();
@@ -677,16 +701,6 @@
desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
- // coverage vs. color only applies when there is a color filter
- // (currently)
- if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
- desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
- } else {
- // use canonical value when this won't affect generated
- // code to prevent duplicate programs.
- desc.fFirstCoverageStage = kNumStages;
- }
-
#if GR_AGGRESSIVE_SHADER_OPTS
if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
@@ -704,12 +718,15 @@
desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
+ int lastEnabledStage = -1;
+
for (int s = 0; s < kNumStages; ++s) {
GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
stage.fEnabled = this->isStageEnabled(s);
if (stage.fEnabled) {
+ lastEnabledStage = s;
GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
GrAssert(NULL != texture);
// we matrix to invert when orientation is TopDown, so make sure
@@ -775,6 +792,43 @@
stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
}
}
+
+ desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
+ // use canonical value when coverage/color distinction won't affect
+ // generated code to prevent duplicate programs.
+ desc.fFirstCoverageStage = kNumStages;
+ if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
+ // color filter is applied between color/coverage computation
+ if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
+ desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
+ }
+
+ // 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 (fDualSourceBlendingSupport) {
+ if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
+ // write the coverage value to second color
+ desc.fDualSrcOutput =
+ GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
+ desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
+ } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
+ // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
+ // cover
+ desc.fDualSrcOutput =
+ GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
+ desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
+ } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
+ // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
+ // cover
+ desc.fDualSrcOutput =
+ GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
+ desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
+ }
+ }
+ }
}