Create fragment processor for performing input color blend with child processor
The new FP is used to implement SkXM::Mode color filters and SkXM::Mode image filters. Also, these now support all advanced SkXM::Mode xfermodes.
Review URL: https://codereview.chromium.org/1334293003
diff --git a/src/gpu/GrBlend.cpp b/src/gpu/GrBlend.cpp
new file mode 100644
index 0000000..72a89d8
--- /dev/null
+++ b/src/gpu/GrBlend.cpp
@@ -0,0 +1,124 @@
+/*
+* Copyright 2015 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "GrBlend.h"
+
+/**
+ * MaskedColor is used to evaluate the color and valid color component flags through the
+ * blending equation. Could possibly extend this to be used more broadly.
+ */
+class MaskedColor {
+public:
+ MaskedColor(GrColor color, GrColorComponentFlags flags)
+ : fColor(color)
+ , fFlags(flags) {}
+
+ MaskedColor() {}
+
+ void set(GrColor color, GrColorComponentFlags flags) {
+ fColor = color;
+ fFlags = flags;
+ }
+
+ static MaskedColor Invert(const MaskedColor& in) {
+ return MaskedColor(GrInvertColor(in.fColor), in.fFlags);
+ }
+
+ static MaskedColor ExtractAlpha(const MaskedColor& in) {
+ GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ?
+ kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags;
+ return MaskedColor(GrColorPackA4(GrColorUnpackA(in.fColor)), flags);
+ }
+
+ static MaskedColor ExtractInverseAlpha(const MaskedColor& in) {
+ GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ?
+ kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags;
+ return MaskedColor(GrColorPackA4(0xFF - GrColorUnpackA(in.fColor)), flags);
+ }
+
+ static MaskedColor Mul(const MaskedColor& a, const MaskedColor& b) {
+ GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0) |
+ b.componentsWithValue(0);
+ return MaskedColor(GrColorMul(a.fColor, b.fColor), outFlags);
+ }
+
+ static MaskedColor SatAdd(const MaskedColor& a, const MaskedColor& b) {
+ GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0xFF) |
+ b.componentsWithValue(0xFF);
+ return MaskedColor(GrColorSatAdd(a.fColor, b.fColor), outFlags);
+ }
+
+ GrColor color() const { return fColor; }
+
+ GrColorComponentFlags validFlags () const { return fFlags; }
+
+private:
+ GrColorComponentFlags componentsWithValue(unsigned value) const {
+ GrColorComponentFlags flags = kNone_GrColorComponentFlags;
+ if ((kR_GrColorComponentFlag & fFlags) && value == GrColorUnpackR(fColor)) {
+ flags |= kR_GrColorComponentFlag;
+ }
+ if ((kG_GrColorComponentFlag & fFlags) && value == GrColorUnpackG(fColor)) {
+ flags |= kG_GrColorComponentFlag;
+ }
+ if ((kB_GrColorComponentFlag & fFlags) && value == GrColorUnpackB(fColor)) {
+ flags |= kB_GrColorComponentFlag;
+ }
+ if ((kA_GrColorComponentFlag & fFlags) && value == GrColorUnpackA(fColor)) {
+ flags |= kA_GrColorComponentFlag;
+ }
+ return flags;
+ }
+
+ GrColor fColor;
+ GrColorComponentFlags fFlags;
+};
+
+static MaskedColor get_term(GrBlendCoeff coeff, const MaskedColor& src, const MaskedColor& dst,
+ const MaskedColor& value) {
+ switch (coeff) {
+ case kZero_GrBlendCoeff:
+ return MaskedColor(0, kRGBA_GrColorComponentFlags);
+ case kOne_GrBlendCoeff:
+ return value;
+ case kDC_GrBlendCoeff:
+ return MaskedColor::Mul(dst, value);
+ case kIDC_GrBlendCoeff:
+ return MaskedColor::Mul(MaskedColor::Invert(dst), value);
+ case kDA_GrBlendCoeff:
+ return MaskedColor::Mul(MaskedColor::ExtractAlpha(dst), value);
+ case kIDA_GrBlendCoeff:
+ return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(dst), value);
+ case kSC_GrBlendCoeff:
+ return MaskedColor::Mul(src, value);
+ case kISC_GrBlendCoeff:
+ return MaskedColor::Mul(MaskedColor::Invert(src), value);
+ case kSA_GrBlendCoeff:
+ return MaskedColor::Mul(MaskedColor::ExtractAlpha(src), value);
+ case kISA_GrBlendCoeff:
+ return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(src), value);
+ default:
+ SkFAIL("Illegal coefficient");
+ return MaskedColor();
+ }
+}
+
+void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff,
+ GrColor srcColor, GrColorComponentFlags srcColorFlags,
+ GrColor dstColor, GrColorComponentFlags dstColorFlags,
+ GrColor* outColor,
+ GrColorComponentFlags* outFlags) {
+ MaskedColor src(srcColor, srcColorFlags);
+ MaskedColor dst(dstColor, dstColorFlags);
+
+ MaskedColor srcTerm = get_term(srcCoeff, src, dst, src);
+ MaskedColor dstTerm = get_term(dstCoeff, src, dst, dst);
+
+ MaskedColor output = MaskedColor::SatAdd(srcTerm, dstTerm);
+ *outColor = output.color();
+ *outFlags = output.validFlags();
+}
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index b3544b0..782b82b 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -50,7 +50,7 @@
* we verify the count is as expected. If a new factory is added, then these numbers must be
* manually adjusted.
*/
-static const int kFPFactoryCount = 40;
+static const int kFPFactoryCount = 39;
static const int kGPFactoryCount = 14;
static const int kXPFactoryCount = 5;
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 471c972..ee06f3e 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -734,7 +734,7 @@
SkColor filtered = colorFilter->filterColor(skPaint.getColor());
grPaint->setColor(SkColor2GrColor(filtered));
} else {
- SkTDArray<GrFragmentProcessor*> array;
+ SkTDArray<const GrFragmentProcessor*> array;
// return false if failed?
if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(),
&array)) {
diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp
index f626e7a..0d31034 100644
--- a/src/gpu/effects/GrCustomXfermode.cpp
+++ b/src/gpu/effects/GrCustomXfermode.cpp
@@ -6,7 +6,6 @@
*/
#include "effects/GrCustomXfermode.h"
-#include "effects/GrCustomXfermodePriv.h"
#include "GrCoordTransform.h"
#include "GrContext.h"
@@ -18,6 +17,7 @@
#include "SkXfermode.h"
#include "gl/GrGLCaps.h"
#include "gl/GrGLGpu.h"
+#include "gl/GrGLSLBlend.h"
#include "gl/GrGLFragmentProcessor.h"
#include "gl/GrGLProgramDataManager.h"
#include "gl/builders/GrGLProgramBuilder.h"
@@ -67,452 +67,6 @@
return true;
}
-static void hard_light(GrGLFragmentBuilder* fsBuilder,
- const char* final,
- const char* src,
- const char* dst) {
- static const char kComponents[] = {'r', 'g', 'b'};
- for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
- char component = kComponents[i];
- fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
- fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;",
- final, component, src, component, dst, component);
- fsBuilder->codeAppend("} else {");
- fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);",
- final, component, src, dst, dst, dst, component, src, src,
- component);
- fsBuilder->codeAppend("}");
- }
- fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);",
- final, src, dst, dst, src);
-}
-
-// Does one component of color-dodge
-static void color_dodge_component(GrGLFragmentBuilder* fsBuilder,
- const char* final,
- const char* src,
- const char* dst,
- const char component) {
- fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component);
- fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
- final, component, src, component, dst);
- fsBuilder->codeAppend("} else {");
- fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component);
- fsBuilder->codeAppend("if (0.0 == d) {");
- fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
- final, component, src, dst, src, component, dst, dst, component,
- src);
- fsBuilder->codeAppend("} else {");
- fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);",
- dst, dst, component, src);
- fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
- final, component, src, src, component, dst, dst, component, src);
- fsBuilder->codeAppend("}");
- fsBuilder->codeAppend("}");
-}
-
-// Does one component of color-burn
-static void color_burn_component(GrGLFragmentBuilder* fsBuilder,
- const char* final,
- const char* src,
- const char* dst,
- const char component) {
- fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component);
- fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
- final, component, src, dst, src, component, dst, dst, component,
- src);
- fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component);
- fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
- final, component, dst, component, src);
- fsBuilder->codeAppend("} else {");
- fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);",
- dst, dst, dst, component, src, src, component);
- fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
- final, component, src, src, component, dst, dst, component, src);
- fsBuilder->codeAppend("}");
-}
-
-// Does one component of soft-light. Caller should have already checked that dst alpha > 0.
-static void soft_light_component_pos_dst_alpha(GrGLFragmentBuilder* fsBuilder,
- const char* final,
- const char* src,
- const char* dst,
- const char component) {
- // if (2S < Sa)
- fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
- // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
- fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +"
- "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);",
- final, component, dst, component, dst, component, src, src,
- component, dst, dst, src, component, dst, component, src, src,
- component);
- // else if (4D < Da)
- fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
- dst, component, dst);
- fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;",
- dst, component, dst, component);
- fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component);
- fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst);
- fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst);
- // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
- fsBuilder->codeAppendf("%s.%c ="
- "(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +"
- " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -"
- " DaCub*%s.%c) / DaSqd;",
- final, component, src, component, dst, component,
- src, src, component, dst, src, src, component, src, src,
- component, src, component);
- fsBuilder->codeAppendf("} else {");
- // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
- fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -"
- " sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c;",
- final, component, dst, component, src, src, component, src, component,
- dst, dst, component, src, src, component, dst, src, component);
- fsBuilder->codeAppendf("}");
-}
-
-// Adds a function that takes two colors and an alpha as input. It produces a color with the
-// hue and saturation of the first color, the luminosity of the second color, and the input
-// alpha. It has this signature:
-// vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
-static void add_lum_function(GrGLFragmentBuilder* fsBuilder, SkString* setLumFunction) {
- // Emit a helper that gets the luminance of a color.
- SkString getFunction;
- GrGLShaderVar getLumArgs[] = {
- GrGLShaderVar("color", kVec3f_GrSLType),
- };
- SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);");
- fsBuilder->emitFunction(kFloat_GrSLType,
- "luminance",
- SK_ARRAY_COUNT(getLumArgs), getLumArgs,
- getLumBody.c_str(),
- &getFunction);
-
- // Emit the set luminance function.
- GrGLShaderVar setLumArgs[] = {
- GrGLShaderVar("hueSat", kVec3f_GrSLType),
- GrGLShaderVar("alpha", kFloat_GrSLType),
- GrGLShaderVar("lumColor", kVec3f_GrSLType),
- };
- SkString setLumBody;
- setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str());
- setLumBody.append("vec3 outColor = hueSat + diff;");
- setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str());
- setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);"
- "float maxComp = max(max(outColor.r, outColor.g), outColor.b);"
- "if (minComp < 0.0 && outLum != minComp) {"
- "outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /"
- "(outLum - minComp);"
- "}"
- "if (maxComp > alpha && maxComp != outLum) {"
- "outColor = outLum +"
- "((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /"
- "(maxComp - outLum);"
- "}"
- "return outColor;");
- fsBuilder->emitFunction(kVec3f_GrSLType,
- "set_luminance",
- SK_ARRAY_COUNT(setLumArgs), setLumArgs,
- setLumBody.c_str(),
- setLumFunction);
-}
-
-// Adds a function that creates a color with the hue and luminosity of one input color and
-// the saturation of another color. It will have this signature:
-// float set_saturation(vec3 hueLumColor, vec3 satColor)
-static void add_sat_function(GrGLFragmentBuilder* fsBuilder, SkString* setSatFunction) {
- // Emit a helper that gets the saturation of a color
- SkString getFunction;
- GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
- SkString getSatBody;
- getSatBody.printf("return max(max(color.r, color.g), color.b) - "
- "min(min(color.r, color.g), color.b);");
- fsBuilder->emitFunction(kFloat_GrSLType,
- "saturation",
- SK_ARRAY_COUNT(getSatArgs), getSatArgs,
- getSatBody.c_str(),
- &getFunction);
-
- // Emit a helper that sets the saturation given sorted input channels. This used
- // to use inout params for min, mid, and max components but that seems to cause
- // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
- // adjusted min, mid, and max inputs, respectively.
- SkString helperFunction;
- GrGLShaderVar helperArgs[] = {
- GrGLShaderVar("minComp", kFloat_GrSLType),
- GrGLShaderVar("midComp", kFloat_GrSLType),
- GrGLShaderVar("maxComp", kFloat_GrSLType),
- GrGLShaderVar("sat", kFloat_GrSLType),
- };
- static const char kHelperBody[] = "if (minComp < maxComp) {"
- "vec3 result;"
- "result.r = 0.0;"
- "result.g = sat * (midComp - minComp) / (maxComp - minComp);"
- "result.b = sat;"
- "return result;"
- "} else {"
- "return vec3(0, 0, 0);"
- "}";
- fsBuilder->emitFunction(kVec3f_GrSLType,
- "set_saturation_helper",
- SK_ARRAY_COUNT(helperArgs), helperArgs,
- kHelperBody,
- &helperFunction);
-
- GrGLShaderVar setSatArgs[] = {
- GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
- GrGLShaderVar("satColor", kVec3f_GrSLType),
- };
- const char* helpFunc = helperFunction.c_str();
- SkString setSatBody;
- setSatBody.appendf("float sat = %s(satColor);"
- "if (hueLumColor.r <= hueLumColor.g) {"
- "if (hueLumColor.g <= hueLumColor.b) {"
- "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);"
- "} else if (hueLumColor.r <= hueLumColor.b) {"
- "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);"
- "} else {"
- "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);"
- "}"
- "} else if (hueLumColor.r <= hueLumColor.b) {"
- "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);"
- "} else if (hueLumColor.g <= hueLumColor.b) {"
- "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);"
- "} else {"
- "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);"
- "}"
- "return hueLumColor;",
- getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
- helpFunc, helpFunc);
- fsBuilder->emitFunction(kVec3f_GrSLType,
- "set_saturation",
- SK_ARRAY_COUNT(setSatArgs), setSatArgs,
- setSatBody.c_str(),
- setSatFunction);
-
-}
-
-static void emit_custom_xfermode_code(SkXfermode::Mode mode,
- GrGLFragmentBuilder* fsBuilder,
- const char* outputColor,
- const char* inputColor,
- const char* dstColor) {
- // We don't try to optimize for this case at all
- if (nullptr == inputColor) {
- fsBuilder->codeAppendf("const vec4 ones = vec4(1);");
- inputColor = "ones";
- }
- fsBuilder->codeAppendf("// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
-
- // These all perform src-over on the alpha channel.
- fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;",
- outputColor, inputColor, inputColor, dstColor);
-
- switch (mode) {
- case SkXfermode::kOverlay_Mode:
- // Overlay is Hard-Light with the src and dst reversed
- hard_light(fsBuilder, outputColor, dstColor, inputColor);
- break;
- case SkXfermode::kDarken_Mode:
- fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
- "(1.0 - %s.a) * %s.rgb + %s.rgb);",
- outputColor,
- inputColor, dstColor, inputColor,
- dstColor, inputColor, dstColor);
- break;
- case SkXfermode::kLighten_Mode:
- fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
- "(1.0 - %s.a) * %s.rgb + %s.rgb);",
- outputColor,
- inputColor, dstColor, inputColor,
- dstColor, inputColor, dstColor);
- break;
- case SkXfermode::kColorDodge_Mode:
- color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'r');
- color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'g');
- color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'b');
- break;
- case SkXfermode::kColorBurn_Mode:
- color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'r');
- color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'g');
- color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'b');
- break;
- case SkXfermode::kHardLight_Mode:
- hard_light(fsBuilder, outputColor, inputColor, dstColor);
- break;
- case SkXfermode::kSoftLight_Mode:
- fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor);
- fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, inputColor);
- fsBuilder->codeAppendf("} else {");
- soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'r');
- soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'g');
- soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'b');
- fsBuilder->codeAppendf("}");
- break;
- case SkXfermode::kDifference_Mode:
- fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -"
- "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);",
- outputColor, inputColor, dstColor, inputColor, dstColor,
- dstColor, inputColor);
- break;
- case SkXfermode::kExclusion_Mode:
- fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
- "2.0 * %s.rgb * %s.rgb;",
- outputColor, dstColor, inputColor, dstColor, inputColor);
- break;
- case SkXfermode::kMultiply_Mode:
- fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + "
- "(1.0 - %s.a) * %s.rgb + "
- "%s.rgb * %s.rgb;",
- outputColor, inputColor, dstColor, dstColor, inputColor,
- inputColor, dstColor);
- break;
- case SkXfermode::kHue_Mode: {
- // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
- SkString setSat, setLum;
- add_sat_function(fsBuilder, &setSat);
- add_lum_function(fsBuilder, &setLum);
- fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
- dstColor, inputColor);
- fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb),"
- "dstSrcAlpha.a, dstSrcAlpha.rgb);",
- outputColor, setLum.c_str(), setSat.c_str(), inputColor,
- dstColor);
- fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
- outputColor, inputColor, dstColor, dstColor, inputColor);
- break;
- }
- case SkXfermode::kSaturation_Mode: {
- // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
- SkString setSat, setLum;
- add_sat_function(fsBuilder, &setSat);
- add_lum_function(fsBuilder, &setLum);
- fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
- dstColor, inputColor);
- fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a),"
- "dstSrcAlpha.a, dstSrcAlpha.rgb);",
- outputColor, setLum.c_str(), setSat.c_str(), inputColor,
- dstColor);
- fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
- outputColor, inputColor, dstColor, dstColor, inputColor);
- break;
- }
- case SkXfermode::kColor_Mode: {
- // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
- SkString setLum;
- add_lum_function(fsBuilder, &setLum);
- fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
- inputColor, dstColor);
- fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);",
- outputColor, setLum.c_str(), dstColor, inputColor);
- fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
- outputColor, inputColor, dstColor, dstColor, inputColor);
- break;
- }
- case SkXfermode::kLuminosity_Mode: {
- // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
- SkString setLum;
- add_lum_function(fsBuilder, &setLum);
- fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
- inputColor, dstColor);
- fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);",
- outputColor, setLum.c_str(), dstColor, inputColor);
- fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
- outputColor, inputColor, dstColor, dstColor, inputColor);
- break;
- }
- default:
- SkFAIL("Unknown Custom Xfer mode.");
- break;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Fragment Processor
-///////////////////////////////////////////////////////////////////////////////
-
-GrFragmentProcessor* GrCustomXfermode::CreateFP(GrProcessorDataManager* procDataManager,
- SkXfermode::Mode mode, GrTexture* background) {
- if (!GrCustomXfermode::IsSupportedMode(mode)) {
- return nullptr;
- } else {
- return new GrCustomXferFP(procDataManager, mode, background);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-class GLCustomXferFP : public GrGLFragmentProcessor {
-public:
- GLCustomXferFP(const GrFragmentProcessor&) {}
- ~GLCustomXferFP() override {};
-
- void emitCode(EmitArgs& args) override {
- SkXfermode::Mode mode = args.fFp.cast<GrCustomXferFP>().mode();
- GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
- const char* dstColor = "bgColor";
- fsBuilder->codeAppendf("vec4 %s = ", dstColor);
- fsBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0].c_str(),
- args.fCoords[0].getType());
- fsBuilder->codeAppendf(";");
-
- emit_custom_xfermode_code(mode, fsBuilder, args.fOutputColor, args.fInputColor, dstColor);
- }
-
- static void GenKey(const GrFragmentProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
- // The background may come from the dst or from a texture.
- uint32_t key = proc.numTextures();
- SkASSERT(key <= 1);
- key |= proc.cast<GrCustomXferFP>().mode() << 1;
- b->add32(key);
- }
-
-protected:
- void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override {}
-
-private:
- typedef GrGLFragmentProcessor INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrCustomXferFP::GrCustomXferFP(GrProcessorDataManager*, SkXfermode::Mode mode, GrTexture* background)
- : fMode(mode) {
- this->initClassID<GrCustomXferFP>();
-
- SkASSERT(background);
- fBackgroundTransform.reset(kLocal_GrCoordSet, background,
- GrTextureParams::kNone_FilterMode);
- this->addCoordTransform(&fBackgroundTransform);
- fBackgroundAccess.reset(background);
- this->addTextureAccess(&fBackgroundAccess);
-}
-
-void GrCustomXferFP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
- GLCustomXferFP::GenKey(*this, caps, b);
-}
-
-GrGLFragmentProcessor* GrCustomXferFP::onCreateGLInstance() const {
- return new GLCustomXferFP(*this);
-}
-
-bool GrCustomXferFP::onIsEqual(const GrFragmentProcessor& other) const {
- const GrCustomXferFP& s = other.cast<GrCustomXferFP>();
- return fMode == s.fMode;
-}
-
-void GrCustomXferFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
- inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
-}
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCustomXferFP);
-const GrFragmentProcessor* GrCustomXferFP::TestCreate(GrProcessorTestData* d) {
- int mode = d->fRandom->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
-
- return new GrCustomXferFP(d->fProcDataManager, static_cast<SkXfermode::Mode>(mode),
- d->fTextures[0]);
-}
-
///////////////////////////////////////////////////////////////////////////////
// Xfer Processor
///////////////////////////////////////////////////////////////////////////////
@@ -567,16 +121,6 @@
///////////////////////////////////////////////////////////////////////////////
-GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
- if (!GrCustomXfermode::IsSupportedMode(mode)) {
- return nullptr;
- } else {
- return new GrCustomXPFactory(mode);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
class GLCustomXP : public GrGLXferProcessor {
public:
GLCustomXP(const GrXferProcessor&) {}
@@ -621,7 +165,7 @@
SkASSERT(!xp.hasHWBlendEquation());
GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
- emit_custom_xfermode_code(xp.mode(), fsBuilder, outColor, srcColor, dstColor);
+ GrGLSLBlend::AppendMode(fsBuilder, srcColor, dstColor, outColor, xp.mode());
}
void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
@@ -770,20 +314,54 @@
}
///////////////////////////////////////////////////////////////////////////////
+class CustomXPFactory : public GrXPFactory {
+public:
+ CustomXPFactory(SkXfermode::Mode mode);
-GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode)
+ bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override {
+ return true;
+ }
+
+ void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
+ GrXPFactory::InvariantBlendedColor*) const override;
+
+private:
+ GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ bool hasMixedSamples,
+ const DstTexture*) const override;
+
+ bool willReadDstColor(const GrCaps& caps,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ bool hasMixedSamples) const override;
+
+ bool onIsEqual(const GrXPFactory& xpfBase) const override {
+ const CustomXPFactory& xpf = xpfBase.cast<CustomXPFactory>();
+ return fMode == xpf.fMode;
+ }
+
+ GR_DECLARE_XP_FACTORY_TEST;
+
+ SkXfermode::Mode fMode;
+ GrBlendEquation fHWBlendEquation;
+
+ typedef GrXPFactory INHERITED;
+};
+
+CustomXPFactory::CustomXPFactory(SkXfermode::Mode mode)
: fMode(mode),
fHWBlendEquation(hw_blend_equation(mode)) {
SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
- this->initClassID<GrCustomXPFactory>();
+ this->initClassID<CustomXPFactory>();
}
-GrXferProcessor*
-GrCustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
- const GrProcOptInfo& colorPOI,
- const GrProcOptInfo& coveragePOI,
- bool hasMixedSamples,
- const DstTexture* dstTexture) const {
+GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ bool hasMixedSamples,
+ const DstTexture* dstTexture) const {
if (can_use_hw_blend_equation(fHWBlendEquation, coveragePOI, caps)) {
SkASSERT(!dstTexture || !dstTexture->texture());
return new CustomXP(fMode, fHWBlendEquation);
@@ -791,24 +369,33 @@
return new CustomXP(dstTexture, hasMixedSamples, fMode);
}
-bool GrCustomXPFactory::willReadDstColor(const GrCaps& caps,
- const GrProcOptInfo& colorPOI,
- const GrProcOptInfo& coveragePOI,
- bool hasMixedSamples) const {
+bool CustomXPFactory::willReadDstColor(const GrCaps& caps,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ bool hasMixedSamples) const {
return !can_use_hw_blend_equation(fHWBlendEquation, coveragePOI, caps);
}
-void GrCustomXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
- InvariantBlendedColor* blendedColor) const {
+void CustomXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
+ InvariantBlendedColor* blendedColor) const {
blendedColor->fWillBlendWithDst = true;
blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
}
-GR_DEFINE_XP_FACTORY_TEST(GrCustomXPFactory);
-const GrXPFactory* GrCustomXPFactory::TestCreate(GrProcessorTestData* d) {
+GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory);
+const GrXPFactory* CustomXPFactory::TestCreate(GrProcessorTestData* d) {
int mode = d->fRandom->nextRangeU(SkXfermode::kLastCoeffMode + 1,
SkXfermode::kLastSeparableMode);
- return new GrCustomXPFactory(static_cast<SkXfermode::Mode>(mode));
+ return new CustomXPFactory(static_cast<SkXfermode::Mode>(mode));
}
+///////////////////////////////////////////////////////////////////////////////
+
+GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
+ if (!GrCustomXfermode::IsSupportedMode(mode)) {
+ return nullptr;
+ } else {
+ return new CustomXPFactory(mode);
+ }
+}
diff --git a/src/gpu/effects/GrCustomXfermodePriv.h b/src/gpu/effects/GrCustomXfermodePriv.h
deleted file mode 100644
index 05e07b6..0000000
--- a/src/gpu/effects/GrCustomXfermodePriv.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrCustomXfermodePriv_DEFINED
-#define GrCustomXfermodePriv_DEFINED
-
-#include "GrCaps.h"
-#include "GrCoordTransform.h"
-#include "GrFragmentProcessor.h"
-#include "GrTextureAccess.h"
-#include "GrXferProcessor.h"
-#include "SkXfermode.h"
-
-class GrGLCaps;
-class GrGLFragmentProcessor;
-class GrInvariantOutput;
-class GrProcessorKeyBuilder;
-class GrTexture;
-
-///////////////////////////////////////////////////////////////////////////////
-// Fragment Processor
-///////////////////////////////////////////////////////////////////////////////
-
-class GrCustomXferFP : public GrFragmentProcessor {
-public:
- GrCustomXferFP(GrProcessorDataManager*, SkXfermode::Mode mode, GrTexture* background);
-
- const char* name() const override { return "Custom Xfermode"; }
-
- SkXfermode::Mode mode() const { return fMode; }
- const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; }
-
-private:
- GrGLFragmentProcessor* onCreateGLInstance() const override;
-
- void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
-
- bool onIsEqual(const GrFragmentProcessor& other) const override;
-
- void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- SkXfermode::Mode fMode;
- GrCoordTransform fBackgroundTransform;
- GrTextureAccess fBackgroundAccess;
-
- typedef GrFragmentProcessor INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Xfer Processor
-///////////////////////////////////////////////////////////////////////////////
-
-class GrCustomXPFactory : public GrXPFactory {
-public:
- GrCustomXPFactory(SkXfermode::Mode mode);
-
- bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override {
- return true;
- }
-
- void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
- GrXPFactory::InvariantBlendedColor*) const override;
-
-private:
- GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
- const GrProcOptInfo& colorPOI,
- const GrProcOptInfo& coveragePOI,
- bool hasMixedSamples,
- const DstTexture*) const override;
-
- bool willReadDstColor(const GrCaps& caps,
- const GrProcOptInfo& colorPOI,
- const GrProcOptInfo& coveragePOI,
- bool hasMixedSamples) const override;
-
- bool onIsEqual(const GrXPFactory& xpfBase) const override {
- const GrCustomXPFactory& xpf = xpfBase.cast<GrCustomXPFactory>();
- return fMode == xpf.fMode;
- }
-
- GR_DECLARE_XP_FACTORY_TEST;
-
- SkXfermode::Mode fMode;
- GrBlendEquation fHWBlendEquation;
-
- typedef GrXPFactory INHERITED;
-};
-#endif
-
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index 4c50e47..1312d35 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -13,7 +13,7 @@
#include "GrProcOptInfo.h"
#include "GrTypes.h"
#include "GrXferProcessor.h"
-#include "gl/GrGLBlend.h"
+#include "gl/GrGLSLBlend.h"
#include "gl/GrGLXferProcessor.h"
#include "gl/builders/GrGLFragmentShaderBuilder.h"
#include "gl/builders/GrGLProgramBuilder.h"
@@ -547,7 +547,7 @@
const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
- GrGLBlend::AppendPorterDuffBlend(fsBuilder, srcColor, dstColor, outColor, xp.getXfermode());
+ GrGLSLBlend::AppendMode(fsBuilder, srcColor, dstColor, outColor, xp.getXfermode());
}
void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
@@ -651,7 +651,7 @@
return nullptr;
}
- GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
+ GrColor blendConstant = GrUnpremulColor(colorPOI.color());
uint8_t alpha = GrColorUnpackA(blendConstant);
blendConstant |= (0xff << GrColor_SHIFT_A);
diff --git a/src/gpu/effects/GrSimpleTextureEffect.h b/src/gpu/effects/GrSimpleTextureEffect.h
index 7f66f90..d99c30e 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.h
+++ b/src/gpu/effects/GrSimpleTextureEffect.h
@@ -15,18 +15,16 @@
/**
* The output color of this effect is a modulation of the input color and a sample from a texture.
* It allows explicit specification of the filtering and wrap modes (GrTextureParams). It can use
- * local coords, positions, or a custom vertex attribute as input texture coords. The input coords
- * can have a matrix applied in the VS in both the local and position cases but not with a custom
- * attribute coords at this time. It will add a varying to input interpolate texture coords to the
- * FS.
+ * local coords or device space coords as input texture coords. The input coords may be transformed
+ * by a matrix.
*/
class GrSimpleTextureEffect : public GrSingleTextureEffect {
public:
/* unfiltered, clamp mode */
- static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
- GrTexture* tex,
- const SkMatrix& matrix,
- GrCoordSet coordSet = kLocal_GrCoordSet) {
+ static const GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
+ GrTexture* tex,
+ const SkMatrix& matrix,
+ GrCoordSet coordSet = kLocal_GrCoordSet) {
return new GrSimpleTextureEffect(procDataManager, tex, matrix,
GrTextureParams::kNone_FilterMode, coordSet);
}
diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
index ab944d8..942251c 100644
--- a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
@@ -9,25 +9,23 @@
#include "GrFragmentProcessor.h"
#include "effects/GrConstColorProcessor.h"
-#include "gl/GrGLBlend.h"
+#include "gl/GrGLSLBlend.h"
#include "gl/builders/GrGLProgramBuilder.h"
+#include "SkGr.h"
-
-class GrComposeTwoFragmentProcessor : public GrFragmentProcessor {
+class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
public:
- GrComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragmentProcessor* dst,
+ ComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragmentProcessor* dst,
SkXfermode::Mode mode)
: fMode(mode) {
- // Only coefficient xfer modes are supported
- SkASSERT(SkXfermode::kLastCoeffMode >= mode);
- this->initClassID<GrComposeTwoFragmentProcessor>();
+ this->initClassID<ComposeTwoFragmentProcessor>();
SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(src);
SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(dst);
SkASSERT(0 == shaderAChildIndex);
SkASSERT(1 == shaderBChildIndex);
}
- const char* name() const override { return "ComposeShader"; }
+ const char* name() const override { return "ComposeTwo"; }
void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
b->add32(fMode);
@@ -37,7 +35,7 @@
protected:
bool onIsEqual(const GrFragmentProcessor& other) const override {
- const GrComposeTwoFragmentProcessor& cs = other.cast<GrComposeTwoFragmentProcessor>();
+ const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
return fMode == cs.fMode;
}
@@ -57,9 +55,9 @@
/////////////////////////////////////////////////////////////////////
-class GrGLComposeTwoFragmentProcessor : public GrGLFragmentProcessor {
+class GLComposeTwoFragmentProcessor : public GrGLFragmentProcessor {
public:
- GrGLComposeTwoFragmentProcessor(const GrProcessor& processor) {}
+ GLComposeTwoFragmentProcessor(const GrProcessor& processor) {}
void emitCode(EmitArgs&) override;
@@ -69,28 +67,28 @@
/////////////////////////////////////////////////////////////////////
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrComposeTwoFragmentProcessor);
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor);
-const GrFragmentProcessor* GrComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
+const GrFragmentProcessor* ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
// Create two random frag procs.
SkAutoTUnref<const GrFragmentProcessor> fpA(GrProcessorUnitTest::CreateChildFP(d));
SkAutoTUnref<const GrFragmentProcessor> fpB(GrProcessorUnitTest::CreateChildFP(d));
SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(
- d->fRandom->nextRangeU(0, SkXfermode::kLastCoeffMode));
- return SkNEW_ARGS(GrComposeTwoFragmentProcessor, (fpA, fpB, mode));
+ d->fRandom->nextRangeU(0, SkXfermode::kLastMode));
+ return new ComposeTwoFragmentProcessor(fpA, fpB, mode);
}
-GrGLFragmentProcessor* GrComposeTwoFragmentProcessor::onCreateGLInstance() const{
- return SkNEW_ARGS(GrGLComposeTwoFragmentProcessor, (*this));
+GrGLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLInstance() const{
+ return new GLComposeTwoFragmentProcessor(*this);
}
/////////////////////////////////////////////////////////////////////
-void GrGLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
+void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
- const GrComposeTwoFragmentProcessor& cs = args.fFp.cast<GrComposeTwoFragmentProcessor>();
+ const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>();
// Store alpha of input color and un-premultiply the input color by its alpha. We will
// re-multiply by this alpha after blending the output colors of the two child procs.
@@ -122,8 +120,8 @@
SkXfermode::Mode mode = cs.getMode();
fsBuilder->codeAppend("{");
fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
- GrGLBlend::AppendPorterDuffBlend(fsBuilder, outputColorSrc.c_str(),
- outputColorDst.c_str(), args.fOutputColor, mode);
+ GrGLSLBlend::AppendMode(fsBuilder, outputColorSrc.c_str(),
+ outputColorDst.c_str(), args.fOutputColor, mode);
fsBuilder->codeAppend("}");
// re-multiply the output color by the input color's alpha
@@ -134,21 +132,184 @@
const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromTwoProcessors(
const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkXfermode::Mode mode) {
- if (SkXfermode::kLastCoeffMode < mode) {
- return nullptr;
- }
switch (mode) {
case SkXfermode::kClear_Mode:
- return GrConstColorProcessor::Create(GrColor_TRANS_BLACK,
+ return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
GrConstColorProcessor::kIgnore_InputMode);
- break;
case SkXfermode::kSrc_Mode:
return SkRef(src);
- break;
case SkXfermode::kDst_Mode:
return SkRef(dst);
- break;
default:
- return new GrComposeTwoFragmentProcessor(src, dst, mode);
+ return new ComposeTwoFragmentProcessor(src, dst, mode);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+class ComposeOneFragmentProcessor : public GrFragmentProcessor {
+public:
+ enum Child {
+ kDst_Child,
+ kSrc_Child,
+ };
+
+ ComposeOneFragmentProcessor(const GrFragmentProcessor* dst, SkXfermode::Mode mode, Child child)
+ : fMode(mode)
+ , fChild(child) {
+ this->initClassID<ComposeOneFragmentProcessor>();
+ SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst);
+ SkASSERT(0 == dstIndex);
+ }
+
+ const char* name() const override { return "ComposeOne"; }
+
+ void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
+ GR_STATIC_ASSERT((SkXfermode::kLastMode & SK_MaxU16) == SkXfermode::kLastMode);
+ b->add32(fMode | (fChild << 16));
+ }
+
+ SkXfermode::Mode mode() const { return fMode; }
+
+ Child child() const { return fChild; }
+
+protected:
+ bool onIsEqual(const GrFragmentProcessor& that) const override {
+ return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
+ }
+
+ void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
+ SkXfermode::Coeff skSrcCoeff, skDstCoeff;
+ if (SkXfermode::ModeAsCoeff(fMode, &skSrcCoeff, &skDstCoeff)) {
+ GrBlendCoeff srcCoeff = SkXfermodeCoeffToGrBlendCoeff(skSrcCoeff);
+ GrBlendCoeff dstCoeff = SkXfermodeCoeffToGrBlendCoeff(skDstCoeff);
+ GrInvariantOutput childOutput(0xFFFFFFFF, kRGBA_GrColorComponentFlags, false);
+ this->childProcessor(0).computeInvariantOutput(&childOutput);
+ GrColor blendColor;
+ GrColorComponentFlags blendFlags;
+ if (kDst_Child == fChild) {
+ GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
+ inout->color(), inout->validFlags(),
+ childOutput.color(), childOutput.validFlags(),
+ &blendColor, &blendFlags);
+ } else {
+ GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
+ childOutput.color(), childOutput.validFlags(),
+ inout->color(), inout->validFlags(),
+ &blendColor, &blendFlags);
+ }
+ // will the shader code reference the input color?
+ GrInvariantOutput::ReadInput readsInput = GrInvariantOutput::kWillNot_ReadInput;
+ if (kDst_Child == fChild) {
+ if (kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff)) {
+ readsInput = GrInvariantOutput::kWill_ReadInput;
+ }
+ } else {
+ if (kZero_GrBlendCoeff != dstCoeff || GrBlendCoeffRefsDst(srcCoeff)) {
+ readsInput = GrInvariantOutput::kWill_ReadInput;
+ }
+ }
+ inout->setToOther(blendFlags, blendColor, readsInput);
+ } else {
+ inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
+ }
+ }
+
+private:
+ GrGLFragmentProcessor* onCreateGLInstance() const override;
+
+ SkXfermode::Mode fMode;
+ Child fChild;
+
+ GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
+
+ typedef GrFragmentProcessor INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+class GLComposeOneFragmentProcessor : public GrGLFragmentProcessor {
+public:
+ GLComposeOneFragmentProcessor(const GrProcessor& processor) {}
+
+ void emitCode(EmitArgs& args) override {
+ GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
+ SkXfermode::Mode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
+ ComposeOneFragmentProcessor::Child child =
+ args.fFp.cast<ComposeOneFragmentProcessor>().child();
+ // declare _dstColor and emit the code for the two child
+ fsBuilder->codeAppendf("vec4 _child;");
+ this->emitChild(0, nullptr, "_child", args);
+
+ const char* inputColor = args.fInputColor;
+ // We don't try to optimize for this case at all
+ if (!inputColor) {
+ fsBuilder->codeAppendf("const vec4 ones = vec4(1);");
+ inputColor = "ones";
+ }
+
+ // emit blend code
+ fsBuilder->codeAppend("{");
+ fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
+ if (ComposeOneFragmentProcessor::kDst_Child == child) {
+ GrGLSLBlend::AppendMode(fsBuilder, inputColor, "_child", args.fOutputColor, mode);
+ } else {
+ GrGLSLBlend::AppendMode(fsBuilder, "_child", inputColor, args.fOutputColor, mode);
+ }
+ fsBuilder->codeAppend("}");
+ }
+
+private:
+ typedef GrGLFragmentProcessor INHERITED;
+};
+
+/////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
+
+const GrFragmentProcessor* ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) {
+ // Create one random frag procs.
+ // For now, we'll prevent either children from being a shader with children to prevent the
+ // possibility of an arbitrarily large tree of procs.
+ SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d));
+ SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(
+ d->fRandom->nextRangeU(0, SkXfermode::kLastMode));
+ ComposeOneFragmentProcessor::Child child = d->fRandom->nextBool() ?
+ ComposeOneFragmentProcessor::kDst_Child :
+ ComposeOneFragmentProcessor::kSrc_Child;
+ return new ComposeOneFragmentProcessor(dst, mode, child);
+}
+
+GrGLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLInstance() const {
+ return new GLComposeOneFragmentProcessor(*this);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromDstProcessor(
+ const GrFragmentProcessor* dst, SkXfermode::Mode mode) {
+ switch (mode) {
+ case SkXfermode::kClear_Mode:
+ return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
+ GrConstColorProcessor::kIgnore_InputMode);
+ case SkXfermode::kSrc_Mode:
+ return nullptr;
+ default:
+ return new ComposeOneFragmentProcessor(dst, mode,
+ ComposeOneFragmentProcessor::kDst_Child);
+ }
+}
+
+const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromSrcProcessor(
+ const GrFragmentProcessor* src, SkXfermode::Mode mode) {
+ switch (mode) {
+ case SkXfermode::kClear_Mode:
+ return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
+ GrConstColorProcessor::kIgnore_InputMode);
+ case SkXfermode::kDst_Mode:
+ return nullptr;
+ default:
+ return new ComposeOneFragmentProcessor(src, mode,
+ ComposeOneFragmentProcessor::kSrc_Child);
}
}
diff --git a/src/gpu/gl/GrGLBlend.cpp b/src/gpu/gl/GrGLBlend.cpp
deleted file mode 100644
index 4179ec0..0000000
--- a/src/gpu/gl/GrGLBlend.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include "GrGLBlend.h"
-#include "gl/builders/GrGLFragmentShaderBuilder.h"
-
-static bool append_porterduff_term(GrGLFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff,
- const char* colorName, const char* srcColorName,
- const char* dstColorName, bool hasPrevious) {
- if (SkXfermode::kZero_Coeff == coeff) {
- return hasPrevious;
- } else {
- if (hasPrevious) {
- fsBuilder->codeAppend(" + ");
- }
- fsBuilder->codeAppendf("%s", colorName);
- switch (coeff) {
- case SkXfermode::kOne_Coeff:
- break;
- case SkXfermode::kSC_Coeff:
- fsBuilder->codeAppendf(" * %s", srcColorName);
- break;
- case SkXfermode::kISC_Coeff:
- fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
- break;
- case SkXfermode::kDC_Coeff:
- fsBuilder->codeAppendf(" * %s", dstColorName);
- break;
- case SkXfermode::kIDC_Coeff:
- fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
- break;
- case SkXfermode::kSA_Coeff:
- fsBuilder->codeAppendf(" * %s.a", srcColorName);
- break;
- case SkXfermode::kISA_Coeff:
- fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
- break;
- case SkXfermode::kDA_Coeff:
- fsBuilder->codeAppendf(" * %s.a", dstColorName);
- break;
- case SkXfermode::kIDA_Coeff:
- fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
- break;
- default:
- SkFAIL("Unsupported Blend Coeff");
- }
- return true;
- }
-}
-
-void GrGLBlend::AppendPorterDuffBlend(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
- const char* dstColor, const char* outColor,
- SkXfermode::Mode mode) {
-
- SkXfermode::Coeff srcCoeff, dstCoeff;
- SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff);
-
- fsBuilder->codeAppendf("%s = ", outColor);
- // append src blend
- bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
- false);
- // append dst blend
- if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
- fsBuilder->codeAppend("vec4(0, 0, 0, 0)");
- }
- fsBuilder->codeAppend(";");
-}
diff --git a/src/gpu/gl/GrGLSLBlend.cpp b/src/gpu/gl/GrGLSLBlend.cpp
new file mode 100644
index 0000000..b6224e8
--- /dev/null
+++ b/src/gpu/gl/GrGLSLBlend.cpp
@@ -0,0 +1,435 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "GrGLSLBlend.h"
+#include "gl/builders/GrGLFragmentShaderBuilder.h"
+
+//////////////////////////////////////////////////////////////////////////////
+// Advanced (non-coeff) blend helpers
+//////////////////////////////////////////////////////////////////////////////
+
+static void hard_light(GrGLFragmentBuilder* fsBuilder,
+ const char* final,
+ const char* src,
+ const char* dst) {
+ static const char kComponents[] = { 'r', 'g', 'b' };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
+ char component = kComponents[i];
+ fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
+ fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;",
+ final, component, src, component, dst, component);
+ fsBuilder->codeAppend("} else {");
+ fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);",
+ final, component, src, dst, dst, dst, component, src, src,
+ component);
+ fsBuilder->codeAppend("}");
+ }
+ fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);",
+ final, src, dst, dst, src);
+}
+
+// Does one component of color-dodge
+static void color_dodge_component(GrGLFragmentBuilder* fsBuilder,
+ const char* final,
+ const char* src,
+ const char* dst,
+ const char component) {
+ fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component);
+ fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
+ final, component, src, component, dst);
+ fsBuilder->codeAppend("} else {");
+ fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component);
+ fsBuilder->codeAppend("if (0.0 == d) {");
+ fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
+ final, component, src, dst, src, component, dst, dst, component,
+ src);
+ fsBuilder->codeAppend("} else {");
+ fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);",
+ dst, dst, component, src);
+ fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
+ final, component, src, src, component, dst, dst, component, src);
+ fsBuilder->codeAppend("}");
+ fsBuilder->codeAppend("}");
+}
+
+// Does one component of color-burn
+static void color_burn_component(GrGLFragmentBuilder* fsBuilder,
+ const char* final,
+ const char* src,
+ const char* dst,
+ const char component) {
+ fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component);
+ fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
+ final, component, src, dst, src, component, dst, dst, component,
+ src);
+ fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component);
+ fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
+ final, component, dst, component, src);
+ fsBuilder->codeAppend("} else {");
+ fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);",
+ dst, dst, dst, component, src, src, component);
+ fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
+ final, component, src, src, component, dst, dst, component, src);
+ fsBuilder->codeAppend("}");
+}
+
+// Does one component of soft-light. Caller should have already checked that dst alpha > 0.
+static void soft_light_component_pos_dst_alpha(GrGLFragmentBuilder* fsBuilder,
+ const char* final,
+ const char* src,
+ const char* dst,
+ const char component) {
+ // if (2S < Sa)
+ fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
+ // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
+ fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +"
+ "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);",
+ final, component, dst, component, dst, component, src, src,
+ component, dst, dst, src, component, dst, component, src, src,
+ component);
+ // else if (4D < Da)
+ fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
+ dst, component, dst);
+ fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;",
+ dst, component, dst, component);
+ fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component);
+ fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst);
+ fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst);
+ // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
+ fsBuilder->codeAppendf("%s.%c ="
+ "(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +"
+ " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -"
+ " DaCub*%s.%c) / DaSqd;",
+ final, component, src, component, dst, component,
+ src, src, component, dst, src, src, component, src, src,
+ component, src, component);
+ fsBuilder->codeAppendf("} else {");
+ // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
+ fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -"
+ " sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c;",
+ final, component, dst, component, src, src, component, src, component,
+ dst, dst, component, src, src, component, dst, src, component);
+ fsBuilder->codeAppendf("}");
+}
+
+// Adds a function that takes two colors and an alpha as input. It produces a color with the
+// hue and saturation of the first color, the luminosity of the second color, and the input
+// alpha. It has this signature:
+// vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
+static void add_lum_function(GrGLFragmentBuilder* fsBuilder, SkString* setLumFunction) {
+ // Emit a helper that gets the luminance of a color.
+ SkString getFunction;
+ GrGLShaderVar getLumArgs[] = {
+ GrGLShaderVar("color", kVec3f_GrSLType),
+ };
+ SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);");
+ fsBuilder->emitFunction(kFloat_GrSLType,
+ "luminance",
+ SK_ARRAY_COUNT(getLumArgs), getLumArgs,
+ getLumBody.c_str(),
+ &getFunction);
+
+ // Emit the set luminance function.
+ GrGLShaderVar setLumArgs[] = {
+ GrGLShaderVar("hueSat", kVec3f_GrSLType),
+ GrGLShaderVar("alpha", kFloat_GrSLType),
+ GrGLShaderVar("lumColor", kVec3f_GrSLType),
+ };
+ SkString setLumBody;
+ setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str());
+ setLumBody.append("vec3 outColor = hueSat + diff;");
+ setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str());
+ setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);"
+ "float maxComp = max(max(outColor.r, outColor.g), outColor.b);"
+ "if (minComp < 0.0 && outLum != minComp) {"
+ "outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /"
+ "(outLum - minComp);"
+ "}"
+ "if (maxComp > alpha && maxComp != outLum) {"
+ "outColor = outLum +"
+ "((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /"
+ "(maxComp - outLum);"
+ "}"
+ "return outColor;");
+ fsBuilder->emitFunction(kVec3f_GrSLType,
+ "set_luminance",
+ SK_ARRAY_COUNT(setLumArgs), setLumArgs,
+ setLumBody.c_str(),
+ setLumFunction);
+}
+
+// Adds a function that creates a color with the hue and luminosity of one input color and
+// the saturation of another color. It will have this signature:
+// float set_saturation(vec3 hueLumColor, vec3 satColor)
+static void add_sat_function(GrGLFragmentBuilder* fsBuilder, SkString* setSatFunction) {
+ // Emit a helper that gets the saturation of a color
+ SkString getFunction;
+ GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
+ SkString getSatBody;
+ getSatBody.printf("return max(max(color.r, color.g), color.b) - "
+ "min(min(color.r, color.g), color.b);");
+ fsBuilder->emitFunction(kFloat_GrSLType,
+ "saturation",
+ SK_ARRAY_COUNT(getSatArgs), getSatArgs,
+ getSatBody.c_str(),
+ &getFunction);
+
+ // Emit a helper that sets the saturation given sorted input channels. This used
+ // to use inout params for min, mid, and max components but that seems to cause
+ // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
+ // adjusted min, mid, and max inputs, respectively.
+ SkString helperFunction;
+ GrGLShaderVar helperArgs[] = {
+ GrGLShaderVar("minComp", kFloat_GrSLType),
+ GrGLShaderVar("midComp", kFloat_GrSLType),
+ GrGLShaderVar("maxComp", kFloat_GrSLType),
+ GrGLShaderVar("sat", kFloat_GrSLType),
+ };
+ static const char kHelperBody[] = "if (minComp < maxComp) {"
+ "vec3 result;"
+ "result.r = 0.0;"
+ "result.g = sat * (midComp - minComp) / (maxComp - minComp);"
+ "result.b = sat;"
+ "return result;"
+ "} else {"
+ "return vec3(0, 0, 0);"
+ "}";
+ fsBuilder->emitFunction(kVec3f_GrSLType,
+ "set_saturation_helper",
+ SK_ARRAY_COUNT(helperArgs), helperArgs,
+ kHelperBody,
+ &helperFunction);
+
+ GrGLShaderVar setSatArgs[] = {
+ GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
+ GrGLShaderVar("satColor", kVec3f_GrSLType),
+ };
+ const char* helpFunc = helperFunction.c_str();
+ SkString setSatBody;
+ setSatBody.appendf("float sat = %s(satColor);"
+ "if (hueLumColor.r <= hueLumColor.g) {"
+ "if (hueLumColor.g <= hueLumColor.b) {"
+ "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);"
+ "} else if (hueLumColor.r <= hueLumColor.b) {"
+ "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);"
+ "} else {"
+ "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);"
+ "}"
+ "} else if (hueLumColor.r <= hueLumColor.b) {"
+ "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);"
+ "} else if (hueLumColor.g <= hueLumColor.b) {"
+ "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);"
+ "} else {"
+ "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);"
+ "}"
+ "return hueLumColor;",
+ getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
+ helpFunc, helpFunc);
+ fsBuilder->emitFunction(kVec3f_GrSLType,
+ "set_saturation",
+ SK_ARRAY_COUNT(setSatArgs), setSatArgs,
+ setSatBody.c_str(),
+ setSatFunction);
+}
+
+static void emit_advanced_xfermode_code(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
+ const char* dstColor, const char* outputColor,
+ SkXfermode::Mode mode) {
+ SkASSERT(srcColor);
+ SkASSERT(dstColor);
+ SkASSERT(outputColor);
+ // These all perform src-over on the alpha channel.
+ fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;",
+ outputColor, srcColor, srcColor, dstColor);
+
+ switch (mode) {
+ case SkXfermode::kOverlay_Mode:
+ // Overlay is Hard-Light with the src and dst reversed
+ hard_light(fsBuilder, outputColor, dstColor, srcColor);
+ break;
+ case SkXfermode::kDarken_Mode:
+ fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
+ "(1.0 - %s.a) * %s.rgb + %s.rgb);",
+ outputColor,
+ srcColor, dstColor, srcColor,
+ dstColor, srcColor, dstColor);
+ break;
+ case SkXfermode::kLighten_Mode:
+ fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
+ "(1.0 - %s.a) * %s.rgb + %s.rgb);",
+ outputColor,
+ srcColor, dstColor, srcColor,
+ dstColor, srcColor, dstColor);
+ break;
+ case SkXfermode::kColorDodge_Mode:
+ color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
+ color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
+ color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
+ break;
+ case SkXfermode::kColorBurn_Mode:
+ color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
+ color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
+ color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
+ break;
+ case SkXfermode::kHardLight_Mode:
+ hard_light(fsBuilder, outputColor, srcColor, dstColor);
+ break;
+ case SkXfermode::kSoftLight_Mode:
+ fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor);
+ fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, srcColor);
+ fsBuilder->codeAppendf("} else {");
+ soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'r');
+ soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'g');
+ soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'b');
+ fsBuilder->codeAppendf("}");
+ break;
+ case SkXfermode::kDifference_Mode:
+ fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -"
+ "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);",
+ outputColor, srcColor, dstColor, srcColor, dstColor,
+ dstColor, srcColor);
+ break;
+ case SkXfermode::kExclusion_Mode:
+ fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
+ "2.0 * %s.rgb * %s.rgb;",
+ outputColor, dstColor, srcColor, dstColor, srcColor);
+ break;
+ case SkXfermode::kMultiply_Mode:
+ fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + "
+ "(1.0 - %s.a) * %s.rgb + "
+ "%s.rgb * %s.rgb;",
+ outputColor, srcColor, dstColor, dstColor, srcColor,
+ srcColor, dstColor);
+ break;
+ case SkXfermode::kHue_Mode: {
+ // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
+ SkString setSat, setLum;
+ add_sat_function(fsBuilder, &setSat);
+ add_lum_function(fsBuilder, &setLum);
+ fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
+ dstColor, srcColor);
+ fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb),"
+ "dstSrcAlpha.a, dstSrcAlpha.rgb);",
+ outputColor, setLum.c_str(), setSat.c_str(), srcColor,
+ dstColor);
+ fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
+ outputColor, srcColor, dstColor, dstColor, srcColor);
+ break;
+ }
+ case SkXfermode::kSaturation_Mode: {
+ // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
+ SkString setSat, setLum;
+ add_sat_function(fsBuilder, &setSat);
+ add_lum_function(fsBuilder, &setLum);
+ fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
+ dstColor, srcColor);
+ fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a),"
+ "dstSrcAlpha.a, dstSrcAlpha.rgb);",
+ outputColor, setLum.c_str(), setSat.c_str(), srcColor,
+ dstColor);
+ fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
+ outputColor, srcColor, dstColor, dstColor, srcColor);
+ break;
+ }
+ case SkXfermode::kColor_Mode: {
+ // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
+ SkString setLum;
+ add_lum_function(fsBuilder, &setLum);
+ fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
+ srcColor, dstColor);
+ fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);",
+ outputColor, setLum.c_str(), dstColor, srcColor);
+ fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
+ outputColor, srcColor, dstColor, dstColor, srcColor);
+ break;
+ }
+ case SkXfermode::kLuminosity_Mode: {
+ // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
+ SkString setLum;
+ add_lum_function(fsBuilder, &setLum);
+ fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
+ srcColor, dstColor);
+ fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);",
+ outputColor, setLum.c_str(), dstColor, srcColor);
+ fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
+ outputColor, srcColor, dstColor, dstColor, srcColor);
+ break;
+ }
+ default:
+ SkFAIL("Unknown Custom Xfer mode.");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Porter-Duff blend helper
+//////////////////////////////////////////////////////////////////////////////
+
+static bool append_porterduff_term(GrGLFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff,
+ const char* colorName, const char* srcColorName,
+ const char* dstColorName, bool hasPrevious) {
+ if (SkXfermode::kZero_Coeff == coeff) {
+ return hasPrevious;
+ } else {
+ if (hasPrevious) {
+ fsBuilder->codeAppend(" + ");
+ }
+ fsBuilder->codeAppendf("%s", colorName);
+ switch (coeff) {
+ case SkXfermode::kOne_Coeff:
+ break;
+ case SkXfermode::kSC_Coeff:
+ fsBuilder->codeAppendf(" * %s", srcColorName);
+ break;
+ case SkXfermode::kISC_Coeff:
+ fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
+ break;
+ case SkXfermode::kDC_Coeff:
+ fsBuilder->codeAppendf(" * %s", dstColorName);
+ break;
+ case SkXfermode::kIDC_Coeff:
+ fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
+ break;
+ case SkXfermode::kSA_Coeff:
+ fsBuilder->codeAppendf(" * %s.a", srcColorName);
+ break;
+ case SkXfermode::kISA_Coeff:
+ fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
+ break;
+ case SkXfermode::kDA_Coeff:
+ fsBuilder->codeAppendf(" * %s.a", dstColorName);
+ break;
+ case SkXfermode::kIDA_Coeff:
+ fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
+ break;
+ default:
+ SkFAIL("Unsupported Blend Coeff");
+ }
+ return true;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GrGLSLBlend::AppendMode(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
+ const char* dstColor, const char* outColor,
+ SkXfermode::Mode mode) {
+
+ SkXfermode::Coeff srcCoeff, dstCoeff;
+ if (SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff)) {
+ fsBuilder->codeAppendf("%s = ", outColor);
+ // append src blend
+ bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
+ false);
+ // append dst blend
+ if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
+ fsBuilder->codeAppend("vec4(0, 0, 0, 0)");
+ }
+ fsBuilder->codeAppend(";");
+ } else {
+ emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode);
+ }
+}
diff --git a/src/gpu/gl/GrGLBlend.h b/src/gpu/gl/GrGLSLBlend.h
similarity index 67%
rename from src/gpu/gl/GrGLBlend.h
rename to src/gpu/gl/GrGLSLBlend.h
index af447b4..b763f45 100644
--- a/src/gpu/gl/GrGLBlend.h
+++ b/src/gpu/gl/GrGLSLBlend.h
@@ -12,13 +12,13 @@
class GrGLFragmentBuilder;
-namespace GrGLBlend {
+namespace GrGLSLBlend {
/*
* Appends GLSL code to fsBuilder that assigns a specified blend of the srcColor and dstColor
* variables to the outColor variable.
*/
- void AppendPorterDuffBlend(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
- const char* dstColor, const char* outColor, SkXfermode::Mode mode);
+ void AppendMode(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
+ const char* dstColor, const char* outColor, SkXfermode::Mode mode);
};
#endif