aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-05-16 20:56:06 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-05-16 20:56:06 +0000
commitf2d91557b2c353429e40aa0f87c523119002f41b (patch)
tree75ac4c31ac3cbf4af818072543811a1274e6625c
parent852fa0fafaad359f3feffae28747e17ccadc70c5 (diff)
separate coverage stages from color stages.
Review URL: http://codereview.appspot.com/4538064/ git-svn-id: http://skia.googlecode.com/svn/trunk@1339 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gpu/include/GrDrawTarget.h31
-rw-r--r--gpu/src/GrGLProgram.cpp392
-rw-r--r--gpu/src/GrGLProgram.h1
-rw-r--r--gpu/src/GrGpuGLShaders.cpp51
-rw-r--r--include/core/SkXfermode.h10
5 files changed, 362 insertions, 123 deletions
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index 93b381dd9f..5020e1659c 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -137,10 +137,16 @@ protected:
// all DrState members should default to something
// valid by the memset
memset(this, 0, sizeof(DrState));
- // This is an exception to our memset, since it will
- // result in no change.
+
+ // memset exceptions
fColorFilterXfermode = SkXfermode::kDstIn_Mode;
+ fFirstCoverageStage = kNumStages;
+
+ // pedantic assertion that our ptrs will
+ // be NULL (0 ptr is mem addr 0)
GrAssert((intptr_t)(void*)NULL == 0LL);
+
+ // default stencil setting should be disabled
GrAssert(fStencilSettings.isDisabled());
}
uint32_t fFlagBits;
@@ -150,6 +156,7 @@ protected:
GrTexture* fTextures[kNumStages];
GrEffect* fEffects[kNumStages];
GrSamplerState fSamplerStates[kNumStages];
+ int fFirstCoverageStage;
GrRenderTarget* fRenderTarget;
GrColor fColor;
DrawFace fDrawFace;
@@ -343,6 +350,26 @@ public:
void setDrawFace(DrawFace face) { fCurrDrawState.fDrawFace = face; }
/**
+ * A common pattern is to compute a color with the initial stages and then
+ * modulate that color by a coverage value in later stage(s) (AA, mask-
+ * filters, glyph mask, etc). Color-filters, xfermodes, etc should be
+ * computed based on the pre-coverage-modulated color. The division of
+ * stages between color-computing and coverage-computing is specified by
+ * this method. Initially this is kNumStages (all stages are color-
+ * computing).
+ */
+ void setFirstCoverageStage(int firstCoverageStage) {
+ fCurrDrawState.fFirstCoverageStage = firstCoverageStage;
+ }
+
+ /**
+ * Gets the index of the first coverage-computing stage.
+ */
+ int getFirstCoverageStage() const {
+ return fCurrDrawState.fFirstCoverageStage;
+ }
+
+ /**
* Gets whether the target is drawing clockwise, counterclockwise,
* or both faces.
* @return the current draw face(s).
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index ab327d0e7d..bd95f3cb8c 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -86,6 +86,20 @@ static inline const char* vector_all_coords(int count) {
return ALL[count];
}
+static inline const char* all_ones_vec(int count) {
+ static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
+ "vec3(1,1,1)", "vec4(1,1,1,1)"};
+ GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC));
+ return ONESVEC[count];
+}
+
+static inline const char* all_zeros_vec(int count) {
+ static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
+ "vec3(0,0,0)", "vec4(0,0,0,0)"};
+ GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC));
+ return ZEROSVEC[count];
+}
+
static void tex_matrix_name(int stage, GrStringBuilder* s) {
#if GR_GL_ATTRIBUTE_MATRICES
*s = "aTexM";
@@ -183,55 +197,157 @@ void GrGLProgram::doGLPost() const {
}
}
+// assigns modulation of two vars to an output var
+// if either var is "" then assign to the other var
+// if both are "" then assign all ones
+static inline void modulate_helper(const char* outputVar,
+ const char* var0,
+ const char* var1,
+ GrStringBuilder* code) {
+ GrAssert(NULL != outputVar);
+ GrAssert(NULL != var0);
+ GrAssert(NULL != var1);
+ GrAssert(NULL != code);
+
+ bool has0 = '\0' != *var0;
+ bool has1 = '\0' != *var1;
+
+ if (!has0 && !has1) {
+ code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
+ } else if (!has0) {
+ code->appendf("\t%s = %s;\n", outputVar, var1);
+ } else if (!has1) {
+ code->appendf("\t%s = %s;\n", outputVar, var0);
+ } else {
+ code->appendf("\t%s = %s * %s;\n", outputVar, var0, var1);
+ }
+}
+
+// assigns addition of two vars to an output var
+// if either var is "" then assign to the other var
+// if both are "" then assign all zeros
+static inline void add_helper(const char* outputVar,
+ const char* var0,
+ const char* var1,
+ GrStringBuilder* code) {
+ GrAssert(NULL != outputVar);
+ GrAssert(NULL != var0);
+ GrAssert(NULL != var1);
+ GrAssert(NULL != code);
+
+ bool has0 = '\0' != *var0;
+ bool has1 = '\0' != *var1;
+
+ if (!has0 && !has1) {
+ code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
+ } else if (!has0) {
+ code->appendf("\t%s = %s;\n", outputVar, var1);
+ } else if (!has1) {
+ code->appendf("\t%s = %s;\n", outputVar, var0);
+ } else {
+ code->appendf("\t%s = %s + %s;\n", outputVar, var0, var1);
+ }
+}
+
+// given two blend coeffecients determine whether the src
+// and/or dst computation can be omitted.
+static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
+ SkXfermode::Coeff dstCoeff,
+ bool* needSrcValue,
+ bool* needDstValue) {
+ if (SkXfermode::kZero_Coeff == srcCoeff) {
+ switch (dstCoeff) {
+ // these all read the src
+ case SkXfermode::kSC_Coeff:
+ case SkXfermode::kISC_Coeff:
+ case SkXfermode::kSA_Coeff:
+ case SkXfermode::kISA_Coeff:
+ *needSrcValue = true;
+ break;
+ default:
+ *needSrcValue = false;
+ break;
+ }
+ } else {
+ *needSrcValue = true;
+ }
+ if (SkXfermode::kZero_Coeff == dstCoeff) {
+ switch (srcCoeff) {
+ // these all read the dst
+ case SkXfermode::kDC_Coeff:
+ case SkXfermode::kIDC_Coeff:
+ case SkXfermode::kDA_Coeff:
+ case SkXfermode::kIDA_Coeff:
+ *needDstValue = true;
+ break;
+ default:
+ *needDstValue = false;
+ break;
+ }
+ } else {
+ *needDstValue = true;
+ }
+}
+
/**
- * Create a text coefficient to be used in fragment shader code.
+ * Create a blend_coeff * value string to be used in shader code. Sets empty
+ * string if result is trivially zero.
*/
-static void coefficientString(GrStringBuilder* str, SkXfermode::Coeff coeff,
- const char* src, const char* dst) {
+static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
+ const char* src, const char* dst,
+ const char* value) {
+
switch (coeff) {
case SkXfermode::kZero_Coeff: /** 0 */
- *str = "0.0";
+ *str = "";
break;
case SkXfermode::kOne_Coeff: /** 1 */
- *str = "1.0";
+ *str = value;
+ break;
+ case SkXfermode::kSC_Coeff:
+ str->printf("(%s * %s)", src, value);
+ break;
+ case SkXfermode::kISC_Coeff:
+ str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
+ break;
+ case SkXfermode::kDC_Coeff:
+ str->printf("(%s * %s)", dst, value);
+ break;
+ case SkXfermode::kIDC_Coeff:
+ str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
break;
case SkXfermode::kSA_Coeff: /** src alpha */
- str->appendf("%s.a", src);
+ str->printf("(%s.a * %s)", src, value);
break;
case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
- str->appendf("(1.0 - %s.a)", src);
+ str->printf("((1.0 - %s.a) * %s)", src, value);
break;
case SkXfermode::kDA_Coeff: /** dst alpha */
- str->appendf("%s.a", dst);
+ str->printf("(%s.a * %s)", dst, value);
break;
case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
- str->appendf("(1.0 - %s.a)", dst);
- break;
- case SkXfermode::kSC_Coeff:
- str->append(src);
+ str->printf("((1.0 - %s.a) * %s)", dst, value);
break;
default:
+ GrCrash("Unexpected xfer coeff.");
break;
}
}
-
/**
* Adds a line to the fragment shader code which modifies the color by
* the specified color filter.
*/
-static void addColorFilter(GrStringBuilder* FSCode, const char * outputVar,
- SkXfermode::Mode colorFilterXfermode, const char* dstColor) {
- SkXfermode::Coeff srcCoeff, dstCoeff;
- SkDEBUGCODE(bool success =)
- SkXfermode::ModeAsCoeff(colorFilterXfermode, &srcCoeff, &dstCoeff);
- // We currently do not handle modes that cannot be represented as
- // coefficients.
- GrAssert(success);
- GrStringBuilder srcCoeffStr, dstCoeffStr;
- coefficientString(&srcCoeffStr, srcCoeff, COL_FILTER_UNI_NAME, dstColor);
- coefficientString(&dstCoeffStr, dstCoeff, COL_FILTER_UNI_NAME, dstColor);
- FSCode->appendf("\t%s = %s*%s + %s*%s;\n", outputVar, srcCoeffStr.c_str(),
- COL_FILTER_UNI_NAME, dstCoeffStr.c_str(), dstColor);
+static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
+ SkXfermode::Coeff uniformCoeff,
+ SkXfermode::Coeff colorCoeff,
+ const char* inColor) {
+ GrStringBuilder colorStr, constStr;
+ blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
+ inColor, inColor);
+ blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
+ inColor, COL_FILTER_UNI_NAME);
+
+ add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
}
bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
@@ -241,6 +357,22 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
programData->fUniLocations.reset();
+ SkXfermode::Coeff colorCoeff, uniformCoeff;
+ // The rest of transfer mode color filters have not been implemented
+ if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
+ GR_DEBUGCODE(bool success =)
+ SkXfermode::ModeAsCoeff(fProgramDesc.fColorFilterXfermode, &uniformCoeff, &colorCoeff);
+ GR_DEBUGASSERT(success);
+ } else {
+ colorCoeff = SkXfermode::kOne_Coeff;
+ uniformCoeff = SkXfermode::kZero_Coeff;
+ }
+
+ bool needColorFilterUniform;
+ bool needComputedColor;
+ needBlendInputs(uniformCoeff, colorCoeff,
+ &needColorFilterUniform, &needComputedColor);
+
#if GR_GL_ATTRIBUTE_MATRICES
segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
@@ -258,21 +390,23 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
// incoming color to current stage being processed.
GrStringBuilder inColor;
- switch (fProgramDesc.fColorType) {
- case ProgramDesc::kAttribute_ColorType:
- segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
- segments.fVaryings.append("varying vec4 vColor;\n");
- segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
- inColor = "vColor";
- break;
- case ProgramDesc::kUniform_ColorType:
- segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
- programData->fUniLocations.fColorUni = kUseUniform;
- inColor = COL_UNI_NAME;
- break;
- case ProgramDesc::kNone_ColorType:
- inColor = "";
- break;
+ if (needComputedColor) {
+ switch (fProgramDesc.fColorType) {
+ case ProgramDesc::kAttribute_ColorType:
+ segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
+ segments.fVaryings.append("varying vec4 vColor;\n");
+ segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
+ inColor = "vColor";
+ break;
+ case ProgramDesc::kUniform_ColorType:
+ segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
+ programData->fUniLocations.fColorUni = kUseUniform;
+ inColor = COL_UNI_NAME;
+ break;
+ default:
+ GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
+ break;
+ }
}
if (fProgramDesc.fUsesEdgeAA) {
@@ -294,74 +428,82 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
}
}
- bool useColorFilter =
- // The rest of transfer mode color filters have not been implemented
- fProgramDesc.fColorFilterXfermode <= SkXfermode::kMultiply_Mode
- // This mode has no effect.
- && fProgramDesc.fColorFilterXfermode != SkXfermode::kDst_Mode;
- bool onlyUseColorFilter = useColorFilter
- && (fProgramDesc.fColorFilterXfermode == SkXfermode::kClear_Mode
- || fProgramDesc.fColorFilterXfermode == SkXfermode::kSrc_Mode);
- if (useColorFilter) {
- // Set up a uniform for the color
- segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
- programData->fUniLocations.fColorFilterUni = kUseUniform;
- }
-
- // for each enabled stage figure out what the input coordinates are
- // and count the number of stages in use.
- const char* stageInCoords[GrDrawTarget::kNumStages];
- int numActiveStages = 0;
+ ///////////////////////////////////////////////////////////////////////////
+ // compute the final color
- if (!onlyUseColorFilter) {
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
+ // if we have color stages string them together, feeding the output color
+ // of each to the next and generating code for each stage.
+ if (needComputedColor) {
+ GrStringBuilder outColor;
+ for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
if (fProgramDesc.fStages[s].fEnabled) {
- if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
- stageInCoords[s] = POS_ATTR_NAME;
+ // create var to hold stage result
+ outColor = "color";
+ outColor.appendS32(s);
+ segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
+
+ const char* inCoords;
+ // figure out what our input coords are
+ if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
+ layout) {
+ inCoords = POS_ATTR_NAME;
} else {
int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
// we better have input tex coordinates if stage is enabled.
GrAssert(tcIdx >= 0);
GrAssert(texCoordAttrs[tcIdx].size());
- stageInCoords[s] = texCoordAttrs[tcIdx].c_str();
- }
- ++numActiveStages;
- }
- }
- }
-
- // if we have active stages string them together, feeding the output color
- // of each to the next and generating code for each stage.
- if (numActiveStages) {
- int currActiveStage = 0;
- GrStringBuilder outColor;
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- if (fProgramDesc.fStages[s].fEnabled) {
- if (currActiveStage < (numActiveStages - 1) || useColorFilter) {
- outColor = "color";
- outColor.appendS32(currActiveStage);
- segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
- } else {
- outColor = "gl_FragColor";
+ inCoords = texCoordAttrs[tcIdx].c_str();
}
genStageCode(s,
fProgramDesc.fStages[s],
inColor.size() ? inColor.c_str() : NULL,
outColor.c_str(),
- stageInCoords[s],
+ inCoords,
&segments,
&programData->fUniLocations.fStages[s]);
- ++currActiveStage;
inColor = outColor;
}
}
- if (useColorFilter) {
- addColorFilter(&segments.fFSCode, "gl_FragColor",
- fProgramDesc.fColorFilterXfermode, outColor.c_str());
- }
+ }
- } else {
+ // 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 (needColorFilterUniform) {
+ segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
+ programData->fUniLocations.fColorFilterUni = kUseUniform;
+ }
+
+ bool wroteFragColorZero = false;
+ if (SkXfermode::kZero_Coeff == uniformCoeff &&
+ SkXfermode::kZero_Coeff == colorCoeff) {
+ segments.fFSCode.appendf("\tgl_FragColor = %s;\n", all_zeros_vec(4));
+ 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);
+ addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
+ colorCoeff, color);
+ inColor = "filteredColor";
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // compute the partial coverage (coverage stages and edge aa)
+
+ GrStringBuilder inCoverage;
+ bool coverageIsScalar = false;
+
+ // we will want to compute coverage for some blend when there is no
+ // color (when dual source blending is enabled). But for now we have this if
+ if (!wroteFragColorZero) {
if (fProgramDesc.fUsesEdgeAA) {
// FIXME: put the a's in a loop
segments.fFSCode.append(
@@ -373,25 +515,68 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
"\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n"
"\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n"
"\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n");
- if (inColor.size()) {
- inColor.append(" * edgeAlpha");
- } else {
- inColor = "vec4(edgeAlpha)";
+ inCoverage = "edgeAlpha";
+ coverageIsScalar = true;
+ }
+
+ GrStringBuilder outCoverage;
+ const int& startStage = fProgramDesc.fFirstCoverageStage;
+ for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
+ if (fProgramDesc.fStages[s].fEnabled) {
+
+ // create var to hold stage output
+ outCoverage = "coverage";
+ outCoverage.appendS32(s);
+ segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
+
+ const char* inCoords;
+ // figure out what our input coords are
+ if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
+ inCoords = POS_ATTR_NAME;
+ } else {
+ int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
+ // we better have input tex coordinates if stage is enabled.
+ GrAssert(tcIdx >= 0);
+ GrAssert(texCoordAttrs[tcIdx].size());
+ inCoords = texCoordAttrs[tcIdx].c_str();
+ }
+
+ genStageCode(s,
+ fProgramDesc.fStages[s],
+ inCoverage.size() ? inCoverage.c_str() : NULL,
+ outCoverage.c_str(),
+ inCoords,
+ &segments,
+ &programData->fUniLocations.fStages[s]);
+ inCoverage = outCoverage;
+ coverageIsScalar = false;
}
}
- // we may not have any incoming color
- const char * incomingColor = (inColor.size() ? inColor.c_str()
- : "vec4(1,1,1,1)");
- if (useColorFilter) {
- addColorFilter(&segments.fFSCode, "gl_FragColor",
- fProgramDesc.fColorFilterXfermode, incomingColor);
- } else {
- segments.fFSCode.appendf("\tgl_FragColor = %s;\n", incomingColor);
+ }
+
+ // TODO: ADD dual source blend output based on coverage here
+
+ ///////////////////////////////////////////////////////////////////////////
+ // combine color and coverage as frag color
+
+ if (!wroteFragColorZero) {
+ if (coverageIsScalar && !inColor.size()) {
+ GrStringBuilder oldCoverage = inCoverage;
+ inCoverage.swap(oldCoverage);
+ inCoverage.printf("vec4(%s,%s,%s,%s)", oldCoverage.c_str(),
+ oldCoverage.c_str(), oldCoverage.c_str(),
+ oldCoverage.c_str());
}
+ modulate_helper("gl_FragColor", inColor.c_str(),
+ inCoverage.c_str(), &segments.fFSCode);
}
+
segments.fVSCode.append("}\n");
segments.fFSCode.append("}\n");
+ ///////////////////////////////////////////////////////////////////////////
+ // compile and setup attribs and unis
+
if (!CompileFSAndVS(segments, programData)) {
return false;
}
@@ -565,7 +750,6 @@ bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
}
}
-
GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
GR_GL(LinkProgram(progID));
@@ -610,7 +794,7 @@ void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const
GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
}
- if (fProgramDesc.fUsesEdgeAA) {
+ if (kUseUniform == programData->fUniLocations.fEdgesUni) {
programData->fUniLocations.fEdgesUni =
GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h
index 74078e30b3..64d7088b72 100644
--- a/gpu/src/GrGLProgram.h
+++ b/gpu/src/GrGLProgram.h
@@ -99,6 +99,7 @@ private:
kUniform_ColorType = 2,
} fColorType;
+ int fFirstCoverageStage;
bool fEmitsPointSize;
bool fUsesEdgeAA;
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index 125b8205af..bcf29ae56d 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -169,6 +169,14 @@ void GrGpuGLShaders::ProgramUnitTest() {
GrRandom random;
for (int t = 0; t < NUM_TESTS; ++t) {
+#if 0
+ GrPrintf("\nTest Program %d\n-------------\n", t);
+ static const int stop = -1;
+ if (t == stop) {
+ int breakpointhere = 9;
+ }
+#endif
+
pdesc.fVertexLayout = 0;
pdesc.fEmitsPointSize = random.nextF() > .5f;
float colorType = random.nextF();
@@ -179,6 +187,15 @@ void GrGpuGLShaders::ProgramUnitTest() {
} else {
pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
}
+
+ int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
+ pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
+
+ idx = (int)(random.nextF() * (kNumStages+1));
+ pdesc.fFirstCoverageStage = idx;
+
+ pdesc.fUsesEdgeAA = (random.nextF() > .5f);
+
for (int s = 0; s < kNumStages; ++s) {
// enable the stage?
if (random.nextF() > .5f) {
@@ -194,19 +211,15 @@ void GrGpuGLShaders::ProgramUnitTest() {
if (random.nextF() > .5f) {
pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
}
- }
-
- for (int s = 0; s < kNumStages; ++s) {
- int x;
pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
- x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
- pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
- x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
- pdesc.fStages[s].fModulation = STAGE_MODULATES[x];
- x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
- pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x];
- x = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
- pdesc.fStages[s].fFetchMode = FETCH_MODES[x];
+ idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
+ pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
+ idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
+ pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
+ idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
+ pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
+ idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
+ pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
}
GrGLProgram::CachedData cachedData;
program.genProgram(&cachedData);
@@ -219,7 +232,6 @@ void GrGpuGLShaders::ProgramUnitTest() {
}
}
-
GrGpuGLShaders::GrGpuGLShaders() {
resetContext();
@@ -668,6 +680,18 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
// existing program in the cache.
desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
+ 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;
@@ -764,7 +788,6 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
fCurrentProgram.fStageEffects[s] = NULL;
}
}
- desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
}
diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h
index 4d46bb919a..6ab9d6d562 100644
--- a/include/core/SkXfermode.h
+++ b/include/core/SkXfermode.h
@@ -103,11 +103,15 @@ public:
kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
kXor_Mode, //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
- // these modes are defined in the SVG Compositing standard
+ // all remaining modes are defined in the SVG Compositing standard
// http://www.w3.org/TR/2009/WD-SVGCompositing-20090430/
kPlus_Mode,
- kMultiply_Mode,
- kScreen_Mode,
+ kMultiply_Mode,
+
+ // all above modes can be expressed as pair of src/dst Coeffs
+ kCoeffModesCnt,
+
+ kScreen_Mode = kCoeffModesCnt,
kOverlay_Mode,
kDarken_Mode,
kLighten_Mode,