Add color filters to gpu path.
git-svn-id: http://skia.googlecode.com/svn/trunk@1297 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index abed043..f89de9b 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -21,6 +21,8 @@
#include "GrGLEffect.h"
#include "GrMemory.h"
+#include "SkXfermode.h"
+
namespace {
const char* GrPrecision() {
@@ -52,6 +54,7 @@
#define POS_ATTR_NAME "aPosition"
#define COL_ATTR_NAME "aColor"
#define COL_UNI_NAME "uColor"
+#define COL_FILTER_UNI_NAME "uColorFilter"
static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
*s = "aTexCoord";
@@ -174,6 +177,57 @@
}
}
+/**
+ * Create a text coefficient to be used in fragment shader code.
+ */
+static void coefficientString(GrStringBuilder& str, SkXfermode::Coeff coeff,
+ const char* src, const char* dst) {
+ switch (coeff) {
+ case SkXfermode::kZero_Coeff: /** 0 */
+ str = "0.0";
+ break;
+ case SkXfermode::kOne_Coeff: /** 1 */
+ str = "1.0";
+ break;
+ case SkXfermode::kSA_Coeff: /** src alpha */
+ str.appendf("%s.a", src);
+ break;
+ case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
+ str.appendf("(1.0 - %s.a)", src);
+ break;
+ case SkXfermode::kDA_Coeff: /** dst alpha */
+ str.appendf("%s.a", dst);
+ 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);
+ break;
+ default:
+ 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;
+ 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);
+}
+
bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
ShaderCodeSegments segments;
@@ -230,23 +284,39 @@
}
}
+ 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;
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- if (fProgramDesc.fStages[s].fEnabled) {
- if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
- stageInCoords[s] = 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();
+ if (!onlyUseColorFilter) {
+ for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
+ if (fProgramDesc.fStages[s].fEnabled) {
+ if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
+ stageInCoords[s] = 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;
}
- ++numActiveStages;
}
}
@@ -254,10 +324,10 @@
// 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) {
- GrStringBuilder outColor;
- if (currActiveStage < (numActiveStages - 1)) {
+ if (currActiveStage < (numActiveStages - 1) || useColorFilter) {
outColor = "color";
outColor.appendS32(currActiveStage);
segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
@@ -276,9 +346,21 @@
inColor = outColor;
}
}
+ if (useColorFilter) {
+ addColorFilter(segments.fFSCode, "gl_FragColor",
+ fProgramDesc.fColorFilterXfermode, outColor.c_str());
+ }
+
} else {
// we may not have any incoming color
- segments.fFSCode.appendf("\tgl_FragColor = %s;\n", (inColor.size() ? inColor.c_str() : "vec4(1,1,1,1);\n"));
+ 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);
+ }
}
segments.fVSCode.append("}\n");
segments.fFSCode.append("}\n");
@@ -495,6 +577,11 @@
GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
}
+ if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
+ programData->fUniLocations.fColorFilterUni =
+ GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
+ GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
+ }
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
StageUniLocations& locations = programData->fUniLocations.fStages[s];
@@ -550,6 +637,7 @@
}
programData->fViewMatrix = GrMatrix::InvalidMatrix();
programData->fColor = GrColor_ILLEGAL;
+ programData->fColorFilterColor = GrColor_ILLEGAL;
}
//============================================================================